--!optimize 2 -- GENERATED by tools/bundle.py from *.lua, backends/, fonts/ - do not edit local __FILES, __LOADED = {}, {} function IM_INCLUDE(name) local r = __LOADED[name] if r == nil then r = __FILES[name](); if r == nil then r = true end; __LOADED[name] = r end return r end __FILES['imgui.lua'] = function() --- Dear ImGui WIP -- (Core Code) --- Flags: -- IMGUI_DISABLE_OBSOLETE_FUNCTIONS = true -- This flag is not implemented -- NOTE: you must implement ImStd.ImFileOpen if you are not in GMod IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS = true -- Don't implement ImStd.ImFileOpen/ImStd.ImFileClose/ImStd.ImFileRead/ImFileWrite so you can implement them yourself IMGUI_DISABLE_DEBUG_TOOLS = false -- Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty --- @type ImGuiContext? local GImGui = nil ImGui = {} ImStd = {} -- Contains functions that originally don't belong to cpp namespaces -- IM_INCLUDE(name) is provided by the bundle (see tools/bundle.py): runs the bundled file once, returns its result. function ImGui._GetTypeFunc() return type end local function LUA_TableConstructorWrapper(T, size, userdata) local p = {} for i = 1, size do p[i] = T() end return p end local GImAllocatorAllocFunc = LUA_TableConstructorWrapper local GImAllocatorFreeFunc = function(p0, p1, p2) end local GImAllocatorUserData = nil --- @param constructor function --- @param size int function ImGui.MemAlloc(constructor, size) local p = GImAllocatorAllocFunc(constructor, size, GImAllocatorUserData) local ctx = GImGui if ctx then ImGui.DebugAllocHook(ctx.DebugAllocInfo, ctx.FrameCount, p, size) end return p end -- This does not set `owner[field]` to nil! --- @param owner table --- @param field string|int function ImGui.MemFree(owner, field) if owner ~= nil then local ctx = GImGui if ctx then ImGui.DebugAllocHook(ctx.DebugAllocInfo, ctx.FrameCount, owner, -1) end end return GImAllocatorFreeFunc(owner, field, GImAllocatorUserData) end --- @param info ImGuiDebugAllocInfo --- @param frame_count int --- @param ptr table --- @param size size_t function ImGui.DebugAllocHook(info, frame_count, ptr, size) local entry = info.LastEntriesBuf[info.LastEntriesIdx] if entry.FrameCount ~= frame_count then info.LastEntriesIdx = info.LastEntriesIdx % (#info.LastEntriesBuf) + 1 entry = info.LastEntriesBuf[info.LastEntriesIdx] entry.FrameCount = frame_count entry.AllocCount = 0 entry.FreeCount = 0 end if size ~= -1 then -- print(string.format("[%05d] MemAlloc(%d) -> %p", frame_count, size, ptr)) entry.AllocCount = entry.AllocCount + 1 info.TotalAllocCount = info.TotalAllocCount + 1 else -- print(string.format("[%05d] MemFree(%p)", frame_count, ptr)) entry.FreeCount = entry.FreeCount + 1 info.TotalFreeCount = info.TotalFreeCount + 1 end end IM_INCLUDE"imgui_h.lua" IM_INCLUDE"imgui_internal.lua" IM_INCLUDE"imgui_draw.lua" IM_INCLUDE"imgui_widgets.lua" IM_INCLUDE"imgui_tables.lua" do --[[ [SECTION] imgui_dragdrop (was imgui_dragdrop.lua) ]] --- Dear ImGui -- Drag and drop: 1:1 port of imgui.cpp [SECTION] DRAG AND DROP (docking branch) -- Payload `Data` is any Lua value (no copy is made). `data_size` is optional and only kept for API parity. function ImGui.IsDragDropActive() return ImGui.GetCurrentContext().DragDropActive end function ImGui.ClearDragDrop() local g = ImGui.GetCurrentContext() g.DragDropActive = false ImGuiPayload_Clear(g.DragDropPayload) g.DragDropAcceptFlagsCurr = ImGuiDragDropFlags.None g.DragDropAcceptIdCurr = 0 g.DragDropAcceptIdPrev = 0 g.DragDropAcceptIdCurrRectSurface = FLT_MAX g.DragDropAcceptFrameCount = -1 end function ImGui.BeginDragDropSource(flags) if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local mouse_button = ImGuiMouseButton.Left local source_drag_active = false local source_id = 0 local source_parent_id = 0 if bit32.band(flags, ImGuiDragDropFlags.SourceExtern) == 0 then source_id = g.LastItemData.ID if source_id ~= 0 then if g.ActiveId ~= source_id then return false end if g.ActiveIdMouseButton ~= -1 then mouse_button = g.ActiveIdMouseButton end if g.IO.MouseDown[mouse_button] == false or window.SkipItems then return false end g.ActiveIdAllowOverlap = false else if g.IO.MouseDown[mouse_button] == false or window.SkipItems then return false end if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredRect) == 0 and (g.ActiveId == 0 or g.ActiveIdWindow ~= window) then return false end if bit32.band(flags, ImGuiDragDropFlags.SourceAllowNullID) == 0 then IM_ASSERT(false, "Use ImGuiDragDropFlags.SourceAllowNullID for items without an ID") return false end source_id = window:GetIDFromRectangle(g.LastItemData.Rect) g.LastItemData.ID = source_id ImGui.KeepAliveID(source_id) local is_hovered = ImGui.ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.ItemFlags) if is_hovered and g.IO.MouseClicked[mouse_button] then ImGui.SetActiveID(source_id, window) ImGui.FocusWindow(window) end if g.ActiveId == source_id then g.ActiveIdAllowOverlap = is_hovered end end if g.ActiveId ~= source_id then return false end source_parent_id = window.IDStack.Data[window.IDStack.Size] source_drag_active = ImGui.IsMouseDragging(mouse_button) ImGui.SetActiveIdUsingAllKeyboardKeys() else window = nil source_id = ImHashStr("#SourceExtern") source_drag_active = true mouse_button = g.IO.MouseDown[0] and 0 or -1 ImGui.KeepAliveID(source_id) ImGui.SetActiveID(source_id, nil) end IM_ASSERT(g.DragDropWithinTarget == false) if not source_drag_active then return false end if not g.DragDropActive then IM_ASSERT(source_id ~= 0) ImGui.ClearDragDrop() local payload = g.DragDropPayload payload.SourceId = source_id payload.SourceParentId = source_parent_id g.DragDropActive = true g.DragDropSourceFlags = flags g.DragDropMouseButton = mouse_button if payload.SourceId == g.ActiveId then g.ActiveIdNoClearOnFocusLoss = true end end g.DragDropSourceFrameCount = g.FrameCount g.DragDropWithinSource = true if bit32.band(flags, ImGuiDragDropFlags.SourceNoPreviewTooltip) == 0 then local ret if g.DragDropAcceptIdPrev ~= 0 and bit32.band(g.DragDropAcceptFlagsPrev, ImGuiDragDropFlags.AcceptNoPreviewTooltip) ~= 0 then ret = ImGui.BeginTooltipHidden() else ret = ImGui.BeginTooltip() end IM_ASSERT(ret) end if bit32.band(flags, ImGuiDragDropFlags.SourceNoDisableHover) == 0 and bit32.band(flags, ImGuiDragDropFlags.SourceExtern) == 0 then g.LastItemData.StatusFlags = bit32.band(g.LastItemData.StatusFlags, bit32.bnot(ImGuiItemStatusFlags.HoveredRect)) end return true end function ImGui.EndDragDropSource() local g = ImGui.GetCurrentContext() IM_ASSERT(g.DragDropActive) IM_ASSERT(g.DragDropWithinSource, "Not after a BeginDragDropSource()?") if bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceNoPreviewTooltip) == 0 then ImGui.EndTooltip() end if g.DragDropPayload.DataFrameCount == -1 then ImGui.ClearDragDrop() end g.DragDropWithinSource = false end --- @param data any # any Lua value --- @return bool accepted function ImGui.SetDragDropPayload(type, data, data_size, cond) local g = ImGui.GetCurrentContext() local payload = g.DragDropPayload if cond == nil or cond == 0 then cond = ImGuiCond.Always end IM_ASSERT(type ~= nil) IM_ASSERT(#type < 32, "Payload type can be at most 32 characters long") IM_ASSERT(cond == ImGuiCond.Always or cond == ImGuiCond.Once) IM_ASSERT(payload.SourceId ~= 0) if cond == ImGuiCond.Always or payload.DataFrameCount == -1 then payload.DataType = type payload.Data = data payload.DataSize = data_size or ((data ~= nil) and 1 or 0) end payload.DataFrameCount = g.FrameCount return (g.DragDropAcceptFrameCount == g.FrameCount) or (g.DragDropAcceptFrameCount == g.FrameCount - 1) end function ImGui.BeginDragDropTargetCustom(bb, id) local g = ImGui.GetCurrentContext() if not g.DragDropActive then return false end local window = g.CurrentWindow local hovered_window = g.HoveredWindowUnderMovingWindow if hovered_window == nil or window.RootWindowDockTree ~= hovered_window.RootWindowDockTree then return false end IM_ASSERT(id ~= 0) if not ImGui.IsMouseHoveringRect(bb.Min, bb.Max) or (id == g.DragDropPayload.SourceId) then return false end if window.SkipItems then return false end IM_ASSERT(g.DragDropWithinTarget == false and g.DragDropWithinSource == false) g.DragDropTargetRect = ImRect(bb.Min, bb.Max) g.DragDropTargetClipRect = ImRect(window.ClipRect.Min, window.ClipRect.Max) g.DragDropTargetId = id g.DragDropTargetFullViewport = 0 g.DragDropWithinTarget = true return true end function ImGui.BeginDragDropTargetViewport(viewport, p_bb) local g = ImGui.GetCurrentContext() if not g.DragDropActive then return false end local bb = p_bb or viewport:GetWorkRect() local id = viewport.ID if g.MouseViewport ~= viewport or not ImGui.IsMouseHoveringRect(bb.Min, bb.Max, false) or (id == g.DragDropPayload.SourceId) then return false end IM_ASSERT(g.DragDropWithinTarget == false and g.DragDropWithinSource == false) g.DragDropTargetRect = ImRect(bb.Min, bb.Max) g.DragDropTargetClipRect = ImRect(bb.Min, bb.Max) g.DragDropTargetId = id g.DragDropTargetFullViewport = id g.DragDropWithinTarget = true return true end function ImGui.BeginDragDropTarget() local g = ImGui.GetCurrentContext() if not g.DragDropActive then return false end local window = g.CurrentWindow if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredRect) == 0 then return false end local hovered_window = g.HoveredWindowUnderMovingWindow if hovered_window == nil or window.RootWindowDockTree ~= hovered_window.RootWindowDockTree or window.SkipItems then return false end local display_rect = (bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasDisplayRect) ~= 0) and g.LastItemData.DisplayRect or g.LastItemData.Rect local id = g.LastItemData.ID if id == 0 then id = window:GetIDFromRectangle(display_rect) ImGui.KeepAliveID(id) end if g.DragDropPayload.SourceId == id then return false end IM_ASSERT(g.DragDropWithinTarget == false and g.DragDropWithinSource == false) g.DragDropTargetRect = ImRect(display_rect.Min, display_rect.Max) local clip = (bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasClipRect) ~= 0) and g.LastItemData.ClipRect or window.ClipRect g.DragDropTargetClipRect = ImRect(clip.Min, clip.Max) g.DragDropTargetId = id g.DragDropWithinTarget = true return true end function ImGui.IsDragDropPayloadBeingAccepted() local g = ImGui.GetCurrentContext() return g.DragDropActive and g.DragDropAcceptIdPrev ~= 0 end --- @return ImGuiPayload? function ImGui.AcceptDragDropPayload(type, flags) if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() local payload = g.DragDropPayload IM_ASSERT(g.DragDropActive) IM_ASSERT(payload.DataFrameCount ~= -1) if type ~= nil and not ImGuiPayload_IsDataType(payload, type) then return nil end local was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId) local r = g.DragDropTargetRect local r_surface = r:GetWidth() * r:GetHeight() if r_surface > g.DragDropAcceptIdCurrRectSurface then return nil end g.DragDropAcceptFlagsCurr = flags g.DragDropAcceptIdCurr = g.DragDropTargetId g.DragDropAcceptIdCurrRectSurface = r_surface payload.Preview = was_accepted_previously flags = bit32.bor(flags, bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.AcceptNoDrawDefaultRect)) local draw_target_rect = payload.Preview and bit32.band(flags, ImGuiDragDropFlags.AcceptNoDrawDefaultRect) == 0 if draw_target_rect and g.DragDropTargetFullViewport ~= 0 then ImGui.RenderDragDropTargetRectForViewport(g.DragDropTargetFullViewport, g.DragDropTargetRect) elseif draw_target_rect then ImGui.RenderDragDropTargetRectForItem(r) end g.DragDropAcceptFrameCount = g.FrameCount if bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceExtern) ~= 0 and g.DragDropMouseButton == -1 then payload.Delivery = was_accepted_previously and (g.DragDropSourceFrameCount < g.FrameCount) else payload.Delivery = was_accepted_previously and not ImGui.IsMouseDown(g.DragDropMouseButton) end if not payload.Delivery and bit32.band(flags, ImGuiDragDropFlags.AcceptBeforeDelivery) == 0 then return nil end return payload end function ImGui.RenderDragDropTargetRectForItem(bb) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local bb_display = ImRect(bb.Min, bb.Max) bb_display:ClipWith(g.DragDropTargetClipRect) bb_display:Expand(g.Style.DragDropTargetPadding) local push_clip_rect = not window.ClipRect:Contains(bb_display) if push_clip_rect then window.DrawList:PushClipRectFullScreen() end ImGui.RenderDragDropTargetRectEx(window.DrawList, bb_display, g.Style.DragDropTargetRounding) if push_clip_rect then window.DrawList:PopClipRect() end end function ImGui.RenderDragDropTargetRectForViewport(viewport_id, bb) local g = ImGui.GetCurrentContext() local viewport = ImGui.FindViewportByID(viewport_id) IM_ASSERT(viewport ~= nil) local bb_padded = ImRect(bb.Min, bb.Max) bb_padded:Expand(-g.Style.DragDropTargetPadding) ImGui.RenderDragDropTargetRectEx(ImGui.GetForegroundDrawList(viewport), bb_padded, g.Style.DragDropTargetRounding) end function ImGui.RenderDragDropTargetRectEx(draw_list, bb, rounding) local g = ImGui.GetCurrentContext() draw_list:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.DragDropTargetBg), rounding, 0) draw_list:AddRect(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.DragDropTarget), rounding, g.Style.DragDropTargetBorderSize) end --- @return ImGuiPayload? function ImGui.GetDragDropPayload() local g = ImGui.GetCurrentContext() return (g.DragDropActive and g.DragDropPayload.DataFrameCount ~= -1) and g.DragDropPayload or nil end function ImGui.EndDragDropTarget() local g = ImGui.GetCurrentContext() IM_ASSERT(g.DragDropActive) IM_ASSERT(g.DragDropWithinTarget) g.DragDropWithinTarget = false if g.DragDropPayload.Delivery then ImGui.ClearDragDrop() end end -- Payload methods (C++ ImGuiPayload members): payload:IsDataType(t) etc. also work through these globals function ImGui.PayloadIsDataType(payload, t) return ImGuiPayload_IsDataType(payload, t) end end --[[ [SECTION] imgui_dragdrop (was imgui_dragdrop.lua) ]] do --[[ [SECTION] imgui_docking (was imgui_docking.lua) ]] --- Dear ImGui -- Docking: 1:1 port of imgui.cpp [SECTION] DOCKING (docking branch, 1.93 WIP) -- -- Port notes: -- - Main viewport only (no multi-viewports on Roblox): viewport creation/merging code paths are kept where cheap, but -- windows always live in the main viewport. -- - ImGuiDockContext.Nodes (ImGuiStorage in C++) is a Lua table ID -> node. Iterations that upstream does over the -- sorted storage are done over a sorted snapshot of the IDs (DockContextNodesSorted) for deterministic order. -- - node.ChildNodes is a table indexed [0] and [1] like upstream. -- - ImGuiDockPreviewData.DropRectsDraw is indexed [dir + 1] with dir in -1..3 (so keys 0..4), like upstream. local MT = ImGui.GetMetatables() IMGUI_PAYLOAD_TYPE_WINDOW = "_IMWINDOW" local DOCKING_HOST_DRAW_CHANNEL_BG = 0 -- Dock host: background fill local DOCKING_HOST_DRAW_CHANNEL_FG = 1 -- Dock host: decorations and contents local DOCKING_SPLITTER_SIZE = 2.0 --------------------------------------------------------------------------------------- -- Docking: flags & enums --------------------------------------------------------------------------------------- ImGuiDockNodeFlags = { None = 0, KeepAliveOnly = bit32.lshift(1, 0), NoDockingOverCentralNode = bit32.lshift(1, 2), PassthruCentralNode = bit32.lshift(1, 3), NoDockingSplit = bit32.lshift(1, 4), NoResize = bit32.lshift(1, 5), AutoHideTabBar = bit32.lshift(1, 6), NoUndocking = bit32.lshift(1, 7), -- [Internal] DockSpace = bit32.lshift(1, 10), CentralNode = bit32.lshift(1, 11), NoTabBar = bit32.lshift(1, 12), HiddenTabBar = bit32.lshift(1, 13), NoWindowMenuButton = bit32.lshift(1, 14), NoCloseButton = bit32.lshift(1, 15), NoResizeX = bit32.lshift(1, 16), NoResizeY = bit32.lshift(1, 17), DockedWindowsInFocusRoute = bit32.lshift(1, 18), NoDockingSplitOther = bit32.lshift(1, 19), NoDockingOverMe = bit32.lshift(1, 20), NoDockingOverOther = bit32.lshift(1, 21), NoDockingOverEmpty = bit32.lshift(1, 22), } do local F = ImGuiDockNodeFlags F.NoSplit = F.NoDockingSplit F.NoDockingInCentralNode = F.NoDockingOverCentralNode F.NoDocking = bit32.bor(F.NoDockingOverMe, F.NoDockingOverOther, F.NoDockingOverEmpty, F.NoDockingSplit, F.NoDockingSplitOther) F.SharedFlagsInheritMask_ = 0xFFFFFFFF F.NoResizeFlagsMask_ = bit32.bor(F.NoResize, F.NoResizeX, F.NoResizeY) F.LocalFlagsTransferMask_ = bit32.bor(F.NoDockingSplit, F.NoResizeFlagsMask_, F.AutoHideTabBar, F.CentralNode, F.NoTabBar, F.HiddenTabBar, F.NoWindowMenuButton, F.NoCloseButton) F.SavedFlagsMask_ = bit32.bor(F.NoResizeFlagsMask_, F.DockSpace, F.CentralNode, F.NoTabBar, F.HiddenTabBar, F.NoWindowMenuButton, F.NoCloseButton) end ImGuiDataAuthority = { Auto = 0, DockNode = 1, Window = 2 } ImGuiDockNodeState = { Unknown = 0, HostWindowHiddenBecauseSingleWindow = 1, HostWindowHiddenBecauseWindowsAreResizing = 2, HostWindowVisible = 3, } ImGuiWindowDockStyleCol = { Text = 0, TabHovered = 1, TabFocused = 2, TabSelected = 3, TabSelectedOverline = 4, TabDimmed = 5, TabDimmedSelected = 6, TabDimmedSelectedOverline = 7, UnsavedMarker = 8, COUNT = 9, } local ImGuiDockRequestType = { None = 0, Dock = 1, Undock = 2, Split = 3 } --------------------------------------------------------------------------------------- -- Docking: Internal Types --------------------------------------------------------------------------------------- local function ImGuiDockRequest() return { Type = ImGuiDockRequestType.None, DockTargetWindow = nil, DockTargetNode = nil, DockPayload = nil, DockSplitDir = ImGuiDir.None, DockSplitRatio = 0.5, DockSplitOuter = false, UndockTargetWindow = nil, UndockTargetNode = nil, } end local function ImGuiDockNodeSettings() return { ID = 0, ParentNodeId = 0, ParentWindowId = 0, SelectedTabId = 0, SplitAxis = ImGuiAxis.None, Depth = 0, Flags = 0, Pos = ImVec2(0, 0), Size = ImVec2(0, 0), SizeRef = ImVec2(0, 0), } end function ImGuiDockContext() return { Nodes = {}, Requests = ImVector(), NodesSettings = ImVector(), WantFullRebuild = false } end MT.ImGuiDockNode = {} MT.ImGuiDockNode.__index = MT.ImGuiDockNode local DN = MT.ImGuiDockNode function ImGuiDockNode(id) return setmetatable({ ID = id, SharedFlags = 0, LocalFlags = 0, LocalFlagsInWindows = 0, MergedFlags = 0, State = ImGuiDockNodeState.Unknown, ParentNode = nil, ChildNodes = { [0] = nil, [1] = nil }, Windows = ImVector(), TabBar = nil, Pos = ImVec2(0, 0), Size = ImVec2(0, 0), SizeRef = ImVec2(0, 0), SplitAxis = ImGuiAxis.None, LastBgColor = IM_COL32_WHITE, WindowClass = ImGuiWindowClass(), HostWindow = nil, VisibleWindow = nil, CentralNode = nil, OnlyNodeWithWindows = nil, CountNodeWithWindows = 0, LastFrameAlive = -1, LastFrameActive = -1, LastFrameFocused = -1, LastFocusedNodeId = 0, SelectedTabId = 0, WantCloseTabId = 0, RefViewportId = 0, AuthorityForPos = ImGuiDataAuthority.DockNode, AuthorityForSize = ImGuiDataAuthority.DockNode, AuthorityForViewport = ImGuiDataAuthority.Auto, IsVisible = true, IsFocused = false, IsBgDrawnThisFrame = false, HasCloseButton = false, HasWindowMenuButton = false, HasCentralNodeChild = false, WantCloseAll = false, WantLockSizeOnce = false, WantMouseMove = false, WantHiddenTabBarUpdate = false, WantHiddenTabBarToggle = false, }, DN) end function DN:IsRootNode() return self.ParentNode == nil end function DN:IsDockSpace() return bit32.band(self.MergedFlags, ImGuiDockNodeFlags.DockSpace) ~= 0 end function DN:IsFloatingNode() return self.ParentNode == nil and bit32.band(self.MergedFlags, ImGuiDockNodeFlags.DockSpace) == 0 end function DN:IsCentralNode() return bit32.band(self.MergedFlags, ImGuiDockNodeFlags.CentralNode) ~= 0 end function DN:IsHiddenTabBar() return bit32.band(self.MergedFlags, ImGuiDockNodeFlags.HiddenTabBar) ~= 0 end function DN:IsNoTabBar() return bit32.band(self.MergedFlags, ImGuiDockNodeFlags.NoTabBar) ~= 0 end function DN:IsSplitNode() return self.ChildNodes[0] ~= nil end function DN:IsLeafNode() return self.ChildNodes[0] == nil end function DN:IsEmpty() return self.ChildNodes[0] == nil and self.Windows.Size == 0 end function DN:Rect() return ImRect(self.Pos.x, self.Pos.y, self.Pos.x + self.Size.x, self.Pos.y + self.Size.y) end function DN:SetLocalFlags(flags) self.LocalFlags = flags; self:UpdateMergedFlags() end function DN:UpdateMergedFlags() self.MergedFlags = bit32.bor(self.SharedFlags, self.LocalFlags, self.LocalFlagsInWindows) end local function ImGuiDockPreviewData() local d = { FutureNode = ImGuiDockNode(0), IsDropAllowed = false, IsCenterAvailable = false, IsSidesAvailable = false, IsSplitDirExplicit = false, SplitNode = nil, SplitDir = ImGuiDir.None, SplitRatio = 0.0, DropRectsDraw = {}, } for n = 0, 4 do d.DropRectsDraw[n] = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) end return d end local function DockNodeGetHostWindowTitle(node) return string.format("##DockNode_%02X", node.ID) end local function IsRectInverted(r) return r.Min.x > r.Max.x or r.Min.y > r.Max.y end --- Sorted snapshot of node IDs (upstream iterates ImGuiStorage which is sorted by key) local function DockContextNodesSorted(ctx) local ids = {} for id in pairs(ctx.DockContext.Nodes) do ids[#ids + 1] = id end table.sort(ids) return ids end ImGui.DockContextNodesSorted = DockContextNodesSorted --------------------------------------------------------------------------------------- -- Docking: ImGuiDockContext --------------------------------------------------------------------------------------- local DockSettingsHandler_ClearAll, DockSettingsHandler_ApplyAll, DockSettingsHandler_ReadOpen, DockSettingsHandler_ReadLine, DockSettingsHandler_WriteAll local DockSettingsRenameNodeReferences, DockSettingsRemoveNodeReferences, DockSettingsFindNodeSettings function ImGui.DockContextInitialize(ctx) local g = ctx local ini_handler = ImGuiSettingsHandler() ini_handler.TypeName = "Docking" ini_handler.TypeHash = ImHashStr("Docking") ini_handler.ClearAllFn = DockSettingsHandler_ClearAll ini_handler.ReadInitFn = DockSettingsHandler_ClearAll ini_handler.ReadOpenFn = DockSettingsHandler_ReadOpen ini_handler.ReadLineFn = DockSettingsHandler_ReadLine ini_handler.ApplyAllFn = DockSettingsHandler_ApplyAll ini_handler.WriteAllFn = DockSettingsHandler_WriteAll g.SettingsHandlers:push_back(ini_handler) g.DockNodeWindowMenuHandler = ImGui.DockNodeWindowMenuHandler_Default end function ImGui.DockContextShutdown(ctx) for _, id in ipairs(DockContextNodesSorted(ctx)) do local node = ctx.DockContext.Nodes[id] if node then ImGui.DockContextDeleteNode(ctx, node) end end end function ImGui.DockContextClearNodes(ctx, root_id, clear_settings_refs) ImGui.DockBuilderRemoveNodeDockedWindows(root_id, clear_settings_refs) ImGui.DockBuilderRemoveNodeChildNodes(root_id) end function ImGui.DockContextRebuildNodes(ctx) local dc = ctx.DockContext ImGui.SaveIniSettingsToMemory() local root_id = 0 ImGui.DockContextClearNodes(ctx, root_id, false) ImGui.DockContextBuildNodesFromSettings(ctx, dc.NodesSettings.Data, dc.NodesSettings.Size) ImGui.DockContextBuildAddWindowsToNodes(ctx, root_id) end function ImGui.DockContextNewFrameUpdateUndocking(ctx) local g = ctx local dc = ctx.DockContext if bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.DockingEnable) == 0 then if next(dc.Nodes) ~= nil or dc.Requests.Size > 0 then ImGui.DockContextClearNodes(ctx, 0, true) end return end if g.IO.ConfigDockingNoSplit then for _, id in ipairs(DockContextNodesSorted(ctx)) do local node = dc.Nodes[id] if node and node:IsRootNode() and node:IsSplitNode() then ImGui.DockBuilderRemoveNodeChildNodes(node.ID) end end end if dc.WantFullRebuild then ImGui.DockContextRebuildNodes(ctx) dc.WantFullRebuild = false end for _, req in dc.Requests:iter() do if req.Type == ImGuiDockRequestType.Undock and req.UndockTargetWindow then ImGui.DockContextProcessUndockWindow(ctx, req.UndockTargetWindow) elseif req.Type == ImGuiDockRequestType.Undock and req.UndockTargetNode then ImGui.DockContextProcessUndockNode(ctx, req.UndockTargetNode) end end end function ImGui.DockContextNewFrameUpdateDocking(ctx) local g = ctx local dc = ctx.DockContext if bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.DockingEnable) == 0 then return end g.DebugHoveredDockNode = nil local hovered_window = g.HoveredWindowUnderMovingWindow if hovered_window then if hovered_window.DockNodeAsHost then g.DebugHoveredDockNode = ImGui.DockNodeTreeFindVisibleNodeByPos(hovered_window.DockNodeAsHost, g.IO.MousePos) elseif hovered_window.RootWindow.DockNode then g.DebugHoveredDockNode = hovered_window.RootWindow.DockNode end end for _, req in dc.Requests:iter() do if req.Type == ImGuiDockRequestType.Dock then ImGui.DockContextProcessDock(ctx, req) end end dc.Requests:resize(0) for _, id in ipairs(DockContextNodesSorted(ctx)) do local node = dc.Nodes[id] if node and node:IsFloatingNode() then ImGui.DockNodeUpdate(node) end end end function ImGui.DockContextEndFrame(ctx) local g = ctx local dc = g.DockContext for _, id in ipairs(DockContextNodesSorted(ctx)) do local node = dc.Nodes[id] if node and node.LastFrameActive == g.FrameCount and node.IsVisible and node.HostWindow and node:IsLeafNode() and not node.IsBgDrawnThisFrame then local bg_rect = ImRect(node.Pos + ImVec2(0.0, ImGui.GetFrameHeight()), node.Pos + node.Size) local bg_rounding_flags = ImGui.CalcRoundingFlagsForRectInRect(bg_rect, node.HostWindow:Rect(), g.Style.DockingSeparatorSize) node.HostWindow.DrawList:ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG) node.HostWindow.DrawList:AddRectFilled(bg_rect.Min, bg_rect.Max, node.LastBgColor, node.HostWindow.WindowRounding, bg_rounding_flags) end end end function ImGui.DockContextFindNodeByID(ctx, id) return ctx.DockContext.Nodes[id] end function ImGui.DockContextGenNodeID(ctx) local id = 0x0001 while ImGui.DockContextFindNodeByID(ctx, id) ~= nil do id = id + 1 end return id end function ImGui.DockContextAddNode(ctx, id) if id == 0 then id = ImGui.DockContextGenNodeID(ctx) else IM_ASSERT(ImGui.DockContextFindNodeByID(ctx, id) == nil) end local node = ImGuiDockNode(id) ctx.DockContext.Nodes[node.ID] = node return node end function ImGui.DockContextRemoveNode(ctx, node, merge_sibling_into_parent_node) IM_ASSERT(ImGui.DockContextFindNodeByID(ctx, node.ID) == node) IM_ASSERT(node.ChildNodes[0] == nil and node.ChildNodes[1] == nil) IM_ASSERT(node.Windows.Size == 0) if node.HostWindow then node.HostWindow.DockNodeAsHost = nil end local parent_node = node.ParentNode local merge = (merge_sibling_into_parent_node and parent_node ~= nil) if merge then IM_ASSERT(parent_node.ChildNodes[0] == node or parent_node.ChildNodes[1] == node) local sibling_node = (parent_node.ChildNodes[0] == node) and parent_node.ChildNodes[1] or parent_node.ChildNodes[0] ImGui.DockNodeTreeMerge(ctx, parent_node, sibling_node) else if parent_node then for n = 0, 1 do if parent_node.ChildNodes[n] == node then node.ParentNode.ChildNodes[n] = nil end end end ImGui.DockContextDeleteNode(ctx, node) end end function ImGui.DockContextDeleteNode(ctx, node) local dc = ctx.DockContext node.TabBar = nil dc.Nodes[node.ID] = nil end function ImGui.DockContextPruneUnusedSettingsNodes(ctx) local g = ctx local dc = ctx.DockContext IM_ASSERT(g.Windows.Size == 0) local pool = {} local function GetOrAdd(id) local d = pool[id] if not d then d = { CountWindows = 0, CountChildWindows = 0, CountChildNodes = 0, RootId = 0 }; pool[id] = d end return d end for _, settings in dc.NodesSettings:iter() do if pool[settings.ID] ~= nil then settings.ID = 0 else local parent_data = (settings.ParentNodeId ~= 0) and pool[settings.ParentNodeId] or nil GetOrAdd(settings.ID).RootId = parent_data and parent_data.RootId or settings.ID if settings.ParentNodeId ~= 0 then local p = GetOrAdd(settings.ParentNodeId) p.CountChildNodes = p.CountChildNodes + 1 end end end for _, settings in dc.NodesSettings:iter() do if settings.ParentWindowId ~= 0 then local window_settings = ImGui.FindWindowSettingsByID(settings.ParentWindowId) if window_settings and window_settings.DockId ~= 0 then local data = pool[window_settings.DockId] if data then data.CountChildNodes = data.CountChildNodes + 1 end end end end for _, settings in g.SettingsWindows:iter() do local dock_id = settings.DockId if dock_id and dock_id ~= 0 then local data = pool[dock_id] if data then data.CountWindows = data.CountWindows + 1 local data_root = (data.RootId == dock_id) and data or pool[data.RootId] if data_root then data_root.CountChildWindows = data_root.CountChildWindows + 1 end end end end for _, settings in dc.NodesSettings:iter() do local data = pool[settings.ID] if data ~= nil and data.CountWindows <= 1 then local data_root = (settings.ID == data.RootId) and data or pool[data.RootId] local data_parent = (settings.ParentNodeId ~= 0) and pool[settings.ParentNodeId] or nil local remove = false remove = remove or (data.CountWindows == 1 and settings.ParentNodeId == 0 and data.CountChildNodes == 0 and bit32.band(settings.Flags, ImGuiDockNodeFlags.CentralNode) == 0) remove = remove or (data.CountWindows == 0 and settings.ParentNodeId == 0 and data.CountChildNodes == 0) remove = remove or (data_root == nil or data_root.CountChildWindows == 0) if remove then DockSettingsRemoveNodeReferences({ settings.ID }, 1) settings.ID = 0 elseif data_parent and data_parent.CountChildNodes == 1 then DockSettingsRenameNodeReferences(settings.ID, settings.ParentNodeId) settings.ID = 0 end end end end --- @param node_settings_array table # 1-based array function ImGui.DockContextBuildNodesFromSettings(ctx, node_settings_array, node_settings_count) for node_n = 1, node_settings_count do local settings = node_settings_array[node_n] if settings.ID ~= 0 and ImGui.DockContextFindNodeByID(ctx, settings.ID) == nil then local node = ImGui.DockContextAddNode(ctx, settings.ID) node.ParentNode = (settings.ParentNodeId ~= 0) and ImGui.DockContextFindNodeByID(ctx, settings.ParentNodeId) or nil node.Pos = ImVec2(settings.Pos.x, settings.Pos.y) node.Size = ImVec2(settings.Size.x, settings.Size.y) node.SizeRef = ImVec2(settings.SizeRef.x, settings.SizeRef.y) node.AuthorityForPos = ImGuiDataAuthority.DockNode node.AuthorityForSize = ImGuiDataAuthority.DockNode node.AuthorityForViewport = ImGuiDataAuthority.DockNode if node.ParentNode and node.ParentNode.ChildNodes[0] == nil then node.ParentNode.ChildNodes[0] = node elseif node.ParentNode and node.ParentNode.ChildNodes[1] == nil then node.ParentNode.ChildNodes[1] = node end node.SelectedTabId = settings.SelectedTabId node.SplitAxis = settings.SplitAxis node:SetLocalFlags(bit32.band(settings.Flags, ImGuiDockNodeFlags.SavedFlagsMask_)) local root_node = ImGui.DockNodeGetRootNode(node) node.HostWindow = ImGui.FindWindowByName(DockNodeGetHostWindowTitle(root_node)) end end end function ImGui.DockContextBuildAddWindowsToNodes(ctx, root_id) local g = ctx for _, window in g.Windows:iter() do if window.DockId ~= 0 and window.LastFrameActive >= g.FrameCount - 1 and window.DockNode == nil then local node = ImGui.DockContextFindNodeByID(ctx, window.DockId) IM_ASSERT(node ~= nil) if root_id == 0 or ImGui.DockNodeGetRootNode(node).ID == root_id then ImGui.DockNodeAddWindow(node, window, true) end end end end --------------------------------------------------------------------------------------- -- Docking: ImGuiDockContext Docking/Undocking functions --------------------------------------------------------------------------------------- function ImGui.DockContextQueueDock(ctx, target, target_node, payload, split_dir, split_ratio, split_outer) IM_ASSERT(target ~= payload) local req = ImGuiDockRequest() req.Type = ImGuiDockRequestType.Dock req.DockTargetWindow = target req.DockTargetNode = target_node req.DockPayload = payload req.DockSplitDir = split_dir req.DockSplitRatio = split_ratio req.DockSplitOuter = split_outer ctx.DockContext.Requests:push_back(req) end function ImGui.DockContextQueueUndockWindow(ctx, window) local req = ImGuiDockRequest() req.Type = ImGuiDockRequestType.Undock req.UndockTargetWindow = window ctx.DockContext.Requests:push_back(req) end function ImGui.DockContextQueueUndockNode(ctx, node) local req = ImGuiDockRequest() req.Type = ImGuiDockRequestType.Undock req.UndockTargetNode = node ctx.DockContext.Requests:push_back(req) end function ImGui.DockContextQueueNotifyRemovedNode(ctx, node) for _, req in ctx.DockContext.Requests:iter() do if req.DockTargetNode == node then req.Type = ImGuiDockRequestType.None end end end function ImGui.DockContextProcessDock(ctx, req) IM_ASSERT((req.Type == ImGuiDockRequestType.Dock and req.DockPayload ~= nil) or (req.Type == ImGuiDockRequestType.Split and req.DockPayload == nil)) IM_ASSERT(req.DockTargetWindow ~= nil or req.DockTargetNode ~= nil) local g = ctx local payload_window = req.DockPayload local target_window = req.DockTargetWindow local node = req.DockTargetNode local next_selected_id = 0 local payload_node = nil if payload_window then payload_node = payload_window.DockNodeAsHost payload_window.DockNodeAsHost = nil if payload_node and payload_node:IsLeafNode() then next_selected_id = (payload_node.TabBar.NextSelectedTabId ~= 0) and payload_node.TabBar.NextSelectedTabId or payload_node.TabBar.SelectedTabId end if payload_node == nil then next_selected_id = payload_window.TabId end end if node then IM_ASSERT(node.LastFrameAlive <= g.FrameCount) end if node and target_window and node == target_window.DockNodeAsHost then IM_ASSERT(node.Windows.Size > 0 or node:IsSplitNode() or node:IsCentralNode()) end if node == nil then node = ImGui.DockContextAddNode(ctx, 0) node.Pos = ImVec2(target_window.Pos.x, target_window.Pos.y) node.Size = ImVec2(target_window.Size.x, target_window.Size.y) if target_window.DockNodeAsHost == nil then ImGui.DockNodeAddWindow(node, target_window, true) local t0 = node.TabBar.Tabs.Data[1] t0.Flags = bit32.band(t0.Flags, bit32.bnot(ImGuiTabItemFlags.Unsorted)) target_window.DockIsActive = true end end local split_dir = req.DockSplitDir if split_dir ~= ImGuiDir.None then local split_axis = (split_dir == ImGuiDir.Left or split_dir == ImGuiDir.Right) and ImGuiAxis.X or ImGuiAxis.Y local split_inheritor_child_idx = (split_dir == ImGuiDir.Left or split_dir == ImGuiDir.Up) and 1 or 0 local split_ratio = req.DockSplitRatio ImGui.DockNodeTreeSplit(ctx, node, split_axis, split_inheritor_child_idx, split_ratio, payload_node) local new_node = node.ChildNodes[bit32.bxor(split_inheritor_child_idx, 1)] new_node.HostWindow = node.HostWindow node = new_node end node:SetLocalFlags(bit32.band(node.LocalFlags, bit32.bnot(ImGuiDockNodeFlags.HiddenTabBar))) if node ~= payload_node then if node.Windows.Size > 0 and node.TabBar == nil then ImGui.DockNodeAddTabBar(node) for n = 1, node.Windows.Size do ImGui.TabBarAddTab(node.TabBar, ImGuiTabItemFlags.None, node.Windows.Data[n]) end end if payload_node ~= nil then if payload_node:IsSplitNode() then if node.Windows.Size > 0 then IM_ASSERT(payload_node.OnlyNodeWithWindows ~= nil) local visible_node = payload_node.OnlyNodeWithWindows if visible_node.TabBar then IM_ASSERT(visible_node.TabBar.Tabs.Size > 0) end ImGui.DockNodeMoveWindows(node, visible_node) ImGui.DockNodeMoveWindows(visible_node, node) DockSettingsRenameNodeReferences(node.ID, visible_node.ID) end if node:IsCentralNode() then local last_focused_node = ImGui.DockContextFindNodeByID(ctx, payload_node.LastFocusedNodeId) IM_ASSERT(last_focused_node ~= nil) local last_focused_root_node = ImGui.DockNodeGetRootNode(last_focused_node) IM_ASSERT(last_focused_root_node == ImGui.DockNodeGetRootNode(payload_node)) last_focused_node:SetLocalFlags(bit32.bor(last_focused_node.LocalFlags, ImGuiDockNodeFlags.CentralNode)) node:SetLocalFlags(bit32.band(node.LocalFlags, bit32.bnot(ImGuiDockNodeFlags.CentralNode))) last_focused_root_node.CentralNode = last_focused_node end IM_ASSERT(node.Windows.Size == 0) ImGui.DockNodeMoveChildNodes(node, payload_node) else local payload_dock_id = payload_node.ID ImGui.DockNodeMoveWindows(node, payload_node) DockSettingsRenameNodeReferences(payload_dock_id, node.ID) end ImGui.DockContextRemoveNode(ctx, payload_node, true) elseif payload_window then local payload_dock_id = payload_window.DockId node.VisibleWindow = payload_window ImGui.DockNodeAddWindow(node, payload_window, true) if payload_dock_id ~= 0 then DockSettingsRenameNodeReferences(payload_dock_id, node.ID) end end else node.WantHiddenTabBarUpdate = true end local tab_bar = node.TabBar if tab_bar then tab_bar.NextSelectedTabId = next_selected_id end ImGui.MarkIniSettingsDirty() end local function FixLargeWindowsWhenUndocking(size, ref_viewport) if ref_viewport == nil then return size end local max_size = ImTrunc(ref_viewport.WorkSize * 0.90) return ImVec2(ImMin(size.x, max_size.x), ImMin(size.y, max_size.y)) end function ImGui.DockContextProcessUndockWindow(ctx, window, clear_persistent_docking_ref) if clear_persistent_docking_ref == nil then clear_persistent_docking_ref = true end -- C++ default argument if window.DockNode then ImGui.DockNodeRemoveWindow(window.DockNode, window, clear_persistent_docking_ref and 0 or window.DockId) else window.DockId = 0 end window.Collapsed = false window.DockIsActive = false window.DockNodeIsVisible = false window.DockTabIsVisible = false local sz = FixLargeWindowsWhenUndocking(window.SizeFull, window.Viewport) ImVec2_Copy(window.Size, sz) ImVec2_Copy(window.SizeFull, sz) ImGui.MarkIniSettingsDirty() end function ImGui.DockContextProcessUndockNode(ctx, node) IM_ASSERT(node:IsLeafNode()) IM_ASSERT(node.Windows.Size >= 1) if node:IsRootNode() or node:IsCentralNode() then local new_node = ImGui.DockContextAddNode(ctx, 0) new_node.Pos = ImVec2(node.Pos.x, node.Pos.y) new_node.Size = ImVec2(node.Size.x, node.Size.y) new_node.SizeRef = ImVec2(node.SizeRef.x, node.SizeRef.y) ImGui.DockNodeMoveWindows(new_node, node) DockSettingsRenameNodeReferences(node.ID, new_node.ID) node = new_node else IM_ASSERT(node.ParentNode.ChildNodes[0] == node or node.ParentNode.ChildNodes[1] == node) local index_in_parent = (node.ParentNode.ChildNodes[0] == node) and 0 or 1 node.ParentNode.ChildNodes[index_in_parent] = nil ImGui.DockNodeTreeMerge(ctx, node.ParentNode, node.ParentNode.ChildNodes[bit32.bxor(index_in_parent, 1)]) node.ParentNode.AuthorityForViewport = ImGuiDataAuthority.Window node.ParentNode = nil end for _, window in node.Windows:iter() do window.Flags = bit32.band(window.Flags, bit32.bnot(ImGuiWindowFlags.ChildWindow)) if window.ParentWindow then window.ParentWindow.DC.ChildWindows:find_erase(window) end ImGui.UpdateWindowParentAndRootLinks(window, window.Flags, nil) end node.AuthorityForPos = ImGuiDataAuthority.DockNode node.AuthorityForSize = ImGuiDataAuthority.DockNode node.Size = FixLargeWindowsWhenUndocking(node.Size, node.Windows.Data[1].Viewport) node.WantMouseMove = true ImGui.MarkIniSettingsDirty() end --- @return bool ok, ImVec2? out_pos function ImGui.DockContextCalcDropPosForDocking(target, target_node, payload_window, payload_node, split_dir, split_outer) if target ~= nil and target_node == nil then target_node = target.DockNode end if target_node and target_node.ParentNode == nil and target_node:IsCentralNode() and split_dir ~= ImGuiDir.None then split_outer = true end local split_data = ImGuiDockPreviewData() ImGui.DockNodePreviewDockSetup(target, target_node, payload_window, payload_node, split_data, false, split_outer) local r = split_data.DropRectsDraw[split_dir + 1] if IsRectInverted(r) then return false, nil end return true, r:GetCenter() end --------------------------------------------------------------------------------------- -- Docking: ImGuiDockNode --------------------------------------------------------------------------------------- function ImGui.DockNodeGetTabOrder(window) local tab_bar = window.DockNode.TabBar if tab_bar == nil then return -1 end local tab = ImGui.TabBarFindTabByID(tab_bar, window.TabId) return tab and ImGui.TabBarGetTabOrder(tab_bar, tab) or -1 end local function DockNodeHideWindowDuringHostWindowCreation(window) window.Hidden = true window.HiddenFramesCanSkipItems = window.Active and 1 or 2 end function ImGui.DockNodeAddWindow(node, window, add_to_tab_bar) if window.DockNode then IM_ASSERT(window.DockNode.ID ~= node.ID) ImGui.DockNodeRemoveWindow(window.DockNode, window, 0) end IM_ASSERT(window.DockNode == nil or window.DockNodeAsHost == nil) if node.HostWindow == nil and node.Windows.Size == 1 and node.Windows.Data[1].WasActive == false then DockNodeHideWindowDuringHostWindowCreation(node.Windows.Data[1]) end node.Windows:push_back(window) node.WantHiddenTabBarUpdate = true window.DockNode = node window.DockId = node.ID window.DockIsActive = (node.Windows.Size > 1) window.DockTabWantClose = false if node.HostWindow == nil and node:IsFloatingNode() then if node.AuthorityForPos == ImGuiDataAuthority.Auto then node.AuthorityForPos = ImGuiDataAuthority.Window end if node.AuthorityForSize == ImGuiDataAuthority.Auto then node.AuthorityForSize = ImGuiDataAuthority.Window end if node.AuthorityForViewport == ImGuiDataAuthority.Auto then node.AuthorityForViewport = ImGuiDataAuthority.Window end end if add_to_tab_bar then if node.TabBar == nil then ImGui.DockNodeAddTabBar(node) node.TabBar.SelectedTabId = node.SelectedTabId node.TabBar.NextSelectedTabId = node.SelectedTabId for n = 1, node.Windows.Size - 1 do ImGui.TabBarAddTab(node.TabBar, ImGuiTabItemFlags.None, node.Windows.Data[n]) end end ImGui.TabBarAddTab(node.TabBar, ImGuiTabItemFlags.Unsorted, window) end ImGui.DockNodeUpdateVisibleFlag(node) if node.HostWindow then ImGui.UpdateWindowParentAndRootLinks(window, bit32.bor(window.Flags, ImGuiWindowFlags.ChildWindow), node.HostWindow) end end function ImGui.DockNodeRemoveWindow(node, window, save_dock_id) IM_ASSERT(window.DockNode == node) IM_ASSERT(save_dock_id == 0 or save_dock_id == node.ID) window.DockNode = nil window.DockIsActive = false window.DockTabWantClose = false window.DockId = save_dock_id window.Flags = bit32.band(window.Flags, bit32.bnot(ImGuiWindowFlags.ChildWindow)) if window.ParentWindow then window.ParentWindow.DC.ChildWindows:find_erase(window) end ImGui.UpdateWindowParentAndRootLinks(window, window.Flags, nil) if node.HostWindow and node.HostWindow.ViewportOwned then window.Viewport = nil window.ViewportId = 0 window.ViewportOwned = false window.Hidden = true end local idx = node.Windows:find_index(window) IM_ASSERT(idx ~= nil) node.Windows:erase(idx) if node.VisibleWindow == window then node.VisibleWindow = nil end node.WantHiddenTabBarUpdate = true if node.TabBar then ImGui.TabBarRemoveTab(node.TabBar, window.TabId) local tab_count_threshold_for_tab_bar = node:IsCentralNode() and 1 or 2 if node.Windows.Size < tab_count_threshold_for_tab_bar then ImGui.DockNodeRemoveTabBar(node) end end if node.Windows.Size == 0 and not node:IsCentralNode() and not node:IsDockSpace() and window.DockId ~= node.ID then ImGui.DockContextRemoveNode(ImGui.GetCurrentContext(), node, true) return end if node.Windows.Size == 1 and not node:IsCentralNode() and node.HostWindow then local remaining_window = node.Windows.Data[1] remaining_window.Collapsed = node.HostWindow.Collapsed end ImGui.DockNodeUpdateVisibleFlag(node) end function ImGui.DockNodeMoveChildNodes(dst_node, src_node) IM_ASSERT(dst_node.Windows.Size == 0) dst_node.ChildNodes[0] = src_node.ChildNodes[0] dst_node.ChildNodes[1] = src_node.ChildNodes[1] if dst_node.ChildNodes[0] then dst_node.ChildNodes[0].ParentNode = dst_node end if dst_node.ChildNodes[1] then dst_node.ChildNodes[1].ParentNode = dst_node end dst_node.SplitAxis = src_node.SplitAxis dst_node.SizeRef = ImVec2(src_node.SizeRef.x, src_node.SizeRef.y) src_node.ChildNodes[0] = nil src_node.ChildNodes[1] = nil end function ImGui.DockNodeMoveWindows(dst_node, src_node) IM_ASSERT(src_node and dst_node and dst_node ~= src_node) local src_tab_bar = src_node.TabBar if src_tab_bar ~= nil then IM_ASSERT(src_node.Windows.Size <= src_node.TabBar.Tabs.Size) end local move_tab_bar = (src_tab_bar ~= nil) and (dst_node.TabBar == nil) if move_tab_bar then dst_node.TabBar = src_node.TabBar src_node.TabBar = nil end -- Snapshot: DockNodeAddWindow() won't touch src_node.Windows since window.DockNode is cleared first local windows = {} for i = 1, src_node.Windows.Size do windows[i] = src_node.Windows.Data[i] end for _, window in ipairs(windows) do window.DockNode = nil window.DockIsActive = false ImGui.DockNodeAddWindow(dst_node, window, not move_tab_bar) end src_node.Windows:clear() if not move_tab_bar and src_node.TabBar then if dst_node.TabBar then dst_node.TabBar.SelectedTabId = src_node.TabBar.SelectedTabId end ImGui.DockNodeRemoveTabBar(src_node) end end function ImGui.DockNodeApplyPosSizeToWindows(node) for _, window in node.Windows:iter() do ImGui.SetWindowPos(window, node.Pos, ImGuiCond.Always) ImGui.SetWindowSize(window, node.Size, ImGuiCond.Always) end end function ImGui.DockNodeHideHostWindow(node) if node.HostWindow then if node.HostWindow.DockNodeAsHost == node then node.HostWindow.DockNodeAsHost = nil end node.HostWindow = nil end if node.Windows.Size == 1 then node.VisibleWindow = node.Windows.Data[1] node.Windows.Data[1].DockIsActive = false end if node.TabBar then ImGui.DockNodeRemoveTabBar(node) end end local function DockNodeFindInfo(node, info) if node.Windows.Size > 0 then if info.FirstNodeWithWindows == nil then info.FirstNodeWithWindows = node end info.CountNodesWithWindows = info.CountNodesWithWindows + 1 end if node:IsCentralNode() then IM_ASSERT(info.CentralNode == nil) IM_ASSERT(node:IsLeafNode(), "If you get this assert: please submit .ini file + repro of actions leading to this.") info.CentralNode = node end if info.CountNodesWithWindows > 1 and info.CentralNode ~= nil then return end if node.ChildNodes[0] then DockNodeFindInfo(node.ChildNodes[0], info) end if node.ChildNodes[1] then DockNodeFindInfo(node.ChildNodes[1], info) end end function ImGui.DockNodeFindWindowByID(node, id) IM_ASSERT(id ~= 0) for _, window in node.Windows:iter() do if window.ID == id then return window end end return nil end function ImGui.DockNodeUpdateFlagsAndCollapse(node) local g = ImGui.GetCurrentContext() IM_ASSERT(node.ParentNode == nil or node.ParentNode.ChildNodes[0] == node or node.ParentNode.ChildNodes[1] == node) if node.ParentNode then node.SharedFlags = bit32.band(node.ParentNode.SharedFlags, ImGuiDockNodeFlags.SharedFlagsInheritMask_) end node.HasCentralNodeChild = false if node.ChildNodes[0] then ImGui.DockNodeUpdateFlagsAndCollapse(node.ChildNodes[0]) end if node.ChildNodes[1] then ImGui.DockNodeUpdateFlagsAndCollapse(node.ChildNodes[1]) end node.LocalFlagsInWindows = ImGuiDockNodeFlags.None local window_n = 1 while window_n <= node.Windows.Size do local window = node.Windows.Data[window_n] IM_ASSERT(window.DockNode == node) local node_was_active = (node.LastFrameActive + 1 == g.FrameCount) local remove = false remove = remove or (node_was_active and (window.WasActive == false)) remove = remove or (node_was_active and (node.WantCloseAll or node.WantCloseTabId == window.TabId) and window.HasCloseButton and bit32.band(window.Flags, ImGuiWindowFlags.UnsavedDocument) == 0) remove = remove or window.DockTabWantClose if remove then window.DockTabWantClose = false if node.Windows.Size == 1 and not node:IsCentralNode() then ImGui.DockNodeHideHostWindow(node) node.State = ImGuiDockNodeState.HostWindowHiddenBecauseSingleWindow ImGui.DockNodeRemoveWindow(node, window, node.ID) return end ImGui.DockNodeRemoveWindow(node, window, node.ID) else node.LocalFlagsInWindows = bit32.bor(node.LocalFlagsInWindows, window.WindowClass.DockNodeFlagsOverrideSet) window_n = window_n + 1 end end node:UpdateMergedFlags() local node_flags = node.MergedFlags if node.WantHiddenTabBarUpdate and node.Windows.Size == 1 and bit32.band(node_flags, ImGuiDockNodeFlags.AutoHideTabBar) ~= 0 and not node:IsHiddenTabBar() then node.WantHiddenTabBarToggle = true end node.WantHiddenTabBarUpdate = false if node.WantHiddenTabBarToggle and node.VisibleWindow and bit32.band(node.VisibleWindow.WindowClass.DockNodeFlagsOverrideSet, ImGuiDockNodeFlags.HiddenTabBar) ~= 0 then node.WantHiddenTabBarToggle = false end local prev_local_flags = node.LocalFlags if node.Windows.Size > 1 then node:SetLocalFlags(bit32.band(node.LocalFlags, bit32.bnot(ImGuiDockNodeFlags.HiddenTabBar))) elseif node.WantHiddenTabBarToggle then node:SetLocalFlags(bit32.bxor(node.LocalFlags, ImGuiDockNodeFlags.HiddenTabBar)) end if bit32.band(bit32.bxor(node.LocalFlags, prev_local_flags), ImGuiDockNodeFlags.SavedFlagsMask_) ~= 0 then ImGui.MarkIniSettingsDirty() end node.WantHiddenTabBarToggle = false ImGui.DockNodeUpdateVisibleFlag(node) end function ImGui.DockNodeUpdateHasCentralNodeChild(node) node.HasCentralNodeChild = false if node.ChildNodes[0] then ImGui.DockNodeUpdateHasCentralNodeChild(node.ChildNodes[0]) end if node.ChildNodes[1] then ImGui.DockNodeUpdateHasCentralNodeChild(node.ChildNodes[1]) end if node:IsRootNode() then local mark_node = node.CentralNode while mark_node do mark_node.HasCentralNodeChild = true mark_node = mark_node.ParentNode end end end function ImGui.DockNodeUpdateVisibleFlag(node) local is_visible = (node.ParentNode == nil) and node:IsDockSpace() or node:IsCentralNode() is_visible = is_visible or (node.Windows.Size > 0) is_visible = is_visible or (node.ChildNodes[0] ~= nil and node.ChildNodes[0].IsVisible) is_visible = is_visible or (node.ChildNodes[1] ~= nil and node.ChildNodes[1].IsVisible) node.IsVisible = is_visible and true or false end function ImGui.DockNodeStartMouseMovingWindow(node, window) local g = ImGui.GetCurrentContext() IM_ASSERT(node.WantMouseMove == true) ImGui.StartMouseMovingWindow(window) ImVec2_Copy(g.ActiveIdClickOffset, g.IO.MouseClickedPos[0] - node.Pos) g.MovingWindow = window node.WantMouseMove = false end function ImGui.DockNodeUpdateForRootNode(node) ImGui.DockNodeUpdateFlagsAndCollapse(node) local info = { CentralNode = nil, FirstNodeWithWindows = nil, CountNodesWithWindows = 0 } DockNodeFindInfo(node, info) node.CentralNode = info.CentralNode node.OnlyNodeWithWindows = (info.CountNodesWithWindows == 1) and info.FirstNodeWithWindows or nil node.CountNodeWithWindows = info.CountNodesWithWindows if node.LastFocusedNodeId == 0 and info.FirstNodeWithWindows ~= nil then node.LastFocusedNodeId = info.FirstNodeWithWindows.ID end local first_node_with_windows = info.FirstNodeWithWindows if first_node_with_windows then node.WindowClass = first_node_with_windows.Windows.Data[1].WindowClass for n = 2, first_node_with_windows.Windows.Size do if first_node_with_windows.Windows.Data[n].WindowClass.DockingAllowUnclassed == false then node.WindowClass = first_node_with_windows.Windows.Data[n].WindowClass break end end end local mark_node = node.CentralNode while mark_node do mark_node.HasCentralNodeChild = true mark_node = mark_node.ParentNode end end local function DockNodeSetupHostWindow(node, host_window) if node.HostWindow and node.HostWindow ~= host_window and node.HostWindow.DockNodeAsHost == node then node.HostWindow.DockNodeAsHost = nil end host_window.DockNodeAsHost = node node.HostWindow = host_window end function ImGui.DockNodeUpdate(node) local g = ImGui.GetCurrentContext() IM_ASSERT(node.LastFrameActive ~= g.FrameCount) node.LastFrameAlive = g.FrameCount node.IsBgDrawnThisFrame = false node.CentralNode = nil node.OnlyNodeWithWindows = nil if node:IsRootNode() then ImGui.DockNodeUpdateForRootNode(node) end if node.TabBar and node:IsNoTabBar() then ImGui.DockNodeRemoveTabBar(node) end local want_to_hide_host_window = false if node:IsFloatingNode() then if node.Windows.Size <= 1 and node:IsLeafNode() then if not g.IO.ConfigDockingAlwaysTabBar and (node.Windows.Size == 0 or not node.Windows.Data[1].WindowClass.DockingAlwaysTabBar) then want_to_hide_host_window = true end end if node.CountNodeWithWindows == 0 then want_to_hide_host_window = true end end if want_to_hide_host_window then if node.Windows.Size == 1 then local single_window = node.Windows.Data[1] node.Pos = ImVec2(single_window.Pos.x, single_window.Pos.y) node.Size = ImVec2(single_window.SizeFull.x, single_window.SizeFull.y) node.AuthorityForPos = ImGuiDataAuthority.Window node.AuthorityForSize = ImGuiDataAuthority.Window node.AuthorityForViewport = ImGuiDataAuthority.Window if node.HostWindow and g.NavWindow == node.HostWindow then ImGui.FocusWindow(single_window) end if node.HostWindow then single_window.Viewport = node.HostWindow.Viewport single_window.ViewportId = node.HostWindow.ViewportId end node.RefViewportId = single_window.ViewportId or 0 end ImGui.DockNodeHideHostWindow(node) node.State = ImGuiDockNodeState.HostWindowHiddenBecauseSingleWindow node.WantCloseAll = false node.WantCloseTabId = 0 node.HasCloseButton = false node.HasWindowMenuButton = false node.LastFrameActive = g.FrameCount if node.WantMouseMove and node.Windows.Size == 1 then ImGui.DockNodeStartMouseMovingWindow(node, node.Windows.Data[1]) end return end if node.IsVisible and node.HostWindow == nil and node:IsFloatingNode() and node:IsLeafNode() then IM_ASSERT(node.Windows.Size > 0) local ref_window = nil if node.SelectedTabId ~= 0 then ref_window = ImGui.DockNodeFindWindowByID(node, node.SelectedTabId) end if ref_window == nil then ref_window = node.Windows.Data[1] end if ref_window.AutoFitFramesX > 0 or ref_window.AutoFitFramesY > 0 then node.State = ImGuiDockNodeState.HostWindowHiddenBecauseWindowsAreResizing return end end local node_flags = node.MergedFlags node.HasWindowMenuButton = (node.Windows.Size > 0) and bit32.band(node_flags, ImGuiDockNodeFlags.NoWindowMenuButton) == 0 node.HasCloseButton = false for _, window in node.Windows:iter() do node.HasCloseButton = node.HasCloseButton or window.HasCloseButton window.DockIsActive = (node.Windows.Size > 1) end if bit32.band(node_flags, ImGuiDockNodeFlags.NoCloseButton) ~= 0 or not g.Style.DockingNodeHasCloseButton then node.HasCloseButton = false end local host_window = nil local beginned_into_host_window = false if node:IsDockSpace() then IM_ASSERT(node.HostWindow) host_window = node.HostWindow else if node:IsRootNode() and node.IsVisible then local ref_window = (node.Windows.Size > 0) and node.Windows.Data[1] or nil if node.AuthorityForPos == ImGuiDataAuthority.Window and ref_window then ImGui.SetNextWindowPos(ref_window.Pos) elseif node.AuthorityForPos == ImGuiDataAuthority.DockNode then ImGui.SetNextWindowPos(node.Pos) end if node.AuthorityForSize == ImGuiDataAuthority.Window and ref_window then ImGui.SetNextWindowSize(ref_window.SizeFull) elseif node.AuthorityForSize == ImGuiDataAuthority.DockNode then ImGui.SetNextWindowSize(node.Size) end if node.AuthorityForSize == ImGuiDataAuthority.Window and ref_window then ImGui.SetNextWindowCollapsed(ref_window.Collapsed) end ImGui.SetNextWindowClass(node.WindowClass) local window_label = DockNodeGetHostWindowTitle(node) local window_flags = bit32.bor(ImGuiWindowFlags.NoScrollbar, ImGuiWindowFlags.NoScrollWithMouse, ImGuiWindowFlags.DockNodeHost) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoFocusOnAppearing) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoNavFocus, ImGuiWindowFlags.NoCollapse) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoTitleBar) ImGui.SetNextWindowBgAlpha(0.0) ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) ImGui.Begin(window_label, nil, window_flags) ImGui.PopStyleVar() beginned_into_host_window = true host_window = g.CurrentWindow DockNodeSetupHostWindow(node, host_window) ImVec2_Copy(host_window.DC.CursorPos, host_window.Pos) node.Pos = ImVec2(host_window.Pos.x, host_window.Pos.y) node.Size = ImVec2(host_window.Size.x, host_window.Size.y) if node.HostWindow.Appearing then ImGui.BringWindowToDisplayFront(node.HostWindow) end node.AuthorityForPos = ImGuiDataAuthority.Auto node.AuthorityForSize = ImGuiDataAuthority.Auto node.AuthorityForViewport = ImGuiDataAuthority.Auto elseif node.ParentNode then host_window = node.ParentNode.HostWindow node.HostWindow = host_window node.AuthorityForPos = ImGuiDataAuthority.Auto node.AuthorityForSize = ImGuiDataAuthority.Auto node.AuthorityForViewport = ImGuiDataAuthority.Auto end if node.WantMouseMove and node.HostWindow then ImGui.DockNodeStartMouseMovingWindow(node, node.HostWindow) end end node.RefViewportId = 0 if node:IsSplitNode() then IM_ASSERT(node.TabBar == nil) end if node:IsRootNode() then local p_window = g.NavWindow and g.NavWindow.RootWindow or nil while p_window ~= nil and p_window.DockNode ~= nil do local p_node = ImGui.DockNodeGetRootNode(p_window.DockNode) if p_node == node then node.LastFocusedNodeId = p_window.DockNode.ID break end p_window = p_node.HostWindow and p_node.HostWindow.RootWindow or nil end end local central_node = node.CentralNode local central_node_hole = node:IsRootNode() and host_window ~= nil and bit32.band(node_flags, ImGuiDockNodeFlags.PassthruCentralNode) ~= 0 and central_node ~= nil and central_node:IsEmpty() local central_node_hole_register_hit_test_hole = central_node_hole if central_node_hole then local payload = ImGui.GetDragDropPayload() if payload and ImGuiPayload_IsDataType(payload, IMGUI_PAYLOAD_TYPE_WINDOW) and ImGui.DockNodeIsDropAllowed(host_window, payload.Data) then central_node_hole_register_hit_test_hole = false end end if central_node_hole_register_hit_test_hole then IM_ASSERT(node:IsDockSpace()) local root_node = ImGui.DockNodeGetRootNode(central_node) local root_rect = ImRect(root_node.Pos, root_node.Pos + root_node.Size) local hole_rect = ImRect(central_node.Pos, central_node.Pos + central_node.Size) if hole_rect.Min.x > root_rect.Min.x then hole_rect.Min.x = hole_rect.Min.x + g.WindowsBorderHoverPadding end if hole_rect.Max.x < root_rect.Max.x then hole_rect.Max.x = hole_rect.Max.x - g.WindowsBorderHoverPadding end if hole_rect.Min.y > root_rect.Min.y then hole_rect.Min.y = hole_rect.Min.y + g.WindowsBorderHoverPadding end if hole_rect.Max.y < root_rect.Max.y then hole_rect.Max.y = hole_rect.Max.y - g.WindowsBorderHoverPadding end if central_node_hole and not IsRectInverted(hole_rect) then ImGui.SetWindowHitTestHole(host_window, hole_rect.Min, hole_rect.Max - hole_rect.Min) if host_window.ParentWindow then ImGui.SetWindowHitTestHole(host_window.ParentWindow, hole_rect.Min, hole_rect.Max - hole_rect.Min) end end end if node:IsRootNode() and host_window then ImGui.DockNodeTreeUpdatePosSize(node, host_window.Pos, host_window.Size) ImGui.PushStyleColor(ImGuiCol.Separator, g.Style.Colors[ImGuiCol.Border]) ImGui.PushStyleColor(ImGuiCol.SeparatorActive, g.Style.Colors[ImGuiCol.ResizeGripActive]) ImGui.PushStyleColor(ImGuiCol.SeparatorHovered, g.Style.Colors[ImGuiCol.ResizeGripHovered]) ImGui.DockNodeTreeUpdateSplitter(node) ImGui.PopStyleColor(3) end if host_window and node:IsEmpty() and node.IsVisible then host_window.DrawList:ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG) node.LastBgColor = (bit32.band(node_flags, ImGuiDockNodeFlags.PassthruCentralNode) ~= 0) and 0 or ImGui.GetColorU32(ImGuiCol.DockingEmptyBg) if node.LastBgColor ~= 0 then host_window.DrawList:AddRectFilled(node.Pos, node.Pos + node.Size, node.LastBgColor) end node.IsBgDrawnThisFrame = true end local render_dockspace_bg = node:IsRootNode() and host_window ~= nil and bit32.band(node_flags, ImGuiDockNodeFlags.PassthruCentralNode) ~= 0 if render_dockspace_bg and node.IsVisible then host_window.DrawList:ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG) if central_node_hole then ImGui.RenderRectFilledWithHole(host_window.DrawList, node:Rect(), central_node:Rect(), ImGui.GetColorU32(ImGuiCol.WindowBg), 0.0) else host_window.DrawList:AddRectFilled(node.Pos, node.Pos + node.Size, ImGui.GetColorU32(ImGuiCol.WindowBg), 0.0) end end if host_window then host_window.DrawList:ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_FG) end if host_window and node.Windows.Size > 0 then ImGui.DockNodeUpdateTabBar(node, host_window) else node.WantCloseAll = false node.WantCloseTabId = 0 node.IsFocused = false end if node.TabBar and node.TabBar.SelectedTabId ~= 0 then node.SelectedTabId = node.TabBar.SelectedTabId elseif node.Windows.Size > 0 then node.SelectedTabId = node.Windows.Data[1].TabId end if host_window and node.IsVisible then if node:IsRootNode() and (g.MovingWindow == nil or g.MovingWindow.RootWindowDockTree ~= host_window) then ImGui.BeginDockableDragDropTarget(host_window) end end node.LastFrameActive = g.FrameCount if host_window then if node.ChildNodes[0] then ImGui.DockNodeUpdate(node.ChildNodes[0]) end if node.ChildNodes[1] then ImGui.DockNodeUpdate(node.ChildNodes[1]) end if node:IsRootNode() then ImGui.RenderWindowOuterBorders(host_window) end end if beginned_into_host_window then ImGui.End() end end local GWindowDockStyleColors = { [0] = ImGuiCol.Text, ImGuiCol.TabHovered, ImGuiCol.Tab, ImGuiCol.TabSelected, ImGuiCol.TabSelectedOverline, ImGuiCol.TabDimmed, ImGuiCol.TabDimmedSelected, ImGuiCol.TabDimmedSelectedOverline, ImGuiCol.UnsavedMarker, } ImGui.GWindowDockStyleColors = GWindowDockStyleColors local function TabItemComparerByDockOrder(ta, tb) local a, b = ta.Window, tb.Window local ao = (a.DockOrder == -1) and INT_MAX or a.DockOrder local bo = (b.DockOrder == -1) and INT_MAX or b.DockOrder if ao ~= bo then return ao < bo end return a.BeginOrderWithinContext < b.BeginOrderWithinContext end function ImGui.DockNodeWindowMenuHandler_Default(ctx, node, tab_bar) if tab_bar.Tabs.Size == 1 then if ImGui.MenuItem(ImGui.LocalizeGetMsg(ImGuiLocKey.DockingHideTabBar), nil, node:IsHiddenTabBar()) then node.WantHiddenTabBarToggle = true end else for tab_n = 1, tab_bar.Tabs.Size do local tab = tab_bar.Tabs.Data[tab_n] if bit32.band(tab.Flags, ImGuiTabItemFlags.Button) == 0 then if ImGui.Selectable(ImGui.TabBarGetTabName(tab_bar, tab), tab.ID == tab_bar.SelectedTabId) then ImGui.TabBarQueueFocus(tab_bar, tab) end ImGui.SameLine() ImGui.Text(" ") end end end end function ImGui.DockNodeWindowMenuUpdate(node, tab_bar) local g = ImGui.GetCurrentContext() if g.Style.WindowMenuButtonPosition == ImGuiDir.Left then ImGui.SetNextWindowPos(ImVec2(node.Pos.x, node.Pos.y + ImGui.GetFrameHeight()), ImGuiCond.Always, ImVec2(0.0, 0.0)) else ImGui.SetNextWindowPos(ImVec2(node.Pos.x + node.Size.x, node.Pos.y + ImGui.GetFrameHeight()), ImGuiCond.Always, ImVec2(1.0, 0.0)) end if ImGui.BeginPopup("#WindowMenu") then node.IsFocused = true g.DockNodeWindowMenuHandler(g, node, tab_bar) ImGui.EndPopup() end end function ImGui.DockNodeBeginAmendTabBar(node) if node.TabBar == nil or node.HostWindow == nil then return false end if bit32.band(node.MergedFlags, ImGuiDockNodeFlags.KeepAliveOnly) ~= 0 then return false end if node.TabBar.ID == 0 then return false end ImGui.Begin(node.HostWindow.Name) ImGui.PushOverrideID(node.ID) local ret = ImGui.BeginTabBarEx(node.TabBar, node.TabBar.BarRect, node.TabBar.Flags) IM_ASSERT(ret) return true end function ImGui.DockNodeEndAmendTabBar() ImGui.EndTabBar() ImGui.PopID() ImGui.End() end local function IsDockNodeTitleBarHighlighted(node, root_node) local g = ImGui.GetCurrentContext() if g.NavWindowingTarget then return g.NavWindowingTarget.DockNode == node end if g.NavWindow and root_node.LastFocusedNodeId == node.ID then local parent_window = g.NavWindow.RootWindow while bit32.band(parent_window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 do parent_window = parent_window.ParentWindow.RootWindow end local parent_node = parent_window.DockNodeAsHost or parent_window.DockNode while parent_node ~= nil do parent_node = ImGui.DockNodeGetRootNode(parent_node) if parent_node == root_node then return true end parent_node = parent_node.HostWindow and parent_node.HostWindow.RootWindow.DockNode or nil end end return false end function ImGui.DockNodeUpdateTabBar(node, host_window) local g = ImGui.GetCurrentContext() local style = g.Style local node_was_active = (node.LastFrameActive + 1 == g.FrameCount) node.WantCloseAll = false node.WantCloseTabId = 0 local is_focused = false local root_node = ImGui.DockNodeGetRootNode(node) if IsDockNodeTitleBarHighlighted(node, root_node) then is_focused = true end if node:IsHiddenTabBar() or node:IsNoTabBar() then node.VisibleWindow = (node.Windows.Size > 0) and node.Windows.Data[1] or nil node.IsFocused = is_focused if is_focused then node.LastFrameFocused = g.FrameCount end if node.VisibleWindow then if is_focused or root_node.VisibleWindow == nil then root_node.VisibleWindow = node.VisibleWindow end if node.TabBar then node.TabBar.VisibleTabId = node.VisibleWindow.TabId end end return end local backup_skip_item = host_window.SkipItems if not node:IsDockSpace() then host_window.SkipItems = false host_window.DC.NavLayerCurrent = ImGuiNavLayer.Menu end ImGui.PushOverrideID(node.ID) local tab_bar = node.TabBar local tab_bar_is_recreated = (tab_bar == nil) if tab_bar == nil then ImGui.DockNodeAddTabBar(node) tab_bar = node.TabBar end local focus_tab_id = 0 node.IsFocused = is_focused local node_flags = node.MergedFlags local has_window_menu_button = bit32.band(node_flags, ImGuiDockNodeFlags.NoWindowMenuButton) == 0 and (style.WindowMenuButtonPosition ~= ImGuiDir.None) if has_window_menu_button and ImGui.IsPopupOpen("#WindowMenu") then local next_selected_tab_id = tab_bar.NextSelectedTabId ImGui.DockNodeWindowMenuUpdate(node, tab_bar) if tab_bar.NextSelectedTabId ~= 0 and tab_bar.NextSelectedTabId ~= next_selected_tab_id then focus_tab_id = tab_bar.NextSelectedTabId end is_focused = is_focused or node.IsFocused end local title_bar_rect, tab_bar_rect, window_menu_button_pos, close_button_pos = ImGui.DockNodeCalcTabBarLayout(node) local tabs_count_old = tab_bar.Tabs.Size for window_n = 1, node.Windows.Size do local window = node.Windows.Data[window_n] if ImGui.TabBarFindTabByID(tab_bar, window.TabId) == nil then ImGui.TabBarAddTab(tab_bar, ImGuiTabItemFlags.Unsorted, window) end end if is_focused then node.LastFrameFocused = g.FrameCount end local title_bar_col = ImGui.GetColorU32(host_window.Collapsed and ImGuiCol.TitleBgCollapsed or (is_focused and ImGuiCol.TitleBgActive or ImGuiCol.TitleBg)) local rounding_flags = ImGui.CalcRoundingFlagsForRectInRect(title_bar_rect, host_window:Rect(), g.Style.DockingSeparatorSize) host_window.DrawList:AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window.WindowRounding, rounding_flags) if has_window_menu_button then if ImGui.CollapseButton(host_window:GetID("#COLLAPSE"), window_menu_button_pos, node) then ImGui.OpenPopup("#WindowMenu") end if ImGui.IsItemActive() then focus_tab_id = tab_bar.SelectedTabId end if ImGui.IsItemHovered(bit32.bor(ImGuiHoveredFlags.ForTooltip, ImGuiHoveredFlags.DelayNormal)) and g.HoveredIdTimer > 0.5 then ImGui.SetTooltip("%s", ImGui.LocalizeGetMsg(ImGuiLocKey.DockingDragToUndockOrMoveNode)) end end local tabs_unsorted_start = tab_bar.Tabs.Size -- 0-based local tab_n = tab_bar.Tabs.Size - 1 while tab_n >= 0 and bit32.band(tab_bar.Tabs.Data[tab_n + 1].Flags, ImGuiTabItemFlags.Unsorted) ~= 0 do local t = tab_bar.Tabs.Data[tab_n + 1] t.Flags = bit32.band(t.Flags, bit32.bnot(ImGuiTabItemFlags.Unsorted)) tabs_unsorted_start = tab_n tab_n = tab_n - 1 end if tab_bar.Tabs.Size > tabs_unsorted_start + 1 then local slice = {} for i = tabs_unsorted_start + 1, tab_bar.Tabs.Size do slice[#slice + 1] = tab_bar.Tabs.Data[i] end table.sort(slice, TabItemComparerByDockOrder) for i, t in ipairs(slice) do tab_bar.Tabs.Data[tabs_unsorted_start + i] = t end end if g.NavWindow and g.NavWindow.RootWindow.DockNode == node then tab_bar.SelectedTabId = g.NavWindow.RootWindow.TabId end if tab_bar_is_recreated and ImGui.TabBarFindTabByID(tab_bar, node.SelectedTabId) ~= nil then tab_bar.SelectedTabId = node.SelectedTabId tab_bar.NextSelectedTabId = node.SelectedTabId elseif tab_bar.Tabs.Size > tabs_count_old then tab_bar.SelectedTabId = tab_bar.Tabs.Data[tab_bar.Tabs.Size].Window.TabId tab_bar.NextSelectedTabId = tab_bar.SelectedTabId end local tab_bar_flags = bit32.bor(ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.AutoSelectNewTabs) tab_bar_flags = bit32.bor(tab_bar_flags, ImGuiTabBarFlags.SaveSettings, ImGuiTabBarFlags.DockNode) tab_bar_flags = bit32.bor(tab_bar_flags, ImGuiTabBarFlags.FittingPolicyMixed) tab_bar_flags = bit32.bor(tab_bar_flags, ImGuiTabBarFlags.DrawSelectedOverline) if not host_window.Collapsed and is_focused then tab_bar_flags = bit32.bor(tab_bar_flags, ImGuiTabBarFlags.IsFocused) end tab_bar.ID = node.ID tab_bar.SeparatorMinX = node.Pos.x + host_window.WindowBorderSize tab_bar.SeparatorMaxX = node.Pos.x + node.Size.x - host_window.WindowBorderSize ImGui.BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags) local backup_style_cols = {} for color_n = 0, ImGuiWindowDockStyleCol.COUNT - 1 do local c = g.Style.Colors[GWindowDockStyleColors[color_n]] backup_style_cols[color_n] = ImVec4(c.x, c.y, c.z, c.w) end node.VisibleWindow = nil for window_n = 1, node.Windows.Size do local window = node.Windows.Data[window_n] if not (window.LastFrameActive + 1 < g.FrameCount and node_was_active) then local tab_item_flags = 0 tab_item_flags = bit32.bor(tab_item_flags, window.WindowClass.TabItemFlagsOverrideSet or 0) if bit32.band(window.Flags, ImGuiWindowFlags.UnsavedDocument) ~= 0 then tab_item_flags = bit32.bor(tab_item_flags, ImGuiTabItemFlags.UnsavedDocument) end if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.NoCloseWithMiddleMouseButton) ~= 0 then tab_item_flags = bit32.bor(tab_item_flags, ImGuiTabItemFlags.NoCloseWithMiddleMouseButton) end for color_n = 0, ImGuiWindowDockStyleCol.COUNT - 1 do ImVec4_Copy(g.Style.Colors[GWindowDockStyleColors[color_n]], ImGui.ColorConvertU32ToFloat4(window.DockStyle.Colors[color_n])) end local _, tab_open = ImGui.TabItemEx(tab_bar, window.Name, window.HasCloseButton and true or nil, tab_item_flags, window) if tab_open == false then node.WantCloseTabId = window.TabId end if tab_bar.VisibleTabId == window.TabId then node.VisibleWindow = window end window.DC.DockTabItemStatusFlags = g.LastItemData.StatusFlags window.DC.DockTabItemRect = ImRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max) if g.NavWindow and g.NavWindow.RootWindow == window and bit32.band(window.DC.NavLayersActiveMask, bit32.lshift(1, ImGuiNavLayer.Menu)) == 0 then host_window.NavLastIds[1] = window.TabId end end end for color_n = 0, ImGuiWindowDockStyleCol.COUNT - 1 do ImVec4_Copy(g.Style.Colors[GWindowDockStyleColors[color_n]], backup_style_cols[color_n]) end if node.VisibleWindow then if is_focused or root_node.VisibleWindow == nil then root_node.VisibleWindow = node.VisibleWindow end end local close_button_is_enabled = node.HasCloseButton and node.VisibleWindow and node.VisibleWindow.HasCloseButton local close_button_is_visible = node.HasCloseButton if close_button_is_visible then if not close_button_is_enabled then ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true) local tc = style.Colors[ImGuiCol.Text] ImGui.PushStyleColor(ImGuiCol.Text, ImVec4(tc.x, tc.y, tc.z, tc.w * 0.4)) end if ImGui.CloseButton(host_window:GetID("#CLOSE"), close_button_pos) then node.WantCloseAll = true for n = 1, tab_bar.Tabs.Size do ImGui.TabBarCloseTab(tab_bar, tab_bar.Tabs.Data[n]) end end if not close_button_is_enabled then ImGui.PopStyleColor() ImGui.PopItemFlag() end end local title_bar_id = host_window:GetID("#TITLEBAR") if g.HoveredId == 0 or g.HoveredId == title_bar_id or g.ActiveId == title_bar_id then ImGui.KeepAliveID(title_bar_id) local _, _, held = ImGui.ButtonBehavior(title_bar_rect, title_bar_id, ImGuiButtonFlags.AllowOverlap) if g.HoveredId == title_bar_id then g.LastItemData.ID = title_bar_id end if held then if ImGui.IsMouseClicked(0) then focus_tab_id = tab_bar.SelectedTabId end local tab = ImGui.TabBarFindTabByID(tab_bar, tab_bar.SelectedTabId) if tab then ImGui.StartMouseMovingWindowOrNode(tab.Window or node.HostWindow, node, false) end end end if tab_bar.NextSelectedTabId ~= 0 then focus_tab_id = tab_bar.NextSelectedTabId end if focus_tab_id ~= 0 then local tab = ImGui.TabBarFindTabByID(tab_bar, focus_tab_id) if tab and tab.Window then ImGui.FocusWindow(tab.Window) if g.NavId == 0 then ImGui.NavInitWindow(tab.Window, false) end end end ImGui.EndTabBar() ImGui.PopID() if not node:IsDockSpace() then host_window.DC.NavLayerCurrent = ImGuiNavLayer.Main host_window.SkipItems = backup_skip_item end end function ImGui.DockNodeAddTabBar(node) IM_ASSERT(node.TabBar == nil) node.TabBar = ImGuiTabBar() end function ImGui.DockNodeRemoveTabBar(node) if node.TabBar == nil then return end node.TabBar = nil end local function DockNodeIsDropAllowedOne(payload, host_window) if host_window.DockNodeAsHost and host_window.DockNodeAsHost:IsDockSpace() and payload.BeginOrderWithinContext < host_window.BeginOrderWithinContext then return false end local host_class = host_window.DockNodeAsHost and host_window.DockNodeAsHost.WindowClass or host_window.WindowClass local payload_class = payload.WindowClass if host_class.ClassId ~= payload_class.ClassId then local pass = false if host_class.ClassId ~= 0 and host_class.DockingAllowUnclassed and payload_class.ClassId == 0 then pass = true end if payload_class.ClassId ~= 0 and payload_class.DockingAllowUnclassed and host_class.ClassId == 0 then pass = true end if not pass then return false end end local g = ImGui.GetCurrentContext() for i = g.OpenPopupStack.Size, 1, -1 do local popup_window = g.OpenPopupStack.Data[i].Window if popup_window and ImGui.IsWindowWithinBeginStackOf(payload, popup_window) then return false end end return true end function ImGui.DockNodeIsDropAllowed(host_window, root_payload) if root_payload.DockNodeAsHost and root_payload.DockNodeAsHost:IsSplitNode() then return true end local payload_count = root_payload.DockNodeAsHost and root_payload.DockNodeAsHost.Windows.Size or 1 for payload_n = 1, payload_count do local payload = root_payload.DockNodeAsHost and root_payload.DockNodeAsHost.Windows.Data[payload_n] or root_payload if DockNodeIsDropAllowedOne(payload, host_window) then return true end end return false end --- @return ImRect title_rect, ImRect tab_bar_rect, ImVec2 window_menu_button_pos, ImVec2? close_button_pos function ImGui.DockNodeCalcTabBarLayout(node) local g = ImGui.GetCurrentContext() local style = g.Style local r = ImRect(node.Pos.x, node.Pos.y, node.Pos.x + node.Size.x, node.Pos.y + g.FontSize + g.Style.FramePadding.y * 2.0) local out_title_rect = ImRect(r.Min, r.Max) r.Min.x = r.Min.x + style.WindowBorderSize r.Max.x = r.Max.x - style.WindowBorderSize local button_sz = g.FontSize r.Min.x = r.Min.x + style.FramePadding.x r.Max.x = r.Max.x - style.FramePadding.x local window_menu_button_pos = ImVec2(r.Min.x, r.Min.y + style.FramePadding.y) local out_close_button_pos = nil if node.HasCloseButton then out_close_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y) r.Max.x = r.Max.x - (button_sz + style.ItemInnerSpacing.x) end if node.HasWindowMenuButton and style.WindowMenuButtonPosition == ImGuiDir.Left then r.Min.x = r.Min.x + button_sz + style.ItemInnerSpacing.x elseif node.HasWindowMenuButton and style.WindowMenuButtonPosition == ImGuiDir.Right then window_menu_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y) r.Max.x = r.Max.x - (button_sz + style.ItemInnerSpacing.x) end return out_title_rect, r, window_menu_button_pos, out_close_button_pos end --- Modifies pos_old/size_old/pos_new/size_new in place (ImVec2 tables) function ImGui.DockNodeCalcSplitRects(pos_old, size_old, pos_new, size_new, dir, size_new_desired) local g = ImGui.GetCurrentContext() local dock_spacing = g.Style.ItemInnerSpacing.x local axis = (dir == ImGuiDir.Left or dir == ImGuiDir.Right) and ImGuiAxis.X or ImGuiAxis.Y local a, o = axis, 3 - axis -- the port's ImGuiAxis is 1-based (X=1,Y=2): it is directly the ImVec2 index pos_new[o] = pos_old[o] size_new[o] = size_old[o] local w_avail = size_old[a] - dock_spacing if size_new_desired[a] > 0.0 and size_new_desired[a] <= w_avail * 0.5 then size_new[a] = size_new_desired[a] size_old[a] = IM_TRUNC(w_avail - size_new[a]) else size_new[a] = IM_TRUNC(w_avail * 0.5) size_old[a] = IM_TRUNC(w_avail - size_new[a]) end if dir == ImGuiDir.Right or dir == ImGuiDir.Down then pos_new[a] = pos_old[a] + size_old[a] + dock_spacing elseif dir == ImGuiDir.Left or dir == ImGuiDir.Up then pos_new[a] = pos_old[a] pos_old[a] = pos_new[a] + size_new[a] + dock_spacing end end local function ImGetDirQuadrantFromDeltaLocal(dx, dy) if math.abs(dx) > math.abs(dy) then return (dx > 0.0) and ImGuiDir.Right or ImGuiDir.Left end return (dy > 0.0) and ImGuiDir.Down or ImGuiDir.Up end --- @return bool hit, ImRect out_r function ImGui.DockNodeCalcDropRectsAndTestMousePos(parent, dir, outer_docking, test_mouse_pos) local g = ImGui.GetCurrentContext() local parent_smaller_axis = ImMin(parent:GetWidth(), parent:GetHeight()) local hs_for_central_nodes = ImMin(g.FontSize * 1.5, ImMax(g.FontSize * 0.5, parent_smaller_axis / 8.0)) local hs_w, hs_h, off if outer_docking then hs_w = ImTrunc(hs_for_central_nodes * 1.50) hs_h = ImTrunc(hs_for_central_nodes * 0.80) off = ImVec2(ImTrunc(parent:GetWidth() * 0.5 - hs_h), ImTrunc(parent:GetHeight() * 0.5 - hs_h)) else hs_w = ImTrunc(hs_for_central_nodes) hs_h = ImTrunc(hs_for_central_nodes * 0.90) off = ImVec2(ImTrunc(hs_w * 2.40), ImTrunc(hs_w * 2.40)) end local pc = parent:GetCenter() local c = ImVec2(ImTrunc(pc.x), ImTrunc(pc.y)) local out_r if dir == ImGuiDir.None then out_r = ImRect(c.x - hs_w, c.y - hs_w, c.x + hs_w, c.y + hs_w) elseif dir == ImGuiDir.Up then out_r = ImRect(c.x - hs_w, c.y - off.y - hs_h, c.x + hs_w, c.y - off.y + hs_h) elseif dir == ImGuiDir.Down then out_r = ImRect(c.x - hs_w, c.y + off.y - hs_h, c.x + hs_w, c.y + off.y + hs_h) elseif dir == ImGuiDir.Left then out_r = ImRect(c.x - off.x - hs_h, c.y - hs_w, c.x - off.x + hs_h, c.y + hs_w) elseif dir == ImGuiDir.Right then out_r = ImRect(c.x + off.x - hs_h, c.y - hs_w, c.x + off.x + hs_h, c.y + hs_w) end if test_mouse_pos == nil then return false, out_r end local hit_r = ImRect(out_r.Min, out_r.Max) if not outer_docking then hit_r:Expand(ImTrunc(hs_w * 0.30)) local mdx, mdy = test_mouse_pos.x - c.x, test_mouse_pos.y - c.y local mouse_delta_len2 = mdx * mdx + mdy * mdy local r_threshold_center = hs_w * 1.4 local r_threshold_sides = hs_w * (1.4 + 1.2) if mouse_delta_len2 < r_threshold_center * r_threshold_center then return (dir == ImGuiDir.None), out_r end if mouse_delta_len2 < r_threshold_sides * r_threshold_sides then return (dir == ImGetDirQuadrantFromDeltaLocal(mdx, mdy)), out_r end end return hit_r:Contains(test_mouse_pos), out_r end function ImGui.DockNodePreviewDockSetup(host_window, host_node, payload_window, payload_node, data, is_explicit_target, is_outer_docking) local g = ImGui.GetCurrentContext() if payload_node == nil then payload_node = payload_window.DockNodeAsHost end local ref_node_for_rect = (host_node and not host_node.IsVisible) and ImGui.DockNodeGetRootNode(host_node) or host_node if ref_node_for_rect then IM_ASSERT(ref_node_for_rect.IsVisible == true) end local src_node_flags = payload_node and payload_node.MergedFlags or payload_window.WindowClass.DockNodeFlagsOverrideSet local dst_node_flags = host_node and host_node.MergedFlags or host_window.WindowClass.DockNodeFlagsOverrideSet data.IsCenterAvailable = true if is_outer_docking then data.IsCenterAvailable = false elseif g.IO.ConfigDockingNoDockingOver then data.IsCenterAvailable = false elseif bit32.band(dst_node_flags, ImGuiDockNodeFlags.NoDockingOverMe) ~= 0 then data.IsCenterAvailable = false elseif host_node and bit32.band(dst_node_flags, ImGuiDockNodeFlags.NoDockingOverCentralNode) ~= 0 and host_node:IsCentralNode() then data.IsCenterAvailable = false elseif (not host_node or not host_node:IsEmpty()) and payload_node and payload_node:IsSplitNode() and (payload_node.OnlyNodeWithWindows == nil) then data.IsCenterAvailable = false elseif bit32.band(src_node_flags, ImGuiDockNodeFlags.NoDockingOverOther) ~= 0 and (not host_node or not host_node:IsEmpty()) then data.IsCenterAvailable = false elseif bit32.band(src_node_flags, ImGuiDockNodeFlags.NoDockingOverEmpty) ~= 0 and host_node and host_node:IsEmpty() then data.IsCenterAvailable = false end data.IsSidesAvailable = true if bit32.band(dst_node_flags, ImGuiDockNodeFlags.NoDockingSplit) ~= 0 or g.IO.ConfigDockingNoSplit then data.IsSidesAvailable = false elseif not is_outer_docking and host_node and host_node.ParentNode == nil and host_node:IsCentralNode() then data.IsSidesAvailable = false elseif bit32.band(src_node_flags, ImGuiDockNodeFlags.NoDockingSplitOther) ~= 0 then data.IsSidesAvailable = false end data.FutureNode.HasCloseButton = (host_node and host_node.HasCloseButton or (not host_node and host_window.HasCloseButton)) or payload_window.HasCloseButton data.FutureNode.HasWindowMenuButton = host_node and true or (bit32.band(host_window.Flags, ImGuiWindowFlags.NoCollapse) == 0) local rp = ref_node_for_rect and ref_node_for_rect.Pos or host_window.Pos local rs = ref_node_for_rect and ref_node_for_rect.Size or host_window.Size data.FutureNode.Pos = ImVec2(rp.x, rp.y) data.FutureNode.Size = ImVec2(rs.x, rs.y) data.SplitNode = host_node data.SplitDir = ImGuiDir.None data.IsSplitDirExplicit = false if not host_window.Collapsed then for dir = ImGuiDir.None, ImGuiDir.COUNT - 1 do if not ((dir == ImGuiDir.None and not data.IsCenterAvailable) or (dir ~= ImGuiDir.None and not data.IsSidesAvailable)) then local hit, r = ImGui.DockNodeCalcDropRectsAndTestMousePos(data.FutureNode:Rect(), dir, is_outer_docking, g.IO.MousePos) data.DropRectsDraw[dir + 1] = r if hit then data.SplitDir = dir data.IsSplitDirExplicit = true end end end end data.IsDropAllowed = (data.SplitDir ~= ImGuiDir.None) or data.IsCenterAvailable if not is_explicit_target and not data.IsSplitDirExplicit and not g.IO.ConfigDockingWithShift then data.IsDropAllowed = false end data.SplitRatio = 0.0 if data.SplitDir ~= ImGuiDir.None then local split_dir = data.SplitDir local split_axis = (split_dir == ImGuiDir.Left or split_dir == ImGuiDir.Right) and ImGuiAxis.X or ImGuiAxis.Y local pos_new, pos_old = ImVec2(0, 0), ImVec2(data.FutureNode.Pos.x, data.FutureNode.Pos.y) local size_new, size_old = ImVec2(0, 0), ImVec2(data.FutureNode.Size.x, data.FutureNode.Size.y) ImGui.DockNodeCalcSplitRects(pos_old, size_old, pos_new, size_new, split_dir, payload_window.Size) local split_ratio = ImSaturate(size_new[split_axis] / data.FutureNode.Size[split_axis]) data.FutureNode.Pos = pos_new data.FutureNode.Size = size_new data.SplitRatio = (split_dir == ImGuiDir.Right or split_dir == ImGuiDir.Down) and (1.0 - split_ratio) or split_ratio end end function ImGui.DockNodePreviewDockRender(host_window, host_node, root_payload, data) local g = ImGui.GetCurrentContext() IM_ASSERT(g.CurrentWindow == host_window) local is_transparent_payload = g.IO.ConfigDockingTransparentPayload local overlay_draw_lists = { ImGui.GetForegroundDrawList(host_window.Viewport) } local overlay_col_main = ImGui.GetColorU32(ImGuiCol.DockingPreview, is_transparent_payload and 0.60 or 0.40) local overlay_col_drop = ImGui.GetColorU32(ImGuiCol.DockingPreview, is_transparent_payload and 0.90 or 0.70) local overlay_col_drop_hovered = ImGui.GetColorU32(ImGuiCol.DockingPreview, is_transparent_payload and 1.20 or 1.00) local overlay_col_lines = ImGui.GetColorU32(ImGuiCol.NavWindowingHighlight, is_transparent_payload and 0.80 or 0.60) local can_preview_tabs = (root_payload.DockNodeAsHost == nil or root_payload.DockNodeAsHost.Windows.Size > 0) if data.IsDropAllowed then local overlay_rect = data.FutureNode:Rect() if data.SplitDir == ImGuiDir.None and can_preview_tabs then overlay_rect.Min.y = overlay_rect.Min.y + ImGui.GetFrameHeight() end if data.SplitDir ~= ImGuiDir.None or data.IsCenterAvailable then for _, dl in ipairs(overlay_draw_lists) do dl:AddRectFilled(overlay_rect.Min, overlay_rect.Max, overlay_col_main, host_window.WindowRounding, ImGui.CalcRoundingFlagsForRectInRect(overlay_rect, host_window:Rect(), g.Style.DockingSeparatorSize)) end end end if data.IsDropAllowed and can_preview_tabs and data.SplitDir == ImGuiDir.None and data.IsCenterAvailable then local _, tab_bar_rect = ImGui.DockNodeCalcTabBarLayout(data.FutureNode) local tab_pos = ImVec2(tab_bar_rect.Min.x, tab_bar_rect.Min.y) if host_node and host_node.TabBar then if not host_node:IsHiddenTabBar() and not host_node:IsNoTabBar() then tab_pos.x = tab_pos.x + host_node.TabBar.WidthAllTabs + g.Style.ItemInnerSpacing.x else tab_pos.x = tab_pos.x + g.Style.ItemInnerSpacing.x + ImGui.TabItemCalcSize(host_node.Windows.Data[1]).x end elseif bit32.band(host_window.Flags, ImGuiWindowFlags.DockNodeHost) == 0 then tab_pos.x = tab_pos.x + g.Style.ItemInnerSpacing.x + ImGui.TabItemCalcSize(host_window).x end if root_payload.DockNodeAsHost then IM_ASSERT(root_payload.DockNodeAsHost.Windows.Size <= root_payload.DockNodeAsHost.TabBar.Tabs.Size) end local tab_bar_with_payload = root_payload.DockNodeAsHost and root_payload.DockNodeAsHost.TabBar or nil local payload_count = tab_bar_with_payload and tab_bar_with_payload.Tabs.Size or 1 for payload_n = 1, payload_count do local payload_window = tab_bar_with_payload and tab_bar_with_payload.Tabs.Data[payload_n].Window or root_payload if not (tab_bar_with_payload and payload_window == nil) and DockNodeIsDropAllowedOne(payload_window, host_window) then local tab_size = ImGui.TabItemCalcSize(payload_window) local tab_bb = ImRect(tab_pos.x, tab_pos.y, tab_pos.x + tab_size.x, tab_pos.y + tab_size.y) tab_pos.x = tab_pos.x + tab_size.x + g.Style.ItemInnerSpacing.x local overlay_col_text = ImGui.GetColorU32(payload_window.DockStyle.Colors[ImGuiWindowDockStyleCol.Text], 1.0, true) local overlay_col_tabs = ImGui.GetColorU32(payload_window.DockStyle.Colors[ImGuiWindowDockStyleCol.TabSelected], 1.0, true) local overlay_col_unsaved_marker = ImGui.GetColorU32(payload_window.DockStyle.Colors[ImGuiWindowDockStyleCol.UnsavedMarker], 1.0, true) ImGui.PushStyleColor(ImGuiCol.Text, ImGui.ColorConvertU32ToFloat4(overlay_col_text)) ImGui.PushStyleColor(ImGuiCol.UnsavedMarker, ImGui.ColorConvertU32ToFloat4(overlay_col_unsaved_marker)) for _, dl in ipairs(overlay_draw_lists) do local tab_flags = bit32.band(payload_window.Flags, ImGuiWindowFlags.UnsavedDocument) ~= 0 and ImGuiTabItemFlags.UnsavedDocument or 0 local contains = tab_bar_rect:Contains(tab_bb) if not contains then dl:PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max) end ImGui.TabItemBackground(dl, tab_bb, tab_flags, overlay_col_tabs) ImGui.TabItemLabelAndCloseButton(dl, tab_bb, tab_flags, g.Style.FramePadding, payload_window.Name, 0, 0, false) if not contains then dl:PopClipRect() end end ImGui.PopStyleColor(2) end end end local scale = g.Style._MainScale or 1.0 local overlay_rounding = ImMax(math.floor(3.0 * scale), g.Style.FrameRounding) for dir = ImGuiDir.None, ImGuiDir.COUNT - 1 do local draw_r = data.DropRectsDraw[dir + 1] if not IsRectInverted(draw_r) then local draw_r_in = ImRect(draw_r.Min, draw_r.Max) draw_r_in:Expand(math.floor(-2.0 * scale)) local overlay_col = (data.SplitDir == dir and data.IsSplitDirExplicit) and overlay_col_drop_hovered or overlay_col_drop local thickness = math.floor(1.0 * scale) for _, dl in ipairs(overlay_draw_lists) do local cc = draw_r_in:GetCenter() local center = ImVec2(math.floor(cc.x), math.floor(cc.y)) dl:AddRectFilled(draw_r.Min, draw_r.Max, overlay_col, overlay_rounding) dl:AddRect(draw_r_in.Min, draw_r_in.Max, overlay_col_lines, overlay_rounding, thickness) if dir == ImGuiDir.Left or dir == ImGuiDir.Right then dl:AddLineV(center.x, draw_r_in.Min.y, draw_r_in.Max.y, overlay_col_lines, thickness) end if dir == ImGuiDir.Up or dir == ImGuiDir.Down then dl:AddLineH(draw_r_in.Min.x, draw_r_in.Max.x, center.y, overlay_col_lines, thickness) end end end if (host_node and bit32.band(host_node.MergedFlags, ImGuiDockNodeFlags.NoDockingSplit) ~= 0) or g.IO.ConfigDockingNoSplit then return end end end --------------------------------------------------------------------------------------- -- Docking: ImGuiDockNode Tree manipulation functions --------------------------------------------------------------------------------------- function ImGui.DockNodeTreeSplit(ctx, parent_node, split_axis, split_inheritor_child_idx, split_ratio, new_node) local g = ImGui.GetCurrentContext() IM_ASSERT(split_axis ~= ImGuiAxis.None) local child_0 = (new_node and split_inheritor_child_idx ~= 0) and new_node or ImGui.DockContextAddNode(ctx, 0) child_0.ParentNode = parent_node local child_1 = (new_node and split_inheritor_child_idx ~= 1) and new_node or ImGui.DockContextAddNode(ctx, 0) child_1.ParentNode = parent_node local child_inheritor = (split_inheritor_child_idx == 0) and child_0 or child_1 ImGui.DockNodeMoveChildNodes(child_inheritor, parent_node) parent_node.ChildNodes[0] = child_0 parent_node.ChildNodes[1] = child_1 parent_node.ChildNodes[split_inheritor_child_idx].VisibleWindow = parent_node.VisibleWindow parent_node.SplitAxis = split_axis parent_node.VisibleWindow = nil parent_node.AuthorityForPos = ImGuiDataAuthority.DockNode parent_node.AuthorityForSize = ImGuiDataAuthority.DockNode local a = split_axis local size_avail = parent_node.Size[a] - g.Style.DockingSeparatorSize size_avail = ImMax(size_avail, g.Style.WindowMinSize[a] * 2.0) IM_ASSERT(size_avail > 0.0) child_0.SizeRef = ImVec2(parent_node.Size.x, parent_node.Size.y) child_1.SizeRef = ImVec2(parent_node.Size.x, parent_node.Size.y) child_0.SizeRef[a] = ImTrunc(size_avail * split_ratio) child_1.SizeRef[a] = ImTrunc(size_avail - child_0.SizeRef[a]) ImGui.DockNodeMoveWindows(parent_node.ChildNodes[split_inheritor_child_idx], parent_node) DockSettingsRenameNodeReferences(parent_node.ID, parent_node.ChildNodes[split_inheritor_child_idx].ID) ImGui.DockNodeUpdateHasCentralNodeChild(ImGui.DockNodeGetRootNode(parent_node)) ImGui.DockNodeTreeUpdatePosSize(parent_node, parent_node.Pos, parent_node.Size) child_0.SharedFlags = bit32.band(parent_node.SharedFlags, ImGuiDockNodeFlags.SharedFlagsInheritMask_) child_1.SharedFlags = bit32.band(parent_node.SharedFlags, ImGuiDockNodeFlags.SharedFlagsInheritMask_) child_inheritor.LocalFlags = bit32.band(parent_node.LocalFlags, ImGuiDockNodeFlags.LocalFlagsTransferMask_) parent_node.LocalFlags = bit32.band(parent_node.LocalFlags, bit32.bnot(ImGuiDockNodeFlags.LocalFlagsTransferMask_)) child_0:UpdateMergedFlags() child_1:UpdateMergedFlags() parent_node:UpdateMergedFlags() if child_inheritor:IsCentralNode() then ImGui.DockNodeGetRootNode(parent_node).CentralNode = child_inheritor end end function ImGui.DockNodeTreeMerge(ctx, parent_node, merge_lead_child) local child_0 = parent_node.ChildNodes[0] local child_1 = parent_node.ChildNodes[1] IM_ASSERT(child_0 or child_1) IM_ASSERT(merge_lead_child == child_0 or merge_lead_child == child_1) if (child_0 and child_0.Windows.Size > 0) or (child_1 and child_1.Windows.Size > 0) then IM_ASSERT(parent_node.TabBar == nil) IM_ASSERT(parent_node.Windows.Size == 0) end local backup_last_explicit_size = ImVec2(parent_node.SizeRef.x, parent_node.SizeRef.y) ImGui.DockNodeMoveChildNodes(parent_node, merge_lead_child) if child_0 then ImGui.DockNodeMoveWindows(parent_node, child_0) DockSettingsRenameNodeReferences(child_0.ID, parent_node.ID) end if child_1 then ImGui.DockNodeMoveWindows(parent_node, child_1) DockSettingsRenameNodeReferences(child_1.ID, parent_node.ID) end ImGui.DockNodeApplyPosSizeToWindows(parent_node) parent_node.AuthorityForPos = ImGuiDataAuthority.Auto parent_node.AuthorityForSize = ImGuiDataAuthority.Auto parent_node.AuthorityForViewport = ImGuiDataAuthority.Auto parent_node.VisibleWindow = merge_lead_child.VisibleWindow parent_node.SizeRef = backup_last_explicit_size local M = ImGuiDockNodeFlags.LocalFlagsTransferMask_ parent_node.LocalFlags = bit32.band(parent_node.LocalFlags, bit32.bnot(M)) parent_node.LocalFlags = bit32.bor(parent_node.LocalFlags, bit32.band(child_0 and child_0.LocalFlags or 0, M)) parent_node.LocalFlags = bit32.bor(parent_node.LocalFlags, bit32.band(child_1 and child_1.LocalFlags or 0, M)) parent_node.LocalFlagsInWindows = bit32.bor(child_0 and child_0.LocalFlagsInWindows or 0, child_1 and child_1.LocalFlagsInWindows or 0) parent_node:UpdateMergedFlags() if child_0 then ImGui.DockContextDeleteNode(ctx, child_0) end if child_1 then ImGui.DockContextDeleteNode(ctx, child_1) end end function ImGui.DockNodeTreeUpdatePosSize(node, pos, size, only_write_to_single_node) local g = ImGui.GetCurrentContext() local write_to_node = only_write_to_single_node == nil or only_write_to_single_node == node if write_to_node then node.Pos = ImVec2(pos.x, pos.y) node.Size = ImVec2(size.x, size.y) end if node:IsLeafNode() then return end local child_0 = node.ChildNodes[0] local child_1 = node.ChildNodes[1] local child_0_pos, child_1_pos = ImVec2(pos.x, pos.y), ImVec2(pos.x, pos.y) local child_0_size, child_1_size = ImVec2(size.x, size.y), ImVec2(size.x, size.y) local child_0_is_toward_single_node = (only_write_to_single_node ~= nil and ImGui.DockNodeIsInHierarchyOf(only_write_to_single_node, child_0)) local child_1_is_toward_single_node = (only_write_to_single_node ~= nil and ImGui.DockNodeIsInHierarchyOf(only_write_to_single_node, child_1)) local child_0_is_or_will_be_visible = child_0.IsVisible or child_0_is_toward_single_node local child_1_is_or_will_be_visible = child_1.IsVisible or child_1_is_toward_single_node if child_0_is_or_will_be_visible and child_1_is_or_will_be_visible then local spacing = g.Style.DockingSeparatorSize local a = node.SplitAxis local size_avail = ImMax(size[a] - spacing, 0.0) local size_min_each = ImTrunc(ImMin(size_avail, g.Style.WindowMinSize[a] * 2.0) * 0.5) if child_0.WantLockSizeOnce and not child_1.WantLockSizeOnce then child_0_size[a] = ImMin(size_avail - 1.0, child_0.Size[a]); child_0.SizeRef[a] = child_0_size[a] child_1_size[a] = size_avail - child_0_size[a]; child_1.SizeRef[a] = child_1_size[a] elseif child_1.WantLockSizeOnce and not child_0.WantLockSizeOnce then child_1_size[a] = ImMin(size_avail - 1.0, child_1.Size[a]); child_1.SizeRef[a] = child_1_size[a] child_0_size[a] = size_avail - child_1_size[a]; child_0.SizeRef[a] = child_0_size[a] elseif child_0.WantLockSizeOnce and child_1.WantLockSizeOnce then local split_ratio = child_0_size[a] / (child_0_size[a] + child_1_size[a]) child_0_size[a] = ImTrunc(size_avail * split_ratio); child_0.SizeRef[a] = child_0_size[a] child_1_size[a] = size_avail - child_0_size[a]; child_1.SizeRef[a] = child_1_size[a] elseif child_0.SizeRef[a] ~= 0.0 and child_1.HasCentralNodeChild then child_0_size[a] = ImMin(size_avail - size_min_each, child_0.SizeRef[a]) child_1_size[a] = size_avail - child_0_size[a] elseif child_1.SizeRef[a] ~= 0.0 and child_0.HasCentralNodeChild then child_1_size[a] = ImMin(size_avail - size_min_each, child_1.SizeRef[a]) child_0_size[a] = size_avail - child_1_size[a] else local split_ratio = child_0.SizeRef[a] / (child_0.SizeRef[a] + child_1.SizeRef[a]) child_0_size[a] = ImMax(size_min_each, ImTrunc(size_avail * split_ratio + 0.5)) child_1_size[a] = size_avail - child_0_size[a] end child_1_pos[a] = child_1_pos[a] + spacing + child_0_size[a] end if only_write_to_single_node == nil then child_0.WantLockSizeOnce = false child_1.WantLockSizeOnce = false end local child_0_recurse = only_write_to_single_node and child_0_is_toward_single_node or (not only_write_to_single_node and child_0.IsVisible) local child_1_recurse = only_write_to_single_node and child_1_is_toward_single_node or (not only_write_to_single_node and child_1.IsVisible) if child_0_recurse then ImGui.DockNodeTreeUpdatePosSize(child_0, child_0_pos, child_0_size) end if child_1_recurse then ImGui.DockNodeTreeUpdatePosSize(child_1, child_1_pos, child_1_size) end end local function DockNodeTreeUpdateSplitterFindTouchingNode(node, axis, side, touching_nodes) if node:IsLeafNode() then table.insert(touching_nodes, node) return end if node.ChildNodes[0].IsVisible then if node.SplitAxis ~= axis or side == 0 or not node.ChildNodes[1].IsVisible then DockNodeTreeUpdateSplitterFindTouchingNode(node.ChildNodes[0], axis, side, touching_nodes) end end if node.ChildNodes[1].IsVisible then if node.SplitAxis ~= axis or side == 1 or not node.ChildNodes[0].IsVisible then DockNodeTreeUpdateSplitterFindTouchingNode(node.ChildNodes[1], axis, side, touching_nodes) end end end local WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04 function ImGui.DockNodeTreeUpdateSplitter(node) if node:IsLeafNode() then return end local g = ImGui.GetCurrentContext() local child_0 = node.ChildNodes[0] local child_1 = node.ChildNodes[1] if child_0.IsVisible and child_1.IsVisible then local axis = node.SplitAxis IM_ASSERT(axis ~= ImGuiAxis.None) local a, o = axis, 3 - axis -- the port's ImGuiAxis is 1-based (X=1,Y=2): it is directly the ImVec2 index local bb = ImRect(ImVec2(child_0.Pos.x, child_0.Pos.y), ImVec2(child_1.Pos.x, child_1.Pos.y)) bb.Min[a] = bb.Min[a] + child_0.Size[a] bb.Max[o] = bb.Max[o] + child_1.Size[o] local merged_flags = bit32.bor(child_0.MergedFlags, child_1.MergedFlags) local no_resize_axis_flag = (axis == ImGuiAxis.X) and ImGuiDockNodeFlags.NoResizeX or ImGuiDockNodeFlags.NoResizeY if bit32.band(merged_flags, ImGuiDockNodeFlags.NoResize) ~= 0 or bit32.band(merged_flags, no_resize_axis_flag) ~= 0 then local window = g.CurrentWindow window.DrawList:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Separator), g.Style.FrameRounding) else ImGui.PushID(node.ID) local touching_nodes = { [0] = {}, [1] = {} } local min_size = g.Style.WindowMinSize[a] local resize_limits = { [0] = node.ChildNodes[0].Pos[a] + min_size, [1] = node.ChildNodes[1].Pos[a] + node.ChildNodes[1].Size[a] - min_size } local splitter_id = ImGui.GetID("##Splitter") if g.ActiveId == splitter_id then DockNodeTreeUpdateSplitterFindTouchingNode(child_0, axis, 1, touching_nodes[0]) DockNodeTreeUpdateSplitterFindTouchingNode(child_1, axis, 0, touching_nodes[1]) for _, tn in ipairs(touching_nodes[0]) do resize_limits[0] = ImMax(resize_limits[0], tn:Rect().Min[a] + min_size) end for _, tn in ipairs(touching_nodes[1]) do resize_limits[1] = ImMin(resize_limits[1], tn:Rect().Max[a] - min_size) end end local cur_size_0 = child_0.Size[a] local cur_size_1 = child_1.Size[a] local min_size_0 = resize_limits[0] - child_0.Pos[a] local min_size_1 = child_1.Pos[a] + child_1.Size[a] - resize_limits[1] local bg_col = ImGui.GetColorU32(ImGuiCol.WindowBg) local changed changed, cur_size_0, cur_size_1 = ImGui.SplitterBehavior(bb, ImGui.GetID("##Splitter"), axis, cur_size_0, cur_size_1, min_size_0, min_size_1, g.WindowsBorderHoverPadding, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER, bg_col) if changed then if #touching_nodes[0] > 0 and #touching_nodes[1] > 0 then child_0.Size[a] = cur_size_0; child_0.SizeRef[a] = cur_size_0 child_1.Pos[a] = child_1.Pos[a] - (cur_size_1 - child_1.Size[a]) child_1.Size[a] = cur_size_1; child_1.SizeRef[a] = cur_size_1 for side_n = 0, 1 do for _, touching_node in ipairs(touching_nodes[side_n]) do while touching_node.ParentNode ~= node do if touching_node.ParentNode.SplitAxis == axis then local node_to_preserve = touching_node.ParentNode.ChildNodes[side_n] node_to_preserve.WantLockSizeOnce = true end touching_node = touching_node.ParentNode end end end ImGui.DockNodeTreeUpdatePosSize(child_0, child_0.Pos, child_0.Size) ImGui.DockNodeTreeUpdatePosSize(child_1, child_1.Pos, child_1.Size) ImGui.MarkIniSettingsDirty() end end ImGui.PopID() end end if child_0.IsVisible then ImGui.DockNodeTreeUpdateSplitter(child_0) end if child_1.IsVisible then ImGui.DockNodeTreeUpdateSplitter(child_1) end end function ImGui.DockNodeTreeFindFallbackLeafNode(node) if node:IsLeafNode() then return node end local leaf_node = ImGui.DockNodeTreeFindFallbackLeafNode(node.ChildNodes[0]) if leaf_node then return leaf_node end leaf_node = ImGui.DockNodeTreeFindFallbackLeafNode(node.ChildNodes[1]) if leaf_node then return leaf_node end return nil end function ImGui.DockNodeTreeFindVisibleNodeByPos(node, pos) if not node.IsVisible then return nil end local r = ImRect(node.Pos, node.Pos + node.Size) if not r:Contains(pos) then return nil end if node:IsLeafNode() then return node end local hovered_node = ImGui.DockNodeTreeFindVisibleNodeByPos(node.ChildNodes[0], pos) if hovered_node then return hovered_node end hovered_node = ImGui.DockNodeTreeFindVisibleNodeByPos(node.ChildNodes[1], pos) if hovered_node then return hovered_node end return node end --------------------------------------------------------------------------------------- -- Docking: Public Functions (SetWindowDock, DockSpace, DockSpaceOverViewport) --------------------------------------------------------------------------------------- function ImGui.SetWindowDock(window, dock_id, cond) if cond and cond ~= 0 and bit32.band(window.SetWindowDockAllowFlags, cond) == 0 then return end window.SetWindowDockAllowFlags = bit32.band(window.SetWindowDockAllowFlags, bit32.bnot(bit32.bor(ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing))) if window.DockId == dock_id then return end local g = ImGui.GetCurrentContext() local new_node = ImGui.DockContextFindNodeByID(g, dock_id) if new_node and new_node:IsSplitNode() then new_node = ImGui.DockNodeGetRootNode(new_node) if new_node.CentralNode then IM_ASSERT(new_node.CentralNode:IsCentralNode()) dock_id = new_node.CentralNode.ID else dock_id = new_node.LastFocusedNodeId end end if window.DockId == dock_id then return end if window.DockNode then ImGui.DockNodeRemoveWindow(window.DockNode, window, 0) end window.DockId = dock_id end function ImGui.DockSpace(dockspace_id, size_arg, flags, window_class) if size_arg == nil then size_arg = ImVec2(0, 0) end if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() local window = ImGui.GetCurrentWindowRead() if bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.DockingEnable) == 0 then return 0 end if window.SkipItems then flags = bit32.bor(flags, ImGuiDockNodeFlags.KeepAliveOnly) end if bit32.band(flags, ImGuiDockNodeFlags.KeepAliveOnly) == 0 then window = ImGui.GetCurrentWindow() end IM_ASSERT(bit32.band(flags, ImGuiDockNodeFlags.DockSpace) == 0) IM_ASSERT(bit32.band(flags, ImGuiDockNodeFlags.CentralNode) == 0) IM_ASSERT(dockspace_id ~= 0) local node = ImGui.DockContextFindNodeByID(g, dockspace_id) if node == nil then node = ImGui.DockContextAddNode(g, dockspace_id) node:SetLocalFlags(ImGuiDockNodeFlags.CentralNode) end node.SharedFlags = flags node.WindowClass = window_class or ImGuiWindowClass() if node.LastFrameActive == g.FrameCount and bit32.band(flags, ImGuiDockNodeFlags.KeepAliveOnly) == 0 then IM_ASSERT(node:IsDockSpace() == false, "Cannot call DockSpace() twice a frame with the same ID") node:SetLocalFlags(bit32.bor(node.LocalFlags, ImGuiDockNodeFlags.DockSpace)) return dockspace_id end node:SetLocalFlags(bit32.bor(node.LocalFlags, ImGuiDockNodeFlags.DockSpace)) if bit32.band(flags, ImGuiDockNodeFlags.KeepAliveOnly) ~= 0 then node.LastFrameAlive = g.FrameCount return dockspace_id end local content_avail = ImGui.GetContentRegionAvail() local size = ImVec2(ImTrunc(size_arg.x), ImTrunc(size_arg.y)) if size.x <= 0.0 then size.x = ImMax(content_avail.x + size.x, 4.0) end if size.y <= 0.0 then size.y = ImMax(content_avail.y + size.y, 4.0) end IM_ASSERT(size.x > 0.0 and size.y > 0.0) node.Pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y) node.Size = ImVec2(size.x, size.y) node.SizeRef = ImVec2(size.x, size.y) ImGui.SetNextWindowPos(node.Pos) ImGui.SetNextWindowSize(node.Size) g.NextWindowData.PosUndock = false local window_flags = bit32.bor(ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.DockNodeHost) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoCollapse, ImGuiWindowFlags.NoTitleBar) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollbar, ImGuiWindowFlags.NoScrollWithMouse) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoBackground) local title = string.format("%s/DockSpace_%08X", window.Name, dockspace_id) ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, 0.0) ImGui.Begin(title, nil, window_flags) ImGui.PopStyleVar() local host_window = g.CurrentWindow DockNodeSetupHostWindow(node, host_window) host_window.ChildId = window:GetID(title) node.OnlyNodeWithWindows = nil IM_ASSERT(node:IsRootNode()) if node:IsLeafNode() and not node:IsCentralNode() then node:SetLocalFlags(bit32.bor(node.LocalFlags, ImGuiDockNodeFlags.CentralNode)) end ImGui.DockNodeUpdate(node) ImGui.End() local bb = ImRect(node.Pos, node.Pos + size) ImGui.ItemSize(size) ImGui.ItemAdd(bb, dockspace_id, nil, ImGuiItemFlags.NoNav) if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredRect) ~= 0 and ImGui.IsWindowChildOf(g.HoveredWindow, host_window, false, true) then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow) end return dockspace_id end function ImGui.DockSpaceOverViewport(dockspace_id, viewport, dockspace_flags, window_class) if dockspace_id == nil then dockspace_id = 0 end if dockspace_flags == nil then dockspace_flags = 0 end if viewport == nil then viewport = ImGui.GetMainViewport() end ImGui.SetNextWindowPos(viewport.WorkPos) ImGui.SetNextWindowSize(viewport.WorkSize) ImGui.SetNextWindowViewport(viewport.ID) local host_window_flags = 0 host_window_flags = bit32.bor(host_window_flags, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoCollapse, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoDocking) host_window_flags = bit32.bor(host_window_flags, ImGuiWindowFlags.NoBringToFrontOnFocus, ImGuiWindowFlags.NoNavFocus) if bit32.band(dockspace_flags, ImGuiDockNodeFlags.PassthruCentralNode) ~= 0 then host_window_flags = bit32.bor(host_window_flags, ImGuiWindowFlags.NoBackground) end if bit32.band(dockspace_flags, ImGuiDockNodeFlags.KeepAliveOnly) ~= 0 then host_window_flags = bit32.bor(host_window_flags, ImGuiWindowFlags.NoMouseInputs) end local label = string.format("WindowOverViewport_%08X", viewport.ID) ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0) ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0.0) ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0.0, 0.0)) ImGui.Begin(label, nil, host_window_flags) ImGui.PopStyleVar(3) if dockspace_id == 0 then dockspace_id = ImGui.GetID("DockSpace") end ImGui.DockSpace(dockspace_id, ImVec2(0.0, 0.0), dockspace_flags, window_class) ImGui.End() return dockspace_id end --------------------------------------------------------------------------------------- -- Docking: Builder Functions --------------------------------------------------------------------------------------- function ImGui.DockBuilderDockWindow(window_name, node_id) local window_id = ImHashStr(window_name) local window = ImGui.FindWindowByID(window_id) if window then local prev_node_id = window.DockId ImGui.SetWindowDock(window, node_id, ImGuiCond.Always) if window.DockId ~= prev_node_id then window.DockOrder = -1 end else local settings = ImGui.FindWindowSettingsByID(window_id) if settings == nil then settings = ImGui.CreateNewWindowSettings(window_name) end if settings.DockId ~= node_id then settings.DockOrder = -1 end settings.DockId = node_id end end function ImGui.DockBuilderGetNode(node_id) return ImGui.DockContextFindNodeByID(ImGui.GetCurrentContext(), node_id) end function ImGui.DockBuilderGetCentralNode(node_id) local node = ImGui.DockBuilderGetNode(node_id) if not node then return nil end return ImGui.DockNodeGetRootNode(node).CentralNode end function ImGui.DockBuilderSetNodePos(node_id, pos) local node = ImGui.DockContextFindNodeByID(ImGui.GetCurrentContext(), node_id) if node == nil then return end node.Pos = ImVec2(pos.x, pos.y) node.AuthorityForPos = ImGuiDataAuthority.DockNode end function ImGui.DockBuilderSetNodeSize(node_id, size) local node = ImGui.DockContextFindNodeByID(ImGui.GetCurrentContext(), node_id) if node == nil then return end IM_ASSERT(size.x > 0.0 and size.y > 0.0) node.Size = ImVec2(size.x, size.y) node.SizeRef = ImVec2(size.x, size.y) node.AuthorityForSize = ImGuiDataAuthority.DockNode end function ImGui.DockBuilderAddNode(node_id, flags) if node_id == nil then node_id = 0 end if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() if node_id ~= 0 then ImGui.DockBuilderRemoveNode(node_id) end local node if bit32.band(flags, ImGuiDockNodeFlags.DockSpace) ~= 0 then ImGui.DockSpace(node_id, ImVec2(0, 0), bit32.bor(bit32.band(flags, bit32.bnot(ImGuiDockNodeFlags.DockSpace)), ImGuiDockNodeFlags.KeepAliveOnly)) node = ImGui.DockContextFindNodeByID(g, node_id) else node = ImGui.DockContextAddNode(g, node_id) node:SetLocalFlags(flags) end node.LastFrameAlive = g.FrameCount return node.ID end function ImGui.DockBuilderRemoveNode(node_id) local g = ImGui.GetCurrentContext() local node = ImGui.DockContextFindNodeByID(g, node_id) if node == nil then return end ImGui.DockBuilderRemoveNodeDockedWindows(node_id, true) ImGui.DockBuilderRemoveNodeChildNodes(node_id) node = ImGui.DockContextFindNodeByID(g, node_id) if node == nil then return end if node:IsCentralNode() and node.ParentNode then node.ParentNode:SetLocalFlags(bit32.bor(node.ParentNode.LocalFlags, ImGuiDockNodeFlags.CentralNode)) end ImGui.DockContextRemoveNode(g, node, true) end function ImGui.DockBuilderRemoveNodeChildNodes(root_id) local g = ImGui.GetCurrentContext() local dc = g.DockContext local root_node = (root_id ~= 0) and ImGui.DockContextFindNodeByID(g, root_id) or nil if root_id ~= 0 and root_node == nil then return end local has_central_node = false local backup_root_node_authority_for_pos = root_node and root_node.AuthorityForPos or ImGuiDataAuthority.Auto local backup_root_node_authority_for_size = root_node and root_node.AuthorityForSize or ImGuiDataAuthority.Auto local nodes_to_remove = {} for _, id in ipairs(DockContextNodesSorted(g)) do local node = dc.Nodes[id] if node then local want_removal = (root_id == 0) or (node.ID ~= root_id and ImGui.DockNodeGetRootNode(node).ID == root_id) if want_removal then if node:IsCentralNode() then has_central_node = true end if root_id ~= 0 then ImGui.DockContextQueueNotifyRemovedNode(g, node) end if root_node then ImGui.DockNodeMoveWindows(root_node, node) DockSettingsRenameNodeReferences(node.ID, root_node.ID) end table.insert(nodes_to_remove, node) end end end if root_node then root_node.AuthorityForPos = backup_root_node_authority_for_pos root_node.AuthorityForSize = backup_root_node_authority_for_size end for _, settings in g.SettingsWindows:iter() do local window_settings_dock_id = settings.DockId if window_settings_dock_id and window_settings_dock_id ~= 0 then for _, n in ipairs(nodes_to_remove) do if n.ID == window_settings_dock_id then settings.DockId = root_id break end end end end if #nodes_to_remove > 1 then local depth = {} for _, n in ipairs(nodes_to_remove) do depth[n] = ImGui.DockNodeGetDepth(n) end table.sort(nodes_to_remove, function(a, b) return depth[a] > depth[b] end) end for _, n in ipairs(nodes_to_remove) do ImGui.DockContextRemoveNode(g, n, false) end if root_id == 0 then dc.Nodes = {} dc.Requests:clear() elseif has_central_node then root_node.CentralNode = root_node root_node:SetLocalFlags(bit32.bor(root_node.LocalFlags, ImGuiDockNodeFlags.CentralNode)) end end function ImGui.DockBuilderRemoveNodeDockedWindows(root_id, clear_settings_refs) if clear_settings_refs == nil then clear_settings_refs = true end local g = ImGui.GetCurrentContext() if clear_settings_refs then for _, settings in g.SettingsWindows:iter() do local want_removal = (root_id == 0) or (settings.DockId == root_id) if not want_removal and settings.DockId ~= 0 then local node = ImGui.DockContextFindNodeByID(g, settings.DockId) if node and ImGui.DockNodeGetRootNode(node).ID == root_id then want_removal = true end end if want_removal then settings.DockId = 0 end end end for n = 1, g.Windows.Size do local window = g.Windows.Data[n] local want_removal = (root_id == 0) or (window.DockNode and ImGui.DockNodeGetRootNode(window.DockNode).ID == root_id) or (window.DockNodeAsHost and window.DockNodeAsHost.ID == root_id) if want_removal then local backup_dock_id = window.DockId ImGui.DockContextProcessUndockWindow(g, window, clear_settings_refs) if not clear_settings_refs then IM_ASSERT(window.DockId == backup_dock_id) end end end end --- @return ImGuiID id_at_dir, ImGuiID id_at_opposite_dir function ImGui.DockBuilderSplitNode(id, split_dir, size_ratio_for_node_at_dir) local g = ImGui.GetCurrentContext() IM_ASSERT(split_dir ~= ImGuiDir.None) local node = ImGui.DockContextFindNodeByID(g, id) if node == nil then IM_ASSERT(node ~= nil) return 0, 0 end local req = ImGuiDockRequest() req.Type = ImGuiDockRequestType.Split req.DockTargetWindow = nil req.DockTargetNode = node req.DockPayload = nil req.DockSplitDir = split_dir req.DockSplitRatio = ImSaturate((split_dir == ImGuiDir.Left or split_dir == ImGuiDir.Up) and size_ratio_for_node_at_dir or (1.0 - size_ratio_for_node_at_dir)) req.DockSplitOuter = false ImGui.DockContextProcessDock(g, req) local first = (split_dir == ImGuiDir.Left or split_dir == ImGuiDir.Up) local id_at_dir = node.ChildNodes[first and 0 or 1].ID local id_at_opposite_dir = node.ChildNodes[first and 1 or 0].ID return id_at_dir, id_at_opposite_dir end local function DockBuilderCopyNodeRec(src_node, dst_node_id_if_known, out_node_remap_pairs) local g = ImGui.GetCurrentContext() local dst_node = ImGui.DockContextAddNode(g, dst_node_id_if_known) dst_node.SharedFlags = src_node.SharedFlags dst_node.LocalFlags = src_node.LocalFlags dst_node.LocalFlagsInWindows = ImGuiDockNodeFlags.None dst_node.Pos = ImVec2(src_node.Pos.x, src_node.Pos.y) dst_node.Size = ImVec2(src_node.Size.x, src_node.Size.y) dst_node.SizeRef = ImVec2(src_node.SizeRef.x, src_node.SizeRef.y) dst_node.SplitAxis = src_node.SplitAxis dst_node:UpdateMergedFlags() table.insert(out_node_remap_pairs, src_node.ID) table.insert(out_node_remap_pairs, dst_node.ID) for child_n = 0, 1 do if src_node.ChildNodes[child_n] then dst_node.ChildNodes[child_n] = DockBuilderCopyNodeRec(src_node.ChildNodes[child_n], 0, out_node_remap_pairs) dst_node.ChildNodes[child_n].ParentNode = dst_node end end return dst_node end --- @param out_node_remap_pairs table # 1-based array, cleared and filled with (src_id, dst_id) pairs function ImGui.DockBuilderCopyNode(src_node_id, dst_node_id, out_node_remap_pairs) local g = ImGui.GetCurrentContext() IM_ASSERT(src_node_id ~= 0) IM_ASSERT(dst_node_id ~= 0) IM_ASSERT(out_node_remap_pairs ~= nil) ImGui.DockBuilderRemoveNode(dst_node_id) local src_node = ImGui.DockContextFindNodeByID(g, src_node_id) IM_ASSERT(src_node ~= nil) for k in pairs(out_node_remap_pairs) do out_node_remap_pairs[k] = nil end DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs) IM_ASSERT((#out_node_remap_pairs % 2) == 0) end function ImGui.DockBuilderCopyWindowSettings(src_name, dst_name) local src_window = ImGui.FindWindowByName(src_name) if src_window == nil then return end local dst_window = ImGui.FindWindowByName(dst_name) if dst_window then ImVec2_Copy(dst_window.Pos, src_window.Pos) ImVec2_Copy(dst_window.Size, src_window.Size) ImVec2_Copy(dst_window.SizeFull, src_window.SizeFull) dst_window.Collapsed = src_window.Collapsed else local dst_settings = ImGui.FindWindowSettingsByID(ImHashStr(dst_name)) if not dst_settings then dst_settings = ImGui.CreateNewWindowSettings(dst_name) end local wx, wy = ImTrunc(src_window.Pos.x), ImTrunc(src_window.Pos.y) if src_window.ViewportId ~= 0 and src_window.ViewportId ~= 0x11111111 then ImVec2_CopyV(dst_settings.ViewportPos, wx, wy) dst_settings.ViewportId = src_window.ViewportId ImVec2_CopyV(dst_settings.Pos, 0, 0) else ImVec2_CopyV(dst_settings.Pos, wx, wy) end ImVec2_CopyV(dst_settings.Size, ImTrunc(src_window.SizeFull.x), ImTrunc(src_window.SizeFull.y)) dst_settings.Collapsed = src_window.Collapsed end end --- @param in_window_remap_pairs table # 1-based array of window names: src0, dst0, src1, dst1, ... function ImGui.DockBuilderCopyDockSpace(src_dockspace_id, dst_dockspace_id, in_window_remap_pairs) IM_ASSERT(src_dockspace_id ~= 0) IM_ASSERT(dst_dockspace_id ~= 0) IM_ASSERT(in_window_remap_pairs ~= nil) IM_ASSERT((#in_window_remap_pairs % 2) == 0) local node_remap_pairs = {} ImGui.DockBuilderCopyNode(src_dockspace_id, dst_dockspace_id, node_remap_pairs) local src_windows = {} for remap_window_n = 1, #in_window_remap_pairs, 2 do local src_window_name = in_window_remap_pairs[remap_window_n] local dst_window_name = in_window_remap_pairs[remap_window_n + 1] local src_window_id = ImHashStr(src_window_name) src_windows[src_window_id] = true local src_dock_id = 0 local src_window = ImGui.FindWindowByID(src_window_id) if src_window then src_dock_id = src_window.DockId else local src_window_settings = ImGui.FindWindowSettingsByID(src_window_id) if src_window_settings then src_dock_id = src_window_settings.DockId end end local dst_dock_id = 0 for dock_remap_n = 1, #node_remap_pairs, 2 do if node_remap_pairs[dock_remap_n] == src_dock_id then dst_dock_id = node_remap_pairs[dock_remap_n + 1] break end end if dst_dock_id ~= 0 then ImGui.DockBuilderDockWindow(dst_window_name, dst_dock_id) else ImGui.DockBuilderCopyWindowSettings(src_window_name, dst_window_name) end end local dock_remaining_windows = {} for dock_remap_n = 1, #node_remap_pairs, 2 do local src_dock_id = node_remap_pairs[dock_remap_n] if src_dock_id ~= 0 then local dst_dock_id = node_remap_pairs[dock_remap_n + 1] local node = ImGui.DockBuilderGetNode(src_dock_id) for _, window in node.Windows:iter() do if not src_windows[window.ID] then table.insert(dock_remaining_windows, { Window = window, DockId = dst_dock_id }) end end end end for _, task in ipairs(dock_remaining_windows) do ImGui.DockBuilderDockWindow(task.Window.Name, task.DockId) end end function ImGui.DockBuilderFinish(root_id) ImGui.DockContextBuildAddWindowsToNodes(ImGui.GetCurrentContext(), root_id) end --------------------------------------------------------------------------------------- -- Docking: Begin/End Support Functions (called from Begin/End) --------------------------------------------------------------------------------------- function ImGui.GetWindowAlwaysWantOwnTabBar(window) local g = ImGui.GetCurrentContext() if g.IO.ConfigDockingAlwaysTabBar or window.WindowClass.DockingAlwaysTabBar then if bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoDocking)) == 0 then if not window.IsFallbackWindow then return true end end end return false end function ImGui.DockContextBindNodeToWindow(ctx, window) local g = ctx local node = ImGui.DockContextFindNodeByID(ctx, window.DockId) IM_ASSERT(window.DockNode == nil) if node and node:IsSplitNode() then ImGui.DockContextProcessUndockWindow(ctx, window) return nil end if node == nil then node = ImGui.DockContextAddNode(ctx, window.DockId) node.AuthorityForPos = ImGuiDataAuthority.Window node.AuthorityForSize = ImGuiDataAuthority.Window node.AuthorityForViewport = ImGuiDataAuthority.Window node.LastFrameAlive = g.FrameCount end if not node.IsVisible then local ancestor_node = node while not ancestor_node.IsVisible and ancestor_node.ParentNode do ancestor_node = ancestor_node.ParentNode end IM_ASSERT(ancestor_node.Size.x > 0.0 and ancestor_node.Size.y > 0.0) ImGui.DockNodeUpdateHasCentralNodeChild(ImGui.DockNodeGetRootNode(ancestor_node)) ImGui.DockNodeTreeUpdatePosSize(ancestor_node, ancestor_node.Pos, ancestor_node.Size, node) end local node_was_visible = node.IsVisible ImGui.DockNodeAddWindow(node, window, true) node.IsVisible = node_was_visible IM_ASSERT(node == window.DockNode) return node end local function StoreDockStyleForWindow(window) local g = ImGui.GetCurrentContext() for color_n = 0, ImGuiWindowDockStyleCol.COUNT - 1 do window.DockStyle.Colors[color_n] = ImGui.ColorConvertFloat4ToU32(g.Style.Colors[GWindowDockStyleColors[color_n]]) end end ImGui.StoreDockStyleForWindow = StoreDockStyleForWindow --- @return bool? p_open function ImGui.BeginDocked(window, p_open) local g = ImGui.GetCurrentContext() if window.IsFallbackWindow and not window.WasActive then DockNodeHideWindowDuringHostWindowCreation(window) return p_open end local auto_dock_node = ImGui.GetWindowAlwaysWantOwnTabBar(window) if auto_dock_node then if window.DockId == 0 then IM_ASSERT(window.DockNode == nil) window.DockId = ImGui.DockContextGenNodeID(g) end else local want_undock = false want_undock = want_undock or bit32.band(window.Flags, ImGuiWindowFlags.NoDocking) ~= 0 want_undock = want_undock or (bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasPos) ~= 0 and bit32.band(window.SetWindowPosAllowFlags, g.NextWindowData.PosCond) ~= 0 and g.NextWindowData.PosUndock) if want_undock then ImGui.DockContextProcessUndockWindow(g, window) return p_open end end local node = window.DockNode if node ~= nil then IM_ASSERT(window.DockId == node.ID) end if window.DockId ~= 0 and node == nil then node = ImGui.DockContextBindNodeToWindow(g, window) if node == nil then return p_open end end if node.LastFrameAlive < g.FrameCount then local root_node = ImGui.DockNodeGetRootNode(node) if root_node.LastFrameAlive < g.FrameCount then ImGui.DockContextProcessUndockWindow(g, window) else window.DockIsActive = true end return p_open end StoreDockStyleForWindow(window) if node.HostWindow == nil then if node.State == ImGuiDockNodeState.HostWindowHiddenBecauseWindowsAreResizing then window.DockIsActive = true end if node.Windows.Size > 1 and window.Appearing then DockNodeHideWindowDuringHostWindowCreation(window) end return p_open end IM_ASSERT(node.HostWindow) IM_ASSERT(node:IsLeafNode()) IM_ASSERT(node.Size.x >= 0.0 and node.Size.y >= 0.0) node.State = ImGuiDockNodeState.HostWindowVisible if bit32.band(node.MergedFlags, ImGuiDockNodeFlags.KeepAliveOnly) == 0 and window.BeginOrderWithinContext < node.HostWindow.BeginOrderWithinContext then ImGui.DockContextProcessUndockWindow(g, window) return p_open end ImGui.SetNextWindowPos(node.Pos) ImGui.SetNextWindowSize(node.Size) g.NextWindowData.PosUndock = false window.DockIsActive = true window.DockNodeIsVisible = true window.DockTabIsVisible = false if bit32.band(node.MergedFlags, ImGuiDockNodeFlags.KeepAliveOnly) ~= 0 then return p_open end if node.VisibleWindow == window then window.DockTabIsVisible = true end IM_ASSERT(bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0) window.Flags = bit32.bor(window.Flags, ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.NoResize) window.ChildFlags = bit32.bor(window.ChildFlags, ImGuiChildFlags.AlwaysUseWindowPadding) if node:IsHiddenTabBar() or node:IsNoTabBar() then window.Flags = bit32.bor(window.Flags, ImGuiWindowFlags.NoTitleBar) else window.Flags = bit32.band(window.Flags, bit32.bnot(ImGuiWindowFlags.NoTitleBar)) end if node.TabBar and window.WasActive then window.DockOrder = ImGui.DockNodeGetTabOrder(window) end if (node.WantCloseAll or node.WantCloseTabId == window.TabId) and p_open ~= nil then p_open = false end local parent_window = window.DockNode.HostWindow window.ChildId = parent_window:GetID(window.Name) return p_open end function ImGui.BeginDockableDragDropSource(window) local g = ImGui.GetCurrentContext() IM_ASSERT(g.ActiveId == window.MoveId) IM_ASSERT(g.MovingWindow == window) IM_ASSERT(g.CurrentWindow == window) if g.IO.ConfigDockingWithShift ~= g.IO.KeyShift then if g.IO.ConfigDockingWithShift and g.MouseStationaryTimer >= 1.0 and g.ActiveId >= 1 then ImGui.SetTooltip("%s", ImGui.LocalizeGetMsg(ImGuiLocKey.DockingHoldShiftToDock)) end return end g.LastItemData.ID = window.MoveId window = window.RootWindowDockTree IM_ASSERT(bit32.band(window.Flags, ImGuiWindowFlags.NoDocking) == 0) local is_drag_docking = g.IO.ConfigDockingWithShift or ImRect(0, 0, window.SizeFull.x, ImGui.GetFrameHeight()):Contains(g.ActiveIdClickOffset) local drag_drop_flags = bit32.bor(ImGuiDragDropFlags.SourceNoPreviewTooltip, ImGuiDragDropFlags.SourceNoHoldToOpenOthers, ImGuiDragDropFlags.PayloadAutoExpire, ImGuiDragDropFlags.PayloadNoCrossContext, ImGuiDragDropFlags.PayloadNoCrossProcess) if is_drag_docking and ImGui.BeginDragDropSource(drag_drop_flags) then ImGui.SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, window) ImGui.EndDragDropSource() StoreDockStyleForWindow(window) end end function ImGui.BeginDockableDragDropTarget(window) local g = ImGui.GetCurrentContext() IM_ASSERT(bit32.band(window.Flags, ImGuiWindowFlags.NoDocking) == 0) if not g.DragDropActive then return end if not ImGui.BeginDragDropTargetCustom(window:Rect(), window.ID) then return end local payload = g.DragDropPayload if not ImGuiPayload_IsDataType(payload, IMGUI_PAYLOAD_TYPE_WINDOW) or not ImGui.DockNodeIsDropAllowed(window, payload.Data) then ImGui.EndDragDropTarget() return end local payload_window = payload.Data if ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, bit32.bor(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoDrawDefaultRect)) then local dock_into_floating_window = false local node = nil if window.DockNodeAsHost then node = ImGui.DockNodeTreeFindVisibleNodeByPos(window.DockNodeAsHost, g.IO.MousePos) if node and node:IsDockSpace() and node:IsRootNode() then node = (node.CentralNode and node:IsLeafNode()) and node.CentralNode or ImGui.DockNodeTreeFindFallbackLeafNode(node) end else if window.DockNode then node = window.DockNode else dock_into_floating_window = true end end local explicit_target_rect if node and node.TabBar and not node:IsHiddenTabBar() and not node:IsNoTabBar() then explicit_target_rect = node.TabBar.BarRect else explicit_target_rect = ImRect(window.Pos, window.Pos + ImVec2(window.Size.x, ImGui.GetFrameHeight())) end local is_explicit_target = g.IO.ConfigDockingWithShift or ImGui.IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max) local do_preview = ImGuiPayload_IsPreview(payload) or ImGuiPayload_IsDelivery(payload) if do_preview and (node ~= nil or dock_into_floating_window) then local split_inner = ImGuiDockPreviewData() local split_outer = ImGuiDockPreviewData() local split_data = split_inner if node and (node.ParentNode or node:IsCentralNode() or not node:IsLeafNode()) then local root_node = ImGui.DockNodeGetRootNode(node) if root_node then ImGui.DockNodePreviewDockSetup(window, root_node, payload_window, nil, split_outer, is_explicit_target, true) if split_outer.IsSplitDirExplicit then split_data = split_outer end end end if not node or node:IsLeafNode() then ImGui.DockNodePreviewDockSetup(window, node, payload_window, nil, split_inner, is_explicit_target, false) end if split_data == split_outer then split_inner.IsDropAllowed = false end ImGui.DockNodePreviewDockRender(window, node, payload_window, split_inner) ImGui.DockNodePreviewDockRender(window, node, payload_window, split_outer) if split_data.IsDropAllowed and ImGuiPayload_IsDelivery(payload) then ImGui.DockContextQueueDock(g, window, split_data.SplitNode, payload_window, split_data.SplitDir, split_data.SplitRatio, split_data == split_outer) end end end ImGui.EndDragDropTarget() end --------------------------------------------------------------------------------------- -- Docking: Settings --------------------------------------------------------------------------------------- DockSettingsRenameNodeReferences = function(old_node_id, new_node_id) local g = ImGui.GetCurrentContext() for _, window in g.Windows:iter() do if window.DockId == old_node_id and window.DockNode == nil then window.DockId = new_node_id end end for _, settings in g.SettingsWindows:iter() do if settings.DockId == old_node_id then settings.DockId = new_node_id end end end --- @param node_ids table # 1-based array DockSettingsRemoveNodeReferences = function(node_ids, node_ids_count) local g = ImGui.GetCurrentContext() local found = 0 for _, settings in g.SettingsWindows:iter() do for node_n = 1, node_ids_count do if settings.DockId == node_ids[node_n] then settings.DockId = 0 settings.DockOrder = -1 found = found + 1 if found < node_ids_count then break end return end end end end DockSettingsFindNodeSettings = function(ctx, id) for _, s in ctx.DockContext.NodesSettings:iter() do if s.ID == id then return s end end return nil end DockSettingsHandler_ClearAll = function(ctx, handler) local dc = ctx.DockContext dc.NodesSettings:clear() ImGui.DockContextClearNodes(ctx, 0, true) end DockSettingsHandler_ApplyAll = function(ctx, handler) local dc = ctx.DockContext if ctx.Windows.Size == 0 then ImGui.DockContextPruneUnusedSettingsNodes(ctx) end ImGui.DockContextBuildNodesFromSettings(ctx, dc.NodesSettings.Data or {}, dc.NodesSettings.Size) ImGui.DockContextBuildAddWindowsToNodes(ctx, 0) end DockSettingsHandler_ReadOpen = function(ctx, handler, name) if name ~= "Data" then return nil end return true end DockSettingsHandler_ReadLine = function(ctx, handler, entry, line) local node = ImGuiDockNodeSettings() line = line:gsub("^[ \t]+", "") if line:sub(1, 8) == "DockNode" then line = line:sub(9) elseif line:sub(1, 9) == "DockSpace" then line = line:sub(10) node.Flags = bit32.bor(node.Flags, ImGuiDockNodeFlags.DockSpace) else return end line = line:gsub("^[ \t]+", "") local function take(pattern) local caps = { line:match("^" .. pattern .. "()") } if #caps == 0 then return nil end line = line:sub(caps[#caps]) caps[#caps] = nil return table.unpack(caps) end local v = take("ID=0x(%x+)") if not v then return end node.ID = tonumber(v, 16) v = take(" Parent=0x(%x+)") if v then node.ParentNodeId = tonumber(v, 16); if node.ParentNodeId == 0 then return end end v = take(" Window=0x(%x+)") if v then node.ParentWindowId = tonumber(v, 16); if node.ParentWindowId == 0 then return end end if node.ParentNodeId == 0 then local x, y = take(" Pos=(%-?%d+),(%-?%d+)") if not x then return end node.Pos = ImVec2(tonumber(x), tonumber(y)) x, y = take(" Size=(%-?%d+),(%-?%d+)") if not x then return end node.Size = ImVec2(tonumber(x), tonumber(y)) else local x, y = take(" SizeRef=(%-?%d+),(%-?%d+)") if x then node.SizeRef = ImVec2(tonumber(x), tonumber(y)) end end local c = take(" Split=(%a)") if c then if c == "X" then node.SplitAxis = ImGuiAxis.X elseif c == "Y" then node.SplitAxis = ImGuiAxis.Y end end local function flag(name, f) local x = take(" " .. name .. "=(%-?%d+)") if x and tonumber(x) ~= 0 then node.Flags = bit32.bor(node.Flags, f) end end flag("NoResize", ImGuiDockNodeFlags.NoResize) flag("CentralNode", ImGuiDockNodeFlags.CentralNode) flag("NoTabBar", ImGuiDockNodeFlags.NoTabBar) flag("HiddenTabBar", ImGuiDockNodeFlags.HiddenTabBar) flag("NoWindowMenuButton", ImGuiDockNodeFlags.NoWindowMenuButton) flag("NoCloseButton", ImGuiDockNodeFlags.NoCloseButton) v = take(" Selected=0x(%x+)") if v then node.SelectedTabId = tonumber(v, 16) end if node.ParentNodeId ~= 0 then local parent_settings = DockSettingsFindNodeSettings(ctx, node.ParentNodeId) if parent_settings then node.Depth = parent_settings.Depth + 1 end end ctx.DockContext.NodesSettings:push_back(node) end local function DockSettingsHandler_DockNodeToSettings(dc, node, depth) local node_settings = ImGuiDockNodeSettings() node_settings.ID = node.ID node_settings.ParentNodeId = node.ParentNode and node.ParentNode.ID or 0 node_settings.ParentWindowId = (node:IsDockSpace() and node.HostWindow and node.HostWindow.ParentWindow) and node.HostWindow.ParentWindow.ID or 0 node_settings.SelectedTabId = node.SelectedTabId node_settings.SplitAxis = node:IsSplitNode() and node.SplitAxis or ImGuiAxis.None node_settings.Depth = depth node_settings.Flags = bit32.band(node.LocalFlags, ImGuiDockNodeFlags.SavedFlagsMask_) node_settings.Pos = ImVec2(ImTrunc(node.Pos.x), ImTrunc(node.Pos.y)) node_settings.Size = ImVec2(ImTrunc(node.Size.x), ImTrunc(node.Size.y)) node_settings.SizeRef = ImVec2(ImTrunc(node.SizeRef.x), ImTrunc(node.SizeRef.y)) dc.NodesSettings:push_back(node_settings) if node.ChildNodes[0] then DockSettingsHandler_DockNodeToSettings(dc, node.ChildNodes[0], depth + 1) end if node.ChildNodes[1] then DockSettingsHandler_DockNodeToSettings(dc, node.ChildNodes[1], depth + 1) end end DockSettingsHandler_WriteAll = function(ctx, handler, buf) local g = ctx local dc = ctx.DockContext if bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.DockingEnable) == 0 then return end dc.NodesSettings:resize(0) for _, id in ipairs(DockContextNodesSorted(ctx)) do local node = dc.Nodes[id] if node and node:IsRootNode() then DockSettingsHandler_DockNodeToSettings(dc, node, 0) end end local max_depth = 0 for _, s in dc.NodesSettings:iter() do max_depth = ImMax(s.Depth, max_depth) end buf:appendf("[%s][Data]\n", handler.TypeName) for _, s in dc.NodesSettings:iter() do buf:append(string.rep(" ", s.Depth * 2) .. ((bit32.band(s.Flags, ImGuiDockNodeFlags.DockSpace) ~= 0) and "DockSpace" or "DockNode ") .. string.rep(" ", (max_depth - s.Depth) * 2)) buf:appendf(" ID=0x%08X", s.ID) if s.ParentNodeId ~= 0 then buf:appendf(" Parent=0x%08X SizeRef=%d,%d", s.ParentNodeId, s.SizeRef.x, s.SizeRef.y) else if s.ParentWindowId ~= 0 then buf:appendf(" Window=0x%08X", s.ParentWindowId) end buf:appendf(" Pos=%d,%d Size=%d,%d", s.Pos.x, s.Pos.y, s.Size.x, s.Size.y) end if s.SplitAxis ~= ImGuiAxis.None then buf:appendf(" Split=%s", (s.SplitAxis == ImGuiAxis.X) and "X" or "Y") end if bit32.band(s.Flags, ImGuiDockNodeFlags.NoResize) ~= 0 then buf:append(" NoResize=1") end if bit32.band(s.Flags, ImGuiDockNodeFlags.CentralNode) ~= 0 then buf:append(" CentralNode=1") end if bit32.band(s.Flags, ImGuiDockNodeFlags.NoTabBar) ~= 0 then buf:append(" NoTabBar=1") end if bit32.band(s.Flags, ImGuiDockNodeFlags.HiddenTabBar) ~= 0 then buf:append(" HiddenTabBar=1") end if bit32.band(s.Flags, ImGuiDockNodeFlags.NoWindowMenuButton) ~= 0 then buf:append(" NoWindowMenuButton=1") end if bit32.band(s.Flags, ImGuiDockNodeFlags.NoCloseButton) ~= 0 then buf:append(" NoCloseButton=1") end if s.SelectedTabId ~= 0 then buf:appendf(" Selected=0x%08X", s.SelectedTabId) end buf:append("\n") end buf:append("\n") end --------------------------------------------------------------------------------------- -- Docking: helpers (imgui_internal.h inlines) + widgets used by docking --------------------------------------------------------------------------------------- function ImGui.DockNodeGetRootNode(node) while node.ParentNode do node = node.ParentNode end return node end function ImGui.DockNodeIsInHierarchyOf(node, parent) while node do if node == parent then return true end node = node.ParentNode end return false end function ImGui.DockNodeGetDepth(node) local depth = 0 while node.ParentNode do node = node.ParentNode; depth = depth + 1 end return depth end function ImGui.DockNodeGetWindowMenuButtonId(node) return ImHashStr("#COLLAPSE", nil, node.ID) end function ImGui.GetWindowDockID() return ImGui.GetCurrentContext().CurrentWindow.DockId end function ImGui.IsWindowDocked() return ImGui.GetCurrentContext().CurrentWindow.DockIsActive end function ImGui.SetNextWindowDockID(id, cond) local g = ImGui.GetCurrentContext() g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasDock) g.NextWindowData.DockCond = (cond and cond ~= 0) and cond or ImGuiCond.Always g.NextWindowData.DockId = id end function ImGui.StartMouseMovingWindowOrNode(window, node, undock) local g = ImGui.GetCurrentContext() local can_undock_node = false if undock and node ~= nil and node.VisibleWindow and bit32.band(node.VisibleWindow.Flags, ImGuiWindowFlags.NoMove) == 0 and bit32.band(node.MergedFlags, ImGuiDockNodeFlags.NoUndocking) == 0 then local root_node = ImGui.DockNodeGetRootNode(node) if root_node.OnlyNodeWithWindows ~= node or root_node.CentralNode ~= nil then can_undock_node = true end end local clicked = ImGui.IsMouseClicked(0) local dragging = ImGui.IsMouseDragging(0) if can_undock_node and dragging then ImGui.DockContextQueueUndockNode(g, node) elseif not can_undock_node and (clicked or dragging) and g.MovingWindow ~= window then ImGui.StartMouseMovingWindow(window) end end function ImGui.RenderArrowDockMenu(draw_list, p_min, sz, col) draw_list:AddRectFilled(p_min + ImVec2(sz * 0.20, sz * 0.15), p_min + ImVec2(sz * 0.80, sz * 0.30), col) ImGui.RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.50, sz * 0.85), ImVec2(sz * 0.30, sz * 0.40), ImGuiDir.Down, col) end -- Upstream CollapseButton (docking branch): replaces the port's simpler version function ImGui.CollapseButton(id, pos, dock_node) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local bb = ImRect(pos, pos + ImVec2(g.FontSize, g.FontSize)) local is_clipped = not ImGui.ItemAdd(bb, id) local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, ImGuiButtonFlags.None) if is_clipped then return pressed end local bg_col = ImGui.GetColorU32((held and hovered) and ImGuiCol.ButtonActive or (hovered and ImGuiCol.ButtonHovered or ImGuiCol.Button)) local text_col = ImGui.GetColorU32(ImGuiCol.Text) if hovered or held then window.DrawList:AddRectFilled(bb.Min, bb.Max, bg_col) end ImGui.RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags and ImGuiNavRenderCursorFlags.Compact or nil) if dock_node then ImGui.RenderArrowDockMenu(window.DrawList, bb.Min, g.FontSize, text_col) else ImGui.RenderArrow(window.DrawList, bb.Min, text_col, window.Collapsed and ImGuiDir.Right or ImGuiDir.Down, 1.0) end if ImGui.IsItemActive() and ImGui.IsMouseDragging(0) then ImGui.StartMouseMovingWindowOrNode(window, dock_node, true) end return pressed end --- @return bool held, float size1, float size2 function ImGui.SplitterBehavior(bb, id, axis, size1, size2, min_size1, min_size2, hover_extend, hover_visibility_delay, bg_col) hover_extend = hover_extend or 0.0 hover_visibility_delay = hover_visibility_delay or 0.0 bg_col = bg_col or 0 local g = ImGui.GetCurrentContext() local window = g.CurrentWindow if not ImGui.ItemAdd(bb, id, nil, ImGuiItemFlags.NoNav) then return false, size1, size2 end local button_flags = bit32.bor(ImGuiButtonFlags.FlattenChildren, ImGuiButtonFlags.AllowOverlap) local bb_interact = ImRect(bb.Min, bb.Max) bb_interact:Expand(axis == ImGuiAxis.Y and ImVec2(0.0, hover_extend) or ImVec2(hover_extend, 0.0)) local _, hovered, held = ImGui.ButtonBehavior(bb_interact, id, button_flags) if hovered then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredRect) end if held or (hovered and g.HoveredIdPreviousFrame == id and g.HoveredIdTimer >= hover_visibility_delay) then ImGui.SetMouseCursor(axis == ImGuiAxis.Y and ImGuiMouseCursor.ResizeNS or ImGuiMouseCursor.ResizeEW) end local bb_render = ImRect(bb.Min, bb.Max) if held then local d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min local mouse_delta = d[axis] local size_1_maximum_delta = ImMax(0.0, size1 - min_size1) local size_2_maximum_delta = ImMax(0.0, size2 - min_size2) if mouse_delta < -size_1_maximum_delta then mouse_delta = -size_1_maximum_delta end if mouse_delta > size_2_maximum_delta then mouse_delta = size_2_maximum_delta end if mouse_delta ~= 0.0 then size1 = ImMax(size1 + mouse_delta, min_size1) size2 = ImMax(size2 - mouse_delta, min_size2) bb_render:Translate(axis == ImGuiAxis.X and ImVec2(mouse_delta, 0.0) or ImVec2(0.0, mouse_delta)) ImGui.MarkItemEdited(id) end end if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then window.DrawList:AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0) end local col = ImGui.GetColorU32(held and ImGuiCol.SeparatorActive or ((hovered and g.HoveredIdTimer >= hover_visibility_delay) and ImGuiCol.SeparatorHovered or ImGuiCol.Separator)) window.DrawList:AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0) return held, size1, size2 end end --[[ [SECTION] imgui_docking (was imgui_docking.lua) ]] local IMGUI_DEBUG_NAV_SCORING = false local IMGUI_DEBUG_NAV_RECTS = false local FONT_DEFAULT_SIZE_BASE = 20 local WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04 local WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70 local TOOLTIP_DEFAULT_OFFSET_MOUSE = ImVec2(16, 10) -- Multiplied by g.Style.MouseCursorScale local TOOLTIP_DEFAULT_OFFSET_TOUCH = ImVec2(0, -20) -- Multiplied by g.Style.MouseCursorScale local TOOLTIP_DEFAULT_PIVOT_TOUCH = ImVec2(0.5, 1.0) -- Multiplied by g.Style.MouseCursorScale local IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111 local string = string ImFormatString = string.format -- TODO: an simplified version that operates on byte tables directly? --- @module "imstd_minstdio" ImStd.sscanf = IM_INCLUDE"imstd_minstdio.lua" local math = math local bit32 = bit32 --------------------------------------------------------------------------------------- -- [SECTION] MISC HELPERS/UTILITIES (File functions) --------------------------------------------------------------------------------------- --- This closes the _file. --- @param _file any # File object function IM_FILE_CLOSE(_file) end --- This returns the size of _file in bytes. --- @param _file any # File object --- @return int function IM_FILE_SIZE(_file) return -1 end --- This writes _str into _file. --- @param _file any # File object --- @param _str string function IM_FILE_WRITE(_file, _str) end --- This reads the specified _count of chars and returns them as a binary string. --- @param _file any # File object --- @param _count int --- @return string function IM_FILE_READ(_file, _count) return "" end --- This opens the file at _filename in _mode and returns the File object. --- @param _filename string --- @param _mode string # e.g. "rb" --- @return any function ImStd.ImFileOpen(_filename, _mode) end --- [GMod] Platform specific if gmod then IM_FILE_CLOSE = FindMetaTable("File").Close --- @type function IM_FILE_SIZE = FindMetaTable("File").Size --- @type function IM_FILE_WRITE = FindMetaTable("File").Write --- @type function IM_FILE_READ = FindMetaTable("File").Read --- @type function end if not IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS then --- [GMod] Another Platform specific if gmod then function ImStd.ImFileOpen(filename, mode) return file.Open(filename, mode, "GAME") end end function ImStd.ImFileClose(f) IM_FILE_CLOSE(f) end function ImStd.ImFileGetSize(f) return IM_FILE_SIZE(f) end --- @param f any # File object --- @param data table # 1-based table to store result data --- @param count int # Amount of bytes to read from `f` function ImStd.ImFileRead(f, data, count) local CHUNK_SIZE = 8000 -- We don't read byte by byte local offset = 0 while offset < count do local read_size = math.min(CHUNK_SIZE, count - offset) local str = IM_FILE_READ(f, read_size) local bytes = {string.byte(str, 1, read_size)} for i = 1, read_size do data[offset + i] = bytes[i] end offset = offset + read_size end end --- @param filename string --- @param mode string --- @return table?, integer? function ImStd.ImFileLoadToMemory(filename, mode) local f = ImStd.ImFileOpen(filename, mode) if not f then return end local file_size = ImStd.ImFileGetSize(f) if file_size <= 0 then ImStd.ImFileClose(f) return end local file_data = {} ImStd.ImFileRead(f, file_data, file_size) if #file_data == 0 then ImStd.ImFileClose(f) return end ImStd.ImFileClose(f) return file_data, file_size end end --- Forward Declarations local CalcNextScrollFromScrollTargetAndClamp local MT = ImGui.GetMetatables() --- @param scale_factor float function MT.ImGuiStyle:ScaleAllSizes(scale_factor) self._MainScale = self._MainScale * scale_factor self.WindowPadding = ImTrunc(self.WindowPadding * scale_factor) self.WindowRounding = ImTrunc(self.WindowRounding * scale_factor) self.WindowBorderSize = ImTrunc(self.WindowBorderSize * scale_factor) self.WindowMinSize = ImTrunc(self.WindowMinSize * scale_factor) self.WindowBorderHoverPadding = ImTrunc(self.WindowBorderHoverPadding * scale_factor) self.ChildRounding = ImTrunc(self.ChildRounding * scale_factor) self.ChildBorderSize = ImTrunc(self.ChildBorderSize * scale_factor) self.PopupRounding = ImTrunc(self.PopupRounding * scale_factor) self.PopupBorderSize = ImTrunc(self.PopupBorderSize * scale_factor) self.FramePadding = ImTrunc(self.FramePadding * scale_factor) self.FrameBorderSize = ImTrunc(self.FrameBorderSize * scale_factor) self.FrameRounding = ImTrunc(self.FrameRounding * scale_factor) self.ItemSpacing = ImTrunc(self.ItemSpacing * scale_factor) self.ItemInnerSpacing = ImTrunc(self.ItemInnerSpacing * scale_factor) self.CellPadding = ImTrunc(self.CellPadding * scale_factor) self.TouchExtraPadding = ImTrunc(self.TouchExtraPadding * scale_factor) self.IndentSpacing = ImTrunc(self.IndentSpacing * scale_factor) self.ColumnsMinSpacing = ImTrunc(self.ColumnsMinSpacing * scale_factor) self.ScrollbarSize = ImTrunc(self.ScrollbarSize * scale_factor) self.ScrollbarRounding = ImTrunc(self.ScrollbarRounding * scale_factor) self.ScrollbarPadding = ImTrunc(self.ScrollbarPadding * scale_factor) self.GrabMinSize = ImTrunc(self.GrabMinSize * scale_factor) self.GrabRounding = ImTrunc(self.GrabRounding * scale_factor) self.LogSliderDeadzone = ImTrunc(self.LogSliderDeadzone * scale_factor) self.ImageRounding = ImTrunc(self.ImageRounding * scale_factor) self.ImageBorderSize = ImTrunc(self.ImageBorderSize * scale_factor) self.TabRounding = ImTrunc(self.TabRounding * scale_factor) self.TabBorderSize = ImTrunc(self.TabBorderSize * scale_factor) self.TabMinWidthBase = ImTrunc(self.TabMinWidthBase * scale_factor) self.TabMinWidthShrink = ImTrunc(self.TabMinWidthShrink * scale_factor) self.TabCloseButtonMinWidthSelected = (self.TabCloseButtonMinWidthSelected > 0.0 and self.TabCloseButtonMinWidthSelected ~= FLT_MAX) and ImTrunc(self.TabCloseButtonMinWidthSelected * scale_factor) or self.TabCloseButtonMinWidthSelected self.TabCloseButtonMinWidthUnselected = (self.TabCloseButtonMinWidthUnselected > 0.0 and self.TabCloseButtonMinWidthUnselected ~= FLT_MAX) and ImTrunc(self.TabCloseButtonMinWidthUnselected * scale_factor) or self.TabCloseButtonMinWidthUnselected self.TabBarBorderSize = ImTrunc(self.TabBarBorderSize * scale_factor) self.TabBarOverlineSize = ImTrunc(self.TabBarOverlineSize * scale_factor) self.TreeLinesSize = ImTrunc(self.TreeLinesSize * scale_factor) self.TreeLinesRounding = ImTrunc(self.TreeLinesRounding * scale_factor) self.MenuItemRounding = ImTrunc(self.MenuItemRounding * scale_factor) self.SelectableRounding = ImTrunc(self.SelectableRounding * scale_factor) self.DragDropTargetRounding = ImTrunc(self.DragDropTargetRounding * scale_factor) self.DragDropTargetBorderSize = ImTrunc(self.DragDropTargetBorderSize * scale_factor) self.DragDropTargetPadding = ImTrunc(self.DragDropTargetPadding * scale_factor) self.ColorMarkerSize = ImTrunc(self.ColorMarkerSize * scale_factor) self.InputTextCursorSize = ImTrunc(self.InputTextCursorSize * scale_factor) self.SeparatorSize = ImTrunc(self.SeparatorSize * scale_factor) self.SeparatorTextBorderSize = ImTrunc(self.SeparatorTextBorderSize * scale_factor) self.SeparatorTextPadding = ImTrunc(self.SeparatorTextPadding * scale_factor) self.DockingSeparatorSize = ImTrunc(self.DockingSeparatorSize * scale_factor) self.DisplayWindowPadding = ImTrunc(self.DisplayWindowPadding * scale_factor) self.DisplaySafeAreaPadding = ImTrunc(self.DisplaySafeAreaPadding * scale_factor) self.MouseCursorScale = ImTrunc(self.MouseCursorScale * scale_factor) end local ImGuiResizeGripDef = { {CornerPosN = ImVec2(1, 1), InnerDir = ImVec2(-1, -1), AngleMin12 = 0, AngleMax12 = 3}, -- Bottom right grip {CornerPosN = ImVec2(0, 1), InnerDir = ImVec2( 1, -1), AngleMin12 = 3, AngleMax12 = 6} -- Bottom left } --- [1] Left, [2] Right, [3] Up, [4] Down local ImGuiResizeBorderDef = { {InnerDir = ImVec2( 1, 0), SegmentN1 = ImVec2( 0, 1), SegmentN2 = ImVec2( 0, 0), OuterAngle = IM_PI * 1.00}, {InnerDir = ImVec2(-1, 0), SegmentN1 = ImVec2( 1, 0), SegmentN2 = ImVec2( 1, 1), OuterAngle = IM_PI * 0.00}, {InnerDir = ImVec2( 0, 1), SegmentN1 = ImVec2( 0, 0), SegmentN2 = ImVec2( 1, 0), OuterAngle = IM_PI * 1.50}, {InnerDir = ImVec2( 0, -1), SegmentN1 = ImVec2( 1, 1), SegmentN2 = ImVec2( 0, 1), OuterAngle = IM_PI * 0.50} } --- @param window ImGuiWindow --- @param border_n int --- @param perp_padding float --- @param thickness float --- @return ImRect --- @nodiscard local function GetResizeBorderRect(window, border_n, perp_padding, thickness) local rect = window:Rect() if thickness == 0.0 then ImVec2_CopyV(rect.Max, rect.Max.x - 1, rect.Max.y - 1) end if border_n == ImGuiDir.Left then return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding) end if border_n == ImGuiDir.Right then return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding) end if border_n == ImGuiDir.Up then return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness) end if border_n == ImGuiDir.Down then return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness) end IM_ASSERT(false) return ImRect() end --- @param data table|number --- @param size int? # size = -1 to indicate that `data` is a single number --- @param seed int? --- @return int function ImHashData(data, size, seed) seed = seed or 0 local FNV_OFFSET_BASIS = 0x811C9DC5 local FNV_PRIME = 0x01000193 local hash = bit32.bxor(FNV_OFFSET_BASIS, seed) if size == -1 then --- @cast data number hash = bit32.bxor(hash, data) hash = bit32.band(hash * FNV_PRIME, 0xFFFFFFFF) else size = size or #data for i = 1, size do hash = bit32.bxor(hash, data[i]) hash = bit32.band(hash * FNV_PRIME, 0xFFFFFFFF) end end return hash end -- Use FNV1a, as one ImGui FIXME suggested --- @param str string --- @param size int? --- @param seed int? --- @return int -- [Luau] memo for whole-string hashes: labels are re-hashed with the same seed every frame. -- ponytail: whole-memo reset at HASH_MEMO_MAX entries, LRU if ID churn makes it thrash local hash_memo, hash_memo_n, HASH_MEMO_MAX = {}, 0, 16384 local ImHashStrRaw function ImHashStr(str, size, seed) if seed == nil then seed = 0 end if size == nil or size == #str then local m = hash_memo[seed] if m == nil then m = {}; hash_memo[seed] = m end local h = m[str] if h == nil then if hash_memo_n >= HASH_MEMO_MAX then hash_memo = { [seed] = m }; table.clear(m); hash_memo_n = 0 end h = ImHashStrRaw(str, #str, seed) m[str] = h hash_memo_n += 1 end return h end return ImHashStrRaw(str, size, seed) end @native function ImHashStrRaw(str, size, seed) if str == "" or size == 0 then return seed -- need to match cpp code edge case behavior while using FNV ourselves end local FNV_OFFSET_BASIS = 0x811C9DC5 local FNV_PRIME = 0x01000193 local hash = bit32.bxor(FNV_OFFSET_BASIS, seed) local i = 1 local c while i <= size do c = string.byte(str, i) -- `###` to reset back to initial hash value if c == 35 and string.byte(str, i + 1) == 35 and string.byte(str, i + 2) == 35 then hash = bit32.bxor(FNV_OFFSET_BASIS, seed) i = i + 2 else hash = bit32.bxor(hash, c) hash = bit32.band(hash * FNV_PRIME, 0xFFFFFFFF) end i = i + 1 end return hash end do --[[CharFromUtf8]] local lengths = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0} local masks = {0x00, 0x7f, 0x1f, 0x0f, 0x07} local mins = {0x400000, 0, 0x80, 0x800, 0x10000} local shiftc = {0, 18, 12, 6, 0} local shifte = {0, 6, 4, 2, 0} local s = {0, 0, 0, 0} --- @param in_text ImString --- @param pos int --- @param in_text_end int --- @return int wanted --- @return unsigned_int out_char function ImStd.ImTextCharFromUtf8(in_text, pos, in_text_end) local len = lengths[bit32.rshift(ImStrByte(in_text, pos), 3) + 1] local wanted = len > 0 and len or 1 if in_text_end == nil then in_text_end = pos + wanted end s[1] = (pos < in_text_end) and ImStrByte(in_text, pos) or 0 s[2] = (pos + 1 < in_text_end) and ImStrByte(in_text, pos + 1) or 0 s[3] = (pos + 2 < in_text_end) and ImStrByte(in_text, pos + 2) or 0 s[4] = (pos + 3 < in_text_end) and ImStrByte(in_text, pos + 3) or 0 local out_char out_char = bit32.lshift(bit32.band(s[1], masks[len + 1]), 18) out_char = bit32.bor(out_char, bit32.lshift(bit32.band(s[2], 0x3f), 12)) out_char = bit32.bor(out_char, bit32.lshift(bit32.band(s[3], 0x3f), 6)) out_char = bit32.bor(out_char, bit32.lshift(bit32.band(s[4], 0x3f), 0)) out_char = bit32.rshift(out_char, shiftc[len + 1]) local e = 0 e = bit32.lshift((out_char < mins[len + 1]) and 1 or 0, 6) e = bit32.bor(e, bit32.lshift((bit32.rshift(out_char, 11) == 0x1b) and 1 or 0, 7)) e = bit32.bor(e, bit32.lshift((out_char > IM_UNICODE_CODEPOINT_MAX) and 1 or 0, 8)) e = bit32.bor(e, bit32.rshift(bit32.band(s[2], 0xc0), 2)) e = bit32.bor(e, bit32.rshift(bit32.band(s[3], 0xc0), 4)) e = bit32.bor(e, bit32.rshift(s[4], 6)) e = bit32.bxor(e, 0x2a) e = bit32.rshift(e, shifte[len + 1]) if e ~= 0 then wanted = ImMin(wanted, (s[1] ~= 0 and 1 or 0) + (s[2] ~= 0 and 1 or 0) + (s[3] ~= 0 and 1 or 0) + (s[4] ~= 0 and 1 or 0)) out_char = IM_UNICODE_CODEPOINT_INVALID end return wanted, out_char end end --- @param buf char[] --- @param buf_size int --- @param c unsigned_int local function ImTextCharToUtf8_inline(buf, buf_size, c) if c < 0x80 then buf[1] = c return 1 end if c < 0x800 then if buf_size < 2 then return 0 end buf[1] = (0xc0 + bit32.rshift(c, 6)) buf[2] = (0x80 + bit32.band(c, 0x3f)) return 2 end if c < 0x10000 then if buf_size < 3 then return 0 end buf[1] = (0xe0 + bit32.rshift(c, 12)) buf[2] = (0x80 + bit32.band(bit32.rshift(c, 6), 0x3f)) buf[3] = (0x80 + bit32.band(c, 0x3f)) return 3 end if c <= 0x10FFFF then if buf_size < 4 then return 0 end buf[1] = (0xf0 + bit32.rshift(c, 18)) buf[2] = (0x80 + bit32.band(bit32.rshift(c, 12), 0x3f)) buf[3] = (0x80 + bit32.band(bit32.rshift(c, 6), 0x3f)) buf[4] = (0x80 + bit32.band(c, 0x3f)) return 4 end -- Invalid code point, the max unicode is 0x10FFFF return 0 end --- @param out_buf [char, char, char, char, char] --- @param c unsigned_int function ImStd.ImTextCharToUtf8(out_buf, c) local count = ImTextCharToUtf8_inline(out_buf, 5, c) out_buf[count + 1] = 0 return count end --- @param in_text ImString --- @param pos int --- @param in_text_end int --- @return int function ImStd.ImTextCountUtf8BytesFromChar(in_text, pos, in_text_end) local bytes, unused = ImStd.ImTextCharFromUtf8(in_text, pos, in_text_end) return bytes end --- @param text ImString --- @param in_text_start int --- @param in_p int function ImStd.ImTextFindPreviousUtf8Codepoint(text, in_text_start, in_p) while in_p > in_text_start do in_p = in_p - 1 if bit32.band(ImStrByte(text, in_p), 0xC0) ~= 0x80 then return in_p end end return in_text_start end --- @param text ImString --- @param in_text_start int --- @param in_text_end int --- @param in_p int --- @return int function ImStd.ImTextFindValidUtf8CodepointEnd(text, in_text_start, in_text_end, in_p) if in_text_start == in_p then return in_text_start end local prev = ImStd.ImTextFindPreviousUtf8Codepoint(text, in_text_start, in_p) local prev_c_len, prev_c = ImStd.ImTextCharFromUtf8(text, prev, in_text_end) -- Check if the previous character is valid and fits within the range if prev_c ~= IM_UNICODE_CODEPOINT_INVALID and prev_c_len <= (in_p - prev) then return in_p end return prev end --- @param a ImVec2 --- @param b ImVec2 --- @param p ImVec2 --- @return ImVec2 --- @nodiscard function ImStd.ImLineClosestPoint(a, b, p) local ap = p - a local ab_dir = b - a local dot = ap.x * ab_dir.x + ap.y * ab_dir.y if dot < 0.0 then return a end local ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y if dot > ab_len_sqr then return b end return a + ab_dir * (dot / ab_len_sqr) end --- @param a ImVec2 --- @param b ImVec2 --- @param c ImVec2 --- @param p ImVec2 function ImStd.ImTriangleContainsPoint(a, b, c, p) local b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0 local b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0 local b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0 return (b1 == b2) and (b2 == b3) end --- @param a ImVec2 --- @param b ImVec2 --- @param c ImVec2 --- @param p ImVec2 --- @return float, float, float function ImStd.ImTriangleBarycentricCoords(a, b, c, p) local v0 = b - a local v1 = c - a local v2 = p - a local denom = v0.x * v1.y - v1.x * v0.y local out_v = (v2.x * v1.y - v1.x * v2.y) / denom local out_w = (v0.x * v2.y - v2.x * v0.y) / denom local out_u = 1.0 - out_v - out_w return out_u, out_v, out_w end --- @param a ImVec2 --- @param b ImVec2 --- @param c ImVec2 --- @param p ImVec2 --- @return ImVec2 --- @nodiscard function ImStd.ImTriangleClosestPoint(a, b, c, p) local proj_ab = ImStd.ImLineClosestPoint(a, b, p) local proj_bc = ImStd.ImLineClosestPoint(b, c, p) local proj_ca = ImStd.ImLineClosestPoint(c, a, p) local dist2_ab = ImLengthSqr(p - proj_ab) local dist2_bc = ImLengthSqr(p - proj_bc) local dist2_ca = ImLengthSqr(p - proj_ca) local m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)) if m == dist2_ab then return proj_ab elseif m == dist2_bc then return proj_bc else return proj_ca end end --- @param dst char[] --- @param dst_pos int --- @param src char[] --- @param src_pos int --- @param count size_t function ImStd.ImStrncpy(dst, dst_pos, src, src_pos, count) if count < 1 then return end if count > 1 then ImStd.memmove(dst, dst_pos, src, src_pos, count - 1) end dst[dst_pos + (count - 1)] = 0 end --- @param str char[] --- @param mid_line int --- @param begin int function ImStd.ImStrbol(str, mid_line, begin) IM_ASSERT_PARANOID(mid_line >= begin and mid_line <= #str) while mid_line > begin and str[mid_line - 1] ~= 10 do mid_line = mid_line - 1 end return mid_line end --- @param buf char[] function ImStd.ImStrTrimBlanks(buf) local p = 1 -- buf_begin while buf[p] == 32 or buf[p] == 9 do p = p + 1 end local p_start = p while buf[p] ~= 0 do p = p + 1 end while p > p_start and (buf[p - 1] == 32 or buf[p - 1] == 9) do p = p - 1 end if p_start > 1 then ImStd.memmove(buf, 1, buf, p_start, p - p_start) end buf[p - p_start + 1] = 0 end function ImGui.UpdateCurrentFontSize(restore_font_size_after_scaling) local g = GImGui local window = g.CurrentWindow g.Style.FontSizeBase = g.FontSizeBase -- if (window ~= nil and window.SkipItems) then -- local table = g.CurrentTable -- if (table == nil or (table.CurrentColumn ~= -1 and table.Columns[table.CurrentColumn].IsSkipItems == false)) then -- return -- end -- end local final_size = (restore_font_size_after_scaling > 0.0) and restore_font_size_after_scaling or 0.0 if final_size == 0.0 then final_size = g.FontSizeBase final_size = final_size * g.Style.FontScaleMain final_size = final_size * g.Style.FontScaleDpi if window ~= nil then final_size = final_size * window.FontWindowScale end end final_size = ImGui.GetRoundedFontSize(final_size) final_size = ImClamp(final_size, 4.0, IMGUI_FONT_SIZE_MAX) if (g.Font ~= nil and bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ~= 0) then g.Font.CurrentRasterizerDensity = g.FontRasterizerDensity end g.FontSize = final_size g.FontBaked = (g.Font ~= nil and window ~= nil) and g.Font:GetFontBaked(final_size) or nil g.FontBakedScale = (g.FontBaked ~= nil) and (g.FontSize / g.FontBaked.Size) or 0.0 g.DrawListSharedData.FontSize = g.FontSize g.DrawListSharedData.FontScale = g.FontBakedScale end function ImGui.SetCurrentFont(font, font_size_before_scaling, font_size_after_scaling) local g = GImGui g.Font = font g.FontSizeBase = font_size_before_scaling ImGui.UpdateCurrentFontSize(font_size_after_scaling) if font ~= nil then IM_ASSERT(font and font:IsLoaded()) local atlas = font.OwnerAtlas g.DrawListSharedData.FontAtlas = atlas g.DrawListSharedData.Font = font ImFontAtlasUpdateDrawListsSharedData(atlas) if (g.CurrentWindow ~= nil) then g.CurrentWindow.DrawList:_SetTexture(atlas.TexRef) end end end function ImGui.PushFont(font, font_size_base) local g = GImGui if font == nil then font = g.Font end IM_ASSERT(font ~= nil) IM_ASSERT(font_size_base >= 0.0) g.FontStack:push_back(ImFontStackData(font, g.FontSizeBase, g.FontSize)) if font_size_base == 0.0 then font_size_base = g.FontSizeBase end ImGui.SetCurrentFont(font, font_size_base, 0.0) end function ImGui.PopFont() local g = GImGui if (g.FontStack.Size <= 0) then IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!") return end local font_stack_data = g.FontStack:back() ImGui.SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, font_stack_data.FontSizeAfterScaling) g.FontStack:pop_back() end function ImGui.UpdateTexturesNewFrame() local g = GImGui local has_textures = bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ~= 0 for _, atlas in g.FontAtlases:iter() do if (atlas.OwnerContext == g) then ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures) else IM_ASSERT(atlas.Builder ~= nil and atlas.Builder.FrameCount ~= -1) IM_ASSERT(atlas.RendererHasTextures == has_textures) end end for _, tex in g.UserTextures:iter() do ImTextureDataUpdateNewFrame(tex) end end function ImGui.UpdateTexturesEndFrame() local g = GImGui g.PlatformIO.Textures:resize(0) for _, atlas in g.FontAtlases:iter() do for _, tex in atlas.TexList:iter() do tex.RefCount = atlas.RefCount g.PlatformIO.Textures:push_back(tex) end end for _, tex in g.UserTextures:iter() do g.PlatformIO.Textures:push_back(tex) end end function ImGui.UpdateFontsNewFrame() local g = GImGui if (bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.RendererHasTextures) == 0) then for _, atlas in g.FontAtlases:iter() do atlas.Locked = true end end if (g.Style._NextFrameFontSizeBase ~= 0.0) then g.Style.FontSizeBase = g.Style._NextFrameFontSizeBase g.Style._NextFrameFontSizeBase = 0.0 end local font = ImGui.GetDefaultFont() if g.Style.FontSizeBase <= 0.0 then g.Style.FontSizeBase = ((font.LegacySize > 0.0) and font.LegacySize or FONT_DEFAULT_SIZE_BASE) end g.Font = font g.FontSizeBase = g.Style.FontSizeBase g.FontSize = 0.0 local font_stack_data = ImFontStackData(font, g.Style.FontSizeBase, g.Style.FontSizeBase) ImGui.SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0) g.FontStack:push_back(font_stack_data) IM_ASSERT(g.Font:IsLoaded()) end function ImGui.UpdateFontsEndFrame() ImGui.PopFont() end --- @return ImFont function ImGui.GetDefaultFont() local g = GImGui local atlas = g.IO.Fonts if (atlas.Builder == nil or atlas.Fonts.Size == 0) then ImFontAtlasBuildMain(atlas) end return g.IO.FontDefault and g.IO.FontDefault or atlas.Fonts[1] end --- @param atlas ImFontAtlas function ImGui.RegisterFontAtlas(atlas) local g = GImGui if (g.FontAtlases.Size == 0) then IM_ASSERT(atlas == g.IO.Fonts) end atlas.RefCount = atlas.RefCount + 1 g.FontAtlases:push_back(atlas) ImFontAtlasAddDrawListSharedData(atlas, g.DrawListSharedData) for _, tex in atlas.TexList:iter() do tex.RefCount = atlas.RefCount end end --- @param atlas ImFontAtlas function ImGui.UnregisterFontAtlas(atlas) local g = GImGui IM_ASSERT(atlas.RefCount > 0) ImFontAtlasRemoveDrawListSharedData(atlas, g.DrawListSharedData) g.FontAtlases:find_erase(atlas) atlas.RefCount = atlas.RefCount - 1 for _, tex in atlas.TexList:iter() do tex.RefCount = atlas.RefCount end end function ImGui.GetCurrentContext() return GImGui end --- @param ctx ImGuiContext? function ImGui.SetCurrentContext(ctx) GImGui = ctx ImGui._SetCurrentContext_Internal(ctx) ImGui._SetCurrentContext_Widgets(ctx) ImGui._SetCurrentContext_Tables(ctx) end --- @param alloc_func ImGuiMemAllocFunc --- @param free_func ImGuiMemFreeFunc --- @param user_data any function ImGui.SetAllocatorFunctions(alloc_func, free_func, user_data) GImAllocatorAllocFunc = alloc_func GImAllocatorFreeFunc = free_func GImAllocatorUserData = user_data end --- @param key ImGuiLocKey --- @param text string --- @return ImGuiLocEntry --- @nodiscard --- @package local function ImGuiLocEntry(key, text) return { Key = key, Text = text } end local GLocalizationEntriesEnUS = { ImGuiLocEntry(ImGuiLocKey.VersionStr, "Dear ImGui WIP"), ImGuiLocEntry(ImGuiLocKey.TableSizeOne, "Size column to fit###SizeOne"), ImGuiLocEntry(ImGuiLocKey.TableSizeAllFit, "Size all columns to fit###SizeAll"), ImGuiLocEntry(ImGuiLocKey.TableSizeAllDefault, "Size all columns to default###SizeAll"), ImGuiLocEntry(ImGuiLocKey.TableReset, "Reset"), ImGuiLocEntry(ImGuiLocKey.TableResetOrder, "Reset order###ResetOrder"), ImGuiLocEntry(ImGuiLocKey.TableResetVisibility, "Reset visibility###ResetVisibility"), ImGuiLocEntry(ImGuiLocKey.WindowingMainMenuBar, "(Main menu bar)"), ImGuiLocEntry(ImGuiLocKey.WindowingPopup, "(Popup)"), ImGuiLocEntry(ImGuiLocKey.WindowingUntitled, "(Untitled)"), ImGuiLocEntry(ImGuiLocKey.OpenLink_s, "Open '%s'"), ImGuiLocEntry(ImGuiLocKey.CopyLink, "Copy Link###CopyLink"), ImGuiLocEntry(ImGuiLocKey.DockingHideTabBar, "Hide tab bar###HideTabBar"), ImGuiLocEntry(ImGuiLocKey.DockingHoldShiftToDock, "Hold SHIFT to enable Docking window."), ImGuiLocEntry(ImGuiLocKey.DockingDragToUndockOrMoveNode, "Click and drag to move or undock whole node."), } function ImGui.Initialize() local g = GImGui IM_ASSERT(not g.Initialized and not g.SettingsLoaded) ImGui.WindowSettingsAddSettingsHandler() if ImGui.TableSettingsAddSettingsHandler then ImGui.TableSettingsAddSettingsHandler() end ImGui.DockContextInitialize(g) ImGui.LocalizeRegisterEntries(GLocalizationEntriesEnUS, #GLocalizationEntriesEnUS) local viewport = ImGuiViewportP() viewport.ID = IMGUI_VIEWPORT_DEFAULT_ID viewport.Idx = 1 viewport.PlatformWindowCreated = true viewport.Flags = ImGuiViewportFlags.OwnedByApp g.Viewports:push_back(viewport) g.ViewportCreatedCount = g.ViewportCreatedCount + 1 g.PlatformIO.Viewports:push_back(g.Viewports.Data[1]) for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do if (key >= ImGuiKey.K0 and key <= ImGuiKey.K9) or (key >= ImGuiKey.A and key <= ImGuiKey.Z) or (key >= ImGuiKey.Keypad0 and key <= ImGuiKey.Keypad9) or key == ImGuiKey.Tab or key == ImGuiKey.Space or key == ImGuiKey.Apostrophe or key == ImGuiKey.Comma or key == ImGuiKey.Minus or key == ImGuiKey.Period or key == ImGuiKey.Slash or key == ImGuiKey.Semicolon or key == ImGuiKey.Equal or key == ImGuiKey.LeftBracket or key == ImGuiKey.RightBracket or key == ImGuiKey.GraveAccent or key == ImGuiKey.KeypadDecimal or key == ImGuiKey.KeypadDivide or key == ImGuiKey.KeypadMultiply or key == ImGuiKey.KeypadSubtract or key == ImGuiKey.KeypadAdd or key == ImGuiKey.KeypadEqual then g.KeysMayBeCharInput:SetBit(key + 1) end end local atlas = g.IO.Fonts g.DrawListSharedData.Context = g ImGui.RegisterFontAtlas(atlas) g.Initialized = true end --- @param shared_font_atlas? ImFontAtlas function ImGui.CreateContext(shared_font_atlas) local prev_ctx = ImGui.GetCurrentContext() local ctx = ImGuiContext(shared_font_atlas) ImGui.SetCurrentContext(ctx) ImGui.Initialize() if prev_ctx ~= nil then ImGui.SetCurrentContext(prev_ctx) -- Restore previous context if any, else keep new one end return ctx end --- @param ctx? ImGuiContext function ImGui.DestroyContext(ctx) local prev_ctx = ImGui.GetCurrentContext() if ctx == nil then ctx = prev_ctx end ImGui.SetCurrentContext(ctx) ImGui.Shutdown() ImGui.SetCurrentContext((prev_ctx ~= ctx) and prev_ctx or nil) end --- @param window ImGuiWindow --- @return any function ImGui.FindWindowSettingsByWindow(window) local g = GImGui if window.SettingsOffset ~= -1 then return g.SettingsWindows[window.SettingsOffset + 1] end return ImGui.FindWindowSettingsByID(window.ID) end --- @param id ImGuiID --- @return any function ImGui.FindWindowSettingsByID(id) local g = GImGui for _, settings in g.SettingsWindows:iter() do if settings.ID == id and not settings.WantDelete then return settings end end return nil end --- @param window ImGuiWindow --- @return ImGuiWindow? function ImGui.FindFrontMostVisibleChildWindow(window) for n = window.DC.ChildWindows.Size, 1, -1 do if ImGui.IsWindowActiveAndVisible(window.DC.ChildWindows.Data[n]) then return ImGui.FindFrontMostVisibleChildWindow(window.DC.ChildWindows.Data[n]) end end return window end --- @param window ImGuiWindow --- @param cond ImGuiCond --- @param allow bool local function SetWindowConditionAllowFlags(window, cond, allow) if allow then window.SetWindowPosAllowFlags = bit32.bor(window.SetWindowPosAllowFlags, cond) window.SetWindowSizeAllowFlags = bit32.bor(window.SetWindowSizeAllowFlags, cond) window.SetWindowCollapsedAllowFlags = bit32.bor(window.SetWindowCollapsedAllowFlags, cond) else window.SetWindowPosAllowFlags = bit32.band(window.SetWindowPosAllowFlags, bit32.bnot(cond)) window.SetWindowSizeAllowFlags = bit32.band(window.SetWindowSizeAllowFlags, bit32.bnot(cond)) window.SetWindowCollapsedAllowFlags = bit32.band(window.SetWindowCollapsedAllowFlags, bit32.bnot(cond)) end end --- @param window ImGuiWindow --- @param settings ImGuiWindowSettings local function ApplyWindowSettings(window, settings) if settings ~= nil then local main_viewport = ImGui.GetMainViewport() ImVec2_Copy(window.ViewportPos, main_viewport.Pos) if (settings.ViewportId ~= 0) then window.ViewportId = settings.ViewportId ImVec2_Copy(window.ViewportPos, settings.ViewportPos) end window.Pos = ImTrunc(ImVec2(settings.Pos.x + window.ViewportPos.x, settings.Pos.y + window.ViewportPos.y)) if settings.Size.x > 0 and settings.Size.y > 0 then local size = ImVec2(ImTrunc(settings.Size.x), ImTrunc(settings.Size.y)) ImVec2_Copy(window.Size, size) ImVec2_Copy(window.SizeFull, size) window.AutoFitFramesX = 0; window.AutoFitFramesY = 0 end window.Collapsed = settings.Collapsed window.DockId = settings.DockId or 0 window.DockOrder = settings.DockOrder or -1 SetWindowConditionAllowFlags(window, ImGuiCond.FirstUseEver, false) end -- So first call to CalcWindowContentSizes() doesn't return crazy values ImVec2_Copy(window.DC.CursorStartPos, window.Pos) ImVec2_Copy(window.DC.CursorMaxPos, window.Pos) ImVec2_Copy(window.DC.IdealMaxPos, window.Pos) if (bit32.band(window.Flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0) then window.AutoFitFramesX = 2; window.AutoFitFramesY = 2 window.AutoFitOnlyGrows = false else window.AutoFitFramesX = (window.Size.x <= 0.0) and 2 or 0 window.AutoFitFramesY = (window.Size.y <= 0.0) and 2 or 0 window.AutoFitOnlyGrows = (window.AutoFitFramesX > 0) or (window.AutoFitFramesY > 0) end end --- @param window ImGuiWindow --- @param settings ImGuiWindowSettings local function InitOrLoadWindowSettings(window, settings) -- Initial window state with e.g. default/arbitrary window position -- Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. local main_viewport = ImGui.GetMainViewport() ImVec2_Copy(window.Pos, main_viewport.Pos + ImVec2(60, 60)) ImVec2_Copy(window.Size, ImVec2(0, 0)) ImVec2_Copy(window.SizeFull, ImVec2(0, 0)) ImVec2_Copy(window.ViewportPos, main_viewport.Pos) window.SetWindowPosAllowFlags = bit32.bor(ImGuiCond.Always, ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing) window.SetWindowSizeAllowFlags = window.SetWindowPosAllowFlags window.SetWindowCollapsedAllowFlags = window.SetWindowPosAllowFlags window.SetWindowDockAllowFlags = window.SetWindowPosAllowFlags ApplyWindowSettings(window, settings) if settings ~= nil then -- TODO: settings.LastUsedDate = g.SessionDate end end --- @param name string --- @param flags ImGuiWindowFlags --- @return ImGuiWindow local function CreateNewWindow(name, flags) local g = GImGui local window_id = ImHashStr(name) local window = ImGuiWindow(g, name) window.ID = window_id window.Flags = flags g.WindowsById[window_id] = window local settings = nil if bit32.band(window.Flags, ImGuiWindowFlags.NoSavedSettings) == 0 then settings = ImGui.FindWindowSettingsByWindow(window) if settings ~= nil then window.SettingsOffset = g.SettingsWindows:index_from_ptr(settings) end end InitOrLoadWindowSettings(window, settings) if bit32.band(flags, ImGuiWindowFlags.NoBringToFrontOnFocus) ~= 0 then g.Windows:push_front(window) else g.Windows:push_back(window) end return window end --------------------------------------------------------------------------------------- -- [SECTION] SETTINGS (in-memory .ini; Roblox has no disk) --------------------------------------------------------------------------------------- function ImGui.UpdateSettings() local g = GImGui if not g.SettingsLoaded then if g.IO.IniFilename then ImGui.LoadIniSettingsFromDisk(g.IO.IniFilename) end g.SettingsLoaded = true end if g.SettingsDirtyTimer > 0.0 then g.SettingsDirtyTimer = g.SettingsDirtyTimer - g.IO.DeltaTime if g.SettingsDirtyTimer <= 0.0 then -- No disk: always let the user know they can call SaveIniSettingsToMemory() g.IO.WantSaveIniSettings = true g.SettingsDirtyTimer = 0.0 end end end --- @param window? ImGuiWindow function ImGui.MarkIniSettingsDirty(window) local g = GImGui if window ~= nil and bit32.band(window.Flags, ImGuiWindowFlags.NoSavedSettings) ~= 0 then return end if g.SettingsDirtyTimer <= 0.0 then g.SettingsDirtyTimer = g.IO.IniSavingRate end end --- @param handler ImGuiSettingsHandler function ImGui.AddSettingsHandler(handler) local g = GImGui IM_ASSERT(ImGui.FindSettingsHandler(handler.TypeName) == nil) if handler.TypeHash == 0 or handler.TypeHash == nil then handler.TypeHash = ImHashStr(handler.TypeName) end g.SettingsHandlers:push_back(handler) end function ImGui.RemoveSettingsHandler(type_name) local g = GImGui local handler = ImGui.FindSettingsHandler(type_name) if handler then g.SettingsHandlers:find_erase(handler) end end function ImGui.FindSettingsHandler(type_name) local g = GImGui local type_hash = ImHashStr(type_name) for _, handler in g.SettingsHandlers:iter() do if handler.TypeHash == type_hash then return handler end end return nil end function ImGui.ClearIniSettings() local g = GImGui g.SettingsIniData = "" for _, handler in g.SettingsHandlers:iter() do if handler.ClearAllFn then handler.ClearAllFn(g, handler) end end end function ImGui.CleanupIniSettings(args) local g = GImGui if args.DiscardAll then for _, handler in g.SettingsHandlers:iter() do if (args.TypeHashFilter or 0) == 0 or handler.TypeHash == args.TypeHashFilter then if handler.ClearAllFn then handler.ClearAllFn(g, handler) end end end end end function ImGui.LoadIniSettingsFromDisk(ini_filename) local data = ImStd.ImFileLoadToMemory and ImStd.ImFileLoadToMemory(ini_filename, "rb") if not data or #data == 0 then return end local parts = {} for i = 1, #data do parts[i] = string.char(data[i]) end ImGui.LoadIniSettingsFromMemory(table.concat(parts)) end --- Zero-tolerance, cheap .ini parsing. `ini_size` ignored (Lua strings know their length). function ImGui.LoadIniSettingsFromMemory(ini_data, ini_size) local g = GImGui IM_ASSERT(g.Initialized) if ini_size and ini_size > 0 then ini_data = ini_data:sub(1, ini_size) end g.SettingsIniData = ini_data for _, handler in g.SettingsHandlers:iter() do if handler.ReadInitFn then handler.ReadInitFn(g, handler) end end local entry_data, entry_handler = nil, nil for line in ini_data:gmatch("[^\r\n]+") do local c = line:sub(1, 1) if c == ";" then -- comment elseif c == "[" and line:sub(-1) == "]" then -- "[Type][Name]" (Name may contain [] characters) local type_name, name = line:match("^%[([^%]]*)%]%[(.*)%]$") if type_name then entry_handler = ImGui.FindSettingsHandler(type_name) entry_data = entry_handler and entry_handler.ReadOpenFn(g, entry_handler, name) or nil else entry_handler, entry_data = nil, nil end elseif entry_handler ~= nil and entry_data ~= nil then entry_handler.ReadLineFn(g, entry_handler, entry_data, line) end end g.SettingsLoaded = true for _, handler in g.SettingsHandlers:iter() do if handler.ApplyAllFn then handler.ApplyAllFn(g, handler) end end end function ImGui.SaveIniSettingsToDisk(ini_filename) local g = GImGui g.SettingsDirtyTimer = 0.0 -- Roblox: no disk. Call SaveIniSettingsToMemory() and persist the string yourself (e.g. DataStore). end --- @return string ini_data, int size function ImGui.SaveIniSettingsToMemory() local g = GImGui g.SettingsDirtyTimer = 0.0 local buf = ImGuiTextBuffer() for _, handler in g.SettingsHandlers:iter() do handler.WriteAllFn(g, handler, buf) end g.SettingsIniData = buf:c_str() return g.SettingsIniData, #g.SettingsIniData end function ImGui.CreateNewWindowSettings(name) local g = GImGui if not g.IO.ConfigDebugIniSettings then -- ImHashSkipUncontributingPrefix: skip everything up to the last "###" local p = name:match("^.*()###") if p then name = name:sub(p) end end local settings = ImGuiWindowSettings() settings.ID = ImHashStr(name) settings.Name = name g.SettingsWindows:push_back(settings) return settings end function ImGui.ClearWindowSettings(name) local window = ImGui.FindWindowByName(name) if window ~= nil then window.Flags = bit32.bor(window.Flags, ImGuiWindowFlags.NoSavedSettings) InitOrLoadWindowSettings(window, nil) if window.DockId and window.DockId ~= 0 and ImGui.DockContextProcessUndockWindow then ImGui.DockContextProcessUndockWindow(GImGui, window, true) end end local settings = window and ImGui.FindWindowSettingsByWindow(window) or ImGui.FindWindowSettingsByID(ImHashStr(name)) if settings then settings.WantDelete = true end end local function WindowSettingsHandler_ClearAll(ctx, handler) local g = ctx for _, window in g.Windows:iter() do window.SettingsOffset = -1 end g.SettingsWindows:clear() end local function WindowSettingsHandler_ReadOpen(ctx, handler, name) local id = ImHashStr(name) local settings = ImGui.FindWindowSettingsByID(id) if settings then local fresh = ImGuiWindowSettings() for k, v in pairs(fresh) do settings[k] = v end settings.Name = name else settings = ImGui.CreateNewWindowSettings(name) end settings.ID = id settings.WantApply = true return settings end local function WindowSettingsHandler_ReadLine(ctx, handler, settings, line) local x, y = line:match("^Pos=(%-?%d+),(%-?%d+)") if x then ImVec2_CopyV(settings.Pos, tonumber(x), tonumber(y)) return end x, y = line:match("^Size=(%-?%d+),(%-?%d+)") if x then ImVec2_CopyV(settings.Size, tonumber(x), tonumber(y)) return end x = line:match("^ViewportId=0x(%x+)") if x then settings.ViewportId = tonumber(x, 16) return end x, y = line:match("^ViewportPos=(%-?%d+),(%-?%d+)") if x then ImVec2_CopyV(settings.ViewportPos, tonumber(x), tonumber(y)) return end x = line:match("^Collapsed=(%d+)") if x then settings.Collapsed = tonumber(x) ~= 0 return end x = line:match("^IsChild=(%d+)") if x then settings.IsChild = tonumber(x) ~= 0 return end x = line:match("^LastUsed=(%d+)") if x then settings.LastUsedDate = tonumber(x) return end x, y = line:match("^DockId=0x(%x+),(%-?%d+)") if x then settings.DockId = tonumber(x, 16); settings.DockOrder = tonumber(y) return end x = line:match("^DockId=0x(%x+)") if x then settings.DockId = tonumber(x, 16); settings.DockOrder = -1 return end x = line:match("^ClassId=0x(%x+)") if x then settings.ClassId = tonumber(x, 16) return end end local function WindowSettingsHandler_ApplyAll(ctx, handler) local g = ctx for _, settings in g.SettingsWindows:iter() do if settings.WantApply then local window = ImGui.FindWindowByID(settings.ID) if window then ApplyWindowSettings(window, settings) end settings.WantApply = false end end end local function WindowSettingsHandler_WriteAll(ctx, handler, buf) local g = ctx for _, window in g.Windows:iter() do if bit32.band(window.Flags, ImGuiWindowFlags.NoSavedSettings) == 0 then local settings = ImGui.FindWindowSettingsByWindow(window) if not settings then settings = ImGui.CreateNewWindowSettings(window.Name) window.SettingsOffset = g.SettingsWindows:index_from_ptr(settings) end IM_ASSERT(settings.ID == window.ID) ImVec2_CopyV(settings.Pos, ImTrunc(window.Pos.x - window.ViewportPos.x), ImTrunc(window.Pos.y - window.ViewportPos.y)) ImVec2_CopyV(settings.Size, ImTrunc(window.SizeFull.x), ImTrunc(window.SizeFull.y)) settings.ViewportId = window.ViewportId or 0 ImVec2_CopyV(settings.ViewportPos, ImTrunc(window.ViewportPos.x), ImTrunc(window.ViewportPos.y)) settings.DockId = window.DockId or 0 settings.ClassId = window.WindowClass and window.WindowClass.ClassId or 0 settings.DockOrder = window.DockOrder or -1 settings.Collapsed = window.Collapsed settings.IsChild = (window.RootWindow ~= window) settings.WantDelete = false end end for _, settings in g.SettingsWindows:iter() do if not settings.WantDelete then buf:appendf("[%s][%s]\n", handler.TypeName, settings.Name) if settings.IsChild then buf:appendf("IsChild=1\n") buf:appendf("Size=%d,%d\n", settings.Size.x, settings.Size.y) else if settings.ViewportId ~= 0 and settings.ViewportId ~= IMGUI_VIEWPORT_DEFAULT_ID then buf:appendf("ViewportPos=%d,%d\n", settings.ViewportPos.x, settings.ViewportPos.y) buf:appendf("ViewportId=0x%08X\n", settings.ViewportId) end if settings.Pos.x ~= 0 or settings.Pos.y ~= 0 or settings.ViewportId == IMGUI_VIEWPORT_DEFAULT_ID then buf:appendf("Pos=%d,%d\n", settings.Pos.x, settings.Pos.y) end if settings.Size.x ~= 0 or settings.Size.y ~= 0 then buf:appendf("Size=%d,%d\n", settings.Size.x, settings.Size.y) end buf:appendf("Collapsed=%d\n", settings.Collapsed and 1 or 0) if settings.DockId ~= 0 then if settings.DockOrder == -1 then buf:appendf("DockId=0x%08X\n", settings.DockId) else buf:appendf("DockId=0x%08X,%d\n", settings.DockId, settings.DockOrder) end if settings.ClassId ~= 0 then buf:appendf("ClassId=0x%08X\n", settings.ClassId) end end end buf:append("\n") end end end function ImGui.WindowSettingsAddSettingsHandler() local ini_handler = ImGuiSettingsHandler() ini_handler.TypeName = "Window" ini_handler.TypeHash = ImHashStr("Window") ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll ImGui.AddSettingsHandler(ini_handler) end --------------------------------------------------------------------------------------- -- [SECTION] LOGGING/CAPTURING --------------------------------------------------------------------------------------- ImGuiLogFlags = ImGuiLogFlags or { None = 0, OutputTTY = 1, OutputFile = 2, OutputBuffer = 4, OutputClipboard = 8, OutputMask_ = 15, } local function LogTextV_Internal(g, fmt, ...) local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt if g.LogFile then print(s) -- TTY (the only "file" available on Roblox) else g.LogBuffer:append(s) end end function ImGui.LogText(fmt, ...) local g = GImGui if not g.LogEnabled then return end LogTextV_Internal(g, fmt, ...) end ImGui.LogTextV = ImGui.LogText --- Internal version that takes a position to decide on newline placement and pad items according to their depth. --- `text` is a Lua string, `text_begin/text_end` optional 1-based byte range (text_end exclusive). function ImGui.LogRenderedText(ref_pos, text, text_end, text_begin) local g = GImGui local window = g.CurrentWindow local prefix, suffix = g.LogNextPrefix, g.LogNextSuffix g.LogNextPrefix = nil; g.LogNextSuffix = nil text_begin = text_begin or 1 if not text_end then text_end = ImGui.FindRenderedTextEnd(text, text_end) end local log_new_line = ref_pos and (ref_pos.y > g.LogLinePosY + ImMax(g.Style.FramePadding.y, g.Style.ItemSpacing.y) + 1) if ref_pos then g.LogLinePosY = ref_pos.y end if log_new_line then ImGui.LogText("\n") g.LogLineFirstItem = true end if prefix then ImGui.LogRenderedText(ref_pos, prefix, #prefix + 1) end if g.LogDepthRef > window.DC.TreeDepth then g.LogDepthRef = window.DC.TreeDepth end local tree_depth = window.DC.TreeDepth - g.LogDepthRef local text_remaining = text_begin while true do local line_start = text_remaining local nl = string.find(text, "\n", line_start, true) local line_end = (nl and nl < text_end) and nl or text_end local is_last_line = (line_end == text_end) if line_start ~= line_end or not is_last_line then local indentation = g.LogLineFirstItem and tree_depth * 4 or 1 ImGui.LogText(string.rep(" ", indentation) .. string.sub(text, line_start, line_end - 1)) g.LogLineFirstItem = false if string.byte(text, line_end) == 10 then ImGui.LogText("\n") g.LogLineFirstItem = true end end if is_last_line then break end text_remaining = line_end + 1 end if suffix then ImGui.LogRenderedText(ref_pos, suffix, #suffix + 1) end end function ImGui.LogBegin(flags, auto_open_depth) local g = GImGui local window = g.CurrentWindow IM_ASSERT(g.LogEnabled == false) g.LogEnabled = true; g.ItemUnclipByLog = true g.LogFlags = flags g.LogWindow = window g.LogNextPrefix = nil; g.LogNextSuffix = nil g.LogDepthRef = window.DC.TreeDepth g.LogDepthToExpand = ((auto_open_depth or -1) >= 0) and auto_open_depth or g.LogDepthToExpandDefault g.LogLinePosY = FLT_MAX g.LogLineFirstItem = true g.LogBuffer = ImGuiTextBuffer() end function ImGui.LogSetNextTextDecoration(prefix, suffix) local g = GImGui g.LogNextPrefix = prefix g.LogNextSuffix = suffix end function ImGui.LogToTTY(auto_open_depth) local g = GImGui if g.LogEnabled then return end ImGui.LogBegin(ImGuiLogFlags.OutputTTY, auto_open_depth or -1) g.LogFile = "stdout" end function ImGui.LogToFile(auto_open_depth, filename) -- Roblox: no file access. Falls back to TTY (output window). ImGui.LogToTTY(auto_open_depth) end function ImGui.LogToClipboard(auto_open_depth) local g = GImGui if g.LogEnabled then return end ImGui.LogBegin(ImGuiLogFlags.OutputClipboard, auto_open_depth or -1) end function ImGui.LogToBuffer(auto_open_depth) local g = GImGui if g.LogEnabled then return end ImGui.LogBegin(ImGuiLogFlags.OutputBuffer, auto_open_depth or -1) end function ImGui.LogFinish() local g = GImGui if not g.LogEnabled then return end ImGui.LogText("\n") local out = bit32.band(g.LogFlags, ImGuiLogFlags.OutputMask_) if out == ImGuiLogFlags.OutputClipboard then if not g.LogBuffer:empty() then ImGui.SetClipboardText(g.LogBuffer:c_str()) end end g.LogEnabled = false; g.ItemUnclipByLog = false g.LogFlags = ImGuiLogFlags.None g.LogFile = nil g.LogBuffer = ImGuiTextBuffer() end function ImGui.LogButtons() local g = GImGui ImGui.PushID("LogButtons") local log_to_tty = ImGui.Button("Log To TTY"); ImGui.SameLine() local log_to_file = ImGui.Button("Log To File"); ImGui.SameLine() local log_to_clipboard = ImGui.Button("Log To Clipboard"); ImGui.SameLine() ImGui.PushItemFlag(ImGuiItemFlags.NoTabStop, true) ImGui.SetNextItemWidth(ImGui.CalcTextSize("999").x) g.LogDepthToExpandDefault = ImGui.SliderInt("Default Depth", g.LogDepthToExpandDefault, 0, 9, nil) ImGui.PopItemFlag() ImGui.PopID() if log_to_tty then ImGui.LogToTTY() end if log_to_file then ImGui.LogToFile() end if log_to_clipboard then ImGui.LogToClipboard() end end --- @param window ImGuiWindow --- @return ImGuiWindow? local function GetWindowForTitleDisplay(window) if window.DockNodeAsHost then return window.DockNodeAsHost.VisibleWindow else return window end end --- @param id ImGuiID @native function ImGui.KeepAliveID(id) local g = GImGui if g.ActiveId == id then g.ActiveIdIsAlive = id end if g.DeactivatedItemData.ID == id then g.DeactivatedItemData.IsAlive = true end end --- @param r_min ImVec2 --- @param r_max ImVec2 --- @param clip? bool @native function ImGui.IsMouseHoveringRect(r_min, r_max, clip) if clip == nil then clip = true end local g = GImGui -- [Luau] scalar version of: rect_clipped = ImRect(r_min, r_max); ClipWith(window.ClipRect); ContainsWithPad(); viewport Overlaps() local x0, y0, x1, y1 = r_min.x, r_min.y, r_max.x, r_max.y if clip then local cr = g.CurrentWindow.ClipRect local cmin, cmax = cr.Min, cr.Max x0 = math.max(x0, cmin.x); y0 = math.max(y0, cmin.y) x1 = math.min(x1, cmax.x); y1 = math.min(y1, cmax.y) end local p, pad = g.IO.MousePos, g.Style.TouchExtraPadding if not (p.x >= x0 - pad.x and p.y >= y0 - pad.y and p.x < x1 + pad.x and p.y < y1 + pad.y) then return false end local vp = g.MouseViewport local vx0, vy0 = vp.Pos.x, vp.Pos.y local vx1, vy1 = vx0 + vp.Size.x, vy0 + vp.Size.y if not (vx0 <= x1 and vx1 >= x0 and vy0 <= y1 and vy1 >= y0) then return false end return true end -- Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. -- [Internal] This doesn't test if the button is pressed --- @param button ImGuiMouseButton --- @param lock_threshold? float function ImGui.IsMouseDragPastThreshold(button, lock_threshold) if lock_threshold == nil then lock_threshold = -1.0 end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- IM_COUNTOF(g.IO.MouseDown) if lock_threshold < 0.0 then lock_threshold = g.IO.MouseDragThreshold end return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold end --- @param button ImGuiMouseButton --- @param lock_threshold? float function ImGui.IsMouseDragging(button, lock_threshold) if lock_threshold == nil then lock_threshold = -1.0 end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- IM_COUNTOF(g.IO.MouseDown) if not g.IO.MouseDown[button] then return false end return ImGui.IsMouseDragPastThreshold(button, lock_threshold) end --- @param pos ImVec2 function ImGui.TeleportMousePos(pos) local g = GImGui ImVec2_Copy(g.IO.MousePos, pos) ImVec2_Copy(g.IO.MousePosPrev, pos) ImVec2_CopyV(g.IO.MouseDelta, 0.0, 0.0) g.IO.WantSetMousePos = true -- IMGUI_DEBUG_LOG_IO("TeleportMousePos: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) end --- @param id ImGuiID function ImGui.ItemHandleShortcut(id) local g = GImGui local flags = g.NextItemData.ShortcutFlags IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedBySetNextItemShortcut)) == 0) if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.Disabled) ~= 0 then return end if bit32.band(flags, ImGuiInputFlags.Tooltip) ~= 0 then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasShortcut) g.LastItemData.Shortcut = g.NextItemData.Shortcut end if not ImGui.Shortcut(g.NextItemData.Shortcut, bit32.band(flags, ImGuiInputFlags.SupportedByShortcut), id) or g.NavActivateId ~= 0 then return end g.NavActivateId = id g.NavActivateFlags = bit32.bor(ImGuiActivateFlags.PreferInput, ImGuiActivateFlags.FromShortcut) g.NavActivateDownId = id g.NavActivatePressedId = id ImGui.NavHighlightActivated(id) end --- @param bb ImRect --- @param id ImGuiID --- @param nav_bb_arg? ImRect --- @param extra_flags? ImGuiItemFlags @native function ImGui.ItemAdd(bb, id, nav_bb_arg, extra_flags) if extra_flags == nil then extra_flags = 0 end local g = GImGui local window = g.CurrentWindow g.LastItemData.ID = id ImRect_Copy(g.LastItemData.Rect, bb) ImRect_Copy(g.LastItemData.NavRect, nav_bb_arg and nav_bb_arg or bb) g.LastItemData.ItemFlags = bit32.bor(g.CurrentItemFlags, g.NextItemData.ItemFlagsSet, extra_flags) g.LastItemData.StatusFlags = ImGuiItemStatusFlags.None if id ~= 0 then ImGui.KeepAliveID(id) if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.NoNav) == 0 then window.DC.NavLayersActiveMaskNext = bit32.bor(window.DC.NavLayersActiveMaskNext, bit32.lshift(1, window.DC.NavLayerCurrent)) if g.NavId == id or g.NavAnyRequest then if g.NavWindow.RootWindowForNav == window.RootWindowForNav then if window == g.NavWindow or bit32.band(bit32.bor(window.ChildFlags, g.NavWindow.ChildFlags), ImGuiChildFlags.NavFlattened) ~= 0 then ImGui.NavProcessItem() end end end end if bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasShortcut) ~= 0 then ImGui.ItemHandleShortcut(id) end end g.NextItemData.HasFlags = ImGuiNextItemDataFlags.None g.NextItemData.ItemFlagsSet = ImGuiItemFlags.None local bmin, bmax, cr = bb.Min, bb.Max, window.ClipRect local is_rect_visible = bmin.x <= cr.Max.x and bmax.x >= cr.Min.x and bmin.y <= cr.Max.y and bmax.y >= cr.Min.y if not is_rect_visible then if id == 0 or not (id == g.ActiveId or id == g.ActiveIdPreviousFrame or id == g.NavId or id == g.NavActivateId or g.ItemUnclipByLog) then return false end end if id ~= 0 and g.DeactivatedItemData.ID == id then g.DeactivatedItemData.ElapseFrame = g.FrameCount end if is_rect_visible then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) end if ImGui.IsMouseHoveringRect(bb.Min, bb.Max) then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredRect) end return true end --- @param size_or_bb ImVec2|ImRect --- @param text_baseline_y? float @native function ImGui.ItemSize(size_or_bb, text_baseline_y) if text_baseline_y == nil then text_baseline_y = -1.0 end local size_x, size_y local bb_min = size_or_bb.Min if bb_min then --- @cast size_or_bb ImRect size_x = size_or_bb.Max.x - bb_min.x; size_y = size_or_bb.Max.y - bb_min.y else --- @cast size_or_bb ImVec2 size_x = size_or_bb.x; size_y = size_or_bb.y end local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end local dc = window.DC local mathMax = math.max local offset_to_match_baseline_y if text_baseline_y >= 0 then offset_to_match_baseline_y = mathMax(0, dc.CurrLineTextBaseOffset - text_baseline_y) else offset_to_match_baseline_y = 0 end local cursor, prev_line, max_pos = dc.CursorPos, dc.CursorPosPrevLine, dc.CursorMaxPos local line_y1 if dc.IsSameLine then line_y1 = prev_line.y else line_y1 = cursor.y end local line_height = mathMax(dc.CurrLineSize.y, cursor.y - line_y1 + size_y + offset_to_match_baseline_y) local spacing_y = g.Style.ItemSpacing.y prev_line.x = cursor.x + size_x prev_line.y = line_y1 cursor.x = math.floor(window.Pos.x + dc.Indent.x + dc.ColumnsOffset.x) cursor.y = math.floor(line_y1 + line_height + spacing_y) max_pos.x = mathMax(max_pos.x, prev_line.x) max_pos.y = mathMax(max_pos.y, cursor.y - spacing_y) dc.PrevLineSize.y = line_height dc.CurrLineSize.y = 0 dc.PrevLineTextBaseOffset = mathMax(dc.CurrLineTextBaseOffset, text_baseline_y) dc.CurrLineTextBaseOffset = 0 dc.IsSetPos = false dc.IsSameLine = false --- Horizontal layout mode if (dc.LayoutType == ImGuiLayoutType.Horizontal) then ImGui.SameLine() end end --- @param offset_from_start_x float? --- @param spacing_w float? @native function ImGui.SameLine(offset_from_start_x, spacing_w) if offset_from_start_x == nil then offset_from_start_x = 0.0 end if spacing_w == nil then spacing_w = -1.0 end local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end if offset_from_start_x ~= 0.0 then if spacing_w < 0.0 then spacing_w = 0.0 end window.DC.CursorPos.x = window.Pos.x - window.Scroll.x + offset_from_start_x + spacing_w + window.DC.GroupOffset.x + window.DC.ColumnsOffset.x window.DC.CursorPos.y = window.DC.CursorPosPrevLine.y else if spacing_w < 0.0 then spacing_w = g.Style.ItemSpacing.x end window.DC.CursorPos.x = window.DC.CursorPosPrevLine.x + spacing_w window.DC.CursorPos.y = window.DC.CursorPosPrevLine.y end ImVec2_Copy(window.DC.CurrLineSize, window.DC.PrevLineSize) window.DC.CurrLineTextBaseOffset = window.DC.PrevLineTextBaseOffset window.DC.IsSameLine = true end --- @param indent_w? float function ImGui.Indent(indent_w) if indent_w == nil then indent_w = 0.0 end local g = GImGui local window = ImGui.GetCurrentWindow() if indent_w ~= 0.0 then window.DC.Indent.x = window.DC.Indent.x + indent_w else window.DC.Indent.x = window.DC.Indent.x + g.Style.IndentSpacing end window.DC.CursorPos.x = window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x end --- @param indent_w? float function ImGui.Unindent(indent_w) if indent_w == nil then indent_w = 0.0 end local g = GImGui local window = ImGui.GetCurrentWindow() if indent_w ~= 0.0 then window.DC.Indent.x = window.DC.Indent.x - indent_w else window.DC.Indent.x = window.DC.Indent.x - g.Style.IndentSpacing end window.DC.CursorPos.x = window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x end -- Affect large frame+labels widgets only --- @param item_width float function ImGui.SetNextItemWidth(item_width) local g = GImGui g.NextItemData.HasFlags = bit32.bor(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasWidth) g.NextItemData.Width = item_width end --- @param item_width float function ImGui.PushItemWidth(item_width) local g = GImGui local window = g.CurrentWindow window.DC.ItemWidthStack:push_back(window.DC.ItemWidth) window.DC.ItemWidth = (item_width == 0.0) and window.DC.ItemWidthDefault or item_width g.NextItemData.HasFlags = bit32.band(g.NextItemData.HasFlags, bit32.bnot(ImGuiNextItemDataFlags.HasWidth)) end function ImGui.PopItemWidth() local g = GImGui local window = g.CurrentWindow if window.DC.ItemWidthStack.Size <= 0 then IM_ASSERT_USER_ERROR(false, "Calling PopItemWidth() too many times!") return end window.DC.ItemWidth = window.DC.ItemWidthStack:back() window.DC.ItemWidthStack:pop_back() end --- @param components int --- @param w_full float function ImGui.PushMultiItemsWidths(components, w_full) local g = GImGui local window = g.CurrentWindow IM_ASSERT(components > 0) local style = g.Style window.DC.ItemWidthStack:push_back(window.DC.ItemWidth) local w_items = w_full - style.ItemInnerSpacing.x * (components - 1) local prev_split = w_items for i = components - 1, 1, -1 do local next_split = IM_TRUNC(w_items * i / components) window.DC.ItemWidthStack:push_back(ImMax(prev_split - next_split, 1.0)) prev_split = next_split end window.DC.ItemWidth = ImMax(prev_split, 1.0) g.NextItemData.HasFlags = bit32.band(g.NextItemData.HasFlags, bit32.bnot(ImGuiNextItemDataFlags.HasWidth)) end --- @return float function ImGui.GetFrameHeight() local g = GImGui return g.FontSize + g.Style.FramePadding.y * 2.0 end --- @return ImVec2 --- @nodiscard @native function ImGui.GetContentRegionAvail() local g = GImGui local window = g.CurrentWindow local mx if window.DC.CurrentColumns or g.CurrentTable then mx = window.WorkRect.Max else mx = window.ContentRegionRect.Max end return ImVec2(mx.x - window.DC.CursorPos.x, mx.y - window.DC.CursorPos.y) end --- @return ImVec2 --- @nodiscard function ImGui.GetCursorScreenPos() local window = ImGui.GetCurrentWindowRead() local ret = ImVec2() ImVec2_Copy(ret, window.DC.CursorPos) return ret end --- @param pos ImVec2 function ImGui.SetCursorScreenPos(pos) local window = ImGui.GetCurrentWindow() ImVec2_Copy(window.DC.CursorPos, pos) window.DC.IsSetPos = true end -- [window-local] cursor position, in window coordinates (relative to window position, including scrolling) --- @return ImVec2 function ImGui.GetCursorPos() local window = ImGui.GetCurrentWindowRead() return ImVec2(window.DC.CursorPos.x - window.Pos.x + window.Scroll.x, window.DC.CursorPos.y - window.Pos.y + window.Scroll.y) end function ImGui.GetCursorPosX() local window = ImGui.GetCurrentWindowRead() return window.DC.CursorPos.x - window.Pos.x + window.Scroll.x end function ImGui.GetCursorPosY() local window = ImGui.GetCurrentWindowRead() return window.DC.CursorPos.y - window.Pos.y + window.Scroll.y end --- @param local_pos ImVec2 function ImGui.SetCursorPos(local_pos) local window = ImGui.GetCurrentWindow() ImVec2_CopyV(window.DC.CursorPos, window.Pos.x - window.Scroll.x + local_pos.x, window.Pos.y - window.Scroll.y + local_pos.y) window.DC.IsSetPos = true end --- @param x float function ImGui.SetCursorPosX(x) local window = ImGui.GetCurrentWindow() window.DC.CursorPos.x = window.Pos.x - window.Scroll.x + x window.DC.IsSetPos = true end --- @param y float function ImGui.SetCursorPosY(y) local window = ImGui.GetCurrentWindow() window.DC.CursorPos.y = window.Pos.y - window.Scroll.y + y window.DC.IsSetPos = true end --- @return ImVec2 function ImGui.GetCursorStartPos() local window = ImGui.GetCurrentWindowRead() return window.DC.CursorStartPos - window.Pos end function ImGui.GetFrameHeightWithSpacing() local g = GImGui return g.FontSize + g.Style.FramePadding.y * 2.0 + g.Style.ItemSpacing.y end function ImGui.GetTextLineHeightWithSpacing() local g = GImGui return g.FontSize + g.Style.ItemSpacing.y end --- @return ImVec2 function ImGui.GetContentRegionMax() local window = GImGui.CurrentWindow return ImGui.GetContentRegionAvail() + window.DC.CursorPos - window.Pos end --- @return ImVec2 function ImGui.GetWindowContentRegionMin() local window = GImGui.CurrentWindow return window.ContentRegionRect.Min - window.Pos end --- @return ImVec2 function ImGui.GetWindowContentRegionMax() local window = GImGui.CurrentWindow return window.ContentRegionRect.Max - window.Pos end -- Overloads: IsRectVisible(size) / IsRectVisible(rect_min, rect_max) function ImGui.IsRectVisible(a, b) local window = GImGui.CurrentWindow if b == nil then return window.ClipRect:Overlaps(ImRect(window.DC.CursorPos, window.DC.CursorPos + a)) end return window.ClipRect:Overlaps(ImRect(a, b)) end -- Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) -- Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. -- FIXME-OPT: Could we safely early out on ->SkipItems? @native function ImGui.BeginGroup() local g = GImGui local window = g.CurrentWindow local group_data = ImGuiGroupData() group_data.WindowID = window.ID ImVec2_Copy(group_data.BackupCursorPos, window.DC.CursorPos) ImVec2_Copy(group_data.BackupCursorPosPrevLine, window.DC.CursorPosPrevLine) ImVec2_Copy(group_data.BackupCursorMaxPos, window.DC.CursorMaxPos) ImVec1_Copy(group_data.BackupIndent, window.DC.Indent) ImVec1_Copy(group_data.BackupGroupOffset, window.DC.GroupOffset) ImVec2_Copy(group_data.BackupCurrLineSize, window.DC.CurrLineSize) group_data.BackupCurrLineTextBaseOffset = window.DC.CurrLineTextBaseOffset group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive group_data.BackupHoveredIdIsAlive = (g.HoveredId ~= 0) group_data.BackupIsSameLine = window.DC.IsSameLine group_data.BackupAnyIdHasBeenEditedThisFrame = g.AnyIdHasBeenEditedThisFrame group_data.BackupDeactivatedIdIsAlive = g.DeactivatedItemData.IsAlive group_data.EmitItem = true g.GroupStack:push_back(group_data) window.DC.GroupOffset.x = window.DC.CursorPos.x - window.Pos.x - window.DC.ColumnsOffset.x ImVec1_Copy(window.DC.Indent, window.DC.GroupOffset) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorPos) ImVec2_CopyV(window.DC.CurrLineSize, 0.0, 0.0) if (g.LogEnabled) then g.LogLinePosY = -FLT_MAX end end @native function ImGui.EndGroup() local g = GImGui local window = g.CurrentWindow IM_ASSERT(g.GroupStack.Size > 0) -- Mismatched BeginGroup()/EndGroup() calls local group_data = g.GroupStack:back() IM_ASSERT(group_data.WindowID == window.ID) -- EndGroup() in wrong window? if (window.DC.IsSetPos) then -- TODO: ImGui.ErrorCheckUsingSetCursorPosToExtendParentBoundaries() end local group_bb = ImRect(group_data.BackupCursorPos, ImMax(ImMax(window.DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos)) ImVec2_Copy(window.DC.CursorPos, group_data.BackupCursorPos) ImVec2_Copy(window.DC.CursorPosPrevLine, group_data.BackupCursorPosPrevLine) ImVec2_Copy(window.DC.CursorMaxPos, ImMax(group_data.BackupCursorMaxPos, group_bb.Max)) ImVec1_Copy(window.DC.Indent, group_data.BackupIndent) ImVec1_Copy(window.DC.GroupOffset, group_data.BackupGroupOffset) ImVec2_Copy(window.DC.CurrLineSize, group_data.BackupCurrLineSize) window.DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset window.DC.IsSameLine = group_data.BackupIsSameLine if (g.LogEnabled) then g.LogLinePosY = -FLT_MAX -- To enforce a carriage return end if (not group_data.EmitItem) then g.GroupStack:pop_back() return end window.DC.CurrLineTextBaseOffset = ImMax(window.DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset) -- FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now ImGui.ItemSize(group_bb:GetSize()) ImGui.ItemAdd(group_bb, 0, nil, ImGuiItemFlags.NoTabStop) -- If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. -- It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. -- Also if you grep for LastItemId you'll notice it is only used in that context. -- (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) local group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive ~= g.ActiveId) and (g.ActiveIdIsAlive == g.ActiveId) and g.ActiveId local group_contains_deactivated_id = (group_data.BackupDeactivatedIdIsAlive == false) and (g.DeactivatedItemData.IsAlive == true) if group_contains_curr_active_id then g.LastItemData.ID = g.ActiveId elseif group_contains_deactivated_id then g.LastItemData.ID = g.DeactivatedItemData.ID end ImRect_Copy(g.LastItemData.Rect, group_bb) -- Forward Hovered flag local group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) and g.HoveredId ~= 0 if group_contains_curr_hovered_id then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow) end -- Forward Edited flag if g.AnyIdHasBeenEditedThisFrame and not group_data.BackupAnyIdHasBeenEditedThisFrame then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Edited) end -- Forward Deactivated flag g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasDeactivated) if group_contains_deactivated_id then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Deactivated) end g.GroupStack:pop_back() if g.DebugShowGroupRects then window.DrawList:AddRect(group_bb.Min, group_bb.Max, IM_COL32(255, 0, 255, 255)) -- [Debug] end end @native function ImGui.CalcItemWidth() local g = GImGui local window = g.CurrentWindow local w if bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasWidth) ~= 0 then w = g.NextItemData.Width else w = window.DC.ItemWidth end if w < 0.0 then local region_avail_x = ImGui.GetContentRegionAvail().x w = ImMax(1.0, region_avail_x + w) end w = IM_TRUNC(w) return w end --- @param size ImVec2 --- @param default_w float --- @param default_h float --- @return ImVec2 function ImGui.CalcItemSize(size, default_w, default_h) local avail if size.x < 0.0 or size.y < 0.0 then avail = ImGui.GetContentRegionAvail() end if size.x == 0.0 then size.x = default_w elseif size.x < 0.0 then size.x = ImMax(4.0, avail.x + size.x) -- size.x is negative here so we are subtracting end if size.y == 0.0 then size.y = default_h elseif size.y < 0.0 then size.y = ImMax(4.0, avail.y + size.y) -- size.y is negative here so we are subtracting end return size end function ImGui.GetTextLineHeight() local g = GImGui return g.FontSize end function ImGui.IsItemActive() local g = GImGui if g.ActiveId ~= 0 then return g.ActiveId == g.LastItemData.ID end return false end function ImGui.IsItemFocused() local g = GImGui if g.NavId ~= g.LastItemData.ID or g.NavId == 0 then return false end local window = g.CurrentWindow if g.LastItemData.ID == window.ID and window.WriteAccessed then return false end return true end function ImGui.IsItemDeactivated() local g = GImGui if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasDeactivated) ~= 0 then return bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Deactivated) ~= 0 end return g.DeactivatedItemData.ID == g.LastItemData.ID and g.LastItemData.ID ~= 0 and g.DeactivatedItemData.ElapseFrame >= g.FrameCount end function ImGui.IsItemDeactivatedAfterEdit() local g = GImGui return ImGui.IsItemDeactivated() and g.DeactivatedItemData.HasBeenEditedBefore end function ImGui.IsItemActivated() local g = GImGui if g.ActiveId ~= 0 then if g.ActiveId == g.LastItemData.ID and g.ActiveIdPreviousFrame ~= g.LastItemData.ID then return true end end return false end -- Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()! --- @param mouse_button? ImGuiMouseButton function ImGui.IsItemClicked(mouse_button) if mouse_button == nil then mouse_button = 0 end return ImGui.IsMouseClicked(mouse_button) and ImGui.IsItemHovered(ImGuiHoveredFlags.None) end function ImGui.IsItemToggledOpen() return bit32.band(GImGui.LastItemData.StatusFlags, ImGuiItemStatusFlags.ToggledOpen) ~= 0 end function ImGui.IsItemToggledSelection() local g = GImGui IM_ASSERT(g.CurrentMultiSelect ~= nil) -- Can only be used inside a BeginMultiSelect()/EndMultiSelect() return bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.ToggledSelection) ~= 0 end function ImGui.IsAnyItemHovered() local g = GImGui return g.HoveredId ~= 0 or g.HoveredIdPreviousFrame ~= 0 end function ImGui.IsAnyItemActive() return GImGui.ActiveId ~= 0 end function ImGui.IsAnyItemFocused() local g = GImGui return g.NavId ~= 0 and g.NavCursorVisible end function ImGui.IsItemVisible() return bit32.band(GImGui.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0 end function ImGui.IsItemEdited() return bit32.band(GImGui.LastItemData.StatusFlags, ImGuiItemStatusFlags.Edited) ~= 0 end -- Allow next item to be overlapped by subsequent items. function ImGui.SetNextItemAllowOverlap() local g = GImGui g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.AllowOverlap) end function ImGui.GetItemID() return GImGui.LastItemData.ID end function ImGui.GetItemFlags() return GImGui.LastItemData.ItemFlags end --- @return ImVec2 function ImGui.GetItemRectSize() return GImGui.LastItemData.Rect:GetSize() end function ImGui.GetHoveredID() local g = GImGui return (g.HoveredId ~= 0) and g.HoveredId or g.HoveredIdPreviousFrame end --------------------------------------------------------------------------------------- -- [SECTION] WINDOW FOCUS --------------------------------------------------------------------------------------- --- @param window? ImGuiWindow --- @param flags? ImGuiFocusRequestFlags function ImGui.FocusWindow(window, flags) if flags == nil then flags = 0 end local g = GImGui if bit32.band(flags, ImGuiFocusRequestFlags.UnlessBelowModal) ~= 0 and g.NavWindow ~= window then local blocking_modal = ImGui.FindBlockingModal(window) if blocking_modal then -- IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".", window ? window->Name : "", blocking_modal->Name) if window and window == window.RootWindow and bit32.band(window.Flags, ImGuiWindowFlags.NoBringToFrontOnFocus) == 0 then ImGui.BringWindowToDisplayBehind(window, blocking_modal) end ImGui.ClosePopupsOverWindow(ImGui.GetTopMostPopupModal(), false) return end end if bit32.band(flags, ImGuiFocusRequestFlags.RestoreFocusedChild) ~= 0 and window ~= nil then window = ImGui.NavRestoreLastChildNavWindow(window) end if g.NavWindow ~= window then ImGui.SetNavWindow(window) if window and g.NavHighlightItemUnderNav then g.NavMousePosDirty = true end g.NavId = window and window.NavLastIds[0] or 0 g.NavLayer = ImGuiNavLayer.Main ImGui.SetNavFocusScope(window and window.NavRootFocusScopeId or 0) g.NavIdIsAlive = false g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid -- Close popups if any ImGui.ClosePopupsOverWindow(window, false) end IM_ASSERT(window == nil or window.RootWindowDockTree ~= nil) local focus_front_window = window and window.RootWindow or nil local display_front_window = window and window.RootWindowDockTree or nil local dock_node = window and window.DockNode or nil local active_id_window_is_dock_node_host = g.ActiveIdWindow and dock_node and dock_node.HostWindow == g.ActiveIdWindow if g.ActiveId ~= 0 and g.ActiveIdWindow and g.ActiveIdWindow.RootWindow ~= focus_front_window then if not g.ActiveIdNoClearOnFocusLoss and not active_id_window_is_dock_node_host then ImGui.ClearActiveID() end end if not window then return end window.LastFrameJustFocused = g.FrameCount ImGui.BringWindowToFocusFront(focus_front_window) if bit32.band(bit32.bor(window.Flags, focus_front_window.Flags, display_front_window.Flags), ImGuiWindowFlags.NoBringToFrontOnFocus) == 0 then ImGui.BringWindowToDisplayFront(display_front_window) end end --- @param window ImGuiWindow --- @return int function ImGui.FindWindowFocusIndex(window) local g = GImGui -- IM_UNUSED(g) local order = window.FocusOrder IM_ASSERT(window.RootWindow == window) -- No child window (not testing _ChildWindow because of docking) IM_ASSERT(g.WindowsFocusOrder.Data[order] == window) return order end --- @param window ImGuiWindow --- @return bool function ImGui.IsWindowNavFocusable(window) return window.WasActive and window == window.RootWindow and bit32.band(window.Flags, ImGuiWindowFlags.NoNavFocus) == 0 end --- @param i_start int --- @param i_stop int --- @param dir int --- @return ImGuiWindow? function ImGui.FindWindowNavFocusable(i_start, i_stop, dir) local g = GImGui local i = i_start while i >= 1 and i <= g.WindowsFocusOrder.Size and i ~= i_stop do local window = g.WindowsFocusOrder.Data[i] if ImGui.IsWindowNavFocusable(window) then return window end i = i + dir end return nil end function ImGui.UpdateWindowInFocusOrderList(window, just_created, new_flags) local g = GImGui local new_is_explicit_child = (bit32.band(new_flags, ImGuiWindowFlags.ChildWindow) ~= 0) and ((bit32.band(new_flags, ImGuiWindowFlags.Popup) == 0) or (bit32.band(new_flags, ImGuiWindowFlags.ChildMenu) ~= 0)) local child_flag_changed = (new_is_explicit_child ~= window.IsExplicitChild) if (just_created or child_flag_changed) and not new_is_explicit_child then IM_ASSERT(not g.WindowsFocusOrder:contains(window)) g.WindowsFocusOrder:push_back(window) window.FocusOrder = g.WindowsFocusOrder.Size elseif not just_created and child_flag_changed and new_is_explicit_child then IM_ASSERT(g.WindowsFocusOrder.Data[window.FocusOrder] == window) for n = window.FocusOrder + 1, g.WindowsFocusOrder.Size do g.WindowsFocusOrder.Data[n].FocusOrder = g.WindowsFocusOrder.Data[n].FocusOrder - 1 end g.WindowsFocusOrder:erase(window.FocusOrder) window.FocusOrder = -1 end window.IsExplicitChild = new_is_explicit_child end --- @param window? ImGuiWindow function ImGui.BringWindowToFocusFront(window) local g = GImGui IM_ASSERT(window == window.RootWindow) local cur_order = window.FocusOrder IM_ASSERT(g.WindowsFocusOrder.Data[cur_order] == window) if g.WindowsFocusOrder:back() == window then return end local new_order = g.WindowsFocusOrder.Size for n = cur_order, new_order - 1 do g.WindowsFocusOrder.Data[n] = g.WindowsFocusOrder.Data[n + 1] g.WindowsFocusOrder.Data[n].FocusOrder = g.WindowsFocusOrder.Data[n].FocusOrder - 1 IM_ASSERT(g.WindowsFocusOrder.Data[n].FocusOrder == n) end g.WindowsFocusOrder.Data[new_order] = window window.FocusOrder = new_order end --- @param window? ImGuiWindow function ImGui.BringWindowToDisplayFront(window) local g = GImGui local current_front_window = g.Windows:back() if current_front_window == window or current_front_window.RootWindowDockTree == window then return end for i, this_window in g.Windows:iter() do if this_window == window then g.Windows:erase(i) break end end g.Windows:push_back(window) end --- @param window ImGuiWindow --- @param behind_window ImGuiWindow function ImGui.BringWindowToDisplayBehind(window, behind_window) IM_ASSERT(window ~= nil and behind_window ~= nil) local g = GImGui window = window.RootWindow behind_window = behind_window.RootWindow -- TODO: end --- @param under_this_window? ImGuiWindow --- @param ignore_window? ImGuiWindow --- @param filter_viewport? ImGuiViewport --- @param flags ImGuiFocusRequestFlags function ImGui.FocusTopMostWindowUnderOne(under_this_window, ignore_window, filter_viewport, flags) local g = GImGui local start_idx = g.WindowsFocusOrder.Size if under_this_window ~= nil then -- Aim at root window behind us, if we are in a child window that's our own root (see #4640) local offset = -1 while bit32.band(under_this_window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 do under_this_window = under_this_window.ParentWindow offset = 0 end --- @cast under_this_window ImGuiWindow start_idx = ImGui.FindWindowFocusIndex(under_this_window) + offset end for i = start_idx, 1, -1 do repeat local window = g.WindowsFocusOrder.Data[i] if window == ignore_window or not window.WasActive then break end if filter_viewport ~= nil and window.Viewport ~= filter_viewport then break end if bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoNavInputs)) ~= bit32.bor(ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoNavInputs) then ImGui.FocusWindow(window, flags) return end until true end ImGui.FocusWindow(nil, flags) end --- @param id ImGuiID --- @param window ImGuiWindow function ImGui.SetFocusID(id, window) local g = GImGui IM_ASSERT(id ~= 0) if g.NavWindow ~= window then ImGui.SetNavWindow(window) end local nav_layer = window.DC.NavLayerCurrent g.NavId = id g.NavLayer = nav_layer ImGui.SetNavFocusScope(g.CurrentFocusScopeId) window.NavLastIds[nav_layer] = id if g.LastItemData.ID == id then ImRect_Copy(window.NavRectRel[nav_layer], ImGui.WindowRectAbsToRel(window, g.LastItemData.NavRect)) end g.NavIdItemFlags = (g.LastItemData.ID == id) and g.LastItemData.ItemFlags or ImGuiItemFlags.None if id == g.ActiveIdIsAlive then g.NavIdIsAlive = true end if g.ActiveIdSource == ImGuiInputSource.Keyboard or g.ActiveIdSource == ImGuiInputSource.Gamepad then g.NavHighlightItemUnderNav = true elseif g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = false end ImGui.NavClearPreferredPosForAxis(ImGuiAxis.X) ImGui.NavClearPreferredPosForAxis(ImGuiAxis.Y) end function ImGui.StopMouseMovingWindow() local g = GImGui local window = g.MovingWindow if window and window.Viewport then if bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) ~= 0 then ImGui.UpdateTryMergeWindowIntoHostViewport(window.RootWindowDockTree, g.MouseViewport) end if (not ImGui.IsDragDropPayloadBeingAccepted()) then g.MouseViewport = window.Viewport end local window_can_use_inputs = bit32.band(window.Flags, ImGuiWindowFlags.NoMouseInputs) == 0 or bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) == 0 if window_can_use_inputs then window.Viewport.Flags = bit32.band(window.Viewport.Flags, bit32.bnot(ImGuiViewportFlags.NoInputs)) end end g.MovingWindow = nil end --- @param id ImGuiID --- @param window? ImGuiWindow function ImGui.SetActiveID(id, window) local g = GImGui if g.ActiveId ~= 0 then local deactivated_data = g.DeactivatedItemData deactivated_data.ID = g.ActiveId deactivated_data.ElapseFrame = (g.LastItemData.ID == g.ActiveId) and g.FrameCount or g.FrameCount + 1 -- FIXME: OK to use LastItemData? deactivated_data.HasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore deactivated_data.IsAlive = (g.ActiveIdIsAlive == g.ActiveId) if g.InputTextState.ID == g.ActiveId then ImGui.InputTextDeactivateHook(g.ActiveId) end if g.MovingWindow and (g.ActiveId == g.MovingWindow.MoveId) then print("SetActiveID() cancel MovingWindow") ImGui.StopMouseMovingWindow() end end g.ActiveIdIsJustActivated = (g.ActiveId ~= id) if (g.ActiveIdIsJustActivated) then -- IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() 0x%08X in \"%s\"%*s(previously 0x%08X in \"%s\")\n", id, window ? window->Name : "", -- ImMax(0, 20 - (int)(window ? strlen(window->Name) : 0)), "", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : ""); g.ActiveIdTimer = 0.0 g.ActiveIdHasBeenPressedBefore = false g.ActiveIdHasBeenEditedBefore = false g.ActiveIdMouseButton = -1 if id ~= 0 then g.LastActiveId = id g.LastActiveIdTimer = 0.0 end end g.ActiveId = id g.ActiveIdAllowOverlap = false g.ActiveIdNoClearOnFocusLoss = false g.ActiveIdWindow = window g.ActiveIdHasBeenEditedThisFrame = false g.ActiveIdFromShortcut = false g.ActiveIdDisabledId = 0 if id ~= 0 then g.ActiveIdIsAlive = id if g.NavActivateId == id or g.NavJustMovedToId == id then g.ActiveIdSource = g.NavInputSource else g.ActiveIdSource = ImGuiInputSource.Mouse end IM_ASSERT(g.ActiveIdSource ~= ImGuiInputSource.None) end g.ActiveIdUsingNavDirMask = 0x00 g.ActiveIdUsingAllKeyboardKeys = false end function ImGui.ClearActiveID() ImGui.SetActiveID(0, nil) end --- @param str_id string|int @native function ImGui.PushID(str_id) local g = GImGui local window = g.CurrentWindow local id = window:GetID(str_id) window.IDStack:push_back(id) end --- @param id ImGuiID function ImGui.PushOverrideID(id) local g = GImGui local window = g.CurrentWindow if g.DebugHookIdInfoId == id and id ~= 0 then ImGui.DebugHookIdInfo(id, ImGuiDataType.ID, nil) end window.IDStack:push_back(id) end @native function ImGui.PopID() local window = GImGui.CurrentWindow IM_ASSERT_USER_ERROR_RET(window.IDStack.Size > 1, "Calling PopID() too many times!") window.IDStack:pop_back() end --- @param id string|int --- @return ImGuiID @native function MT.ImGuiWindow:GetID(id) local seed = self.IDStack:back() local h if type(id) == "string" then h = ImHashStr(id, nil, seed) else --- @cast id int h = ImHashData(id, -1, seed) end local g = GImGui if g.DebugHookIdInfoId == h and h ~= 0 then ImGui.DebugHookIdInfo(h, (type(id) == "string") and ImGuiDataType.String or ImGuiDataType.S32, id) end return h end -- This is only used in rare/specific situations to manufacture an ID out of nowhere -- FIXME: Consider instead storing last non-zero ID + count of successive zero-ID, and combine those? --- @param p_abs ImVec2 --- @return ImGuiID function MT.ImGuiWindow:GetIDFromPos(p_abs) local seed = self.IDStack:back() local p_rel = ImGui.WindowPosAbsToRel(self, p_abs) return ImHashData(p_rel, 2, seed) end -- " --- @param r_abs ImRect --- @return ImGuiID function MT.ImGuiWindow:GetIDFromRectangle(r_abs) local seed = self.IDStack:back() local r_rel = ImGui.WindowRectAbsToRel(self, r_abs) return ImHashData({ math.floor(r_rel.Min.x), math.floor(r_rel.Min.y), math.floor(r_rel.Max.x), math.floor(r_rel.Max.y) }, 4, seed) end -- Overloads: GetID(str_id) / GetID(str_id_begin, str_id_end) / GetID(int_id) --- @param str_or_int string|int --- @param str_end? int # exclusive end (1-based byte position) --- @return ImGuiID function ImGui.GetID(str_or_int, str_end) local window = GImGui.CurrentWindow if str_end ~= nil and type(str_or_int) == "string" then return ImHashStr(str_or_int, str_end - 1, window.IDStack:back()) end return window:GetID(str_or_int) end -- Overloads: GetIDWithSeed(str, str_end, seed) / GetIDWithSeed(n, seed) function ImGui.GetIDWithSeed(a, b, c) local id if type(a) == "number" then id = ImHashData(a, -1, b) else id = ImHashStr(a, b and (b - 1) or nil, c) end if GImGui.DebugHookIdInfoId == id and id ~= 0 then ImGui.DebugHookIdInfo(id, (type(a) == "number") and ImGuiDataType.S32 or ImGuiDataType.String, (b and type(a) == "string") and string.sub(a, 1, b - 1) or a) end return id end --- @param id ImGuiID @native function ImGui.SetHoveredID(id) local g = GImGui g.HoveredId = id g.HoveredIdAllowOverlap = false if id ~= 0 and g.HoveredIdPreviousFrame ~= id then g.HoveredIdTimer = 0.0 g.HoveredIdNotActiveTimer = 0.0 end end --- @param flags ImGuiHoveredFlags --- @return float local function CalcDelayFromHoveredFlags(flags) local g = GImGui if bit32.band(flags, ImGuiHoveredFlags.DelayNormal) ~= 0 then return g.Style.HoverDelayNormal end if bit32.band(flags, ImGuiHoveredFlags.DelayShort) ~= 0 then return g.Style.HoverDelayShort end return 0.0 end --- @param user_flags ImGuiHoveredFlags --- @param shared_flags ImGuiHoveredFlags local function ApplyHoverFlagsForTooltip(user_flags, shared_flags) if bit32.band(user_flags, bit32.bor(ImGuiHoveredFlags.DelayNone, ImGuiHoveredFlags.DelayShort, ImGuiHoveredFlags.DelayNormal)) ~= 0 then shared_flags = bit32.band(shared_flags, bit32.bnot(bit32.bor(ImGuiHoveredFlags.DelayNone, ImGuiHoveredFlags.DelayShort, ImGuiHoveredFlags.DelayNormal))) end return bit32.bor(user_flags, shared_flags) end --- @param id ImGuiID function ImGui.MarkItemEdited(id) -- This marking is to be able to provide info for IsItemDeactivatedAfterEdit(). -- ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. local g = GImGui g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.EditedInternal) if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.NoMarkEdited) ~= 0 then return end g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Edited) if g.ActiveId == id or g.ActiveId == 0 then -- FIXME: Can't we fully rely on LastItemData yet? g.AnyIdHasBeenEditedThisFrame = true g.ActiveIdHasBeenEditedThisFrame = true g.ActiveIdHasBeenEditedBefore = true end if g.DeactivatedItemData.ID == id then g.DeactivatedItemData.HasBeenEditedBefore = true end -- We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343) -- We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714) -- FIXME: This assert is getting a bit meaningless over time. It helped detect some unusual use cases but eventually it is becoming an unnecessary restriction. IM_ASSERT(g.DragDropActive or g.ActiveId == id or g.ActiveId == 0 or g.DeactivatedItemData.ID == id or g.ActiveIdPreviousFrame == id or g.NavJustMovedToId or (g.CurrentMultiSelect ~= nil and g.BoxSelectState.IsActive)) -- IM_ASSERT(g.CurrentWindow.DC.LastItemId == id) g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Edited) end --- @param window ImGuiWindow --- @param flags ImGuiHoveredFlags function ImGui.IsWindowContentHoverable(window, flags) -- An active popup disable hovering on other windows (apart from its own children) -- FIXME-OPT: This could be cached/stored within the window. local g = GImGui if g.NavWindow then local focused_root_window = g.NavWindow.RootWindowDockTree if focused_root_window.WasActive and focused_root_window ~= window.RootWindowDockTree then -- For the purpose of those flags we differentiate "standard popup" from "modal popup" -- NB: The 'else' is important because Modal windows are also Popups. local want_inhibit = false if bit32.band(focused_root_window.Flags, ImGuiWindowFlags.Modal) ~= 0 then want_inhibit = true elseif (bit32.band(focused_root_window.Flags, ImGuiWindowFlags.Popup) ~= 0) and (bit32.band(flags, ImGuiHoveredFlags.AllowWhenBlockedByPopup) == 0) then want_inhibit = true end -- Inhibit hover unless the window is within the stack of our modal/popup if want_inhibit then if not ImGui.IsWindowWithinBeginStackOf(window.RootWindow, focused_root_window) then return false end end end end -- Filter by viewport if (window.Viewport ~= g.MouseViewport) then if (g.MovingWindow == nil or window.RootWindowDockTree ~= g.MovingWindow.RootWindowDockTree) then return false end end return true end --- @param flags? ImGuiHoveredFlags @native function ImGui.IsItemHovered(flags) if flags == nil then flags = 0 end local g = GImGui local window = g.CurrentWindow IM_ASSERT_USER_ERROR(bit32.band(flags, bit32.bnot(ImGuiHoveredFlags.AllowedMaskForIsItemHovered)) == 0, "Invalid flags for IsItemHovered()!") if g.NavHighlightItemUnderNav and g.NavCursorVisible and bit32.band(flags, ImGuiHoveredFlags.NoNavOverride) == 0 then if not ImGui.IsItemFocused() then return false end if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.Disabled) ~= 0 and bit32.band(flags, ImGuiHoveredFlags.AllowWhenDisabled) == 0 then return false end if bit32.band(flags, ImGuiHoveredFlags.ForTooltip) ~= 0 then flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipNav) end else local status_flags = g.LastItemData.StatusFlags if bit32.band(status_flags, ImGuiItemStatusFlags.HoveredRect) == 0 then return false end if bit32.band(flags, ImGuiHoveredFlags.ForTooltip) ~= 0 then flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipMouse) end if g.HoveredWindow ~= window and bit32.band(status_flags, ImGuiItemStatusFlags.HoveredWindow) == 0 then if bit32.band(flags, ImGuiHoveredFlags.AllowWhenOverlappedByWindow) == 0 then return false end end local id = g.LastItemData.ID if bit32.band(flags, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) == 0 then if g.ActiveId ~= 0 and g.ActiveId ~= id and not g.ActiveIdAllowOverlap and not g.ActiveIdFromShortcut then local cancel_is_hovered = true if g.ActiveId == window.MoveId and (id == 0 or g.ActiveIdDisabledId == id) then cancel_is_hovered = false end if g.ActiveId == window.TabId then cancel_is_hovered = false end if cancel_is_hovered then return false end end end if not ImGui.IsWindowContentHoverable(window, flags) and bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.NoWindowHoverableCheck) == 0 then return false end if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.Disabled) ~= 0 and bit32.band(flags, ImGuiHoveredFlags.AllowWhenDisabled) == 0 then return false end if id == window.MoveId and window.WriteAccessed then return false end if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.AllowOverlap) ~= 0 and id ~= 0 then if bit32.band(flags, ImGuiHoveredFlags.AllowWhenOverlappedByItem) == 0 then if g.HoveredIdPreviousFrame ~= g.LastItemData.ID then return false end end end end local delay = CalcDelayFromHoveredFlags(flags) if delay > 0.0 or bit32.band(flags, ImGuiHoveredFlags.Stationary) ~= 0 then local hover_delay_id if g.LastItemData.ID ~= 0 then hover_delay_id = g.LastItemData.ID else hover_delay_id = window:GetIDFromPos(g.LastItemData.Rect.Min) end if bit32.band(flags, ImGuiHoveredFlags.NoSharedDelay) ~= 0 and g.HoverItemDelayIdPreviousFrame ~= hover_delay_id then g.HoverItemDelayTimer = 0.0 end g.HoverItemDelayId = hover_delay_id if bit32.band(flags, ImGuiHoveredFlags.Stationary) ~= 0 and g.HoverItemUnlockedStationaryId ~= hover_delay_id then return false end if g.HoverItemDelayTimer < delay then return false end end return true end --- @param bb ImRect --- @param id ImGuiID --- @param item_flags ImGuiItemFlags @native function ImGui.ItemHoverable(bb, id, item_flags) local g = GImGui local window = g.CurrentWindow if not IMGUI_DISABLE_DEBUG_TOOLS then if id ~= 0 and g.HoveredIdPreviousFrame == id and bit32.band(item_flags, ImGuiItemFlags.AllowDuplicateId) == 0 then g.HoveredIdPreviousFrameItemCount = g.HoveredIdPreviousFrameItemCount + 1 if g.DebugDrawIdConflictsId == id then window.DrawList:AddRect(bb.Min - ImVec2(1, 1), bb.Max + ImVec2(1, 1), IM_COL32(255, 0, 0, 255), 0.0, 2.0, ImDrawFlags.None) end end end if g.HoveredWindow ~= window then return false end if not ImGui.IsMouseHoveringRect(bb.Min, bb.Max) then return false end if g.HoveredId ~= 0 and g.HoveredId ~= id and not g.HoveredIdAllowOverlap then return false end if g.ActiveId ~= 0 and g.ActiveId ~= id and not g.ActiveIdAllowOverlap then if not g.ActiveIdFromShortcut then return false end end if (bit32.band(item_flags, ImGuiItemFlags.NoWindowHoverableCheck) == 0) and not ImGui.IsWindowContentHoverable(window, ImGuiHoveredFlags.None) then g.HoveredIdIsDisabled = true return false end if id ~= 0 then if g.DragDropActive and g.DragDropPayload.SourceId == id and (bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceNoDisableHover) == 0) then return false end ImGui.SetHoveredID(id) if bit32.band(item_flags, ImGuiItemFlags.AllowOverlap) ~= 0 then g.HoveredIdAllowOverlap = true if g.HoveredIdPreviousFrame ~= id then return false end end if id == g.LastItemData.ID and (bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasShortcut) ~= 0) and g.ActiveId ~= id then if ImGui.IsItemHovered(bit32.bor(ImGuiHoveredFlags.ForTooltip, ImGuiHoveredFlags.DelayNormal)) then ImGui.SetTooltip("%s", ImGui.GetKeyChordName(g.LastItemData.Shortcut)) end end end if bit32.band(item_flags, ImGuiItemFlags.Disabled) ~= 0 then -- Release active id if turning disabled if g.ActiveId == id and id ~= 0 then ImGui.ClearActiveID() end g.HoveredIdIsDisabled = true return false end if g.NavHighlightItemUnderNav and (bit32.band(item_flags, ImGuiItemFlags.NoNavDisableMouseHover) == 0) then return false end return true end --- @param bb ImRect --- @param id ImGuiID --- @return bool function ImGui.IsClippedEx(bb, id) local g = GImGui local window = g.CurrentWindow if not bb:Overlaps(window.ClipRect) then if id == 0 or (id ~= g.ActiveId and id ~= g.ActiveIdPreviousFrame and id ~= g.NavId and id ~= g.NavActivateId) then if not g.ItemUnclipByLog then return true end end end return false end --- @param item_id ImGuiID --- @param item_flags ImGuiItemFlags --- @param status_flags ImGuiItemStatusFlags --- @param item_rect ImRect function ImGui.SetLastItemData(item_id, item_flags, status_flags, item_rect) local g = GImGui g.LastItemData.ID = item_id g.LastItemData.ItemFlags = item_flags g.LastItemData.StatusFlags = status_flags ImRect_Copy(g.LastItemData.Rect, item_rect) ImRect_Copy(g.LastItemData.NavRect, item_rect) end --- @param window ImGuiWindow --- @param rect ImRect function ImGui.SetLastItemDataForWindow(window, rect) local g = GImGui if window.DockIsActive then ImGui.SetLastItemData(window.MoveId, g.CurrentItemFlags, window.DC.DockTabItemStatusFlags, window.DC.DockTabItemRect) else ImGui.SetLastItemData(window.MoveId, g.CurrentItemFlags, window.DC.WindowItemStatusFlags, rect) end end --- @param c unsigned_int function MT.ImGuiIO:AddInputCharacter(c) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx if c == 0 or not self.AppAcceptingEvents then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.Text e.Source = ImGuiInputSource.Keyboard e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.Text = ImGuiInputEventText() e.Text.Char = c g.InputEventsQueue:push_back(e) end --- @param c ImWchar16 function MT.ImGuiIO:AddInputCharacterUTF16(c) if (c == 0 and self.InputQueueSurrogate == 0) or not self.AppAcceptingEvents then return end if bit32.band(c, 0xFC00) == 0xD800 then -- High surrogate, must save if self.InputQueueSurrogate ~= 0 then self:AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID) end self.InputQueueSurrogate = c return end local cp = c if self.InputQueueSurrogate ~= 0 then if bit32.band(c, 0xFC00) ~= 0xDC00 then -- Invalid low surrogate self:AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID) else -- #if IM_UNICODE_CODEPOINT_MAX == 0xFFFF cp = IM_UNICODE_CODEPOINT_INVALID -- #endif end self.InputQueueSurrogate = 0 end self:AddInputCharacter(cp) end function MT.ImGuiIO:ClearEventsQueue() IM_ASSERT(self.Ctx ~= nil) local g = GImGui g.InputEventsQueue:clear() end function MT.ImGuiIO:ClearInputKeys() local g = self.Ctx for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do if not ImGui.IsMouseKey(key) then local key_data = g.IO.KeysData[key - ImGuiKey.NamedKey_BEGIN] key_data.Down = false key_data.DownDuration = -1.0 key_data.DownDurationPrev = -1.0 end end self.KeyCtrl = false self.KeyShift = false self.KeyAlt = false self.KeySuper = false self.KeyMods = ImGuiMod_None self.InputQueueCharacters:resize(0) end function MT.ImGuiIO:ClearInputMouse() for key = ImGuiKey_Mouse_BEGIN, ImGuiKey_Mouse_END - 1 do local key_data = self.KeysData[key - ImGuiKey.NamedKey_BEGIN] if key_data then key_data.Down = false key_data.DownDuration = -1.0 key_data.DownDurationPrev = -1.0 end end self.MousePos = ImVec2(-FLT_MAX, -FLT_MAX) for n = 0, 2 do -- IM_COUNTOF(MouseDown) self.MouseDown[n] = false self.MouseDownDuration[n] = -1.0 self.MouseDownDurationPrev[n] = -1.0 end self.MouseWheel = 0 self.MouseWheelH = 0 end --- @param ctx ImGuiContext --- @param type ImGuiInputEventType --- @param arg? int --- @return ImGuiInputEvent? function MT.ImGuiIO:FindLatestInputEvent(ctx, type, arg) if arg == nil then arg = -1 end local g = ctx for n = g.InputEventsQueue.Size, 1, -1 do local e = g.InputEventsQueue.Data[n] if e.Type ~= type then elseif type == ImGuiInputEventType.Key and e.Key.Key ~= arg then elseif type == ImGuiInputEventType.MouseButton and e.MouseButton.Button ~= arg then else return e end end return nil end --- @param key ImGuiKey --- @param down bool --- @param analog_value float function MT.ImGuiIO:AddKeyAnalogEvent(key, down, analog_value) IM_ASSERT(self.Ctx ~= nil) if key == ImGuiKey.None or not self.AppAcceptingEvents then return end local g = self.Ctx IM_ASSERT(ImGui.IsNamedKeyOrMod(key)) IM_ASSERT(ImGui.IsAliasKey(key) == false) -- MacOS: swap Cmd(Super) and Ctrl if (g.IO.ConfigMacOSXBehaviors) then if (key == ImGuiMod_Super) then key = ImGuiMod_Ctrl elseif (key == ImGuiMod_Ctrl) then key = ImGuiMod_Super elseif (key == ImGuiKey.LeftSuper) then key = ImGuiKey.LeftCtrl elseif (key == ImGuiKey.RightSuper) then key = ImGuiKey.RightCtrl elseif (key == ImGuiKey.LeftCtrl) then key = ImGuiKey.LeftSuper elseif (key == ImGuiKey.RightCtrl) then key = ImGuiKey.RightSuper end end local latest_event = self:FindLatestInputEvent(g, ImGuiInputEventType.Key, key) local key_data = ImGui.GetKeyData(g, key) local latest_key_down = latest_event and latest_event.Key.Down or key_data.Down local latest_key_analog = latest_event and latest_event.Key.AnalogValue or key_data.AnalogValue if latest_key_down == down and latest_key_analog == analog_value then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.Key e.Source = ImGui.IsGamepadKey(key) and ImGuiInputSource.Gamepad or ImGuiInputSource.Keyboard e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.Key = ImGuiInputEventKey() e.Key.Key = key e.Key.Down = down e.Key.AnalogValue = analog_value g.InputEventsQueue:push_back(e) end --- @param key ImGuiKey --- @param down bool function MT.ImGuiIO:AddKeyEvent(key, down) if not self.AppAcceptingEvents then return end self:AddKeyAnalogEvent(key, down, (down and 1.0 or 0.0)) end --- @param accepting_events bool function MT.ImGuiIO:SetAppAcceptingEvents(accepting_events) self.AppAcceptingEvents = accepting_events end --- @param source ImGuiMouseSource function MT.ImGuiIO:AddMouseSourceEvent(source) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx g.InputEventsNextMouseSource = source end --- @param viewport_id ImGuiID function MT.ImGuiIO:AddMouseViewportEvent(viewport_id) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx -- IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags.HasMouseHoveredViewport); if (not self.AppAcceptingEvents) then return end -- Filter duplicate local latest_event = self:FindLatestInputEvent(g, ImGuiInputEventType.MouseViewport) local latest_viewport_id if latest_event then latest_viewport_id = latest_event.MouseViewport.HoveredViewportID else latest_viewport_id = g.IO.MouseHoveredViewport end if (latest_viewport_id == viewport_id) then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.MouseViewport e.Source = ImGuiInputSource.Mouse e.MouseViewport = ImGuiInputEventMouseViewport() e.MouseViewport.HoveredViewportID = viewport_id g.InputEventsQueue:push_back(e) end --- @param focused bool function MT.ImGuiIO:AddFocusEvent(focused) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx local latest_event = self:FindLatestInputEvent(g, ImGuiInputEventType.Focus) local latest_focused = latest_event and latest_event.AppFocused.Focused or (not g.IO.AppFocusLost) if latest_focused == focused or (self.ConfigDebugIgnoreFocusLoss and not focused) then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.Focus e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.AppFocused = ImGuiInputEventAppFocused() e.AppFocused.Focused = focused g.InputEventsQueue:push_back(e) end --- @param x float --- @param y float function MT.ImGuiIO:AddMousePosEvent(x, y) IM_ASSERT(self.Ctx ~= nil) if not self.AppAcceptingEvents then return end local g = self.Ctx local x_val = x if x > -FLT_MAX then x_val = ImFloor(x) end local y_val = y if y > -FLT_MAX then y_val = ImFloor(y) end local latest_event = self:FindLatestInputEvent(g, ImGuiInputEventType.MousePos) local latest_pos = latest_event and ImVec2(latest_event.MousePos.PosX, latest_event.MousePos.PosY) or self.MousePos if latest_pos.x == x_val and latest_pos.y == y_val then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.MousePos e.Source = ImGuiInputSource.Mouse e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.MousePos = ImGuiInputEventMousePos() e.MousePos.PosX = x_val e.MousePos.PosY = y_val e.MousePos.MouseSource = g.InputEventsNextMouseSource g.InputEventsQueue:push_back(e) end --- @param mouse_button ImGuiMouseButton --- @param down bool function MT.ImGuiIO:AddMouseButtonEvent(mouse_button, down) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx IM_ASSERT(mouse_button >= 0 and mouse_button < ImGuiMouseButton.COUNT) if not self.AppAcceptingEvents then return end -- On MacOS X: Convert Ctrl(Super)+Left click into Right-click: handle held button. if self.ConfigMacOSXBehaviors and mouse_button == 0 and g.IO.MouseCtrlLeftAsRightClick then -- Order of both statements matters: this event will still release mouse button 1 mouse_button = 1 if not down then self.MouseCtrlLeftAsRightClick = false end end local latest_event = self:FindLatestInputEvent(g, ImGuiInputEventType.MouseButton, mouse_button) local latest_button_down = latest_event and latest_event.MouseButton.Down or self.MouseDown[mouse_button] if latest_button_down == down then return end -- On MacOS X: Convert Ctrl(Super)+Left click into Right-click. -- - Note that this is actual physical Ctrl which is ImGuiMod_Super for us. -- - At this point we want from !down to down, so this is handling the initial press. if self.ConfigMacOSXBehaviors and mouse_button == 0 and down then local latest_super_event = self:FindLatestInputEvent(g, ImGuiInputEventType.Key, ImGuiMod_Super) if latest_super_event and latest_super_event.Key.Down or self.KeySuper then -- IMGUI_DEBUG_LOG_IO("[io] Super+Left Click aliased into Right Click\n") self.MouseCtrlLeftAsRightClick = true self:AddMouseButtonEvent(1, true) -- This is just quicker to write that passing through, as we need to filter duplicate again. return end end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.MouseButton e.Source = ImGuiInputSource.Mouse e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.MouseButton = ImGuiInputEventMouseButton() e.MouseButton.Button = mouse_button e.MouseButton.Down = down e.MouseButton.MouseSource = g.InputEventsNextMouseSource g.InputEventsQueue:push_back(e) end --- @param wheel_x float --- @param wheel_y float function MT.ImGuiIO:AddMouseWheelEvent(wheel_x, wheel_y) IM_ASSERT(self.Ctx ~= nil) local g = self.Ctx if not self.AppAcceptingEvents or (wheel_x == 0 and wheel_y == 0) then return end local e = ImGuiInputEvent() e.Type = ImGuiInputEventType.MouseWheel e.Source = ImGuiInputSource.Mouse e.EventId = g.InputEventsNextEventId g.InputEventsNextEventId = g.InputEventsNextEventId + 1 e.MouseWheel = ImGuiInputEventMouseWheel() e.MouseWheel.WheelX = wheel_x e.MouseWheel.WheelY = wheel_y e.MouseWheel.MouseSource = g.InputEventsNextMouseSource g.InputEventsQueue:push_back(e) end --- @param key ImGuiKey local function GetModForLRModKey(key) if key == ImGuiKey.LeftCtrl or key == ImGuiKey.RightCtrl then return ImGuiMod_Ctrl end if key == ImGuiKey.LeftShift or key == ImGuiKey.RightShift then return ImGuiMod_Shift end if key == ImGuiKey.LeftAlt or key == ImGuiKey.RightAlt then return ImGuiMod_Alt end if key == ImGuiKey.LeftSuper or key == ImGuiKey.RightSuper then return ImGuiMod_Super end return ImGuiMod_None end --- @param key_chord ImGuiKeyChord function ImGui.FixupKeyChord(key_chord) local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) if ImGui.IsLRModKey(key) then key_chord = bit32.bor(key_chord, GetModForLRModKey(key)) end return key_chord end --- @param ctx? ImGuiContext --- @param key ImGuiKey --- @return ImGuiKeyData, int function ImGui.GetKeyData(ctx, key) if ctx == nil then ctx = GImGui end if bit32.band(key, ImGuiMod_Mask_) ~= 0 then key = ImGui.ConvertSingleModFlagToKey(key) end IM_ASSERT(ImGui.IsNamedKey(key), "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code.") local idx = key - ImGuiKey.NamedKey_BEGIN return ctx.IO.KeysData[idx], idx end --- @param key_left ImGuiKey --- @param key_right ImGuiKey --- @param key_up ImGuiKey --- @param key_down ImGuiKey function ImGui.GetKeyMagnitude2d(key_left, key_right, key_up, key_down) return ImVec2( ImGui.GetKeyData(nil, key_right).AnalogValue - ImGui.GetKeyData(nil, key_left).AnalogValue, ImGui.GetKeyData(nil, key_down).AnalogValue - ImGui.GetKeyData(nil, key_up).AnalogValue ) end --- @param key ImGuiKey --- @param owner_id ImGuiID function ImGui.TestKeyOwner(key, owner_id) if not ImGui.IsNamedKeyOrMod(key) then return true end local g = GImGui --- @cast g ImGuiContext if g.ActiveIdUsingAllKeyboardKeys and owner_id ~= g.ActiveId and owner_id ~= ImGuiKeyOwner_Any then if key >= ImGuiKey_Keyboard_BEGIN and key < ImGuiKey_Keyboard_END then return false end end local owner_data = ImGui.GetKeyOwnerData(g, key) if owner_id == ImGuiKeyOwner_Any then return not owner_data.LockThisFrame end if owner_data.OwnerCurr ~= owner_id then if owner_data.LockThisFrame then return false end if owner_data.OwnerCurr ~= ImGuiKeyOwner_NoOwner then return false end end return true end --- @param key ImGuiKey --- @param owner_id? ImGuiID function ImGui.IsKeyDown(key, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local key_data = ImGui.GetKeyData(nil, key) if not key_data.Down then return false end if not ImGui.TestKeyOwner(key, owner_id) then return false end return true end --- @param key ImGuiKey --- @param is_repeat? bool function ImGui.IsKeyPressed(key, is_repeat) if is_repeat == nil then is_repeat = true end return ImGui.IsKeyPressedEx(key, is_repeat and ImGuiInputFlags.Repeat or ImGuiInputFlags.None, ImGuiKeyOwner_Any) end --- @param key ImGuiKey --- @param owner_id? ImGuiID --- @return bool function ImGui.IsKeyReleased(key, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local key_data = ImGui.GetKeyData(nil, key) if key_data.DownDurationPrev < 0.0 or key_data.Down then return false end if not ImGui.TestKeyOwner(key, owner_id) then return false end return true end --- @param key ImGuiKey --- @param flags ImGuiInputFlags --- @param owner_id? ImGuiID function ImGui.IsKeyPressedEx(key, flags, owner_id) if owner_id == nil then owner_id = 0 end local g = GImGui local key_data = ImGui.GetKeyData(g, key) -- In theory this should already be encoded as (DownDuration < 0.0), but testing this facilitates eating mechanism (until we finish work on key ownership) if not key_data.Down then return false end local t = key_data.DownDuration if t < 0.0 then return false end IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedByIsKeyPressed)) == 0) -- Passing flags not supported by this function! if bit32.band(flags, bit32.bor(ImGuiInputFlags.RepeatRateMask_, ImGuiInputFlags.RepeatUntilMask_)) ~= 0 then -- Setting any _RepeatXXX option enables _Repeat flags = bit32.bor(flags, ImGuiInputFlags.Repeat) end local pressed = (t == 0.0) if not pressed and bit32.band(flags, ImGuiInputFlags.Repeat) ~= 0 then local repeat_delay, repeat_rate = ImGui.GetTypematicRepeatRate(flags) pressed = (t > repeat_delay) and (ImGui.GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0) if pressed and bit32.band(flags, ImGuiInputFlags.RepeatUntilMask_) ~= 0 then -- Slightly bias 'key_pressed_time' as DownDuration is an accumulation of DeltaTime which we compare to an absolute time value. -- Ideally we'd replace DownDuration with KeyPressedTime but it would break user's code. local key_pressed_time = g.Time - t + 0.00001 if bit32.band(flags, ImGuiInputFlags.RepeatUntilKeyModsChange) ~= 0 and g.LastKeyModsChangeTime > key_pressed_time then pressed = false end if bit32.band(flags, ImGuiInputFlags.RepeatUntilKeyModsChangeFromNone) ~= 0 and g.LastKeyModsChangeFromNoneTime > key_pressed_time then pressed = false end if bit32.band(flags, ImGuiInputFlags.RepeatUntilOtherKeyPress) ~= 0 and g.LastKeyboardKeyPressTime > key_pressed_time then pressed = false end end end if not pressed then return false end if not ImGui.TestKeyOwner(key, owner_id) then return false end return true end -- TODO: function ImGui.GetKeyChordName(key_chord) local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) if ImGui.IsLRModKey(key) then key_chord = bit32.band(key_chord, bit32.bnot(GetModForLRModKey(key))) -- Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift" end local s = ((bit32.band(key_chord, ImGuiMod_Ctrl) ~= 0) and "Ctrl+" or "") .. ((bit32.band(key_chord, ImGuiMod_Shift) ~= 0) and "Shift+" or "") .. ((bit32.band(key_chord, ImGuiMod_Alt) ~= 0) and "Alt+" or "") .. ((bit32.band(key_chord, ImGuiMod_Super) ~= 0) and "Super+" or "") .. ((key ~= ImGuiKey.None or key_chord == ImGuiKey.None) and ImGui.GetKeyName(key) or "") if key == ImGuiKey.None and key_chord ~= 0 and #s > 0 then s = string.sub(s, 1, #s - 1) -- Remove trailing '+' end return s end local GKeyNames = { "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown", "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape", "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket", "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen", "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", "AppBack", "AppForward", "Oem102", "GamepadStart", "GamepadBack", "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3", "GamepadLStickLeft", "GamepadLStickRight", "GamepadLStickUp", "GamepadLStickDown", "GamepadRStickLeft", "GamepadRStickRight", "GamepadRStickUp", "GamepadRStickDown", "MouseLeft", "MouseRight", "MouseMiddle", "MouseX1", "MouseX2", "MouseWheelX", "MouseWheelY", "ModCtrl", "ModShift", "ModAlt", "ModSuper", -- ReservedForModXXX are showing the ModXXX names. } --- @param key ImGuiKey --- @return string function ImGui.GetKeyName(key) if key == ImGuiKey.None then return "None" end IM_ASSERT(ImGui.IsNamedKeyOrMod(key), "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.") if bit32.band(key, ImGuiMod_Mask_) ~= 0 then key = ImGui.ConvertSingleModFlagToKey(key) end if not ImGui.IsNamedKey(key) then return "Unknown" end return GKeyNames[key - ImGuiKey.NamedKey_BEGIN + 1] or "Unknown" end --- @param key ImGuiKey --- @return ImGuiID function ImGui.GetKeyOwner(key) if not ImGui.IsNamedKeyOrMod(key) then return ImGuiKeyOwner_NoOwner end local g = GImGui local owner_data = ImGui.GetKeyOwnerData(g, key) local owner_id = owner_data.OwnerCurr if g.ActiveIdUsingAllKeyboardKeys and owner_id ~= g.ActiveId and owner_id ~= ImGuiKeyOwner_Any then if key >= ImGuiKey_Keyboard_BEGIN and key < ImGuiKey_Keyboard_END then return ImGuiKeyOwner_NoOwner end end return owner_id end --- @param t0 float --- @param t1 float --- @param repeat_delay float --- @param repeat_rate float function ImGui.CalcTypematicRepeatAmount(t0, t1, repeat_delay, repeat_rate) if t1 == 0.0 then return 1 end if t0 >= t1 then return 0 end if repeat_rate <= 0.0 then if t0 < repeat_delay and t1 >= repeat_delay then return 1 else return 0 end end local count_t0 if t0 < repeat_delay then count_t0 = -1 else count_t0 = math.floor((t0 - repeat_delay) / repeat_rate) end local count_t1 if t1 < repeat_delay then count_t1 = -1 else count_t1 = math.floor((t1 - repeat_delay) / repeat_rate) end return count_t1 - count_t0 end --- @param flags ImGuiInputFlags --- @return float repeat_delay --- @return float repeat_rate function ImGui.GetTypematicRepeatRate(flags) local g = GImGui flags = bit32.band(flags, ImGuiInputFlags.RepeatRateMask_) if flags == ImGuiInputFlags.RepeatRateNavMove then repeat_delay = g.IO.KeyRepeatDelay * 0.72; repeat_rate = g.IO.KeyRepeatRate * 0.80; return repeat_delay, repeat_rate elseif flags == ImGuiInputFlags.RepeatRateNavTweak then repeat_delay = g.IO.KeyRepeatDelay * 0.72; repeat_rate = g.IO.KeyRepeatRate * 0.30; return repeat_delay, repeat_rate else repeat_delay = g.IO.KeyRepeatDelay * 1.00; repeat_rate = g.IO.KeyRepeatRate * 1.00; return repeat_delay, repeat_rate end end --- @param key ImGuiKey --- @param repeat_delay float --- @param repeat_rate float function ImGui.GetKeyPressedAmount(key, repeat_delay, repeat_rate) local g = GImGui local key_data = ImGui.GetKeyData(g, key) if not key_data.Down then -- In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) return 0 end local t = key_data.DownDuration return ImGui.CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate) end --- @param rt ImGuiKeyRoutingTable function ImGui.UpdateKeyRoutingTable(rt) local g = GImGui --[[@as ImGuiContext]] rt.EntriesNext:resize(0) for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do local new_routing_start_idx = rt.EntriesNext.Size + 1 local routing_entry local old_routing_idx = rt.Index[key - ImGuiKey.NamedKey_BEGIN + 1] while old_routing_idx ~= -1 do repeat routing_entry = rt.Entries[old_routing_idx] routing_entry.RoutingCurrScore = routing_entry.RoutingNextScore routing_entry.RoutingCurr = routing_entry.RoutingNext routing_entry.RoutingNext = ImGuiKeyOwner_NoOwner routing_entry.RoutingNextScore = 0 if routing_entry.RoutingCurr == ImGuiKeyOwner_NoOwner then break end rt.EntriesNext:push_back(routing_entry) if routing_entry.Mods == g.IO.KeyMods then local owner_data = ImGui.GetKeyOwnerData(g, key) if owner_data.OwnerCurr == ImGuiKeyOwner_NoOwner then owner_data.OwnerCurr = routing_entry.RoutingCurr end end until true old_routing_idx = routing_entry.NextEntryIndex end rt.Index[key - ImGuiKey.NamedKey_BEGIN + 1] = (new_routing_start_idx <= rt.EntriesNext.Size and new_routing_start_idx or -1) for n = new_routing_start_idx, rt.EntriesNext.Size do rt.EntriesNext[n].NextEntryIndex = (n + 1 <= rt.EntriesNext.Size) and (n + 1) or -1 end end rt.Entries:swap(rt.EntriesNext) end -- owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope() --- @param owner_id ImGuiID local function GetRoutingIdFromOwnerId(owner_id) local g = GImGui return (owner_id ~= ImGuiKeyOwner_NoOwner and owner_id ~= ImGuiKeyOwner_Any) and owner_id or g.CurrentFocusScopeId end --- @param key_chord ImGuiKeyChord --- @return ImGuiKeyRoutingData function ImGui.GetShortcutRoutingData(key_chord) local g = GImGui local rt = g.KeysRoutingTable local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) local mods = bit32.band(key_chord, ImGuiMod_Mask_) if key == ImGuiKey.None then key = ImGui.ConvertSingleModFlagToKey(mods) end IM_ASSERT(ImGui.IsNamedKey(key)) local routing_data local idx = rt.Index[key - ImGuiKey.NamedKey_BEGIN + 1] while idx ~= -1 do routing_data = rt.Entries.Data[idx] if routing_data.Mods == mods then return routing_data end idx = routing_data.NextEntryIndex end local routing_data_idx = rt.Entries.Size + 1 rt.Entries:push_back(ImGuiKeyRoutingData()) routing_data = rt.Entries[routing_data_idx] routing_data.Mods = mods routing_data.NextEntryIndex = rt.Index[key - ImGuiKey.NamedKey_BEGIN + 1] rt.Index[key - ImGuiKey.NamedKey_BEGIN + 1] = routing_data_idx return routing_data end --- @param focus_scope_id ImGuiID --- @param owner_id ImGuiID --- @param flags ImGuiInputFlags local function CalcRoutingScore(focus_scope_id, owner_id, flags) local g = GImGui if bit32.band(flags, ImGuiInputFlags.RouteFocused) ~= 0 then if owner_id ~= 0 and g.ActiveId == owner_id then return 300 end if focus_scope_id == 0 then return 0 end for index_in_focus_path = 1, g.NavFocusRoute.Size do if g.NavFocusRoute.Data[index_in_focus_path].ID == focus_scope_id then if bit32.band(flags, ImGuiInputFlags.RouteOverActive) ~= 0 then return 599 - (index_in_focus_path - 1) else return 199 - (index_in_focus_path - 1) end end end return 0 elseif bit32.band(flags, ImGuiInputFlags.RouteActive) ~= 0 then if owner_id ~= 0 and g.ActiveId == owner_id then return 300 end return 0 elseif bit32.band(flags, ImGuiInputFlags.RouteGlobal) ~= 0 then if bit32.band(flags, ImGuiInputFlags.RouteOverActive) ~= 0 then return 400 end if owner_id ~= 0 and g.ActiveId == owner_id then return 300 end if bit32.band(flags, ImGuiInputFlags.RouteOverFocused) ~= 0 then return 200 end return 1 end IM_ASSERT(false) return 0 end --- @param key_chord ImGuiKeyChord local function IsKeyChordPotentiallyCharInput(key_chord) local g = GImGui local mods = bit32.band(key_chord, ImGuiMod_Mask_) local ignore_char_inputs = ((bit32.band(mods, ImGuiMod_Ctrl) ~= 0) and (bit32.band(mods, ImGuiMod_Alt) == 0)) or (g.IO.ConfigMacOSXBehaviors and (bit32.band(mods, ImGuiMod_Ctrl) ~= 0)) if ignore_char_inputs then return false end local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) if key == ImGuiKey.None then return false end return g.KeysMayBeCharInput:TestBit(key + 1) -- TestBit requires 1-based index end --- @param key_chord ImGuiKeyChord --- @param flags ImGuiInputFlags --- @param owner_id ImGuiID function ImGui.SetShortcutRouting(key_chord, flags, owner_id) local g = GImGui if bit32.band(flags, ImGuiInputFlags.RouteTypeMask_) == 0 then flags = bit32.bor(flags, ImGuiInputFlags.RouteGlobal, ImGuiInputFlags.RouteOverFocused, ImGuiInputFlags.RouteOverActive) -- IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut() else IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiInputFlags.RouteTypeMask_))) -- Check that only 1 routing flag is used end IM_ASSERT(owner_id ~= ImGuiKeyOwner_Any and owner_id ~= ImGuiKeyOwner_NoOwner) if bit32.band(flags, bit32.bor(ImGuiInputFlags.RouteOverFocused, ImGuiInputFlags.RouteUnlessBgFocused)) ~= 0 then IM_ASSERT(bit32.band(flags, ImGuiInputFlags.RouteGlobal) ~= 0) end if bit32.band(flags, ImGuiInputFlags.RouteOverActive) ~= 0 then IM_ASSERT(bit32.band(flags, bit32.bor(ImGuiInputFlags.RouteGlobal, ImGuiInputFlags.RouteFocused)) ~= 0) end key_chord = ImGui.FixupKeyChord(key_chord) if g.DebugBreakInShortcutRouting == key_chord then -- IM_DEBUG_BREAK() end if bit32.band(flags, ImGuiInputFlags.RouteUnlessBgFocused) ~= 0 then if g.NavWindow == nil then return false end end if bit32.band(flags, ImGuiInputFlags.RouteAlways) ~= 0 then -- IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> always, no register", ImGui.GetKeyChordName(key_chord), flags, owner_id) return true end if g.ActiveId ~= 0 and g.ActiveId ~= owner_id then if bit32.band(flags, ImGuiInputFlags.RouteActive) ~= 0 then return false end if g.IO.WantTextInput and IsKeyChordPotentiallyCharInput(key_chord) then -- IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> filtered as potential char input", ImGui.GetKeyChordName(key_chord), flags, owner_id) return false end if bit32.band(flags, ImGuiInputFlags.RouteOverActive) == 0 and g.ActiveIdUsingAllKeyboardKeys then local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) if key == ImGuiKey.None then key = ImGui.ConvertSingleModFlagToKey(bit32.band(key_chord, ImGuiMod_Mask_)) end if key >= ImGuiKey_Keyboard_BEGIN and key < ImGuiKey_Keyboard_END then return false end end end local focus_scope_id = g.CurrentFocusScopeId if bit32.band(flags, ImGuiInputFlags.RouteFromRootWindow) ~= 0 then focus_scope_id = g.CurrentWindow.RootWindow.ID end local score = CalcRoutingScore(focus_scope_id, owner_id, flags) -- IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> score %d", ImGui.GetKeyChordName(key_chord), flags, owner_id, score) if score == 0 then return false end local routing_data = ImGui.GetShortcutRoutingData(key_chord) if score > routing_data.RoutingNextScore then routing_data.RoutingNext = owner_id routing_data.RoutingNextScore = score end if routing_data.RoutingCurr == owner_id then -- IMGUI_DEBUG_LOG_INPUTROUTING("--> granting current route") end return routing_data.RoutingCurr == owner_id end --- @param mouse_pos? ImVec2 function ImGui.IsMousePosValid(mouse_pos) local MOUSE_INVALID = -256000.0 local p if mouse_pos then p = mouse_pos else p = GImGui.IO.MousePos end return p.x >= MOUSE_INVALID and p.y >= MOUSE_INVALID end --- @return bool function ImGui.IsAnyMouseDown() local g = GImGui for n = 0, 2 do -- IM_COUNTOF(g.IO.MouseDown) - 1 if g.IO.MouseDown[n] then return true end end return false end --- @param button ImGuiMouseButton --- @param owner_id? ImGuiID function ImGui.IsMouseDown(button, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- IM_COUNTOF(g.IO.MouseDown) return g.IO.MouseDown[button] and ImGui.TestKeyOwner(ImGui.MouseButtonToKey(button), owner_id) end --- @param button ImGuiMouseButton --- @param is_repeat? bool function ImGui.IsMouseClicked(button, is_repeat) if is_repeat == nil then is_repeat = false end return ImGui.IsMouseClickedEx(button, is_repeat and ImGuiInputFlags.Repeat or ImGuiInputFlags.None, ImGuiKeyOwner_Any) end --- @param button ImGuiMouseButton --- @param flags ImGuiInputFlags --- @param owner_id? ImGuiID @native function ImGui.IsMouseClickedEx(button, flags, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- IM_COUNTOF(g.IO.MouseDown) if not g.IO.MouseDown[button] then return false end local t = g.IO.MouseDownDuration[button] if t < 0.0 then return false end IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedByIsMouseClicked)) == 0) local is_repeat = (bit32.band(flags, ImGuiInputFlags.Repeat) ~= 0) local pressed = (t == 0.0) or (is_repeat and t > g.IO.KeyRepeatDelay and ImGui.CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0) if not pressed then return false end if not ImGui.TestKeyOwner(ImGui.MouseButtonToKey(button), owner_id) then return false end return true end --- @param button ImGuiMouseButton --- @param owner_id? ImGuiID function ImGui.IsMouseReleased(button, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- IM_COUNTOF(g.IO.MouseDown) return g.IO.MouseReleased[button] and ImGui.TestKeyOwner(ImGui.MouseButtonToKey(button), owner_id) end -- Use if you absolutely need to distinguish single-click from double-click by introducing a delay. --- @param button ImGuiMouseButton --- @param delay? float function ImGui.IsMouseReleasedWithDelay(button, delay) if delay == nil then delay = -1.0 end local g = GImGui IM_ASSERT(button >= 0 and button < 3) if ImGui.IsMouseDown(button) then return false end if delay < 0.0 then delay = g.IO.MouseSingleClickDelay or 0.50 end local time_since_release = g.Time - g.IO.MouseReleasedTime[button] return (time_since_release - g.IO.DeltaTime < delay) and (time_since_release >= delay) end --- @param button ImGuiMouseButton --- @param owner_id? ImGuiID function ImGui.IsMouseDoubleClicked(button, owner_id) if owner_id == nil then owner_id = ImGuiKeyOwner_Any end local g = GImGui IM_ASSERT(button >= 0 and button < 3) return g.IO.MouseClickedCount[button] == 2 and ImGui.TestKeyOwner(ImGui.MouseButtonToKey(button), owner_id) end --- @param button ImGuiMouseButton function ImGui.GetMouseClickedCount(button) local g = GImGui IM_ASSERT(button >= 0 and button < 3) return g.IO.MouseClickedCount[button] end -- FIXME: This is close to what BeginDragDropSource() is doing, maybe rework. --- @param mouse_button ImGuiMouseButton local function LastItemOverlayButtonForNullId(mouse_button) local g = GImGui IM_ASSERT(g.LastItemData.ID == 0) local window = g.CurrentWindow local id = window:GetIDFromRectangle(g.LastItemData.Rect) if g.IO.MouseClicked[mouse_button] and ImGui.ItemHoverable(g.LastItemData.Rect, id, g.LastItemData.ItemFlags) then ImGui.SetActiveID(id, window) ImGui.FocusWindow(window) elseif g.ActiveId == id then ImGui.KeepAliveID(id) if not g.IO.MouseDown[mouse_button] then ImGui.ClearActiveID() end end return id end --- @param mouse_button? ImGuiMouseButton --- @param delay? float --- @return int function ImGui.GetItemClickedCountWithSingleClickDelay(mouse_button, delay) if mouse_button == nil then mouse_button = 0 end if delay == nil then delay = -1.0 end -- Action: double-click and subsequent clicks local g = GImGui if g.IO.MouseClickedCount[mouse_button] >= 2 and ImGui.IsItemClicked(mouse_button) then return g.IO.MouseClickedCount[mouse_button] end -- Action: second click, delayed local id = g.LastItemData.ID if id == 0 then id = LastItemOverlayButtonForNullId(mouse_button) end if g.LastActiveId == id then if delay >= 0.0 then delay = ImMax(delay, g.IO.MouseDoubleClickTime + 0.01) end if ImGui.IsMouseReleasedWithDelay(mouse_button, delay) and g.IO.MouseClickedLastCount[mouse_button] == 1 then return 1 end end return 0 end --- @return ImVec2 # Ref function ImGui.GetMousePos() return GImGui.IO.MousePos end --- @return ImVec2 function ImGui.GetMousePosOnOpeningCurrentPopup() local g = GImGui if g.BeginPopupStack.Size > 0 then return g.BeginPopupStack.Data[g.BeginPopupStack.Size].OpenMousePos end return g.IO.MousePos end -- Return the delta from the initial clicking position while the mouse button is clicked or was just released. --- @param button? ImGuiMouseButton --- @param lock_threshold? float --- @return ImVec2 function ImGui.GetMouseDragDelta(button, lock_threshold) if button == nil then button = 0 end if lock_threshold == nil then lock_threshold = -1.0 end local g = GImGui IM_ASSERT(button >= 0 and button < 3) if lock_threshold < 0.0 then lock_threshold = g.IO.MouseDragThreshold end if g.IO.MouseDown[button] or g.IO.MouseReleased[button] then if g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold then if ImGui.IsMousePosValid(g.IO.MousePos) and ImGui.IsMousePosValid(g.IO.MouseClickedPos[button]) then return g.IO.MousePos - g.IO.MouseClickedPos[button] end end end return ImVec2(0.0, 0.0) end --- @param button? ImGuiMouseButton function ImGui.ResetMouseDragDelta(button) if button == nil then button = 0 end local g = GImGui IM_ASSERT(button >= 0 and button < 3) -- NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr ImVec2_Copy(g.IO.MouseClickedPos[button], g.IO.MousePos) end do local key_changed_mask = ImBitArray(ImGuiKey.NamedKey_COUNT) --- @param trickle_fast_inputs bool function ImGui.UpdateInputEvents(trickle_fast_inputs) local g = GImGui local io = g.IO local trickle_interleaved_nonchar_keys_and_text = trickle_fast_inputs and g.WantTextInputNextFrame == 1 local mouse_moved = false local mouse_wheeled = false local key_changed = false local key_changed_nonchar = false local text_inputted = false local mouse_button_changed = 0x00 key_changed_mask:ClearAllBits() local event_n = 1 local stop_3231 = false while event_n <= g.InputEventsQueue.Size do repeat local e = g.InputEventsQueue.Data[event_n] if e.Type == ImGuiInputEventType.MousePos then if g.IO.WantSetMousePos then break end if trickle_fast_inputs and (mouse_button_changed ~= 0 or mouse_wheeled or key_changed or text_inputted) then stop_3231 = true; break end local event_pos = ImVec2(e.MousePos.PosX, e.MousePos.PosY) io.MousePos = event_pos io.MouseSource = e.MousePos.MouseSource mouse_moved = true elseif e.Type == ImGuiInputEventType.MouseButton then local button = e.MouseButton.Button IM_ASSERT(button >= 0 and button < ImGuiMouseButton.COUNT) if trickle_fast_inputs and ((bit32.band(mouse_button_changed, bit32.lshift(1, button)) ~= 0) or mouse_wheeled) then stop_3231 = true; break end if trickle_fast_inputs and e.MouseButton.MouseSource == ImGuiMouseSource.TouchScreen and mouse_moved then stop_3231 = true; break end io.MouseDown[button] = e.MouseButton.Down io.MouseSource = e.MouseButton.MouseSource mouse_button_changed = bit32.bor(mouse_button_changed, bit32.lshift(1, button)) elseif e.Type == ImGuiInputEventType.MouseWheel then if trickle_fast_inputs and (mouse_moved or mouse_button_changed ~= 0) then stop_3231 = true; break end io.MouseWheelH = io.MouseWheelH + e.MouseWheel.WheelX io.MouseWheel = io.MouseWheel + e.MouseWheel.WheelY io.MouseSource = e.MouseWheel.MouseSource mouse_wheeled = true elseif e.Type == ImGuiInputEventType.MouseViewport then io.MouseHoveredViewport = e.MouseViewport.HoveredViewportID elseif e.Type == ImGuiInputEventType.Key then -- Trickling Rule: Stop processing queued events if we got multiple action on the same button if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) ~= 0 then break end local key = e.Key.Key IM_ASSERT(key ~= ImGuiKey.None) -- TODO: Also gets 0-based index here, consider making key_data storage 1-based local key_data, key_data_index = ImGui.GetKeyData(g, key) if trickle_fast_inputs and key_data.Down ~= e.Key.Down and (key_changed_mask:TestBit(key_data_index + 1) or mouse_button_changed ~= 0) then stop_3231 = true; break end local key_is_potentially_for_char_input = IsKeyChordPotentiallyCharInput(bit32.bor(ImGui.GetMergedModsFromKeys(), key)) if trickle_interleaved_nonchar_keys_and_text and (text_inputted and not key_is_potentially_for_char_input) then stop_3231 = true; break end if key_data.Down ~= e.Key.Down then key_changed = true key_changed_mask:SetBit(key_data_index + 1) if trickle_interleaved_nonchar_keys_and_text and not key_is_potentially_for_char_input then key_changed_nonchar = true end end key_data.Down = e.Key.Down key_data.AnalogValue = e.Key.AnalogValue elseif e.Type == ImGuiInputEventType.Text then if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) ~= 0 then break end if trickle_fast_inputs and (mouse_button_changed ~= 0 or mouse_moved or mouse_wheeled) then stop_3231 = true; break end if trickle_interleaved_nonchar_keys_and_text and key_changed_nonchar then stop_3231 = true; break end local c = e.Text.Char io.InputQueueCharacters:push_back((c <= IM_UNICODE_CODEPOINT_MAX) and c or IM_UNICODE_CODEPOINT_INVALID) if trickle_interleaved_nonchar_keys_and_text then text_inputted = true end elseif e.Type == ImGuiInputEventType.Focus then local focus_lost = not e.AppFocused.Focused io.AppFocusLost = focus_lost else IM_ASSERT(false, "Unknown event!") end until true if stop_3231 then break end event_n = event_n + 1 end if event_n == g.InputEventsQueue.Size + 1 then g.InputEventsQueue:resize(0) else for i = 1, event_n - 1 do g.InputEventsQueue:erase(1) end end if g.IO.AppFocusLost then g.IO:ClearInputKeys() g.IO:ClearInputMouse() end end end --- @param key ImGuiKey --- @param owner_id ImGuiID --- @param flags? ImGuiInputFlags function ImGui.SetKeyOwner(key, owner_id, flags) if flags == nil then flags = 0 end local g = GImGui --- @cast g ImGuiContext IM_ASSERT(ImGui.IsNamedKeyOrMod(key) and (owner_id ~= ImGuiKeyOwner_Any or (bit32.band(flags, bit32.bor(ImGuiInputFlags.LockThisFrame, ImGuiInputFlags.LockUntilRelease)) ~= 0)), "Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)") IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedBySetKeyOwner)) == 0, "Passing flags not supported by this function!") local owner_data = ImGui.GetKeyOwnerData(g, key) owner_data.OwnerCurr = owner_id owner_data.OwnerNext = owner_id owner_data.LockUntilRelease = (bit32.band(flags, ImGuiInputFlags.LockUntilRelease) ~= 0) owner_data.LockThisFrame = (bit32.band(flags, ImGuiInputFlags.LockThisFrame) ~= 0) or owner_data.LockUntilRelease end -- Rarely used helper --- @param key_chord ImGuiKeyChord --- @param owner_id ImGuiID --- @param flags? ImGuiInputFlags function ImGui.SetKeyOwnersForKeyChord(key_chord, owner_id, flags) if flags == nil then flags = 0 end if bit32.band(key_chord, ImGuiMod_Ctrl) ~= 0 then ImGui.SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags) end if bit32.band(key_chord, ImGuiMod_Shift) ~= 0 then ImGui.SetKeyOwner(ImGuiMod_Shift, owner_id, flags) end if bit32.band(key_chord, ImGuiMod_Alt) ~= 0 then ImGui.SetKeyOwner(ImGuiMod_Alt, owner_id, flags) end if bit32.band(key_chord, ImGuiMod_Super) ~= 0 then ImGui.SetKeyOwner(ImGuiMod_Super, owner_id, flags) end if bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) ~= 0 then ImGui.SetKeyOwner(bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)), owner_id, flags) end end --- @param key ImGuiKey --- @param flags? ImGuiInputFlags function ImGui.SetItemKeyOwner(key, flags) if flags == nil then flags = ImGuiInputFlags.None end local g = GImGui local id = g.LastItemData.ID if id == 0 or (g.HoveredId ~= id and g.ActiveId ~= id) then return false end if bit32.band(flags, ImGuiInputFlags.CondMask_) == 0 then flags = bit32.bor(flags, ImGuiInputFlags.CondDefault_) end if (g.HoveredId == id and bit32.band(flags, ImGuiInputFlags.CondHovered) ~= 0) or (g.ActiveId == id and bit32.band(flags, ImGuiInputFlags.CondActive) ~= 0) then IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedBySetItemKeyOwner)) == 0) if not ImGui.TestKeyOwner(key, id) then return false end ImGui.SetKeyOwner(key, id, bit32.band(flags, bit32.bnot(ImGuiInputFlags.CondMask_))) return true end return false end --- @param key_chord ImGuiKeyChord --- @param flags ImGuiInputFlags --- @param owner_id ImGuiID function ImGui.IsKeyChordPressed(key_chord, flags, owner_id) local g = GImGui key_chord = ImGui.FixupKeyChord(key_chord) local mods = bit32.band(key_chord, ImGuiMod_Mask_) if g.IO.KeyMods ~= mods then return false end -- Special storage location for mods local key = bit32.band(key_chord, bit32.bnot(ImGuiMod_Mask_)) if key == ImGuiKey.None then key = ImGui.ConvertSingleModFlagToKey(mods) end if not ImGui.IsKeyPressedEx(key, bit32.band(flags, ImGuiInputFlags.RepeatMask_), owner_id) then return false end return true end --- @param key_chord ImGuiKeyChord --- @param flags? ImGuiInputFlags function ImGui.SetNextItemShortcut(key_chord, flags) if flags == nil then flags = 0 end local g = GImGui g.NextItemData.HasFlags = bit32.bor(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasShortcut) g.NextItemData.Shortcut = key_chord g.NextItemData.ShortcutFlags = flags end --- @param key_chord ImGuiKeyChord --- @param flags ImGuiInputFlags --- @param owner_id ImGuiID function ImGui.Shortcut(key_chord, flags, owner_id) local g = GImGui -- IMGUI_DEBUG_LOG("Shortcut(%s, flags=%X, owner_id=0x%08X)", ImGui.GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), flags, owner_id) -- When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any. if bit32.band(flags, ImGuiInputFlags.RouteTypeMask_) == 0 then flags = bit32.bor(flags, ImGuiInputFlags.RouteFocused) end -- Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default) -- Effectively makes Shortcut() always input-owner aware. if owner_id == ImGuiKeyOwner_Any or owner_id == ImGuiKeyOwner_NoOwner then owner_id = GetRoutingIdFromOwnerId(owner_id) end if bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0 then return false end -- Submit route if not ImGui.SetShortcutRouting(key_chord, flags, owner_id) then return false end -- Default repeat behavior for Shortcut() -- So e.g. pressing Ctrl+W and releasing Ctrl while holding W will not trigger the W shortcut. if bit32.band(flags, ImGuiInputFlags.Repeat) ~= 0 and bit32.band(flags, ImGuiInputFlags.RepeatUntilMask_) == 0 then flags = bit32.bor(flags, ImGuiInputFlags.RepeatUntilKeyModsChange) end if not ImGui.IsKeyChordPressed(key_chord, flags, owner_id) then return false end -- Claim mods during the press ImGui.SetKeyOwnersForKeyChord(bit32.band(key_chord, ImGuiMod_Mask_), owner_id) IM_ASSERT(bit32.band(flags, bit32.bnot(ImGuiInputFlags.SupportedByShortcut)) == 0) -- Passing flags not supported by this function! return true end --- @param window ImGuiWindow --- @return bool function ImGui.IsWindowActiveAndVisible(window) return window.Active and not window.Hidden end --- @param window ImGuiWindow --- @nodiscard local function CalcWindowMinSize(window) local g = GImGui local size_min = ImVec2() if (bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(window.Flags, ImGuiWindowFlags.Popup) == 0) then if bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeX) ~= 0 then size_min.x = g.Style.WindowMinSize.x else size_min.x = IMGUI_WINDOW_HARD_MIN_SIZE end if bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeY) ~= 0 then size_min.y = g.Style.WindowMinSize.y else size_min.y = IMGUI_WINDOW_HARD_MIN_SIZE end else if bit32.band(window.Flags, ImGuiWindowFlags.AlwaysAutoResize) == 0 then size_min.x = g.Style.WindowMinSize.x else size_min.x = IMGUI_WINDOW_HARD_MIN_SIZE end if bit32.band(window.Flags, ImGuiWindowFlags.AlwaysAutoResize) == 0 then size_min.y = g.Style.WindowMinSize.y else size_min.y = IMGUI_WINDOW_HARD_MIN_SIZE end end local window_for_height = window size_min.y = ImMax(size_min.y, window_for_height.TitleBarHeight + window_for_height.MenuBarHeight + ImMax(0, g.Style.WindowRounding - 1)) return size_min end --- @param window ImGuiWindow --- @param size_desired ImVec2 --- @return ImVec2 --- @nodiscard local function CalcWindowSizeAfterConstraint(window, size_desired) local g = GImGui local new_size = ImVec2() ImVec2_Copy(new_size, size_desired) if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSizeConstraint) ~= 0 then local cr = ImRect() ImRect_Copy(cr, g.NextWindowData.SizeConstraintRect) new_size.x = (cr.Min.x >= 0 and cr.Max.x >= 0) and ImClamp(new_size.x, cr.Min.x, cr.Max.x) or window.SizeFull.x new_size.y = (cr.Min.y >= 0 and cr.Max.y >= 0) and ImClamp(new_size.y, cr.Min.y, cr.Max.y) or window.SizeFull.y if g.NextWindowData.SizeCallback then local data = {} -- TODO: ImGuiSizeCallbackData data.UserData = g.NextWindowData.SizeCallbackUserData data.Pos = ImVec2(window.Pos.x, window.Pos.y) data.CurrentSize = ImVec2(window.SizeFull.x, window.SizeFull.y) data.DesiredSize = ImVec2(new_size.x, new_size.y) g.NextWindowData.SizeCallback(data) new_size.x = data.DesiredSize.x new_size.y = data.DesiredSize.y end new_size.x = IM_TRUNC(new_size.x) new_size.y = IM_TRUNC(new_size.y) end local size_min = CalcWindowMinSize(window) return ImMax(new_size, size_min) end --- @param window ImGuiWindow --- @param content_size_current ImVec2 --- @param content_size_ideal ImVec2 local function CalcWindowContentSizes(window, content_size_current, content_size_ideal) local preserve_old_content_sizes = false if (window.Collapsed and window.AutoFitFramesX <= 0 and window.AutoFitFramesY <= 0) then preserve_old_content_sizes = true elseif (window.Hidden and window.HiddenFramesCannotSkipItems == 0 and window.HiddenFramesCanSkipItems > 0) then preserve_old_content_sizes = true end if preserve_old_content_sizes then content_size_current.x = window.ContentSize.x content_size_current.y = window.ContentSize.y content_size_ideal.x = window.ContentSizeIdeal.x content_size_ideal.y = window.ContentSizeIdeal.y return end if (window.ContentSizeExplicit.x ~= 0.0) then content_size_current.x = window.ContentSizeExplicit.x else content_size_current.x = ImTrunc64(window.DC.CursorMaxPos.x - window.DC.CursorStartPos.x) end if (window.ContentSizeExplicit.y ~= 0.0) then content_size_current.y = window.ContentSizeExplicit.y else content_size_current.y = ImTrunc64(window.DC.CursorMaxPos.y - window.DC.CursorStartPos.y) end if (window.ContentSizeExplicit.x ~= 0.0) then content_size_ideal.x = window.ContentSizeExplicit.x else content_size_ideal.x = ImTrunc64(ImMax(window.DC.CursorMaxPos.x, window.DC.IdealMaxPos.x) - window.DC.CursorStartPos.x) end if (window.ContentSizeExplicit.y ~= 0.0) then content_size_ideal.y = window.ContentSizeExplicit.y else content_size_ideal.y = ImTrunc64(ImMax(window.DC.CursorMaxPos.y, window.DC.IdealMaxPos.y) - window.DC.CursorStartPos.y) end end --- @param window ImGuiWindow # The window to calculate auto-fit size for --- @param size_contents ImVec2 # The content size --- @param axis_mask int # The axis mask to determine which axes to auto-fit --- @return ImVec2 # The auto-fit size local function CalcWindowAutoFitSize(window, size_contents, axis_mask) local g = GImGui local style = g.Style local decoration_w_without_scrollbars = window.DecoOuterSizeX1 + window.DecoOuterSizeX2 - window.ScrollbarSizes.x local decoration_h_without_scrollbars = window.DecoOuterSizeY1 + window.DecoOuterSizeY2 - window.ScrollbarSizes.y local size_pad = ImVec2(window.WindowPadding.x * 2, window.WindowPadding.y * 2) local size_desired = ImVec2() size_desired.x = (bit32.band(axis_mask, 1) ~= 0) and (size_contents.x + size_pad.x + decoration_w_without_scrollbars) or window.Size.x size_desired.y = (bit32.band(axis_mask, 2) ~= 0) and (size_contents.y + size_pad.y + decoration_h_without_scrollbars) or window.Size.y local size_max = ImVec2(FLT_MAX, FLT_MAX) if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0 or bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 then if not window.ViewportOwned then size_max = ImGui.GetMainViewport().WorkSize - style.DisplaySafeAreaPadding * 2.0 end local monitor_idx = window.ViewportAllowPlatformMonitorExtend if monitor_idx >= 1 and monitor_idx <= g.PlatformIO.Monitors.Size then size_max = g.PlatformIO.Monitors.Data[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0 end end if bit32.band(window.Flags, ImGuiWindowFlags.Tooltip) ~= 0 then return ImMin(size_desired, size_max) else local size_min = CalcWindowMinSize(window) local size_auto_fit = ImClamp(size_desired, ImMin(size_min, size_max), size_max) local size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit) local size_contents_for_scrollbar_x = (bit32.band(axis_mask, 1) ~= 0) and size_contents.x or window.ContentSize.x local size_contents_for_scrollbar_y = (bit32.band(axis_mask, 2) ~= 0) and size_contents.y or window.ContentSize.y local will_have_scrollbar_x = (size_auto_fit_after_constraint.x < size_contents_for_scrollbar_x + size_pad.x + decoration_w_without_scrollbars and bit32.band(window.Flags, ImGuiWindowFlags.NoScrollbar) == 0 and bit32.band(window.Flags, ImGuiWindowFlags.HorizontalScrollbar) ~= 0) or bit32.band(window.Flags, ImGuiWindowFlags.AlwaysHorizontalScrollbar) ~= 0 local will_have_scrollbar_y = (size_auto_fit_after_constraint.y < size_contents_for_scrollbar_y + size_pad.y + decoration_h_without_scrollbars and bit32.band(window.Flags, ImGuiWindowFlags.NoScrollbar) == 0) or bit32.band(window.Flags, ImGuiWindowFlags.AlwaysVerticalScrollbar) ~= 0 if will_have_scrollbar_x then size_auto_fit.y = size_auto_fit.y + style.ScrollbarSize end if will_have_scrollbar_y then size_auto_fit.x = size_auto_fit.x + style.ScrollbarSize end return size_auto_fit end end --- @param window ImGuiWindow --- @return ImVec2 function ImGui.CalcWindowNextAutoFitSize(window) local size_contents_current = ImVec2() local size_contents_ideal = ImVec2() CalcWindowContentSizes(window, size_contents_current, size_contents_ideal) local size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal, -1) local size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit) return size_final end --- @param window ImGuiWindow --- @return ImGuiCol local function GetWindowBgColorIdx(window) if bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.Popup)) ~= 0 then return ImGuiCol.PopupBg elseif bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 and not window.DockIsActive then return ImGuiCol.ChildBg else return ImGuiCol.WindowBg end end --- @param window ImGuiWindow --- @param corner_target_arg ImVec2 --- @param corner_norm ImVec2 --- @return ImVec2, ImVec2 --- @nodiscard local function CalcResizePosSizeFromAnyCorner(window, corner_target_arg, corner_norm) local corner_target = ImVec2() ImVec2_Copy(corner_target, corner_target_arg) if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then local parent_window = window.ParentWindow local parent_flags = parent_window.Flags local limit_rect = ImRect() ImRect_Copy(limit_rect, parent_window.InnerRect) limit_rect:Expand(ImVec2(-ImMax(parent_window.WindowPadding.x, parent_window.WindowBorderSize), -ImMax(parent_window.WindowPadding.y, parent_window.WindowBorderSize))) if (bit32.band(parent_flags, bit32.bor(ImGuiWindowFlags.HorizontalScrollbar, ImGuiWindowFlags.AlwaysHorizontalScrollbar)) == 0) or (bit32.band(parent_flags, ImGuiWindowFlags.NoScrollbar) ~= 0) then corner_target.x = ImClamp(corner_target.x, limit_rect.Min.x, limit_rect.Max.x) end if bit32.band(parent_flags, ImGuiWindowFlags.NoScrollbar) ~= 0 then corner_target.y = ImClamp(corner_target.y, limit_rect.Min.y, limit_rect.Max.y) end end local pos_min = ImLerp(corner_target, window.Pos, corner_norm) local pos_max = ImLerp(window.Pos + window.Size, corner_target, corner_norm) local size_expected = pos_max - pos_min local size_constrained = CalcWindowSizeAfterConstraint(window, size_expected) local out_pos = pos_min if corner_norm.x == 0.0 then out_pos.x = out_pos.x - (size_constrained.x - size_expected.x) end if corner_norm.y == 0.0 then out_pos.y = out_pos.y - (size_constrained.y - size_expected.y) end return out_pos, size_constrained end --- @param window ImGuiWindow --- @param resize_grip_count int --- @param resize_grip_col table --- @param visibility_rect ImRect --- @return int, int, int local function UpdateWindowManualResize(window, resize_grip_count, resize_grip_col, visibility_rect) local g = GImGui local flags = window.Flags if (bit32.band(flags, ImGuiWindowFlags.NoResize) ~= 0 or window.AutoFitFramesX > 0 or window.AutoFitFramesY > 0) then return 0, -1, -1 end if (bit32.band(flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0 and bit32.band(window.ChildFlags, bit32.bor(ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY)) == 0) then return 0, -1, -1 end if window.WasActive == false then return 0, -1, -1 end local border_hovered = -1 local border_held = -1 local ret_auto_fit_mask = 0x00 local grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.35, g.Style.WindowRounding + 1.0 + g.FontSize * 0.2)) local grip_hover_inner_size = (resize_grip_count > 0) and IM_TRUNC(grip_draw_size * 0.75) or 0.0 local grip_hover_outer_size = g.WindowsBorderHoverPadding + 1 ImGui.PushID("#RESIZE") local pos_target = ImVec2(FLT_MAX, FLT_MAX) local size_target = ImVec2(FLT_MAX, FLT_MAX) -- Clip mouse interaction rectangles within the viewport rectangle (in practice the narrowing is going to happen most of the time). -- - Not narrowing would mostly benefit the situation where OS windows _without_ decoration have a threshold for hovering when outside their limits. -- This is however not the case with current backends under Win32, but a custom borderless window implementation would benefit from it. -- - When decoration are enabled we typically benefit from that distance, but then our resize elements would be conflicting with OS resize elements, so we also narrow. -- - Note that we are unable to tell if the platform setup allows hovering with a distance threshold (on Win32, decorated window have such threshold). -- We only clip interaction so we overwrite window->ClipRect, cannot call PushClipRect() yet as DrawList is not yet setup. local clip_with_viewport_rect = bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.HasMouseHoveredViewport) == 0 or g.IO.MouseHoveredViewport ~= window.ViewportId or bit32.band(window.Viewport.Flags, ImGuiViewportFlags.NoDecoration) == 0 if (clip_with_viewport_rect) then ImRect_Copy(window.ClipRect, window.Viewport:GetMainRect()) end local clamp_rect = ImRect() ImRect_Copy(clamp_rect, visibility_rect) local window_move_from_title_bar = (bit32.band(window.BgClickFlags, ImGuiWindowBgClickFlags.Move) == 0) and (bit32.band(window.Flags, ImGuiWindowFlags.NoTitleBar) == 0) if window_move_from_title_bar then clamp_rect.Min.y = clamp_rect.Min.y - window.TitleBarHeight end for resize_grip_n = 0, resize_grip_count - 1 do local def = ImGuiResizeGripDef[resize_grip_n + 1] local corner_pos = def.CornerPosN local inner_dir = def.InnerDir local corner = ImVec2(window.Pos.x + corner_pos.x * window.Size.x, window.Pos.y + corner_pos.y * window.Size.y) local resize_rect = ImRect(corner - inner_dir * grip_hover_outer_size, corner + inner_dir * grip_hover_inner_size) if resize_rect.Min.x > resize_rect.Max.x then resize_rect.Min.x, resize_rect.Max.x = resize_rect.Max.x, resize_rect.Min.x end if resize_rect.Min.y > resize_rect.Max.y then resize_rect.Min.y, resize_rect.Max.y = resize_rect.Max.y, resize_rect.Min.y end local resize_grip_id = window:GetID(resize_grip_n) ImGui.ItemAdd(resize_rect, resize_grip_id, nil, ImGuiItemFlags.NoNav) local _, hovered, held = ImGui.ButtonBehavior(resize_rect, resize_grip_id, bit32.bor(ImGuiButtonFlags.FlattenChildren, ImGuiButtonFlags.NoNavFocus)) if hovered or held then ImGui.SetMouseCursor((bit32.band(resize_grip_n, 1) ~= 0) and ImGuiMouseCursor.ResizeNESW or ImGuiMouseCursor.ResizeNWSE) end if held and g.IO.MouseDoubleClicked[0] then local size_auto_fit = CalcWindowAutoFitSize(window, window.ContentSizeIdeal, -1) size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit) ret_auto_fit_mask = 0x03 ImGui.ClearActiveID() elseif held then local clamp_min = ImVec2((corner_pos.x == 1.0) and clamp_rect.Min.x or -FLT_MAX, (corner_pos.y == 1.0) and clamp_rect.Min.y or -FLT_MAX) local clamp_max = ImVec2((corner_pos.x == 0.0) and clamp_rect.Max.x or FLT_MAX, (corner_pos.y == 0.0) and clamp_rect.Max.y or FLT_MAX) local corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN) corner_target = ImClamp(corner_target, clamp_min, clamp_max) pos_target, size_target = CalcResizePosSizeFromAnyCorner(window, corner_target, corner_pos) end local resize_grip_visible = held or hovered or (resize_grip_n == 0 and bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0) if resize_grip_visible then local color if held then color = ImGui.GetColorU32(ImGuiCol.ResizeGripActive) else if hovered then color = ImGui.GetColorU32(ImGuiCol.ResizeGripHovered) else color = ImGui.GetColorU32(ImGuiCol.ResizeGrip) end end resize_grip_col[resize_grip_n + 1] = color end end local resize_border_mask = 0x00 if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then local mask_x = (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeX) ~= 0) and 0x02 or 0 local mask_y = (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeY) ~= 0) and 0x08 or 0 resize_border_mask = bit32.bor(mask_x, mask_y) else resize_border_mask = g.IO.ConfigWindowsResizeFromEdges and 0x0F or 0x00 end for border_n = 0, 3 do repeat if bit32.band(resize_border_mask, bit32.lshift(1, border_n)) == 0 then break end local def = ImGuiResizeBorderDef[border_n + 1] local axis if border_n == ImGuiDir.Left or border_n == ImGuiDir.Right then axis = ImGuiAxis.X else axis = ImGuiAxis.Y end local border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, g.WindowsBorderHoverPadding) local border_id = window:GetID(border_n + 4) ImGui.ItemAdd(border_rect, border_id, nil, ImGuiItemFlags.NoNav) local _, hovered, held = ImGui.ButtonBehavior(border_rect, border_id, bit32.bor(ImGuiButtonFlags.FlattenChildren, ImGuiButtonFlags.NoNavFocus)) if hovered and g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER then hovered = false end if hovered or held then ImGui.SetMouseCursor((axis == ImGuiAxis.X) and ImGuiMouseCursor.ResizeEW or ImGuiMouseCursor.ResizeNS) end if held and g.IO.MouseDoubleClicked[0] then -- Double-clicking bottom or right border auto-fit on this axis -- FIXME: Support top and right borders: rework CalcResizePosSizeFromAnyCorner() to be reusable in both cases. if border_n == 1 or border_n == 3 then -- Right and bottom border local size_auto_fit = CalcWindowAutoFitSize(window, window.ContentSizeIdeal, bit32.lshift(1, axis - 1)) size_target[axis] = CalcWindowSizeAfterConstraint(window, size_auto_fit)[axis] ret_auto_fit_mask = bit32.bor(ret_auto_fit_mask, bit32.lshift(1, axis - 1)) hovered = false held = false -- So border doesn't show highlighted at new position end ImGui.ClearActiveID() elseif held then local just_scrolled_manually_while_resizing = (g.WheelingWindow ~= nil and g.WheelingWindowScrolledFrame == g.FrameCount and ImGui.IsWindowChildOf(window, g.WheelingWindow, false, true)) if g.ActiveIdIsJustActivated or just_scrolled_manually_while_resizing then g.WindowResizeBorderExpectedRect = border_rect g.WindowResizeRelativeMode = false end if (bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0) and g.WindowResizeBorderExpectedRect ~= border_rect then g.WindowResizeRelativeMode = true end local border_curr = window.Pos + ImMin(def.SegmentN1, def.SegmentN2) * window.Size local border_target_rel_mode_for_axis local border_target_abs_mode_for_axis border_target_rel_mode_for_axis = border_curr[axis] + g.IO.MouseDelta[axis] border_target_abs_mode_for_axis = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + g.WindowsBorderHoverPadding -- Match ButtonBehavior() padding above -- Use absolute mode position local border_target = ImVec2() ImVec2_Copy(border_target, window.Pos) border_target[axis] = border_target_abs_mode_for_axis -- Use relative mode target for child window, ignore resize when moving back toward the ideal absolute position. local ignore_resize = false if g.WindowResizeRelativeMode then border_target[axis] = border_target_rel_mode_for_axis if g.IO.MouseDelta[axis] == 0.0 or ((g.IO.MouseDelta[axis] > 0.0) == (border_target_rel_mode_for_axis > border_target_abs_mode_for_axis)) then ignore_resize = true end end local clamp_min = ImVec2((border_n == ImGuiDir.Right) and clamp_rect.Min.x or -FLT_MAX, (border_n == ImGuiDir.Down or (border_n == ImGuiDir.Up and window_move_from_title_bar)) and clamp_rect.Min.y or -FLT_MAX) local clamp_max = ImVec2((border_n == ImGuiDir.Left) and clamp_rect.Max.x or FLT_MAX, (border_n == ImGuiDir.Up) and clamp_rect.Max.y or FLT_MAX) border_target = ImClamp(border_target, clamp_min, clamp_max) if not ignore_resize then pos_target, size_target = CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2)) end end if hovered then border_hovered = border_n end if held then border_held = border_n end until true end ImGui.PopID() window.DC.NavLayerCurrent = ImGuiNavLayer.Main if size_target.x ~= FLT_MAX and (window.Size.x ~= size_target.x or window.SizeFull.x ~= size_target.x) then window.Size.x = size_target.x window.SizeFull.x = size_target.x end if size_target.y ~= FLT_MAX and (window.Size.y ~= size_target.y or window.SizeFull.y ~= size_target.y) then window.Size.y = size_target.y window.SizeFull.y = size_target.y end if pos_target.x ~= FLT_MAX and window.Pos.x ~= ImFloor(pos_target.x) then window.Pos.x = ImFloor(pos_target.x) end if pos_target.y ~= FLT_MAX and window.Pos.y ~= ImFloor(pos_target.y) then window.Pos.y = ImFloor(pos_target.y) end if border_held ~= -1 then g.WindowResizeBorderExpectedRect = GetResizeBorderRect(window, border_held, grip_hover_inner_size, g.WindowsBorderHoverPadding) end return ret_auto_fit_mask, border_hovered, border_held end --- @param pos ImVec2 --- @param wrap_pos_x float --- @return float function ImGui.CalcWrapWidthForPos(pos, wrap_pos_x) if wrap_pos_x < 0.0 then return 0.0 end local g = GImGui local window = g.CurrentWindow if wrap_pos_x == 0.0 then wrap_pos_x = window.WorkRect.Max.x elseif wrap_pos_x > 0.0 then wrap_pos_x = wrap_pos_x + window.Pos.x - window.Scroll.x end return ImMax(wrap_pos_x - pos.x, 1.0) end --- @param text ImString --- @param text_end int? --- @return int # Exclusive upper bound @native function ImGui.FindRenderedTextEnd(text, text_end) local text_display_end = 1 local text_len = #text if not text_end then text_end = text_len + 1 end text_display_end = ImMemchr(text, "##", 1) or text_end text_display_end = ImMin(text_display_end, text_end) return text_display_end end --- @param pos ImVec2 --- @param text string --- @param text_begin int? --- @param text_end int? --- @param hide_text_after_hash bool? # true by default @native function ImGui.RenderText(pos, text, text_begin, text_end, hide_text_after_hash) if text_begin == nil then text_begin = 1 end if hide_text_after_hash == nil then hide_text_after_hash = true end local g = GImGui local window = g.CurrentWindow -- Hide anything after a '##' string local text_display_end if hide_text_after_hash then text_display_end = ImGui.FindRenderedTextEnd(text, text_end) else if text_end == nil then text_end = #text + 1 end text_display_end = text_end end if text ~= "" and text_display_end > 1 then window.DrawList:AddText(g.Font, g.FontSize, pos, ImGui.GetColorU32(ImGuiCol.Text), text, text_begin, text_display_end, 0.0) if g.LogEnabled then -- ImGui.LogRenderedText(&pos, text, text_display_end); end end end --- @param pos ImVec2 --- @param text string --- @param text_end int? --- @param wrap_width float function ImGui.RenderTextWrapped(pos, text, text_end, wrap_width) local g = GImGui local window = g.CurrentWindow if text_end == nil then text_end = #text + 1 end if text ~= "" then window.DrawList:AddText(g.Font, g.FontSize, pos, ImGui.GetColorU32(ImGuiCol.Text), text, 1, text_end, wrap_width) end end --- @param draw_list ImDrawList --- @param pos_min ImVec2 --- @param pos_max ImVec2 --- @param text string --- @param text_begin int --- @param text_display_end int --- @param text_size_if_known? ImVec2 --- @param align? ImVec2 --- @param clip_rect? ImRect @native function ImGui.RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_begin, text_display_end, text_size_if_known, align, clip_rect) if not align then align = ImVec2(0, 0) end local pos = ImVec2() ImVec2_Copy(pos, pos_min) local text_size = text_size_if_known or ImGui.CalcTextSize(text, text_display_end, false, 0.0) local clip_min = clip_rect and clip_rect.Min or pos_min local clip_max = clip_rect and clip_rect.Max or pos_max local need_clipping = (pos.x + text_size.x >= clip_max.x) or (pos.y + text_size.y >= clip_max.y) if (clip_rect) then need_clipping = need_clipping or ((pos.x < clip_min.x) or (pos.y < clip_min.y)) end if (align.x > 0.0) then pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x) end if (align.y > 0.0) then pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y) end local g = GImGui if (need_clipping) then local fine_clip_rect = ImVec4(clip_min.x, clip_min.y, clip_max.x, clip_max.y) draw_list:AddText(nil, 0.0, pos, ImGui.GetColorU32(ImGuiCol.Text), text, text_begin, text_display_end, 0.0, fine_clip_rect) else draw_list:AddText(nil, 0.0, pos, ImGui.GetColorU32(ImGuiCol.Text), text, text_begin, text_display_end, 0.0, nil) end end --- @param pos_min ImVec2 --- @param pos_max ImVec2 --- @param text string --- @param text_end? int --- @param text_size_if_known? ImVec2 --- @param align? ImVec2 --- @param clip_rect? ImRect function ImGui.RenderTextClipped(pos_min, pos_max, text, text_end, text_size_if_known, align, clip_rect) if not align then align = ImVec2(0, 0) end local text_display_end = ImGui.FindRenderedTextEnd(text, text_end) local text_len = text_display_end - 1 if text_len == 0 then return end local g = GImGui local window = g.CurrentWindow ImGui.RenderTextClippedEx(window.DrawList, pos_min, pos_max, text, 1, text_display_end, text_size_if_known, align, clip_rect) -- if (g.LogEnabled) -- ImGui.LogRenderedText(&pos_min, text, text_display_end); end --- @param bb ImRect --- @param id ImGuiID --- @param flags? ImGuiNavRenderCursorFlags --- @param rounding? float @native function ImGui.RenderNavCursor(bb, id, flags, rounding) if flags == nil then flags = ImGuiNavRenderCursorFlags.None end if rounding == nil then rounding = -1.0 end local g = GImGui if id ~= g.NavId then return end if not g.NavCursorVisible and bit32.band(flags, ImGuiNavRenderCursorFlags.AlwaysDraw) == 0 then return end if id == g.LastItemData.ID and bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.NoNav) ~= 0 then return end local window = g.CurrentWindow if window.DC.NavHideHighlightOneFrame then return end if rounding < 0.0 then rounding = g.Style.FrameRounding end local display_rect = ImRect() ImRect_Copy(display_rect, bb) display_rect:ClipWith(window.ClipRect) local scale_factor = ImGui.GetScale() local thickness = ImTrunc(ImMax(2.0, 1.5 * scale_factor)) if bit32.band(flags, ImGuiNavRenderCursorFlags.Compact) ~= 0 then window.DrawList:AddRect(display_rect.Min, display_rect.Max, ImGui.GetColorU32(ImGuiCol.NavCursor), rounding, thickness) else local distance = ImTrunc(3.0 + thickness * 0.5) display_rect:Expand(ImVec2(distance, distance)) local fully_visible = window.ClipRect:Contains(display_rect) if not fully_visible then window.DrawList:PushClipRect(display_rect.Min, display_rect.Max) end window.DrawList:AddRect(display_rect.Min, display_rect.Max, ImGui.GetColorU32(ImGuiCol.NavCursor), rounding, thickness) if not fully_visible then window.DrawList:PopClipRect() end end end do --[[ImGui.RenderMouseCursor]] local offset = ImVec2() local size = ImVec2() local uv_border = {ImVec2(), ImVec2()} local uv_fill = {ImVec2(), ImVec2()} --- @param base_pos ImVec2 --- @param base_scale float --- @param mouse_cursor ImGuiMouseCursor --- @param col_fill ImU32 --- @param col_border ImU32 --- @param col_shadow ImU32 function ImGui.RenderMouseCursor(base_pos, base_scale, mouse_cursor, col_fill, col_border, col_shadow) local g = GImGui if mouse_cursor <= ImGuiMouseCursor.None or mouse_cursor >= ImGuiMouseCursor.COUNT then -- We intentionally accept out of bound values mouse_cursor = ImGuiMouseCursor.Arrow end local font_atlas = g.DrawListSharedData.FontAtlas for _, viewport in g.Viewports:iter() do repeat if not ImFontAtlasGetMouseCursorTexData(font_atlas, mouse_cursor, offset, size, uv_border, uv_fill) then break end local pos = base_pos - offset local scale = base_scale * viewport.DpiScale if not viewport:GetMainRect():Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)) then break end local draw_list = ImGui.GetForegroundDrawList(viewport) local tex_ref = font_atlas.TexRef draw_list:PushTexture(tex_ref); draw_list:AddImage(tex_ref, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv_fill[1], uv_fill[2], col_shadow) draw_list:AddImage(tex_ref, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv_fill[1], uv_fill[2], col_shadow) draw_list:AddImage(tex_ref, pos, pos + size * scale, uv_fill[1], uv_fill[2], col_border) draw_list:AddImage(tex_ref, pos, pos + size * scale, uv_border[1], uv_border[2], col_fill) if mouse_cursor == ImGuiMouseCursor.Wait or mouse_cursor == ImGuiMouseCursor.Progress then local a_min = ImFmod(g.Time * 5.0, 2.0 * IM_PI) local a_max = a_min + IM_PI * 1.65 draw_list:PathArcTo(pos + ImVec2(14, -1) * scale, 6.0 * scale, a_min, a_max) draw_list:PathStroke(col_fill, 3.0 * scale) end draw_list:PopTexture() until true end end end --- Another overly complex function until we reorganize everything into a nice all-in-one helper. --- This is made more complex because we have dissociated the layout rectangle (pos_min .. pos_max) from 'ellipsis_max_x' which may be beyond it. --- This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. --- @param draw_list ImDrawList --- @param pos_min ImVec2 --- @param pos_max ImVec2 --- @param ellipsis_max_x float --- @param text string --- @param text_end_full? int --- @param text_size_if_known? ImVec2 function ImGui.RenderTextEllipsis(draw_list, pos_min, pos_max, ellipsis_max_x, text, text_end_full, text_size_if_known) local g = GImGui if text_end_full == nil then text_end_full = ImGui.FindRenderedTextEnd(text) end local text_size if text_size_if_known then text_size = ImVec2() ImVec2_Copy(text_size, text_size_if_known) else text_size = ImGui.CalcTextSize(text, text_end_full, false, 0.0) end -- draw_list:AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 6), IM_COL32(0, 0, 255, 255)) -- draw_list:AddLine(ImVec2(ellipsis_max_x, pos_min.y - 2), ImVec2(ellipsis_max_x, pos_max.y + 3), IM_COL32(0, 255, 0, 255)) -- FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. if text_size.x > pos_max.x - pos_min.x then -- Hello wo... -- | | | -- min max ellipsis_max -- <-> this is generally some padding value local font = draw_list._Data.Font local font_size = draw_list._Data.FontSize local font_scale = draw_list._Data.FontScale local text_end_ellipsis = nil local baked = font:GetFontBaked(font_size) local ellipsis_width = baked:GetCharAdvance(font.EllipsisChar) * font_scale -- We can now claim the space between pos_max.x and ellipsis_max.x local text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0) local text_size_clipped text_size_clipped, text_end_ellipsis = font:CalcTextSizeA(font_size, text_avail_width, 0.0, text, 1, text_end_full) local text_size_clipped_x = text_size_clipped.x -- Render text, render ellipsis ImGui.RenderTextClippedEx(draw_list, pos_min, pos_max, text, 1, text_end_ellipsis, text_size, ImVec2(0.0, 0.0)) local cpu_fine_clip_rect = ImVec4(pos_min.x, pos_min.y, pos_max.x, pos_max.y) local ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)) font:RenderChar(draw_list, font_size, ellipsis_pos, ImGui.GetColorU32(ImGuiCol.Text), font.EllipsisChar, cpu_fine_clip_rect) else ImGui.RenderTextClippedEx(draw_list, pos_min, pos_max, text, 1, text_end_full, text_size, ImVec2(0.0, 0.0)) end if g.LogEnabled then ImGui.LogRenderedText(pos_min, text, text_end_full) end end --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param fill_col ImU32 --- @param borders? bool --- @param rounding? float @native function ImGui.RenderFrame(p_min, p_max, fill_col, borders, rounding) if borders == nil then borders = true end if rounding == nil then rounding = 0.0 end local g = GImGui local window = g.CurrentWindow window.DrawList:AddRectFilled(p_min, p_max, fill_col, rounding) local border_size = g.Style.FrameBorderSize if borders and border_size > 0 then window.DrawList:AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), ImGui.GetColorU32(ImGuiCol.BorderShadow), rounding, border_size, 0) window.DrawList:AddRect(p_min, p_max, ImGui.GetColorU32(ImGuiCol.Border), rounding, border_size, 0) end end --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param rounding float @native function ImGui.RenderFrameBorder(p_min, p_max, rounding) local g = GImGui local window = g.CurrentWindow local border_size = g.Style.FrameBorderSize if border_size > 0.0 then window.DrawList:AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), ImGui.GetColorU32(ImGuiCol.BorderShadow), rounding, border_size, 0) window.DrawList:AddRect(p_min, p_max, ImGui.GetColorU32(ImGuiCol.Border), rounding, border_size, 0) end end --- @param bb ImRect --- @param col ImU32 --- @param rounding float function ImGui.RenderColorComponentMarker(bb, col, rounding) if bb.Min.x + 1 >= bb.Max.x then return end local g = GImGui local window = g.CurrentWindow ImGui.RenderRectFilledInRangeH(window.DrawList, bb, col, bb.Min.x, ImMin(bb.Min.x + g.Style.ColorMarkerSize, bb.Max.x), rounding) end --- @param window ImGuiWindow --- @param border_n int --- @param border_col ImU32 --- @param border_size float local function RenderWindowOuterSingleBorder(window, border_n, border_col, border_size) local def = ImGuiResizeBorderDef[border_n + 1] local rounding = window.WindowRounding local border_r = GetResizeBorderRect(window, border_n, rounding, 0.0) window.DrawList:PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5, 0.5) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25, def.OuterAngle) window.DrawList:PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5, 0.5) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25) window.DrawList:PathStroke(border_col, border_size) end local function RenderWindowOuterBorders(window) local g = GImGui local border_size = window.WindowBorderSize local border_col = ImGui.GetColorU32(ImGuiCol.Border) if border_size > 0.0 and (bit32.band(window.Flags, ImGuiWindowFlags.NoBackground) == 0) then window.DrawList:AddRect(window.Pos, window.Pos + window.Size, border_col, window.WindowRounding, window.WindowBorderSize, 0) elseif border_size > 0.0 then if bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeX) ~= 0 then RenderWindowOuterSingleBorder(window, 1, border_col, border_size) end if bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeY) ~= 0 then RenderWindowOuterSingleBorder(window, 3, border_col, border_size) end end if window.ResizeBorderHovered ~= -1 or window.ResizeBorderHeld ~= -1 then local border_n = (window.ResizeBorderHeld ~= -1) and window.ResizeBorderHeld or window.ResizeBorderHovered local border_col_resizing = ImGui.GetColorU32((window.ResizeBorderHeld ~= -1) and ImGuiCol.SeparatorActive or ImGuiCol.SeparatorHovered) RenderWindowOuterSingleBorder(window, border_n, border_col_resizing, ImMax(2.0, window.WindowBorderSize)) end if g.Style.FrameBorderSize > 0 and (bit32.band(window.Flags, ImGuiWindowFlags.NoTitleBar) == 0) and not window.DockIsActive then local y = window.Pos.y + window.TitleBarHeight - 1 window.DrawList:AddLineH(window.Pos.x + border_size * 0.5, window.Pos.x + window.Size.x - border_size * 0.5, y, border_col, g.Style.FrameBorderSize) end end --- @param window ImGuiWindow --- @param title_bar_rect ImRect --- @param title_bar_is_highlight bool --- @param handle_borders_and_resize_grips bool --- @param resize_grip_col ImU32[] --- @param resize_grip_draw_size float local function RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_col, resize_grip_draw_size) local g = GImGui local style = g.Style local flags = window.Flags local window_rounding = window.WindowRounding local window_border_size = window.WindowBorderSize if window.Collapsed then local backup_border_size = style.FrameBorderSize g.Style.FrameBorderSize = window.WindowBorderSize local title_bar_col = ImGui.GetColorU32((title_bar_is_highlight and g.NavCursorVisible) and ImGuiCol.TitleBgActive or ImGuiCol.TitleBgCollapsed) ImGui.RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding) g.Style.FrameBorderSize = backup_border_size else -- Window background if bit32.band(flags, ImGuiWindowFlags.NoBackground) == 0 then local bg_col = ImGui.GetColorU32(GetWindowBgColorIdx(window)) local override_alpha = false local alpha = 1.0 if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasBgAlpha) ~= 0 then alpha = g.NextWindowData.BgAlphaVal override_alpha = true end if override_alpha then bg_col = bit32.band(bg_col, bit32.bnot(IM_COL32_A_MASK)) or bit32.lshift(IM_F32_TO_INT8_SAT(alpha), IM_COL32_A_SHIFT) end if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then local bg_rect = ImRect(window.Pos + ImVec2(0, window.TitleBarHeight), window.Pos + window.Size) local bg_rounding_flags if window.DockIsActive then bg_rounding_flags = ImGui.CalcRoundingFlagsForRectInRect(bg_rect, window.DockNode.HostWindow:Rect(), 0.0) else bg_rounding_flags = (bit32.band(flags, ImGuiWindowFlags.NoTitleBar) ~= 0) and ImDrawFlags.RoundCornersAll or ImDrawFlags.RoundCornersBottom end local bg_draw_list = window.DockIsActive and window.DockNode.HostWindow.DrawList or window.DrawList if window.DockIsActive then bg_draw_list:ChannelsSetCurrent(0) end bg_draw_list:AddRectFilled(bg_rect.Min, bg_rect.Max, bg_col, window_rounding, bg_rounding_flags) if window.DockIsActive then bg_draw_list:ChannelsSetCurrent(1) end end end if window.DockIsActive then window.DockNode.IsBgDrawnThisFrame = true end -- Title bar if bit32.band(flags, ImGuiWindowFlags.NoTitleBar) == 0 and not window.DockIsActive then local title_bar_col = ImGui.GetColorU32(title_bar_is_highlight and ImGuiCol.TitleBgActive or ImGuiCol.TitleBg) window.DrawList:AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags.RoundCornersTop) end -- Menu bar if bit32.band(flags, ImGuiWindowFlags.MenuBar) ~= 0 then local menu_bar_rect = window:MenuBarRect() menu_bar_rect:ClipWith(window:Rect()) window.DrawList:AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, ImGui.GetColorU32(ImGuiCol.MenuBarBg), (bit32.band(flags, ImGuiWindowFlags.NoTitleBar) ~= 0) and window_rounding or 0.0, ImDrawFlags.RoundCornersTop) if style.FrameBorderSize > 0.0 and menu_bar_rect.Max.y < window.Pos.y + window.Size.y then window.DrawList:AddLineH(menu_bar_rect.Min.x + window_border_size * 0.5, menu_bar_rect.Max.x - window_border_size * 0.5, menu_bar_rect.Max.y, ImGui.GetColorU32(ImGuiCol.Border), style.FrameBorderSize) end end -- Docking: Unhide tab bar (small triangle in the corner), drag from small triangle to quickly undock local node = window.DockNode if window.DockIsActive and node:IsHiddenTabBar() and not node:IsNoTabBar() then local unhide_sz_draw = ImTrunc(g.FontSize * 0.70) local unhide_sz_hit = ImTrunc(g.FontSize * 0.55) local p = node.Pos local r = ImRect(p, p + ImVec2(unhide_sz_hit, unhide_sz_hit)) local unhide_id = window:GetID("#UNHIDE") ImGui.KeepAliveID(unhide_id) local pressed, hovered, held = ImGui.ButtonBehavior(r, unhide_id, ImGuiButtonFlags.FlattenChildren) if pressed then node.WantHiddenTabBarToggle = true elseif held and ImGui.IsMouseDragging(0) then ImGui.StartMouseMovingWindowOrNode(window, node, true) end local col = ImGui.GetColorU32(((held and hovered) or (node.IsFocused and not hovered)) and ImGuiCol.ButtonActive or (hovered and ImGuiCol.ButtonHovered or ImGuiCol.Button)) window.DrawList:AddTriangleFilled(p, p + ImVec2(unhide_sz_draw, 0.0), p + ImVec2(0.0, unhide_sz_draw), col) end if window.ScrollbarX then ImGui.Scrollbar(ImGuiAxis.X) end if window.ScrollbarY then ImGui.Scrollbar(ImGuiAxis.Y) end -- Resize grip(s) if handle_borders_and_resize_grips and (bit32.band(flags, ImGuiWindowFlags.NoResize) == 0) then for resize_grip_n = 1, #ImGuiResizeGripDef do repeat local col = resize_grip_col[resize_grip_n] if bit32.band(col, IM_COL32_A_MASK) == 0 then break end local grip = ImGuiResizeGripDef[resize_grip_n] local corner = ImLerp(window.Pos, window.Pos + window.Size, grip.CornerPosN) local border_inner = IM_ROUND(window_border_size * 0.5) window.DrawList:PathLineTo(corner + grip.InnerDir * ((resize_grip_n % 2 == 0) and ImVec2(border_inner, resize_grip_draw_size) or ImVec2(resize_grip_draw_size, border_inner))) window.DrawList:PathLineTo(corner + grip.InnerDir * ((resize_grip_n % 2 == 0) and ImVec2(resize_grip_draw_size, border_inner) or ImVec2(border_inner, resize_grip_draw_size))) window.DrawList:PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12) window.DrawList:PathFillConvex(col) until true end end if handle_borders_and_resize_grips and not window.DockNodeAsHost then RenderWindowOuterBorders(window) end end window.DC.NavLayerCurrent = ImGuiNavLayer.Main end ImGui.RenderWindowOuterBorders = RenderWindowOuterBorders --- @param window ImGuiWindow --- @param title_bar_rect ImRect --- @param name string --- @param open bool? --- @return bool? local function RenderWindowTitleBarContents(window, title_bar_rect, name, open) local g = GImGui local style = g.Style local flags = window.Flags local has_close_button = (open ~= nil) local has_collapse_button = bit32.band(flags, ImGuiWindowFlags.NoCollapse) == 0 and (style.WindowMenuButtonPosition ~= ImGuiDir.None) local item_flags_backup = g.CurrentItemFlags g.CurrentItemFlags = bit32.bor(g.CurrentItemFlags, ImGuiItemFlags.NoNavDefaultFocus) window.DC.NavLayerCurrent = ImGuiNavLayer.Menu local pad_l = g.Style.FramePadding.x local pad_r = g.Style.FramePadding.x local button_sz = g.FontSize local close_button_pos local collapse_button_pos if has_close_button then close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y) pad_r = pad_r + button_sz + style.ItemInnerSpacing.x end if has_collapse_button and style.WindowMenuButtonPosition == ImGuiDir.Right then collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y) pad_r = pad_r + button_sz + style.ItemInnerSpacing.x end if has_collapse_button and style.WindowMenuButtonPosition == ImGuiDir.Left then collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y) pad_l = pad_l + button_sz + style.ItemInnerSpacing.x end if has_collapse_button then if ImGui.CollapseButton(window:GetID("#COLLAPSE"), collapse_button_pos) then window.WantCollapseToggle = true -- Defer actual collapsing to next frame as we are too far in the Begin() function end end if has_close_button then local backup_item_flags = g.CurrentItemFlags g.CurrentItemFlags = bit32.bor(g.CurrentItemFlags, ImGuiItemFlags.NoFocus) if ImGui.CloseButton(window:GetID("#CLOSE"), close_button_pos) then open = false end g.CurrentItemFlags = backup_item_flags end window.DC.NavLayerCurrent = ImGuiNavLayer.Main g.CurrentItemFlags = item_flags_backup local marker_size_x = (bit32.band(flags, ImGuiWindowFlags.UnsavedDocument) ~= 0) and (button_sz * 0.80) or 0.0 local text_size = ImGui.CalcTextSize(name, nil, true) + ImVec2(marker_size_x, 0.0) if (pad_l > style.FramePadding.x) then pad_l = pad_l + g.Style.ItemInnerSpacing.x end if (pad_r > style.FramePadding.x) then pad_r = pad_r + g.Style.ItemInnerSpacing.x end if (style.WindowTitleAlign.x > 0.0 and style.WindowTitleAlign.x < 1.0) then local centerness = ImSaturate(1.0 - ImFabs(style.WindowTitleAlign.x - 0.5) * 2.0) local pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect:GetWidth() - pad_l - pad_r - text_size.x) pad_l = ImMax(pad_l, pad_extend * centerness) pad_r = ImMax(pad_r, pad_extend * centerness) end local layout_r = ImRect(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y) local clip_r = ImRect(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y) if bit32.band(flags, ImGuiWindowFlags.UnsavedDocument) ~= 0 then local marker_pos = ImVec2() marker_pos.x = ImClamp(layout_r.Min.x + (layout_r:GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x) marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5 if marker_pos.x > layout_r.Min.x then ImGui.RenderBullet(window.DrawList, marker_pos, ImGui.GetColorU32(ImGuiCol.UnsavedMarker)) clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - math.floor(marker_size_x * 0.5)) end end ImGui.RenderTextClipped(layout_r.Min, layout_r.Max, name, nil, text_size, style.WindowTitleAlign, clip_r) return open end --- @param window ImGuiWindow --- @param flags ImGuiWindowFlags --- @param parent_window? ImGuiWindow function ImGui.UpdateWindowParentAndRootLinks(window, flags, parent_window) window.ParentWindow = parent_window window.RootWindow = window window.RootWindowPopupTree = window window.RootWindowDockTree = window window.RootWindowForTitleBarHighlight = window window.RootWindowForNav = window if parent_window and (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.Tooltip) == 0) then window.RootWindowDockTree = parent_window.RootWindowDockTree if not window.DockIsActive and (bit32.band(parent_window.Flags, ImGuiWindowFlags.DockNodeHost) == 0) then window.RootWindow = parent_window.RootWindow end end if parent_window and (bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0) then window.RootWindowPopupTree = parent_window.RootWindowPopupTree end if parent_window and (bit32.band(flags, ImGuiWindowFlags.Modal) == 0) and (bit32.band(flags, bit32.bor(ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0) then window.RootWindowForTitleBarHighlight = parent_window.RootWindowForTitleBarHighlight end while bit32.band(window.RootWindowForNav.ChildFlags, ImGuiChildFlags.NavFlattened) ~= 0 do IM_ASSERT(window.RootWindowForNav.ParentWindow ~= nil) window.RootWindowForNav = window.RootWindowForNav.ParentWindow end end -- [EXPERIMENTAL] Called by Begin(). NextWindowData is valid at this point. -- This is designed as a toy/test-bed for --- @param window ImGuiWindow function ImGui.UpdateWindowSkipRefresh(window) local g = GImGui window.SkipRefresh = false if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasRefreshPolicy) == 0 then return end if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.TryToAvoidRefresh) ~= 0 then -- FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused. if window.Appearing then -- If currently appearing return end if window.Hidden then -- If was hidden (previous frame) return end if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.RefreshOnHover) ~= 0 and g.HoveredWindow then if window.RootWindow == g.HoveredWindow.RootWindow or ImGui.IsWindowWithinBeginStackOf(g.HoveredWindow.RootWindow, window) then return end end if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.RefreshOnFocus) ~= 0 and g.NavWindow then if window.RootWindow == g.NavWindow.RootWindow or ImGui.IsWindowWithinBeginStackOf(g.NavWindow.RootWindow, window) then return end end window.DrawList = nil window.SkipRefresh = true end end --- @param window ImGuiWindow local function SetWindowActiveForSkipRefresh(window) window.Active = true for _, child in window.DC.ChildWindows:iter() do if not child.Hidden then child.Active = true child.SkipRefresh = true SetWindowActiveForSkipRefresh(child) end end end --- @param window ImGuiWindow? local function SetCurrentWindow(window) local g = GImGui --- @diagnostic disable-next-line g.CurrentWindow = window g.CurrentTable = (window and window.DC.CurrentTableIdx ~= -1) and g.Tables:GetByIndex(window.DC.CurrentTableIdx) or nil if window then if bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ~= 0 then local viewport = window.Viewport g.FontRasterizerDensity = (viewport.FramebufferScale.x ~= 0.0) and viewport.FramebufferScale.x or g.IO.DisplayFramebufferScale.x end local backup_skip_items = window.SkipItems window.SkipItems = false ImGui.UpdateCurrentFontSize(0.0) window.SkipItems = backup_skip_items ImGui.NavUpdateCurrentWindowIsScrollPushableX() end end -- TODO: function ImGui.GcCompactTransientMiscBuffers() local g = GImGui g.ItemFlagsStack:clear() g.GroupStack:clear() g.InputTextLineIndex:clear() ImGui.TableGcCompactSettings() for _, atlas in g.FontAtlases:iter() do atlas:CompactCache() end end --- @param window ImGuiWindow function ImGui.GcCompactTransientWindowBuffers(window) window.MemoryCompacted = true window.MemoryDrawListIdxCapacity = ImMin(math.floor(window.DrawList.IdxBuffer.Size * 1.05), window.DrawList.IdxBuffer.Capacity) window.MemoryDrawListVtxCapacity = ImMin(math.floor(window.DrawList.VtxBuffer.Size * 1.05), window.DrawList.VtxBuffer.Capacity) window.IDStack:clear() window.DrawList:_ClearFreeMemory() window.DC.ChildWindows:clear() window.DC.ItemWidthStack:clear() window.DC.TextWrapPosStack:clear() end --- @param window ImGuiWindow function ImGui.GcAwakeTransientWindowBuffers(window) window.MemoryCompacted = false window.DrawList.IdxBuffer:reserve(window.MemoryDrawListIdxCapacity) window.DrawList.VtxBuffer:reserve(window.MemoryDrawListVtxCapacity) window.MemoryDrawListIdxCapacity = 0 window.MemoryDrawListVtxCapacity = 0 end function ImGui.GetWindowWidth() local window = GImGui.CurrentWindow return window.Size.x end --- @param window ImGuiWindow --- @param pos ImVec2 --- @param cond? ImGuiCond function ImGui.SetWindowPos(window, pos, cond) -- Overloads: SetWindowPos(pos, cond) / SetWindowPos(name, pos, cond) / SetWindowPos(window, pos, cond) if type(window) == "string" then window = ImGui.FindWindowByName(window) if window == nil then return end elseif window.SetWindowPosAllowFlags == nil then window, pos, cond = ImGui.GetCurrentWindowRead(), window, pos end if cond == nil then cond = 0 end if (cond ~= 0) and (bit32.band(window.SetWindowPosAllowFlags, cond) == 0) then return end IM_ASSERT(cond == 0 or ImIsPowerOfTwo(cond)) window.SetWindowPosAllowFlags = bit32.band(window.SetWindowPosAllowFlags, bit32.bnot(bit32.bor(ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing))) ImVec2_Copy(window.SetWindowPosVal, ImVec2(FLT_MAX, FLT_MAX)) local old_pos = ImVec2() ImVec2_Copy(old_pos, window.Pos) window.Pos.x = ImTrunc(pos.x) window.Pos.y = ImTrunc(pos.y) local offset = window.Pos - old_pos if offset.x == 0 and offset.y == 0 then return end ImGui.MarkIniSettingsDirty(window) ImVec2_Copy(window.DC.CursorPos, window.DC.CursorPos + offset) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorMaxPos + offset) ImVec2_Copy(window.DC.IdealMaxPos, window.DC.IdealMaxPos + offset) ImVec2_Copy(window.DC.CursorStartPos, window.DC.CursorStartPos + offset) end --- @param window ImGuiWindow --- @param size ImVec2 --- @param cond? ImGuiCond function ImGui.SetWindowSize(window, size, cond) -- Overloads: SetWindowSize(size, cond) / SetWindowSize(name, size, cond) / SetWindowSize(window, size, cond) if type(window) == "string" then window = ImGui.FindWindowByName(window) if window == nil then return end elseif window.SetWindowSizeAllowFlags == nil then window, size, cond = GImGui.CurrentWindow, window, size end if cond == nil then cond = 0 end if ((cond ~= 0) and bit32.band(window.SetWindowSizeAllowFlags, cond) == 0) then return end IM_ASSERT(cond == 0 or ImIsPowerOfTwo(cond)) window.SetWindowSizeAllowFlags = bit32.band(window.SetWindowSizeAllowFlags, bit32.bnot(bit32.bor(ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing))) if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0 or window.Appearing or bit32.band(window.ChildFlags, ImGuiChildFlags.AlwaysAutoResize) ~= 0 then window.AutoFitFramesX = (size.x <= 0.0) and 2 or 0 end if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0 or window.Appearing or bit32.band(window.ChildFlags, ImGuiChildFlags.AlwaysAutoResize) ~= 0 then window.AutoFitFramesY = (size.y <= 0.0) and 2 or 0 end local old_size_x, old_size_y = window.SizeFull.x, window.SizeFull.y if size.x <= 0.0 then window.AutoFitOnlyGrows = false else window.SizeFull.x = IM_TRUNC(size.x) end if size.y <= 0.0 then window.AutoFitOnlyGrows = false else window.SizeFull.y = IM_TRUNC(size.y) end if old_size_x ~= window.SizeFull.x or old_size_y ~= window.SizeFull.y then ImGui.MarkIniSettingsDirty(window) end end --- Overloads: SetWindowCollapsed(collapsed, cond) / SetWindowCollapsed(name, collapsed, cond) / SetWindowCollapsed(window, collapsed, cond) function ImGui.SetWindowCollapsed(window, collapsed, cond) if type(window) == "string" then window = ImGui.FindWindowByName(window) if window == nil then return end elseif type(window) == "boolean" then window, collapsed, cond = GImGui.CurrentWindow, window, collapsed end if cond == nil then cond = 0 end if cond ~= 0 and bit32.band(window.SetWindowCollapsedAllowFlags, cond) == 0 then return end window.SetWindowCollapsedAllowFlags = bit32.band(window.SetWindowCollapsedAllowFlags, bit32.bnot(bit32.bor(ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing))) -- Queue applying in Begin() if window.WantCollapseToggle then window.Collapsed = not window.Collapsed end window.WantCollapseToggle = (window.Collapsed ~= collapsed) end --- @param window ImGuiWindow --- @param pos ImVec2 --- @param size ImVec2 function ImGui.SetWindowHitTestHole(window, pos, size) IM_ASSERT(window.HitTestHoleSize.x == 0) -- We don't support multiple holes/hit test filters window.HitTestHoleSize = ImVec2(math.floor(size.x), math.floor(size.y)) window.HitTestHoleOffset = ImVec2(math.floor(pos.x - window.Pos.x), math.floor(pos.y - window.Pos.y)) end function ImGui.IsWindowCollapsed() return ImGui.GetCurrentWindowRead().Collapsed end function ImGui.IsWindowAppearing() return ImGui.GetCurrentWindowRead().Appearing end function ImGui.GetWindowHeight() return GImGui.CurrentWindow.Size.y end --- @return ImVec2 # Ref, do not modify function ImGui.GetWindowPos() return GImGui.CurrentWindow.Pos end --- @return ImVec2 # Ref, do not modify function ImGui.GetWindowSize() return ImGui.GetCurrentWindowRead().Size end -- Overloads: SetWindowFocus() / SetWindowFocus(name). Passing nil name removes focus. --- @param name? string function ImGui.SetWindowFocus(...) if select("#", ...) == 0 then ImGui.FocusWindow(GImGui.CurrentWindow) return end local name = ... if name then local window = ImGui.FindWindowByName(name) if window then ImGui.FocusWindow(window) end else ImGui.FocusWindow(nil) end end --- @param window ImGuiWindow function ImGui.SetWindowHiddenAndSkipItemsForCurrentFrame(window) window.Hidden = true window.SkipItems = true window.HiddenFramesCanSkipItems = 1 end --- @param pos ImVec2 --- @param cond? ImGuiCond --- @param pivot? ImVec2 function ImGui.SetNextWindowPos(pos, cond, pivot) if cond == nil then cond = 0 end if pivot == nil then pivot = ImVec2(0, 0) end local g = GImGui IM_ASSERT(cond == 0 or ImIsPowerOfTwo(cond)) g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasPos) ImVec2_Copy(g.NextWindowData.PosVal, pos) ImVec2_Copy(g.NextWindowData.PosPivotVal, pivot) g.NextWindowData.PosCond = (cond ~= 0) and cond or ImGuiCond.Always g.NextWindowData.PosUndock = true end --- @param size ImVec2 --- @param cond? ImGuiCond function ImGui.SetNextWindowSize(size, cond) if cond == nil then cond = 0 end local g = GImGui IM_ASSERT(cond == 0 or ImIsPowerOfTwo(cond)) g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) ImVec2_Copy(g.NextWindowData.SizeVal, size) g.NextWindowData.SizeCond = (cond ~= 0) and cond or ImGuiCond.Always end -- For each axis: -- - Use 0.0f as min or FLT_MAX as max if you don't want limits, e.g. size_min = (500.0f, 0.0f), size_max = (FLT_MAX, FLT_MAX) sets a minimum width. -- - Use -1 for both min and max of same axis to preserve current size which itself is a constraint. -- - See "Demo->Examples->Constrained-resizing window" for examples. --- @param size_min ImVec2 --- @param size_max ImVec2 --- @param custom_callback? function --- @param custom_callback_user_data? any function ImGui.SetNextWindowSizeConstraints(size_min, size_max, custom_callback, custom_callback_user_data) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSizeConstraint) g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max) g.NextWindowData.SizeCallback = custom_callback g.NextWindowData.SizeCallbackUserData = custom_callback_user_data end --- @param alpha float function ImGui.SetNextWindowBgAlpha(alpha) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasBgAlpha) g.NextWindowData.BgAlphaVal = alpha end function ImGui.GetWindowDrawList() local window = ImGui.GetCurrentWindow() return window.DrawList end function ImGui.GetFont() return GImGui.Font end function ImGui.GetFontSize() return GImGui.FontSize end --- @return ImVec2 function ImGui.GetFontTexUvWhitePixel() return GImGui.DrawListSharedData.TexUvWhitePixel end -- This is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations. -- FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version if needed? function ImGui.SetActiveIdUsingAllKeyboardKeys() local g = GImGui IM_ASSERT(g.ActiveId ~= 0) g.ActiveIdUsingNavDirMask = (bit32.lshift(1, ImGuiDir.COUNT) - 1) g.ActiveIdUsingAllKeyboardKeys = true ImGui.NavMoveRequestCancel() end --- @return ImVec2 # Ref function ImGui.GetItemRectMin() local g = GImGui return g.LastItemData.Rect.Min end --- @return ImVec2 # Ref function ImGui.GetItemRectMax() local g = GImGui return g.LastItemData.Rect.Max end --- @param name string --- @param id ImGuiID --- @param size_arg ImVec2 --- @param child_flags ImGuiChildFlags --- @param window_flags ImGuiWindowFlags function ImGui.BeginChildEx(name, id, size_arg, child_flags, window_flags) local g = GImGui local parent_window = g.CurrentWindow IM_ASSERT(id ~= 0) if child_flags == nil then child_flags = 0 end if window_flags == nil then window_flags = 0 end if size_arg == nil then size_arg = ImVec2(0, 0) end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasChildFlags) ~= 0 then child_flags = bit32.band(bit32.bor(child_flags, g.NextWindowData.ChildFlagsSet), bit32.bnot(g.NextWindowData.ChildFlagsClear)) end -- Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument local ImGuiChildFlags_SupportedMask_ = bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.AlwaysUseWindowPadding, ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY, ImGuiChildFlags.AutoResizeX, ImGuiChildFlags.AutoResizeY, ImGuiChildFlags.AlwaysAutoResize, ImGuiChildFlags.FrameStyle, ImGuiChildFlags.NavFlattened) -- IM_UNUSED(ImGuiChildFlags_SupportedMask_) IM_ASSERT(bit32.band(child_flags, bit32.bnot(ImGuiChildFlags_SupportedMask_)) == 0, "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?") IM_ASSERT(bit32.band(window_flags, ImGuiWindowFlags.AlwaysAutoResize) == 0, "Cannot specify ImGuiWindowFlags.AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags.AlwaysAutoResize!") if bit32.band(child_flags, ImGuiChildFlags.AlwaysAutoResize) ~= 0 then IM_ASSERT(bit32.band(child_flags, bit32.bor(ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY)) == 0, "Cannot use ImGuiChildFlags.ResizeX or ImGuiChildFlags.ResizeY with ImGuiChildFlags.AlwaysAutoResize!") IM_ASSERT(bit32.band(child_flags, bit32.bor(ImGuiChildFlags.AutoResizeX, ImGuiChildFlags.AutoResizeY)) ~= 0, "Must use ImGuiChildFlags.AutoResizeX or ImGuiChildFlags.AutoResizeY with ImGuiChildFlags.AlwaysAutoResize!") end if bit32.band(child_flags, ImGuiChildFlags.AutoResizeX) ~= 0 then child_flags = bit32.band(child_flags, bit32.bnot(ImGuiChildFlags.ResizeX)) end if bit32.band(child_flags, ImGuiChildFlags.AutoResizeY) ~= 0 then child_flags = bit32.band(child_flags, bit32.bnot(ImGuiChildFlags.ResizeY)) end -- Set window flags window_flags = bit32.bor(window_flags, ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoDocking) window_flags = bit32.bor(window_flags, bit32.band(parent_window.Flags, ImGuiWindowFlags.NoMove)) -- Inherit the NoMove flag if bit32.band(child_flags, bit32.bor(ImGuiChildFlags.AutoResizeX, ImGuiChildFlags.AutoResizeY, ImGuiChildFlags.AlwaysAutoResize)) ~= 0 then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.AlwaysAutoResize) end if bit32.band(child_flags, bit32.bor(ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY)) == 0 then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoSavedSettings) end -- Special framed style if bit32.band(child_flags, ImGuiChildFlags.FrameStyle) ~= 0 then ImGui.PushStyleColor(ImGuiCol.ChildBg, g.Style.Colors[ImGuiCol.FrameBg]) ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, g.Style.FrameRounding) ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, g.Style.FrameBorderSize) ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, g.Style.FramePadding) child_flags = bit32.bor(child_flags, ImGuiChildFlags.Borders, ImGuiChildFlags.AlwaysUseWindowPadding) window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoMove) end -- Forward size -- Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags.ResizeXXX is set. -- (the alternative would to store conditional flags per axis, which is possible but more code) local size_avail = ImGui.GetContentRegionAvail() local size_default = ImVec2((bit32.band(child_flags, ImGuiChildFlags.AutoResizeX) ~= 0) and 0.0 or size_avail.x, (bit32.band(child_flags, ImGuiChildFlags.AutoResizeY) ~= 0) and 0.0 or size_avail.y) local size = ImGui.CalcItemSize(size_arg, size_default.x, size_default.y) -- A SetNextWindowSize() call always has priority (#8020) -- (since the code in Begin() never supported SizeVal==0.0f aka auto-resize via SetNextWindowSize() call, we don't support it here for now) -- FIXME: We only support ImGuiCond_Always in this path. Supporting other paths would requires to obtain window pointer. if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) ~= 0 and bit32.band(g.NextWindowData.SizeCond, ImGuiCond.Always) ~= 0 then if g.NextWindowData.SizeVal.x > 0.0 then size.x = g.NextWindowData.SizeVal.x child_flags = bit32.band(child_flags, bit32.bnot(ImGuiChildFlags.ResizeX)) end if g.NextWindowData.SizeVal.y > 0.0 then size.y = g.NextWindowData.SizeVal.y child_flags = bit32.band(child_flags, bit32.bnot(ImGuiChildFlags.ResizeY)) end end ImGui.SetNextWindowSize(size) ImGui.SetNextWindowChildFlags(child_flags, true) -- Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. -- FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround. -- e.g. "ParentName###ParentIdentifier/ChildName###ChildIdentifier" would get hashed incorrectly by ImHashStr(), trailing _%08X somehow fixes it. local temp_window_name if name then temp_window_name = ImFormatString("%s/%s_%08X", parent_window.Name, name, id) else temp_window_name = ImFormatString("%s/%08X", parent_window.Name, id) end -- Set style local backup_border_size = g.Style.ChildBorderSize if bit32.band(child_flags, ImGuiChildFlags.Borders) == 0 then g.Style.ChildBorderSize = 0.0 end -- Begin into window local _, ret = ImGui.Begin(temp_window_name, nil, window_flags) -- Restore style g.Style.ChildBorderSize = backup_border_size if bit32.band(child_flags, ImGuiChildFlags.FrameStyle) ~= 0 then ImGui.PopStyleVar(3) ImGui.PopStyleColor() end local child_window = g.CurrentWindow child_window.ChildId = id -- Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. -- While this is not really documented/defined, it seems that the expected thing to do. if child_window.BeginCount == 1 then ImVec2_Copy(parent_window.DC.CursorPos, child_window.Pos) end -- Process navigation-in immediately so NavInit can run on first frame -- Can enter a child if (A) it has navigable items or (B) it can be scrolled. local temp_id_for_activation = ImHashStr("##Child", nil, id) if g.ActiveId == temp_id_for_activation then ImGui.ClearActiveID() end if g.NavActivateId == id and bit32.band(child_flags, ImGuiChildFlags.NavFlattened) == 0 and (child_window.DC.NavLayersActiveMask ~= 0 or child_window.DC.NavWindowHasScrollY) then ImGui.FocusWindow(child_window) ImGui.NavInitWindow(child_window, false) ImGui.SetActiveID(temp_id_for_activation, child_window) -- Steal ActiveId with another arbitrary id so that key-press won't activate child item g.ActiveIdSource = g.NavInputSource end return ret end -- Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'. -- `true` is accepted as ImGuiChildFlags.Borders for legacy code. --- @param str_id_or_id string|ImGuiID --- @param size_arg? ImVec2 --- @param child_flags? ImGuiChildFlags|bool --- @param window_flags? ImGuiWindowFlags --- @return bool # visible (always call EndChild()!) function ImGui.BeginChild(str_id_or_id, size_arg, child_flags, window_flags) if child_flags == true then child_flags = ImGuiChildFlags.Borders elseif not child_flags then child_flags = 0 end if type(str_id_or_id) == "number" then return ImGui.BeginChildEx(nil, str_id_or_id, size_arg, child_flags, window_flags) end local id = ImGui.GetCurrentWindow():GetID(str_id_or_id) return ImGui.BeginChildEx(str_id_or_id, id, size_arg, child_flags, window_flags) end --- @param window ImGuiWindow --- @param rect ImRect function ImGui.SetLastItemDataForChildWindowItem(window, rect) local g = GImGui ImGui.SetLastItemData(window.ChildId, g.CurrentItemFlags, window.DC.ChildItemStatusFlags or 0, rect) end function ImGui.EndChild() local g = GImGui local child_window = g.CurrentWindow local backup_within_end_child_id = g.WithinEndChildID IM_ASSERT(bit32.band(child_window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0) -- Mismatched BeginChild()/EndChild() calls g.WithinEndChildID = child_window.ID local child_size = ImVec2(child_window.Size.x, child_window.Size.y) ImGui.End() if child_window.BeginCount == 1 then local parent_window = g.CurrentWindow local bb = ImRect(parent_window.DC.CursorPos, parent_window.DC.CursorPos + child_size) ImGui.ItemSize(child_size) local nav_flattened = bit32.band(child_window.ChildFlags, ImGuiChildFlags.NavFlattened) ~= 0 if (child_window.DC.NavLayersActiveMask ~= 0 or child_window.DC.NavWindowHasScrollY) and not nav_flattened then ImGui.ItemAdd(bb, child_window.ChildId) ImGui.RenderNavCursor(bb, child_window.ChildId) -- When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) if child_window.DC.NavLayersActiveMask == 0 and child_window == g.NavWindow then ImGui.RenderNavCursor(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavRenderCursorFlags.Compact) end else -- Not navigable into ImGui.ItemAdd(bb, child_window.ChildId, nil, ImGuiItemFlags.NoNav) -- But when flattened we directly reach items, adjust active layer mask accordingly if nav_flattened then parent_window.DC.NavLayersActiveMaskNext = bit32.bor(parent_window.DC.NavLayersActiveMaskNext, child_window.DC.NavLayersActiveMaskNext) end end if g.HoveredWindow == child_window then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow) end child_window.DC.ChildItemStatusFlags = g.LastItemData.StatusFlags else ImGui.SetLastItemDataForChildWindowItem(child_window, child_window:Rect()) end g.WithinEndChildID = backup_within_end_child_id g.LogLinePosY = -FLT_MAX -- To enforce a carriage return end --- @param flags ImGuiChildFlags --- @param enabled bool function ImGui.SetNextWindowChildFlags(flags, enabled) local g = GImGui local nwd = g.NextWindowData if bit32.band(nwd.HasFlags, ImGuiNextWindowDataFlags.HasChildFlags) == 0 then nwd.ChildFlagsSet = 0; nwd.ChildFlagsClear = 0 end if enabled then nwd.ChildFlagsSet = bit32.bor(nwd.ChildFlagsSet, flags) nwd.ChildFlagsClear = bit32.band(nwd.ChildFlagsClear, bit32.bnot(flags)) else nwd.ChildFlagsSet = bit32.band(nwd.ChildFlagsSet, bit32.bnot(flags)) nwd.ChildFlagsClear = bit32.bor(nwd.ChildFlagsClear, flags) end nwd.HasFlags = bit32.bor(nwd.HasFlags, ImGuiNextWindowDataFlags.HasChildFlags) end --- @param flags ImGuiWindowFlags --- @param enabled bool function ImGui.SetNextWindowFlags(flags, enabled) local g = GImGui local nwd = g.NextWindowData if bit32.band(nwd.HasFlags, ImGuiNextWindowDataFlags.HasWindowFlags) == 0 then nwd.WindowFlagsSet = 0; nwd.WindowFlagsClear = 0 end if enabled then nwd.WindowFlagsSet = bit32.bor(nwd.WindowFlagsSet, flags) nwd.WindowFlagsClear = bit32.band(nwd.WindowFlagsClear, bit32.bnot(flags)) else nwd.WindowFlagsSet = bit32.band(nwd.WindowFlagsSet, bit32.bnot(flags)) nwd.WindowFlagsClear = bit32.bor(nwd.WindowFlagsClear, flags) end nwd.HasFlags = bit32.bor(nwd.HasFlags, ImGuiNextWindowDataFlags.HasWindowFlags) end -- Content size = inner scrollable rectangle, padded with WindowPadding. --- @param size ImVec2 function ImGui.SetNextWindowContentSize(size) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasContentSize) ImVec2_CopyV(g.NextWindowData.ContentSizeVal, ImTrunc(size.x), ImTrunc(size.y)) end --- @param scroll ImVec2 function ImGui.SetNextWindowScroll(scroll) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasScroll) ImVec2_Copy(g.NextWindowData.ScrollVal, scroll) end --- @param collapsed bool --- @param cond? ImGuiCond function ImGui.SetNextWindowCollapsed(collapsed, cond) if cond == nil then cond = 0 end local g = GImGui IM_ASSERT(cond == 0 or ImIsPowerOfTwo(cond)) g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasCollapsed) g.NextWindowData.CollapsedVal = collapsed g.NextWindowData.CollapsedCond = (cond ~= 0) and cond or ImGuiCond.Always end function ImGui.SetNextWindowFocus() local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasFocus) end --- @param id ImGuiID function ImGui.SetNextWindowViewport(id) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasViewport) g.NextWindowData.ViewportId = id end --- @param window_class ImGuiWindowClass function ImGui.SetNextWindowClass(window_class) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasWindowClass) local wc = ImGuiWindowClass() for k, v in pairs(window_class) do wc[k] = v end -- C++ copies the struct g.NextWindowData.WindowClass = wc end -- This is experimental and meant to be a toy for exploring a future/wider range of features. --- @param flags ImGuiWindowRefreshFlags function ImGui.SetNextWindowRefreshPolicy(flags) local g = GImGui g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasRefreshPolicy) g.NextWindowData.RefreshFlagsVal = flags end function ImGui.GetWindowDpiScale() return 1.0 -- Roblox: single viewport, no DPI scaling end function ImGui.GetWindowViewport() local g = GImGui return g.CurrentViewport or ImGui.GetMainViewport() end -- Prefer using PushFont(nil, style.FontSizeBase * factor), or use style.FontScaleMain to scale all windows. --- @param scale float function ImGui.SetWindowFontScale(scale) IM_ASSERT(scale > 0.0) local window = ImGui.GetCurrentWindow() window.FontWindowScale = scale ImGui.UpdateCurrentFontSize(0.0) end --- @param window ImGuiWindow function ImGui.StartMouseMovingWindow(window) local g = GImGui ImGui.FocusWindow(window) ImGui.SetActiveID(window.MoveId, window) if (g.IO.ConfigNavCursorVisibleAuto) then g.NavCursorVisible = false end g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window.RootWindowDockTree.Pos g.ActiveIdNoClearOnFocusLoss = true ImGui.SetActiveIdUsingAllKeyboardKeys() local can_move_window = true if bit32.band(window.Flags, ImGuiWindowFlags.NoMove) ~= 0 or bit32.band(window.RootWindowDockTree.Flags, ImGuiWindowFlags.NoMove) ~= 0 then can_move_window = false end local node = window.DockNodeAsHost if node and node.VisibleWindow and bit32.band(node.VisibleWindow.Flags, ImGuiWindowFlags.NoMove) ~= 0 then can_move_window = false end if can_move_window then g.MovingWindow = window end end function ImGui.UpdateMouseMovingWindowNewFrame() local g = GImGui if g.MovingWindow then ImGui.KeepAliveID(g.ActiveId) IM_ASSERT(g.MovingWindow and g.MovingWindow.RootWindowDockTree) local moving_window = g.MovingWindow.RootWindowDockTree local window_disappeared = (not moving_window.WasActive and not moving_window.Active) if g.IO.MouseDown[0] and ImGui.IsMousePosValid(g.IO.MousePos) and not window_disappeared then local pos = g.IO.MousePos - g.ActiveIdClickOffset if moving_window.Pos.x ~= pos.x or moving_window.Pos.y ~= pos.y then ImGui.SetWindowPos(moving_window, pos, ImGuiCond.Always) if moving_window.Viewport and moving_window.ViewportOwned then -- Synchronize viewport immediately because some overlays may relies on clipping rectangle before we Begin() into the window. ImVec2_Copy(moving_window.Viewport.Pos, pos) moving_window.Viewport:UpdateWorkRect() end end ImGui.FocusWindow(g.MovingWindow) else ImGui.StopMouseMovingWindow() ImGui.ClearActiveID() end else if (g.ActiveIdWindow and g.ActiveIdWindow.MoveId == g.ActiveId) then ImGui.KeepAliveID(g.ActiveId) if not g.IO.MouseDown[0] then ImGui.ClearActiveID() end end end end function ImGui.GetDrawListSharedData() return GImGui.DrawListSharedData end --- @param id ImGuiID --- @param popup_flags ImGuiPopupFlags function ImGui.IsPopupOpen(id, popup_flags) local g = GImGui if popup_flags == nil then popup_flags = 0 end if type(id) == "string" then -- str_id overload: with AnyPopupId the id must be 0, otherwise it is hashed with the current window's ID stack id = (bit32.band(popup_flags, ImGuiPopupFlags.AnyPopupId) ~= 0) and 0 or g.CurrentWindow:GetID(id) end if bit32.band(popup_flags, ImGuiPopupFlags.AnyPopupId) ~= 0 then -- Return true if any popup is open at the current BeginPopup() level of the popup stack -- This may be used to e.g. test for another popups already opened to handle popups priorities at the same level. IM_ASSERT(id == 0) if bit32.band(popup_flags, ImGuiPopupFlags.AnyPopupLevel) ~= 0 then return g.OpenPopupStack.Size > 0 else return g.OpenPopupStack.Size > g.BeginPopupStack.Size end else if bit32.band(popup_flags, ImGuiPopupFlags.AnyPopupLevel) ~= 0 then -- Return true if the popup is open anywhere in the popup stack for n = 1, g.OpenPopupStack.Size do if g.OpenPopupStack.Data[n].PopupId == id then return true end end return false else -- Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query) return g.OpenPopupStack.Size > g.BeginPopupStack.Size and g.OpenPopupStack.Data[g.BeginPopupStack.Size + 1].PopupId == id end end end --- @return ImGuiWindow? function ImGui.GetTopMostPopupModal() local g = GImGui for n = g.OpenPopupStack.Size, 1, -1 do local popup = g.OpenPopupStack.Data[n].Window if popup then if bit32.band(popup.Flags, ImGuiWindowFlags.Modal) ~= 0 then return popup end end end return nil end function ImGui.UpdateMouseMovingWindowEndFrame() local g = GImGui if g.ActiveId ~= 0 or (g.HoveredId ~= 0 and not g.HoveredIdIsDisabled) then return end if g.NavWindow and g.NavWindow.Appearing then return end local hovered_window = g.HoveredWindow if ImGui.IsMouseClickedEx(0, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner) then local hovered_root if hovered_window then hovered_root = hovered_window.RootWindow else hovered_root = nil end local is_closed_popup = hovered_root and (bit32.band(hovered_root.Flags, ImGuiWindowFlags.Popup) ~= 0) and not ImGui.IsPopupOpen(hovered_root.PopupId, ImGuiPopupFlags.AnyPopupLevel) local is_queued_focus_request = g.NavMoveSubmitted and (bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.FocusApi) ~= 0) if hovered_window ~= nil and not is_closed_popup and not is_queued_focus_request then ImGui.StartMouseMovingWindow(hovered_window) -- Cancel moving if clicked outside of title bar if bit32.band(hovered_window.BgClickFlags, ImGuiWindowBgClickFlags.Move) == 0 then -- set by io.ConfigWindowsMoveFromTitleBarOnly if bit32.band(hovered_root.Flags, ImGuiWindowFlags.NoTitleBar) == 0 then if not hovered_root:TitleBarRect():Contains(g.IO.MouseClickedPos[0]) then g.MovingWindow = nil end end end -- Cancel moving if clicked over an item which was disabled or inhibited by popups -- (when g.HoveredIdIsDisabled == true && g.HoveredId == 0 we are inhibited by popups, when g.HoveredIdIsDisabled == true && g.HoveredId != 0 we are over a disabled item) if g.HoveredIdIsDisabled then g.MovingWindow = nil g.ActiveIdDisabledId = g.HoveredId end elseif hovered_window == nil and g.NavWindow ~= nil then ImGui.FocusWindow(nil, ImGuiFocusRequestFlags.UnlessBelowModal) end end -- With right mouse button we close popups without changing focus based on where the mouse is aimed -- Instead, focus will be restored to the window under the bottom-most closed popup. -- (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) if g.HoveredId == 0 and ImGui.IsMouseClickedEx(1, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner) then -- Find the top-most window between HoveredWindow and the top-most Modal Window. -- This is where we can trim the popup stack. local modal = ImGui.GetTopMostPopupModal() local hovered_window_above_modal = hovered_window and (modal == nil or ImGui.IsWindowAbove(hovered_window, modal)) ImGui.ClosePopupsOverWindow(hovered_window_above_modal and hovered_window or modal, true) end end --- @param window ImGuiWindow --- @param delta ImVec2 function ImGui.TranslateWindow(window, delta) ImVec2_Copy(window.Pos, window.Pos + delta) window.ClipRect:Translate(delta) window.OuterRectClipped:Translate(delta) window.InnerRect:Translate(delta) ImVec2_Copy(window.DC.CursorPos, window.DC.CursorPos + delta) ImVec2_Copy(window.DC.CursorStartPos, window.DC.CursorStartPos + delta) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorMaxPos + delta) ImVec2_Copy(window.DC.IdealMaxPos, window.DC.IdealMaxPos + delta) end --- ImGui::FindWindowByID function ImGui.FindWindowByID(id) local g = GImGui if not g then return end return g.WindowsById[id] end --- @param name string --- @return ImGuiWindow? function ImGui.FindWindowByName(name) local id = ImHashStr(name) return ImGui.FindWindowByID(id) end --- Push a new Dear ImGui window to add widgets to. --- - Passing a non-nil `open` displays a close button on the upper-right corner of the window --- @param name string --- @param open? bool --- @param flags? ImGuiWindowFlags --- @return bool is_open # The updated `open` passed in --- @return bool no_skip_items # You always need to call `ImGui.End()` even if false is returned function ImGui.Begin(name, open, flags) if flags == nil then flags = 0 end local g = GImGui local style = g.Style IM_ASSERT(name ~= nil and name ~= "") IM_ASSERT(g.WithinFrameScope) IM_ASSERT(g.FrameCountEnded ~= g.FrameCount) local window = ImGui.FindWindowByName(name) local window_just_created = (window == nil) if window_just_created then window = CreateNewWindow(name, flags) --- @cast window ImGuiWindow end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasWindowFlags) ~= 0 then flags = bit32.band(bit32.bor(flags, g.NextWindowData.WindowFlagsSet), bit32.bnot(g.NextWindowData.WindowFlagsClear)) end -- Automatically disable manual moving/resizing when NoInputs is set if bit32.band(flags, ImGuiWindowFlags.NoInputs) == ImGuiWindowFlags.NoInputs then flags = bit32.bor(flags, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize) end local current_frame = g.FrameCount local first_begin_of_the_frame = (window.LastFrameActive ~= current_frame) window.IsFallbackWindow = (g.CurrentWindowStack.Size == 0 and g.WithinFrameScopeWithImplicitWindow) local window_just_activated_by_user = (window.LastFrameActive < (current_frame - 1)) if bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0 then local popup_ref = g.OpenPopupStack.Data[g.BeginPopupStack.Size + 1] window_just_activated_by_user = window_just_activated_by_user or (window.PopupId ~= popup_ref.PopupId) -- We recycle popups so treat window as activated if popup id changed window_just_activated_by_user = window_just_activated_by_user or (window ~= popup_ref.Window) end -- Update Flags, LastFrameActive, BeginOrderXXX fields local window_was_appearing = window.Appearing if first_begin_of_the_frame then ImGui.UpdateWindowInFocusOrderList(window, window_just_created, flags) window.Appearing = window_just_activated_by_user if (window.Appearing) then SetWindowConditionAllowFlags(window, ImGuiCond.Appearing, true) end window.FlagsPreviousFrame = window.Flags window.Flags = flags window.ChildFlags = (bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasChildFlags) ~= 0) and g.NextWindowData.ChildFlagsSet or 0 window.LastFrameActive = current_frame window.LastTimeActive = g.Time window.BeginOrderWithinParent = 0 window.BeginOrderWithinContext = g.WindowsActiveCount g.WindowsActiveCount = g.WindowsActiveCount + 1 else flags = window.Flags end -- Docking -- (NB: during the frame dock nodes are created, it is possible that (window->DockIsActive == false) even though (window->DockNode->Windows.Size > 1) IM_ASSERT(window.DockNode == nil or window.DockNodeAsHost == nil) -- Cannot be both if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasDock) ~= 0 then ImGui.SetWindowDock(window, g.NextWindowData.DockId, g.NextWindowData.DockCond) end if first_begin_of_the_frame then local has_dock_node = (window.DockId ~= 0 or window.DockNode ~= nil) local new_auto_dock_node = not has_dock_node and ImGui.GetWindowAlwaysWantOwnTabBar(window) local dock_node_was_visible = window.DockNodeIsVisible local dock_tab_was_visible = window.DockTabIsVisible window.DockIsActive = false window.DockNodeIsVisible = false window.DockTabIsVisible = false if has_dock_node or new_auto_dock_node then open = ImGui.BeginDocked(window, open) flags = window.Flags if window.DockIsActive then IM_ASSERT(window.DockNode ~= nil) g.NextWindowData.HasFlags = bit32.band(g.NextWindowData.HasFlags, bit32.bnot(ImGuiNextWindowDataFlags.HasSizeConstraint)) end -- Amend the Appearing flag if window.DockTabIsVisible and not dock_tab_was_visible and dock_node_was_visible and not window.Appearing and not window_was_appearing then window.Appearing = true SetWindowConditionAllowFlags(window, ImGuiCond.Appearing, true) end end end local parent_window_in_stack if window.DockIsActive and window.DockNode.HostWindow then parent_window_in_stack = window.DockNode.HostWindow elseif g.CurrentWindowStack:empty() then parent_window_in_stack = nil else parent_window_in_stack = g.CurrentWindowStack:back().Window end local parent_window if first_begin_of_the_frame then if (bit32.band(flags, bit32.bor(ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0) then parent_window = parent_window_in_stack else parent_window = nil end else parent_window = window.ParentWindow end if window.IDStack.Size == 0 then window.IDStack:push_back(window.ID) end -- Add to stack g.CurrentWindow = window g.CurrentWindowStack:resize(g.CurrentWindowStack.Size + 1) g.CurrentWindowStack.Data[g.CurrentWindowStack.Size] = ImGuiWindowStackData() local window_stack_data = g.CurrentWindowStack.Data[g.CurrentWindowStack.Size] window_stack_data.Window = window ImGuiLastItemData_Copy(window_stack_data.ParentLastItemDataBackup, g.LastItemData) window_stack_data.DisabledOverrideReenable = (bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0) and (bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0) window_stack_data.DisabledOverrideReenableAlphaBackup = 0.0 window_stack_data.StackSizesInBegin = ImGuiErrorRecoveryState() ImGui.ErrorRecoveryStoreState(window_stack_data.StackSizesInBegin) g.StackSizesInBeginForCurrentWindow = window_stack_data.StackSizesInBegin if bit32.band(flags, ImGuiWindowFlags.ChildMenu) ~= 0 then g.BeginMenuDepth = g.BeginMenuDepth + 1 end if first_begin_of_the_frame then ImGui.UpdateWindowParentAndRootLinks(window, flags, parent_window) window.ParentWindowInBeginStack = parent_window_in_stack if window.RootWindow ~= window then window.ParentWindowForFocusRoute = parent_window_in_stack else window.ParentWindowForFocusRoute = nil end if window.ParentWindowForFocusRoute == nil and window.DockNode ~= nil then if bit32.band(window.DockNode.MergedFlags, ImGuiDockNodeFlags.DockedWindowsInFocusRoute) ~= 0 then window.ParentWindowForFocusRoute = window.DockNode.HostWindow end end if window.WindowClass and window.WindowClass.FocusRouteParentWindowId ~= nil and window.WindowClass.FocusRouteParentWindowId ~= 0 then window.ParentWindowForFocusRoute = ImGui.FindWindowByID(window.WindowClass.FocusRouteParentWindowId) end if parent_window then window.FontWindowScaleParents = parent_window.FontWindowScaleParents * parent_window.FontWindowScale else window.FontWindowScaleParents = 1.0 end end ImGui.PushFocusScope((bit32.band(window.ChildFlags, ImGuiChildFlags.NavFlattened) ~= 0) and g.CurrentFocusScopeId or window.ID) window.NavRootFocusScopeId = g.CurrentFocusScopeId -- Add to popup stacks: update OpenPopupStack data, push to BeginPopupStack if bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0 then local popup_ref = g.OpenPopupStack.Data[g.BeginPopupStack.Size + 1] popup_ref.Window = window popup_ref.ParentNavLayer = parent_window_in_stack.DC.NavLayerCurrent g.BeginPopupStack:push_back(popup_ref) window.PopupId = popup_ref.PopupId end local window_pos_set_by_api = false local window_size_x_set_by_api = false local window_size_y_set_by_api = false if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasPos) ~= 0 then window_pos_set_by_api = (bit32.band(window.SetWindowPosAllowFlags, g.NextWindowData.PosCond) ~= 0) if window_pos_set_by_api and ImLengthSqr(g.NextWindowData.PosPivotVal) > 1e-5 then -- FIXME: Look into removing the branch so everything can go through this same code path for consistency. ImVec2_Copy(window.SetWindowPosVal, g.NextWindowData.PosVal) ImVec2_Copy(window.SetWindowPosPivot, g.NextWindowData.PosPivotVal) window.SetWindowPosAllowFlags = bit32.band(window.SetWindowPosAllowFlags, bit32.bnot(bit32.bor(ImGuiCond.Once, ImGuiCond.FirstUseEver, ImGuiCond.Appearing))) else ImGui.SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond) end end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) ~= 0 then window_size_x_set_by_api = (bit32.band(window.SetWindowSizeAllowFlags, g.NextWindowData.SizeCond) ~= 0) and (g.NextWindowData.SizeVal.x > 0.0) window_size_y_set_by_api = (bit32.band(window.SetWindowSizeAllowFlags, g.NextWindowData.SizeCond) ~= 0) and (g.NextWindowData.SizeVal.y > 0.0) if (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeX) ~= 0 and bit32.band(window.SetWindowSizeAllowFlags, ImGuiCond.FirstUseEver) == 0) then g.NextWindowData.SizeVal.x = window.SizeFull.x end if (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeY) ~= 0 and bit32.band(window.SetWindowSizeAllowFlags, ImGuiCond.FirstUseEver) == 0) then g.NextWindowData.SizeVal.y = window.SizeFull.y end ImGui.SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasScroll) ~= 0 then if g.NextWindowData.ScrollVal.x >= 0.0 then window.ScrollTarget.x = g.NextWindowData.ScrollVal.x window.ScrollTargetCenterRatio.x = 0.0 end if g.NextWindowData.ScrollVal.y >= 0.0 then window.ScrollTarget.y = g.NextWindowData.ScrollVal.y window.ScrollTargetCenterRatio.y = 0.0 end end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasContentSize) ~= 0 then ImVec2_Copy(window.ContentSizeExplicit, g.NextWindowData.ContentSizeVal) elseif first_begin_of_the_frame then window.ContentSizeExplicit = ImVec2(0.0, 0.0) end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasWindowClass) ~= 0 then window.WindowClass = g.NextWindowData.WindowClass end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasCollapsed) ~= 0 then ImGui.SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond) end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasFocus) ~= 0 then ImGui.FocusWindow(window) end if window.Appearing then SetWindowConditionAllowFlags(window, ImGuiCond.Appearing, false) end -- [EXPERIMENTAL] Skip Refresh mode ImGui.UpdateWindowSkipRefresh(window) if window_stack_data.DisabledOverrideReenable and window.RootWindow == window then ImGui.BeginDisabledOverrideReenable() end g.CurrentWindow = nil if first_begin_of_the_frame and not window.SkipRefresh then local window_is_child_tooltip = (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 and bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0) local window_just_appearing_after_hidden_for_resize = (window.HiddenFramesCannotSkipItems > 0) window.Active = true window.HasCloseButton = (open ~= nil) ImRect_CopyFromV4(window.ClipRect, ImVec4(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX)) window.IDStack:resize(1) window.DrawList:_ResetForNewFrame() window.DC.CurrentTableIdx = -1 if bit32.band(flags, ImGuiWindowFlags.DockNodeHost) ~= 0 then window.DrawList:ChannelsSplit(2) window.DrawList:ChannelsSetCurrent(1) -- DOCKING_HOST_DRAW_CHANNEL_FG: render decorations on channel 1, backgrounds rendered manually later end if window.MemoryCompacted then ImGui.GcAwakeTransientWindowBuffers(window) end -- UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS -- Update contents size from last frame for auto-fitting (or use explicit size) CalcWindowContentSizes(window, window.ContentSize, window.ContentSizeIdeal) if window.HiddenFramesCanSkipItems > 0 then window.HiddenFramesCanSkipItems = window.HiddenFramesCanSkipItems - 1 end if window.HiddenFramesCannotSkipItems > 0 then window.HiddenFramesCannotSkipItems = window.HiddenFramesCannotSkipItems - 1 end if window.HiddenFramesForRenderOnly > 0 then window.HiddenFramesForRenderOnly = window.HiddenFramesForRenderOnly - 1 end -- Hide new windows for one frame until they calculate their size if window_just_created and (not window_size_x_set_by_api or not window_size_y_set_by_api) then window.HiddenFramesCannotSkipItems = 1 end -- Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) -- We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. if window_just_activated_by_user and bit32.band(flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0 then window.HiddenFramesCannotSkipItems = 1 if bit32.band(flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0 then if not window_size_x_set_by_api then window.SizeFull.x = 0.0 window.Size.x = 0.0 end if not window_size_y_set_by_api then window.SizeFull.y = 0.0 window.Size.y = 0.0 end ImVec2_Copy(window.ContentSize, ImVec2(0.0, 0.0)) ImVec2_Copy(window.ContentSizeIdeal, ImVec2(0.0, 0.0)) end end -- SELECT VIEWPORT ImGui.WindowSelectViewport(window) ImGui.SetCurrentViewport(window, window.Viewport) SetCurrentWindow(window) flags = window.Flags if not window.DockIsActive and bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 then window.WindowBorderSize = style.ChildBorderSize else window.WindowBorderSize = (bit32.band(flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0 and bit32.band(flags, ImGuiWindowFlags.Modal) == 0) and style.PopupBorderSize or style.WindowBorderSize end window.WindowPadding = style.WindowPadding if not window.DockIsActive and (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.Popup) == 0) and (bit32.band(window.ChildFlags, ImGuiChildFlags.AlwaysUseWindowPadding) == 0) and window.WindowBorderSize == 0.0 then if bit32.band(flags, ImGuiWindowFlags.MenuBar) ~= 0 then window.WindowPadding = ImVec2(0.0, style.WindowPadding.y) else window.WindowPadding = ImVec2(0.0, 0.0) end end -- Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. window.DC.MenuBarOffset.x = ImMax(ImMax(window.WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x) window.DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y if bit32.band(flags, ImGuiWindowFlags.NoTitleBar) ~= 0 then window.TitleBarHeight = 0.0 else window.TitleBarHeight = g.FontSize + g.Style.FramePadding.y * 2.0 end if bit32.band(flags, ImGuiWindowFlags.MenuBar) ~= 0 then window.MenuBarHeight = window.DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0 else window.MenuBarHeight = 0.0 end window.TitleBarHeight = (bit32.band(flags, ImGuiWindowFlags.NoTitleBar) ~= 0) and 0 or g.FontSize + g.Style.FramePadding.y * 2 window.FontRefSize = g.FontSize -- Lock this to discourage calling window:CalcFontSize() outside of current window. local use_current_size_for_scrollbar_x = window_just_created local use_current_size_for_scrollbar_y = window_just_created if window_size_x_set_by_api and window.ContentSizeExplicit.x ~= 0.0 then use_current_size_for_scrollbar_x = true end if window_size_y_set_by_api and window.ContentSizeExplicit.y ~= 0.0 then use_current_size_for_scrollbar_y = true end -- Collapse window by double-clicking on title bar -- At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing if bit32.band(flags, ImGuiWindowFlags.NoTitleBar) == 0 and bit32.band(flags, ImGuiWindowFlags.NoCollapse) == 0 and not window.DockIsActive then local title_bar_rect = window:TitleBarRect() if g.HoveredWindow == window and g.HoveredId == 0 and g.HoveredIdPreviousFrame == 0 and g.ActiveId == 0 and ImGui.IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) then if g.IO.MouseClickedCount[0] == 2 and ImGui.GetKeyOwner(ImGuiKey.MouseLeft) == ImGuiKeyOwner_NoOwner then window.WantCollapseToggle = true ImGui.SetKeyOwner(ImGuiKey.MouseLeft, window.MoveId) end end if window.WantCollapseToggle then window.Collapsed = not window.Collapsed if not window.Collapsed then use_current_size_for_scrollbar_y = true end ImGui.MarkIniSettingsDirty(window) end else window.Collapsed = false end window.WantCollapseToggle = false local scrollbar_sizes_from_last_frame = ImVec2() ImVec2_Copy(scrollbar_sizes_from_last_frame, window.ScrollbarSizes) window.DecoOuterSizeX1 = 0.0 window.DecoOuterSizeX2 = 0.0 window.DecoOuterSizeY1 = window.TitleBarHeight + window.MenuBarHeight window.DecoOuterSizeY2 = 0.0 window.ScrollbarSizes = ImVec2(0.0, 0.0) -- Calculate auto-fit size, handle automatic resize -- - Using SetNextWindowSize() overrides ImGuiWindowFlags.AlwaysAutoResize, so it can be used on tooltips/popups, etc. -- - We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags.AlwaysAutoResize when collapsed. -- - Auto-fit may only grow window during the first few frames. do local size_auto_fit_x_always = not window_size_x_set_by_api and (bit32.band(flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0) and not window.Collapsed local size_auto_fit_y_always = not window_size_y_set_by_api and (bit32.band(flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0) and not window.Collapsed local size_auto_fit_x_current = not window_size_x_set_by_api and (window.AutoFitFramesX > 0) local size_auto_fit_y_current = not window_size_y_set_by_api and (window.AutoFitFramesY > 0) local size_auto_fit_mask = 0 if size_auto_fit_x_always or size_auto_fit_x_current then size_auto_fit_mask = bit32.bor(size_auto_fit_mask, bit32.lshift(1, ImGuiAxis.X - 1)) end if size_auto_fit_y_always or size_auto_fit_y_current then size_auto_fit_mask = bit32.bor(size_auto_fit_mask, bit32.lshift(1, ImGuiAxis.Y - 1)) end local size_auto_fit = CalcWindowAutoFitSize(window, window.ContentSizeIdeal, size_auto_fit_mask) local old_size = ImVec2(window.SizeFull.x, window.SizeFull.y) if size_auto_fit_x_always or size_auto_fit_x_current then if size_auto_fit_x_always then window.SizeFull.x = size_auto_fit.x else if window.AutoFitOnlyGrows then window.SizeFull.x = ImMax(window.SizeFull.x, size_auto_fit.x) else window.SizeFull.x = size_auto_fit.x end end use_current_size_for_scrollbar_x = true end if size_auto_fit_y_always or size_auto_fit_y_current then if size_auto_fit_y_always then window.SizeFull.y = size_auto_fit.y else if window.AutoFitOnlyGrows then window.SizeFull.y = ImMax(window.SizeFull.y, size_auto_fit.y) else window.SizeFull.y = size_auto_fit.y end end use_current_size_for_scrollbar_y = true end if old_size.x ~= window.SizeFull.x or old_size.y ~= window.SizeFull.y then ImGui.MarkIniSettingsDirty(window) end end ImVec2_Copy(window.SizeFull, CalcWindowSizeAfterConstraint(window, window.SizeFull)) ImVec2_Copy(window.Size, (window.Collapsed and bit32.band(flags, ImGuiWindowFlags.ChildWindow) == 0) and window:TitleBarRect():GetSize() or window.SizeFull) -- POSITION -- Popup latch its initial position, will position itself when it appears next frame if window_just_activated_by_user then window.AutoPosLastDirection = ImGuiDir.None if bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0 and bit32.band(flags, ImGuiWindowFlags.Modal) == 0 and not window_pos_set_by_api then -- FIXME: BeginPopup() could use SetNextWindowPos() ImVec2_Copy(window.Pos, g.BeginPopupStack:back().OpenPopupPos) end end if bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 then IM_ASSERT(parent_window and parent_window.Active) window.BeginOrderWithinParent = parent_window.DC.ChildWindows.Size parent_window.DC.ChildWindows:push_back(window) if (bit32.band(flags, ImGuiWindowFlags.Popup) == 0) and not window_pos_set_by_api and not window_is_child_tooltip then ImVec2_Copy(window.Pos, parent_window.DC.CursorPos) end end local window_pos_with_pivot = (window.SetWindowPosVal.x ~= FLT_MAX and window.HiddenFramesCannotSkipItems == 0) if window_pos_with_pivot then ImGui.SetWindowPos(window, window.SetWindowPosVal - window.Size * window.SetWindowPosPivot, 0) -- Position given a pivot (e.g. for centering) elseif (bit32.band(flags, ImGuiWindowFlags.ChildMenu) ~= 0) then ImVec2_Copy(window.Pos, ImGui.FindBestWindowPosForPopup(window)) elseif (bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0) and not window_pos_set_by_api and window_just_appearing_after_hidden_for_resize then ImVec2_Copy(window.Pos, ImGui.FindBestWindowPosForPopup(window)) elseif (bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0) and not window_pos_set_by_api and not window_is_child_tooltip then ImVec2_Copy(window.Pos, ImGui.FindBestWindowPosForPopup(window)) end -- Late create viewport if we don't fit within our current host viewport. if window.ViewportAllowPlatformMonitorExtend >= 0 and not window.ViewportOwned and bit32.band(window.Viewport.Flags, ImGuiViewportFlags.IsMinimized) == 0 then if not window.Viewport:GetMainRect():Contains(window:Rect()) then -- This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport) -- local old_viewport = window.Viewport window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.Pos, window.Size, ImGuiViewportFlags.NoFocusOnAppearing) -- FIXME-DPI -- IM_ASSERT(old_viewport.DpiScale == window.Viewport.DpiScale) -- FIXME-DPI: Something went wrong ImGui.SetCurrentViewport(window, window.Viewport) SetCurrentWindow(window) end end if window.ViewportOwned then ImGui.WindowSyncOwnedViewport(window, parent_window_in_stack) end local viewport_rect = window.Viewport:GetMainRect() local viewport_work_rect = window.Viewport:GetWorkRect() local visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding) local visibility_rect = ImRect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding) -- Clamp position/size so window stays visible within its viewport or monitor if not window_pos_set_by_api and bit32.band(flags, ImGuiWindowFlags.ChildWindow) == 0 then if not window.ViewportOwned and viewport_rect:GetWidth() > 0 and viewport_rect:GetHeight() > 0.0 then local size_for_clamping_y = window.Size.y if bit32.band(window.BgClickFlags, ImGuiWindowBgClickFlags.Move) == 0 and bit32.band(window.Flags, ImGuiWindowFlags.NoTitleBar) == 0 then size_for_clamping_y = window.TitleBarHeight end window.Pos.x = ImClamp(window.Pos.x, visibility_rect.Min.x - window.Size.x, visibility_rect.Max.x) window.Pos.y = ImClamp(window.Pos.y, visibility_rect.Min.y - size_for_clamping_y, visibility_rect.Max.y) end end window.Pos.x = ImTrunc(window.Pos.x) window.Pos.y = ImTrunc(window.Pos.y) local want_focus = false if (window_just_activated_by_user and bit32.band(flags, ImGuiWindowFlags.NoFocusOnAppearing) == 0) then if bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0 then want_focus = true elseif (window.DockIsActive or bit32.band(flags, ImGuiWindowFlags.ChildWindow) == 0) and bit32.band(flags, ImGuiWindowFlags.Tooltip) == 0 then want_focus = true end end if bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 and not window.DockIsActive then window.WindowRounding = style.ChildRounding elseif window.RootWindowDockTree.ViewportOwned then window.WindowRounding = 0.0 else if (bit32.band(flags, ImGuiWindowFlags.Popup) ~= 0 and bit32.band(flags, ImGuiWindowFlags.Modal) == 0) then window.WindowRounding = style.PopupRounding else window.WindowRounding = style.WindowRounding end end local handle_borders_and_resize_grips = (window.DockNodeAsHost ~= nil or not window.DockIsActive) if bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 and window.ParentWindow.SkipItems then handle_borders_and_resize_grips = false end local border_hovered, border_held = -1, -1 local resize_grip_col = {0, 0, 0, 0} local resize_grip_count if (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.Popup) == 0) then if (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeX) ~= 0) and (bit32.band(window.ChildFlags, ImGuiChildFlags.ResizeY) ~= 0) then resize_grip_count = 1 else resize_grip_count = 0 end else resize_grip_count = g.IO.ConfigWindowsResizeFromEdges and 2 or 1 -- Allow resize from lower-left if we have the mouse cursor feedback for it. end local resize_grip_draw_size = ImTrunc(ImMax(g.FontSize * 1.10, g.Style.WindowRounding + 1.0 + g.FontSize * 0.2)) if handle_borders_and_resize_grips and not window.Collapsed then local auto_fit_mask auto_fit_mask, border_hovered, border_held = UpdateWindowManualResize(window, resize_grip_count, resize_grip_col, visibility_rect) if auto_fit_mask ~= 0 then if bit32.band(auto_fit_mask, bit32.lshift(1, ImGuiAxis.X - 1)) ~= 0 then use_current_size_for_scrollbar_x = true end if bit32.band(auto_fit_mask, bit32.lshift(1, ImGuiAxis.Y - 1)) ~= 0 then use_current_size_for_scrollbar_y = true end end end window.ResizeBorderHovered = border_hovered window.ResizeBorderHeld = border_held -- Synchronize window --> viewport again and one last time (clamping and manual resize may have affected either) if window.ViewportOwned then if not window.Viewport.PlatformRequestMove then ImVec2_Copy(window.Viewport.Pos, window.Pos) end if not window.Viewport.PlatformRequestResize then ImVec2_Copy(window.Viewport.Size, window.Size) end window.Viewport:UpdateWorkRect() viewport_rect = window.Viewport:GetMainRect() end -- Save last known viewport position within the window itself (so it can be saved in .ini file and restored) ImVec2_Copy(window.ViewportPos, window.Viewport.Pos) --- SCROLLBAR VISIBILITY -- Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size) if not window.Collapsed then -- When reading the current size we need to read it after size constraints have been applied. -- Intentionally use previous frame values for InnerRect and ScrollbarSizes. -- And when we use window.DecoOuterSizeY1 here it doesn't have ScrollbarSizes.y applied yet. local avail_size_from_current_frame = ImVec2(window.SizeFull.x, window.SizeFull.y - (window.DecoOuterSizeY1 + window.DecoOuterSizeY2)) local avail_size_from_last_frame = window.InnerRect:GetSize() + scrollbar_sizes_from_last_frame local needed_size_from_last_frame = window_just_created and ImVec2(0, 0) or window.ContentSize + window.WindowPadding * 2.0 local size_for_scrollbars_x = use_current_size_for_scrollbar_x and avail_size_from_current_frame.x or avail_size_from_last_frame.x local size_for_scrollbars_y = use_current_size_for_scrollbar_y and avail_size_from_current_frame.y or avail_size_from_last_frame.y local scrollbar_x_prev = window.ScrollbarX -- local scrollbar_y_from_last_frame = window.ScrollbarY -- FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? window.ScrollbarY = (bit32.band(flags, ImGuiWindowFlags.AlwaysVerticalScrollbar) ~= 0) or ((needed_size_from_last_frame.y > size_for_scrollbars_y) and not (bit32.band(flags, ImGuiWindowFlags.NoScrollbar) ~= 0)) window.ScrollbarX = (bit32.band(flags, ImGuiWindowFlags.AlwaysHorizontalScrollbar) ~= 0) or ((needed_size_from_last_frame.x > size_for_scrollbars_x - (window.ScrollbarY and style.ScrollbarSize or 0.0)) and not (bit32.band(flags, ImGuiWindowFlags.NoScrollbar) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.HorizontalScrollbar) ~= 0)) -- Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488) -- (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause. -- The better solution is to, either (1) enforce visibility by using ImGuiWindowFlags.AlwaysHorizontalScrollbar or (2) declare stable contents width with SetNextWindowContentSize(), if you can compute it) window.ScrollbarXStabilizeToggledHistory = bit32.lshift(window.ScrollbarXStabilizeToggledHistory, 1) if scrollbar_x_prev ~= window.ScrollbarX then window.ScrollbarXStabilizeToggledHistory = bit32.bor(window.ScrollbarXStabilizeToggledHistory, 0x01) end local scrollbar_x_stabilize = (window.ScrollbarXStabilizeToggledHistory ~= 0) and ImCountSetBits(window.ScrollbarXStabilizeToggledHistory) >= 4 -- 4 == half of bits in our U8 history. if scrollbar_x_stabilize then window.ScrollbarX = true end -- if scrollbar_x_stabilize and not window.ScrollbarXStabilizeEnabled then -- IMGUI_DEBUG_LOG("[scroll] Stabilize ScrollbarX for Window '%s'\n", window.Name) -- end window.ScrollbarXStabilizeEnabled = scrollbar_x_stabilize if window.ScrollbarX and not window.ScrollbarY then window.ScrollbarY = (needed_size_from_last_frame.y > size_for_scrollbars_y - style.ScrollbarSize) and not (bit32.band(flags, ImGuiWindowFlags.NoScrollbar) ~= 0) end window.ScrollbarSizes = ImVec2(window.ScrollbarY and style.ScrollbarSize or 0.0, window.ScrollbarX and style.ScrollbarSize or 0.0) -- Amend the partially filled window.DecoOuterSizeX2 values. window.DecoOuterSizeX2 = window.DecoOuterSizeX2 + window.ScrollbarSizes.x window.DecoOuterSizeY2 = window.DecoOuterSizeY2 + window.ScrollbarSizes.y end local host_rect if (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 and bit32.band(flags, ImGuiWindowFlags.Popup) == 0 and not window_is_child_tooltip) then host_rect = parent_window.ClipRect else host_rect = viewport_rect end local outer_rect = window:Rect() local title_bar_rect = window:TitleBarRect() ImRect_Copy(window.OuterRectClipped, outer_rect) if window.DockIsActive then window.OuterRectClipped.Min.y = window.OuterRectClipped.Min.y + window.TitleBarHeight end window.OuterRectClipped:ClipWith(host_rect) window.InnerRect.Min.x = window.Pos.x + window.DecoOuterSizeX1 window.InnerRect.Min.y = window.Pos.y + window.DecoOuterSizeY1 window.InnerRect.Max.x = window.Pos.x + window.Size.x - window.DecoOuterSizeX2 window.InnerRect.Max.y = window.Pos.y + window.Size.y - window.DecoOuterSizeY2 local top_border_size = ((bit32.band(flags, ImGuiWindowFlags.MenuBar) ~= 0 or bit32.band(flags, ImGuiWindowFlags.NoTitleBar) == 0) and style.FrameBorderSize or window.WindowBorderSize) window.InnerClipRect.Min.x = ImFloor(0.5 + window.InnerRect.Min.x + window.WindowBorderSize * 0.5) window.InnerClipRect.Min.y = ImFloor(0.5 + window.InnerRect.Min.y + top_border_size * 0.5) window.InnerClipRect.Max.x = ImFloor(window.InnerRect.Max.x - window.WindowBorderSize * 0.5) window.InnerClipRect.Max.y = ImFloor(window.InnerRect.Max.y - window.WindowBorderSize * 0.5) window.InnerClipRect:ClipWithFull(host_rect) --- Scrolling -- Lock down maximum scrolling -- The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate -- for right/bottom aligned items without creating a scrollbar. window.ScrollMax.x = ImMax(0.0, window.ContentSize.x + window.WindowPadding.x * 2.0 - window.InnerRect:GetWidth()) window.ScrollMax.y = ImMax(0.0, window.ContentSize.y + window.WindowPadding.y * 2.0 - window.InnerRect:GetHeight()) -- Apply scrolling ImVec2_Copy(window.Scroll, CalcNextScrollFromScrollTargetAndClamp(window)) ImVec2_CopyV(window.ScrollTarget, FLT_MAX, FLT_MAX) window.DecoInnerSizeX1 = 0.0; window.DecoInnerSizeY1 = 0.0 IM_ASSERT(window.DrawList.CmdBuffer.Size == 1 and window.DrawList.CmdBuffer.Data[1].ElemCount == 0) window.DrawList:PushTexture(g.Font.OwnerAtlas.TexRef) ImGui.PushClipRect(host_rect.Min, host_rect.Max, false) local is_undocked_or_docked_visible = not window.DockIsActive or window.DockTabIsVisible if is_undocked_or_docked_visible then local render_decorations_in_parent = false if (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.Popup) == 0) and not window_is_child_tooltip then -- - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here) -- - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs local previous_child if parent_window.DC.ChildWindows.Size >= 2 then previous_child = parent_window.DC.ChildWindows.Data[parent_window.DC.ChildWindows.Size - 1] else previous_child = nil end local previous_child_overlapping if previous_child ~= nil then previous_child_overlapping = previous_child:Rect():Overlaps(window:Rect()) else previous_child_overlapping = false end local parent_is_empty = (parent_window.DrawList.VtxBuffer.Size == 0) if (window.DrawList.CmdBuffer:back().ElemCount == 0 and not parent_is_empty and not previous_child_overlapping) then render_decorations_in_parent = true end end if render_decorations_in_parent then window.DrawList = parent_window.DrawList end local window_to_highlight = g.NavWindowingTarget or g.NavWindow local title_bar_is_highlight = want_focus or (window_to_highlight ~= nil and (window.RootWindowForTitleBarHighlight == window_to_highlight.RootWindowForTitleBarHighlight or (window.DockNode ~= nil and window.DockNode == window_to_highlight.DockNode))) RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_col, resize_grip_draw_size) if render_decorations_in_parent then window.DrawList = window.DrawListInst end end local allow_scrollbar_x = (bit32.band(flags, ImGuiWindowFlags.NoScrollbar) == 0) and (bit32.band(flags, ImGuiWindowFlags.HorizontalScrollbar) ~= 0) local allow_scrollbar_y = (bit32.band(flags, ImGuiWindowFlags.NoScrollbar) == 0) local work_rect_size_x if window.ContentSizeExplicit.x ~= 0.0 then work_rect_size_x = window.ContentSizeExplicit.x else local content_size_x = allow_scrollbar_x and (window.ContentSize and window.ContentSize.x or 0.0) or 0.0 local window_size_x = window.Size.x - window.WindowPadding.x * 2.0 - (window.DecoOuterSizeX1 + window.DecoOuterSizeX2) work_rect_size_x = ImMax(content_size_x, window_size_x) end local work_rect_size_y if window.ContentSizeExplicit.y ~= 0.0 then work_rect_size_y = window.ContentSizeExplicit.y else local content_size_y = allow_scrollbar_y and (window.ContentSize and window.ContentSize.y or 0.0) or 0.0 local window_size_y = window.Size.y - window.WindowPadding.y * 2.0 - (window.DecoOuterSizeY1 + window.DecoOuterSizeY2) work_rect_size_y = ImMax(content_size_y, window_size_y) end window.WorkRect.Min.x = ImTrunc(window.InnerRect.Min.x - window.Scroll.x + ImMax(window.WindowPadding.x, window.WindowBorderSize)) window.WorkRect.Min.y = ImTrunc(window.InnerRect.Min.y - window.Scroll.y + ImMax(window.WindowPadding.y, window.WindowBorderSize)) window.WorkRect.Max.x = window.WorkRect.Min.x + work_rect_size_x window.WorkRect.Max.y = window.WorkRect.Min.y + work_rect_size_y window.ParentWorkRect = window.WorkRect -- [LEGACY] Content Region -- FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. -- Unless explicit content size is specified by user, this currently represent the region leading to no scrolling. -- Used by: -- - Mouse wheel scrolling + many other things window.ContentRegionRect.Min.x = window.Pos.x - window.Scroll.x + window.WindowPadding.x + window.DecoOuterSizeX1 window.ContentRegionRect.Min.y = window.Pos.y - window.Scroll.y + window.WindowPadding.y + window.DecoOuterSizeY1 window.ContentRegionRect.Max.x = window.ContentRegionRect.Min.x + (window.ContentSizeExplicit.x ~= 0.0 and window.ContentSizeExplicit.x or (window.Size.x - window.WindowPadding.x * 2.0 - (window.DecoOuterSizeX1 + window.DecoOuterSizeX2))) window.ContentRegionRect.Max.y = window.ContentRegionRect.Min.y + (window.ContentSizeExplicit.y ~= 0.0 and window.ContentSizeExplicit.y or (window.Size.y - window.WindowPadding.y * 2.0 - (window.DecoOuterSizeY1 + window.DecoOuterSizeY2))) -- Setup drawing context -- (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window.DC.Indent.x = window.DecoOuterSizeX1 + window.WindowPadding.x - window.Scroll.x window.DC.GroupOffset.x = 0.0 window.DC.ColumnsOffset.x = 0.0 -- Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount. -- This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64. local start_pos_highp_x = window.Pos.x + window.WindowPadding.x - window.Scroll.x + window.DecoOuterSizeX1 + window.DC.ColumnsOffset.x local start_pos_highp_y = window.Pos.y + window.WindowPadding.y - window.Scroll.y + window.DecoOuterSizeY1 ImVec2_CopyV(window.DC.CursorStartPos, start_pos_highp_x, start_pos_highp_y) ImVec2_CopyV(window.DC.CursorStartPosLossyness, start_pos_highp_x - window.DC.CursorStartPos.x, start_pos_highp_y - window.DC.CursorStartPos.y) ImVec2_Copy(window.DC.CursorPos, window.DC.CursorStartPos) ImVec2_Copy(window.DC.CursorPosPrevLine, window.DC.CursorPos) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorStartPos) ImVec2_Copy(window.DC.IdealMaxPos, window.DC.CursorStartPos) ImVec2_CopyV(window.DC.CurrLineSize, 0.0, 0.0) ImVec2_CopyV(window.DC.PrevLineSize, 0.0, 0.0) window.DC.CurrLineTextBaseOffset = 0.0 window.DC.PrevLineTextBaseOffset = 0.0 window.DC.IsSameLine = false window.DC.IsSetPos = false window.DC.NavLayerCurrent = ImGuiNavLayer.Main window.DC.NavLayersActiveMask = window.DC.NavLayersActiveMaskNext window.DC.NavLayersActiveMaskNext = 0x00 window.DC.NavIsScrollPushableX = true window.DC.NavHideHighlightOneFrame = false window.DC.NavWindowHasScrollY = window.ScrollMax.y > 0.0 window.DC.MenuBarAppending = false window.DC.MenuColumns:Update(style.ItemSpacing.x, window_just_activated_by_user) window.DC.TreeDepth = 0 window.DC.TreeHasStackDataDepthMask = 0x00 window.DC.TreeRecordsClippedNodesY2Mask = 0x00 window.DC.ChildWindows:resize(0) window.DC.StateStorage = window.StateStorage window.DC.CurrentColumns = nil window.DC.LayoutType = ImGuiLayoutType.Vertical window.DC.ParentLayoutType = (parent_window ~= nil) and parent_window.DC.LayoutType or ImGuiLayoutType.Vertical -- Default item width. Make it proportional to window size if window can be manually resized. -- (we cannot use AutoFitFramesX/AutoFitFramesY which is a temporary state) local is_resizable_width if bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 and not window.DockIsActive then is_resizable_width = (window.Size.x > 0.0) and (bit32.band(window.ChildFlags, bit32.bor(ImGuiChildFlags.AutoResizeX, ImGuiChildFlags.AlwaysAutoResize)) == 0) else is_resizable_width = (window.Size.x > 0.0) and (bit32.band(flags, ImGuiWindowFlags.AlwaysAutoResize) == 0) end if is_resizable_width then window.DC.ItemWidthDefault = ImTrunc(window.Size.x * 0.65) else window.DC.ItemWidthDefault = ImTrunc(g.FontSize * 16.0) end window.DC.ItemWidth = window.DC.ItemWidthDefault window.DC.ItemWidthStack:resize(0) window.DC.TextWrapPos = -1.0 window.DC.TextWrapPosStack:resize(0) if bit32.band(flags, ImGuiWindowFlags.Modal) ~= 0 then window.DC.ModalDimBgColor = ImGui.ColorConvertFloat4ToU32(ImGui.GetStyleColorVec4(ImGuiCol.ModalWindowDimBg)) end if window.AutoFitFramesX > 0 then window.AutoFitFramesX = window.AutoFitFramesX - 1 end if window.AutoFitFramesY > 0 then window.AutoFitFramesY = window.AutoFitFramesY - 1 end g.NextWindowData:ClearFlags() if want_focus then ImGui.FocusWindow(window, ImGuiFocusRequestFlags.UnlessBelowModal) end if want_focus and window == g.NavWindow then ImGui.NavInitWindow(window, false) end -- Pressing Ctrl+C copy window content into the clipboard if g.IO.ConfigWindowsCopyContentsWithCtrlC then if g.NavWindow and g.NavWindow.RootWindow == window and g.ActiveId == 0 and ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.C)) then ImGui.LogToClipboard(0) end end if bit32.band(flags, ImGuiWindowFlags.NoTitleBar) == 0 and not window.DockIsActive then open = RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window.WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window.WindowBorderSize, title_bar_rect.Max.y), name, open) elseif bit32.band(flags, ImGuiWindowFlags.NoTitleBar) == 0 and window.DockIsActive then ImGui.LogText("%s\n", string.sub(window.Name, 1, ImGui.FindRenderedTextEnd(window.Name) - 1)) end -- Clear hit test shape every frame window.HitTestHoleSize.x = 0; window.HitTestHoleSize.y = 0 if bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0 then g.TooltipPreviousWindow = window end if bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.DockingEnable) ~= 0 then -- Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source. -- We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it. if g.MovingWindow == window and bit32.band(window.RootWindowDockTree.Flags, ImGuiWindowFlags.NoDocking) == 0 then ImGui.BeginDockableDragDropSource(window) end -- Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead. if g.DragDropActive and bit32.band(flags, ImGuiWindowFlags.NoDocking) == 0 then if g.MovingWindow == nil or g.MovingWindow.RootWindowDockTree ~= window then if window == window.RootWindowDockTree and bit32.band(window.Flags, ImGuiWindowFlags.DockNodeHost) == 0 then ImGui.BeginDockableDragDropTarget(window) end end end end if bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 then window.BgClickFlags = parent_window.BgClickFlags else window.BgClickFlags = g.IO.ConfigWindowsMoveFromTitleBarOnly and ImGuiWindowBgClickFlags.None or ImGuiWindowBgClickFlags.Move end window.DC.WindowItemStatusFlags = ImGuiItemStatusFlags.None if ImGui.IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) then window.DC.WindowItemStatusFlags = bit32.bor(window.DC.WindowItemStatusFlags, ImGuiItemStatusFlags.HoveredRect) end ImGui.SetLastItemDataForWindow(window, title_bar_rect) else if (window.SkipRefresh) then SetWindowActiveForSkipRefresh(window) end ImGui.SetCurrentViewport(window, window.Viewport) SetCurrentWindow(window) g.NextWindowData:ClearFlags() ImGui.SetLastItemDataForWindow(window, window:TitleBarRect()) end if bit32.band(flags, ImGuiWindowFlags.DockNodeHost) == 0 and not window.SkipRefresh then ImGui.PushClipRect(window.InnerClipRect.Min, window.InnerClipRect.Max, true) -- [Roblox backend] content clip + scroll origin: lets the backend move scrolled content instead of redrawing it local dl, cr = window.DrawList, window.DrawList._CmdHeader.ClipRect dl._ContentClipX0, dl._ContentClipY0, dl._ContentClipX1, dl._ContentClipY1 = cr.x, cr.y, cr.z, cr.w dl._ScrollOriginX, dl._ScrollOriginY = window.Pos.x - window.Scroll.x, window.Pos.y - window.Scroll.y end window.WriteAccessed = false window.BeginCount = window.BeginCount + 1 g.NextWindowData:ClearFlags() if first_begin_of_the_frame and not window.SkipRefresh then -- When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems. if window.DockIsActive and not window.DockTabIsVisible then if window.LastFrameJustFocused == g.FrameCount then window.HiddenFramesCannotSkipItems = 1 else window.HiddenFramesCanSkipItems = 1 end end if (bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0) and (bit32.band(flags, ImGuiWindowFlags.ChildMenu) == 0) then -- Child window can be out of sight and have "negative" clip windows. -- Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). IM_ASSERT((bit32.band(flags, ImGuiWindowFlags.NoTitleBar) ~= 0) or window.DockIsActive) local nav_request = (bit32.band(window.ChildFlags, ImGuiChildFlags.NavFlattened) ~= 0) and (g.NavAnyRequest and g.NavWindow and g.NavWindow.RootWindowForNav == window.RootWindowForNav) if not g.LogEnabled and not nav_request then if window.OuterRectClipped.Min.x >= window.OuterRectClipped.Max.x or window.OuterRectClipped.Min.y >= window.OuterRectClipped.Max.y then if window.AutoFitFramesX > 0 or window.AutoFitFramesY > 0 then window.HiddenFramesCannotSkipItems = 1 else window.HiddenFramesCanSkipItems = 1 end end end -- Hide along with parent or if parent is collapsed if parent_window and (parent_window.Collapsed or parent_window.HiddenFramesCanSkipItems > 0) then window.HiddenFramesCanSkipItems = 1 end if parent_window and parent_window.HiddenFramesCannotSkipItems > 0 then window.HiddenFramesCannotSkipItems = 1 end end if style.Alpha <= 0.0 then window.HiddenFramesCanSkipItems = 1 end local hidden_regular = (window.HiddenFramesCanSkipItems > 0) or (window.HiddenFramesCannotSkipItems > 0) window.Hidden = hidden_regular or (window.HiddenFramesForRenderOnly > 0) -- Disable inputs for requested number of frames if window.DisableInputsFrames > 0 then window.DisableInputsFrames = window.DisableInputsFrames - 1 window.Flags = bit32.bor(window.Flags, ImGuiWindowFlags.NoInputs) end -- Update the SkipItems flag, used to early out of all items functions (no layout required) local skip_items = false if window.Collapsed or not window.Active or hidden_regular then if window.AutoFitFramesX <= 0 and window.AutoFitFramesY <= 0 and window.HiddenFramesCannotSkipItems <= 0 then skip_items = true end end window.SkipItems = skip_items -- Restore NavLayersActiveMaskNext to previous value when not visible, so a CTRL+Tab back can use a safe value. if window.SkipItems then window.DC.NavLayersActiveMaskNext = window.DC.NavLayersActiveMask end elseif first_begin_of_the_frame then window.SkipItems = true end if open == nil then open = true end return open, not window.SkipItems end function ImGui.End() local g = GImGui local window = g.CurrentWindow if (g.CurrentWindowStack.Size <= 1 and g.WithinFrameScopeWithImplicitWindow) then IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!") return end local window_stack_data = g.CurrentWindowStack:back() if bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 then IM_ASSERT_USER_ERROR(g.WithinEndPopupID == window.ID, "Must call EndPopup() and not End()!") end if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 and bit32.band(window.Flags, ImGuiWindowFlags.DockNodeHost) == 0 and not window.DockIsActive then IM_ASSERT_USER_ERROR(g.WithinEndChildID == window.ID, "Must call EndChild() and not End()!") end if window.DC.CurrentColumns then ImGui.EndColumns() end if bit32.band(window.Flags, ImGuiWindowFlags.DockNodeHost) == 0 and not window.SkipRefresh then ImGui.PopClipRect() end ImGui.PopFocusScope() if window_stack_data.DisabledOverrideReenable and window.RootWindow == window then ImGui.EndDisabledOverrideReenable() end if (window.SkipRefresh) then IM_ASSERT(window.DrawList == nil) window.DrawList = window.DrawListInst end -- Stop logging if g.LogWindow == window then -- FIXME: add more options for scope of logging ImGui.LogFinish() end if window.DC.IsSetPos then ImGui.ErrorCheckUsingSetCursorPosToExtendParentBoundaries() end -- Docking: report contents sizes to parent to allow for auto-resize if window.DockNode and window.DockTabIsVisible then local host_window = window.DockNode.HostWindow if host_window then ImVec2_Copy(host_window.DC.CursorMaxPos, window.DC.CursorMaxPos + window.WindowPadding - host_window.WindowPadding) end end -- Pop from window stack ImGuiLastItemData_Copy(g.LastItemData, window_stack_data.ParentLastItemDataBackup) if bit32.band(window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then g.BeginMenuDepth = g.BeginMenuDepth - 1 end if bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 then g.BeginPopupStack:pop_back() end -- Error handling, state recovery if g.IO.ConfigErrorRecovery and window_stack_data.StackSizesInBegin then ImGui.ErrorRecoveryTryToRecoverWindowState(window_stack_data.StackSizesInBegin) end g.CurrentWindowStack:pop_back() -- LUA: No "Ternary Operator", since lua (... and (1) or (2)) will eval (1) and (2) no matter what -- so something like `SetCurrentWindow((g.CurrentWindowStack.Size == 0) and nil or g.CurrentWindowStack:back().Window)` will error if (g.CurrentWindowStack.Size == 0) then SetCurrentWindow(nil) else SetCurrentWindow(g.CurrentWindowStack:back().Window) end if g.CurrentWindow then ImGui.SetCurrentViewport(g.CurrentWindow, g.CurrentWindow.Viewport) end end --- @param option ImGuiItemFlags --- @param enabled bool function ImGui.PushItemFlag(option, enabled) local g = GImGui local item_flags = g.CurrentItemFlags IM_ASSERT(item_flags == g.ItemFlagsStack:back()) if enabled then item_flags = bit32.bor(item_flags, option) else item_flags = bit32.band(item_flags, bit32.bnot(option)) end g.CurrentItemFlags = item_flags g.ItemFlagsStack:push_back(item_flags) end function ImGui.PopItemFlag() local g = GImGui IM_ASSERT_USER_ERROR_RET(g.ItemFlagsStack.Size > 1, "Calling PopItemFlag() too many times!") g.ItemFlagsStack:pop_back() g.CurrentItemFlags = g.ItemFlagsStack:back() end --- @param disabled? bool function ImGui.BeginDisabled(disabled) if disabled == nil then disabled = true end local g = GImGui local was_disabled = bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0 if not was_disabled and disabled then g.DisabledAlphaBackup = g.Style.Alpha g.Style.Alpha = g.Style.Alpha * g.Style.DisabledAlpha end if was_disabled or disabled then g.CurrentItemFlags = bit32.bor(g.CurrentItemFlags, ImGuiItemFlags.Disabled) end g.ItemFlagsStack:push_back(g.CurrentItemFlags) g.DisabledStackSize = g.DisabledStackSize + 1 end function ImGui.EndDisabled() local g = GImGui IM_ASSERT_USER_ERROR_RET(g.DisabledStackSize > 0, "Calling EndDisabled() too many times!") g.DisabledStackSize = g.DisabledStackSize - 1 local was_disabled = bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0 g.ItemFlagsStack:pop_back() g.CurrentItemFlags = g.ItemFlagsStack:back() if was_disabled and bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) == 0 then g.Style.Alpha = g.DisabledAlphaBackup end end function ImGui.BeginDisabledOverrideReenable() local g = GImGui IM_ASSERT(bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0) g.CurrentWindowStack.Data[g.CurrentWindowStack.Size].DisabledOverrideReenableAlphaBackup = g.Style.Alpha g.Style.Alpha = g.DisabledAlphaBackup g.CurrentItemFlags = bit32.band(g.CurrentItemFlags, bit32.bnot(ImGuiItemFlags.Disabled)) g.ItemFlagsStack:push_back(g.CurrentItemFlags) g.DisabledStackSize = g.DisabledStackSize + 1 end function ImGui.EndDisabledOverrideReenable() local g = GImGui IM_ASSERT(g.DisabledStackSize > 0) g.DisabledStackSize = g.DisabledStackSize - 1 g.ItemFlagsStack:pop_back() g.CurrentItemFlags = g.ItemFlagsStack:back() g.Style.Alpha = g.CurrentWindowStack:back().DisabledOverrideReenableAlphaBackup end --- @param pos ImVec2 --- @param find_first_and_in_any_viewport bool --- @return ImGuiWindow, ImGuiWindow? local function FindHoveredWindowEx(pos, find_first_and_in_any_viewport) local g = GImGui local hovered_window = nil local hovered_window_under_moving_window = nil -- Special handling for the window being moved: Ignore the mouse viewport check (because it may reset/lose its viewport during the undocking frame) hovered_window = g.MovingWindow local backup_moving_window_viewport = nil if (find_first_and_in_any_viewport == false and g.MovingWindow) then backup_moving_window_viewport = g.MovingWindow.Viewport g.MovingWindow.Viewport = g.MouseViewport if (bit32.band(g.MovingWindow.Flags, ImGuiWindowFlags.NoMouseInputs) == 0) then hovered_window = g.MovingWindow end end local padding_regular = g.Style.TouchExtraPadding local padding_for_resize = ImMax(g.Style.TouchExtraPadding, ImVec2(g.Style.WindowBorderHoverPadding, g.Style.WindowBorderHoverPadding)) local window local stop_6075 = false for i = g.Windows.Size, 1, -1 do repeat window = g.Windows.Data[i] if not window.WasActive or window.Hidden then break end if bit32.band(window.Flags, ImGuiWindowFlags.NoMouseInputs) ~= 0 then break end IM_ASSERT(window.Viewport) if (window.Viewport ~= g.MouseViewport) then break end local hit_padding if bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.NoResize, ImGuiWindowFlags.AlwaysAutoResize)) ~= 0 then hit_padding = padding_regular else hit_padding = padding_for_resize end if not window.OuterRectClipped:ContainsWithPad(pos, hit_padding) then break end if window.HitTestHoleSize.x ~= 0 then local hx, hy = window.Pos.x + window.HitTestHoleOffset.x, window.Pos.y + window.HitTestHoleOffset.y if pos.x >= hx and pos.y >= hy and pos.x < hx + window.HitTestHoleSize.x and pos.y < hy + window.HitTestHoleSize.y then break -- continue end end if find_first_and_in_any_viewport then hovered_window = window stop_6075 = true; break else if hovered_window == nil then hovered_window = window end if hovered_window_under_moving_window == nil and (not g.MovingWindow or window.RootWindowDockTree ~= g.MovingWindow.RootWindowDockTree) then hovered_window_under_moving_window = window end if hovered_window and hovered_window_under_moving_window then stop_6075 = true; break end end until true if stop_6075 then break end end if (find_first_and_in_any_viewport == false and g.MovingWindow) then g.MovingWindow.Viewport = backup_moving_window_viewport end return hovered_window, hovered_window_under_moving_window end -- TODO: function ImGui.UpdateHoveredWindowAndCaptureFlags(mouse_pos) local g = GImGui local io = g.IO g.WindowsBorderHoverPadding = ImMax(ImMax(g.Style.TouchExtraPadding.x, g.Style.TouchExtraPadding.y), g.Style.WindowBorderHoverPadding) local clear_hovered_windows = false g.HoveredWindow, g.HoveredWindowUnderMovingWindow = FindHoveredWindowEx(mouse_pos, false) IM_ASSERT(g.HoveredWindow == nil or g.HoveredWindow == g.MovingWindow or g.HoveredWindow.Viewport == g.MouseViewport) g.HoveredWindowBeforeClear = g.HoveredWindow local modal_window = ImGui.GetTopMostPopupModal() if modal_window and g.HoveredWindow and not ImGui.IsWindowWithinBeginStackOf(g.HoveredWindow.RootWindow, modal_window) then clear_hovered_windows = true end if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoMouse) ~= 0 then clear_hovered_windows = true end local has_open_popup = (g.OpenPopupStack.Size > 0) local has_open_modal = (modal_window ~= nil) local mouse_earliest_down = -1 local mouse_any_down = false for i = 0, 2 do -- IM_COUNTOF(io.MouseDown) if io.MouseClicked[i] then io.MouseDownOwned[i] = (g.HoveredWindow ~= nil) or has_open_popup io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow ~= nil) or has_open_modal end mouse_any_down = mouse_any_down or io.MouseDown[i] if (io.MouseDown[i] or io.MouseReleased[i]) then if (mouse_earliest_down == -1 or (io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])) then mouse_earliest_down = i end end end local mouse_avail = (mouse_earliest_down == -1) or io.MouseDownOwned[mouse_earliest_down] local mouse_avail_unless_popup_close = (mouse_earliest_down == -1) or io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down] local mouse_dragging_extern_payload = g.DragDropActive and bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceExtern) ~= 0 if not mouse_avail and not mouse_dragging_extern_payload then clear_hovered_windows = true end if clear_hovered_windows then g.HoveredWindow = nil g.HoveredWindowUnderMovingWindow = nil end if (g.WantCaptureMouseNextFrame ~= -1) then io.WantCaptureMouse = (g.WantCaptureMouseNextFrame ~= 0) io.WantCaptureMouseUnlessPopupClose = io.WantCaptureMouse else io.WantCaptureMouse = (mouse_avail and (g.HoveredWindow ~= nil or mouse_any_down)) or has_open_popup io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close and (g.HoveredWindow ~= nil or mouse_any_down)) or has_open_modal end io.WantCaptureKeyboard = false if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) == 0 then if (g.ActiveId ~= 0) or (modal_window ~= nil) then io.WantCaptureKeyboard = true elseif io.NavActive and bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 and io.ConfigNavCaptureKeyboard then io.WantCaptureKeyboard = true end end if g.WantCaptureKeyboardNextFrame ~= -1 then io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame ~= 0) end io.WantTextInput = (g.WantTextInputNextFrame ~= -1) and (g.WantTextInputNextFrame ~= 0) or false end --- @param key ImGuiKey --- @param v bool --- @param analog_value float function ImGui.UpdateAliasKey(key, v, analog_value) IM_ASSERT(ImGui.IsAliasKey(key)) local key_data = ImGui.GetKeyData(nil, key) key_data.Down = v key_data.AnalogValue = analog_value end function ImGui.GetMergedModsFromKeys() local g = GImGui local mods = 0 if ImGui.GetKeyData(g, ImGuiMod_Ctrl).Down then mods = bit32.bor(mods, ImGuiMod_Ctrl) end if ImGui.GetKeyData(g, ImGuiMod_Shift).Down then mods = bit32.bor(mods, ImGuiMod_Shift) end if ImGui.GetKeyData(g, ImGuiMod_Alt).Down then mods = bit32.bor(mods, ImGuiMod_Alt) end if ImGui.GetKeyData(g, ImGuiMod_Super).Down then mods = bit32.bor(mods, ImGuiMod_Super) end return mods end function ImGui.UpdateKeyboardInputs() local g = GImGui local io = g.IO if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) ~= 0 then io:ClearInputKeys() end for n = 0, 2 do -- TODO: ImGuiMouseButton.COUNT - 1 ImGui.UpdateAliasKey(ImGui.MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] and 1.0 or 0.0) end ImGui.UpdateAliasKey(ImGuiKey.MouseWheelX, io.MouseWheelH ~= 0.0, io.MouseWheelH) ImGui.UpdateAliasKey(ImGuiKey.MouseWheelY, io.MouseWheel ~= 0.0, io.MouseWheel) -- Synchronize io.KeyMods and io.KeyCtrl/io.KeyShift/etc. values local prev_key_mods = io.KeyMods io.KeyMods = ImGui.GetMergedModsFromKeys() io.KeyCtrl = bit32.band(io.KeyMods, ImGuiMod_Ctrl) ~= 0 io.KeyShift = bit32.band(io.KeyMods, ImGuiMod_Shift) ~= 0 io.KeyAlt = bit32.band(io.KeyMods, ImGuiMod_Alt) ~= 0 io.KeySuper = bit32.band(io.KeyMods, ImGuiMod_Super) ~= 0 if prev_key_mods ~= io.KeyMods then g.LastKeyModsChangeTime = g.Time end if prev_key_mods ~= io.KeyMods and prev_key_mods == 0 then g.LastKeyModsChangeFromNoneTime = g.Time end -- Clear gamepad data if disabled if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) == 0 then for key = ImGuiKey_Gamepad_BEGIN, ImGuiKey_Gamepad_END - 1 do io.KeysData[key - ImGuiKey.NamedKey_BEGIN].Down = false io.KeysData[key - ImGuiKey.NamedKey_BEGIN].AnalogValue = 0.0 end end -- Update keys for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do local key_data = io.KeysData[key - ImGuiKey.NamedKey_BEGIN] key_data.DownDurationPrev = key_data.DownDuration if key_data.Down then if key_data.DownDuration < 0.0 then key_data.DownDuration = 0.0 else key_data.DownDuration = key_data.DownDuration + io.DeltaTime end else key_data.DownDuration = -1.0 end if key_data.DownDuration == 0.0 then if ImGui.IsKeyboardKey(key) then g.LastKeyboardKeyPressTime = g.Time elseif key == ImGuiKey.ReservedForModCtrl or key == ImGuiKey.ReservedForModShift or key == ImGuiKey.ReservedForModAlt or key == ImGuiKey.ReservedForModSuper then g.LastKeyboardKeyPressTime = g.Time end end end -- Update keys/input owner (named keys only): one entry per key for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do local key_data = io.KeysData[key - ImGuiKey.NamedKey_BEGIN] local owner_data = g.KeysOwnerData[key - ImGuiKey.NamedKey_BEGIN] owner_data.OwnerCurr = owner_data.OwnerNext if not key_data.Down then -- Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. owner_data.OwnerNext = ImGuiKeyOwner_NoOwner end owner_data.LockThisFrame = owner_data.LockUntilRelease and key_data.Down owner_data.LockUntilRelease = owner_data.LockUntilRelease and key_data.Down -- Clear LockUntilRelease when key is not Down anymore end ImGui.UpdateKeyRoutingTable(g.KeysRoutingTable) end function ImGui.UpdateMouseInputs() local g = GImGui local io = g.IO -- Mouse Wheel swapping flag -- As a standard behavior holding Shift while using Vertical Mouse Wheel triggers Horizontal scroll instead -- - We avoid doing it on OSX as it the OS input layer handles this already io.MouseWheelRequestAxisSwap = io.KeyShift and not io.ConfigMacOSXBehaviors -- Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) if (ImGui.IsMousePosValid(io.MousePos)) then local x_val = ImFloor(io.MousePos.x) local y_val = ImFloor(io.MousePos.y) io.MousePos = ImVec2(x_val, y_val) g.MouseLastValidPos = ImVec2(x_val, y_val) end -- If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta if (ImGui.IsMousePosValid(io.MousePos) and ImGui.IsMousePosValid(io.MousePosPrev)) then io.MouseDelta = io.MousePos - io.MousePosPrev else io.MouseDelta = ImVec2(0.0, 0.0) end -- Update stationary timer -- FIXME: May need to rework again to have some tolerance for occasional small movement, while being functional on high-framerates local mouse_stationary_threshold = (io.MouseSource == ImGuiMouseSource.Mouse) and 2.0 or 3.0 local mouse_stationary = (ImLengthSqr(io.MouseDelta) <= mouse_stationary_threshold * mouse_stationary_threshold) g.MouseStationaryTimer = mouse_stationary and (g.MouseStationaryTimer + io.DeltaTime) or 0.0 -- If mouse moved we re-enable mouse hovering in case it was disabled by keyboard/gamepad. In theory should use a >0.0 threshold but would need to reset in everywhere we set this to true. if io.MouseDelta.x ~= 0.0 or io.MouseDelta.y ~= 0.0 then g.NavHighlightItemUnderNav = false end for i = 0, 2 do -- IM_COUNTOF(io.MouseDown) io.MouseClicked[i] = io.MouseDown[i] and (io.MouseDownDuration[i] < 0.0) io.MouseClickedCount[i] = 0 -- Will be filled below io.MouseReleased[i] = not io.MouseDown[i] and (io.MouseDownDuration[i] >= 0.0) if (io.MouseReleased[i]) then io.MouseReleasedTime[i] = g.Time end io.MouseDownDurationPrev[i] = io.MouseDownDuration[i] if io.MouseDown[i] then if io.MouseDownDuration[i] < 0.0 then io.MouseDownDuration[i] = 0.0 else io.MouseDownDuration[i] = io.MouseDownDuration[i] + io.DeltaTime end else io.MouseDownDuration[i] = -1.0 end if io.MouseClicked[i] then local is_repeated_click = false if (g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime then local delta_from_click_pos if ImGui.IsMousePosValid(io.MousePos) then delta_from_click_pos = io.MousePos - io.MouseClickedPos[i] else delta_from_click_pos = ImVec2(0.0, 0.0) end if ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist then is_repeated_click = true end end if is_repeated_click then io.MouseClickedLastCount[i] = io.MouseClickedLastCount[i] + 1 else io.MouseClickedLastCount[i] = 1 end io.MouseClickedTime[i] = g.Time io.MouseClickedPos[i] = io.MousePos io.MouseClickedCount[i] = io.MouseClickedLastCount[i] ImVec2_Copy(io.MouseDragMaxDistanceAbs[i], ImVec2(0.0, 0.0)) io.MouseDragMaxDistanceSqr[i] = 0.0 elseif io.MouseDown[i] then -- Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold local delta_from_click_pos if ImGui.IsMousePosValid(io.MousePos) then delta_from_click_pos = (io.MousePos - io.MouseClickedPos[i]) else delta_from_click_pos = ImVec2(0.0, 0.0) end io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)) io.MouseDragMaxDistanceAbs[i].x = ImMax(io.MouseDragMaxDistanceAbs[i].x, (delta_from_click_pos.x < 0.0) and -delta_from_click_pos.x or delta_from_click_pos.x) io.MouseDragMaxDistanceAbs[i].y = ImMax(io.MouseDragMaxDistanceAbs[i].y, (delta_from_click_pos.y < 0.0) and -delta_from_click_pos.y or delta_from_click_pos.y) end io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2) if (io.MouseClicked[i]) then g.NavHighlightItemUnderNav = false end end end --- @param window? ImGuiWindow --- @param wheel_amount float local function LockWheelingWindow(window, wheel_amount) local g = GImGui if window then g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER) else g.WheelingWindowReleaseTimer = 0.0 end if (g.WheelingWindow == window) then return end -- IMGUI_DEBUG_LOG_IO("[io] LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL") g.WheelingWindow = window ImVec2_Copy(g.WheelingWindowRefMousePos, g.IO.MousePos) if window == nil then g.WheelingWindowStartFrame = -1 g.WheelingAxisAvg = ImVec2(0.0, 0.0) end end --- @param wheel ImVec2 --- @return ImGuiWindow? local function FindBestWheelingWindow(wheel) local g = GImGui local windows = {nil, nil} for axis = ImGuiAxis.X, ImGuiAxis.Y do if wheel[axis] ~= 0.0 then windows[axis] = g.HoveredWindow local window = g.HoveredWindow while bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 do local has_scrolling = (window.ScrollMax[axis] ~= 0.0) local inputs_disabled = (bit32.band(window.Flags, ImGuiWindowFlags.NoScrollWithMouse) ~= 0) and not (bit32.band(window.Flags, ImGuiWindowFlags.NoMouseInputs) ~= 0) if has_scrolling and not inputs_disabled then break -- select this window end windows[axis] = window.ParentWindow window = window.ParentWindow end end end if windows[1] == nil and windows[2] == nil then return nil end if (windows[1] == windows[2] or windows[1] == nil or windows[2] == nil) then return windows[2] and windows[2] or windows[1] end if (g.WheelingWindowStartFrame == -1) then g.WheelingWindowStartFrame = g.FrameCount end if ((g.WheelingWindowStartFrame == g.FrameCount and wheel.x ~= 0.0 and wheel.y ~= 0.0) or (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y)) then ImVec2_Copy(g.WheelingWindowWheelRemainder, wheel) return nil end return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) and windows[1] or windows[2] end function ImGui.UpdateMouseWheel() local g = GImGui if g.WheelingWindow ~= nil then g.WheelingWindowReleaseTimer = g.WheelingWindowReleaseTimer - g.IO.DeltaTime if ImGui.IsMousePosValid() and ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold then g.WheelingWindowReleaseTimer = 0.0 end if g.WheelingWindowReleaseTimer <= 0.0 then LockWheelingWindow(nil, 0.0) end end local mouse_window = g.WheelingWindow and g.WheelingWindow or g.HoveredWindow if not mouse_window or mouse_window.Collapsed then return end local owner_id = mouse_window.ID local wheel = ImVec2() wheel.x = ImGui.TestKeyOwner(ImGuiKey.MouseWheelX, owner_id) and g.IO.MouseWheelH or 0.0 wheel.y = ImGui.TestKeyOwner(ImGuiKey.MouseWheelY, owner_id) and g.IO.MouseWheel or 0.0 if g.WheelingWindow ~= nil then ImGui.SetKeyOwner(ImGuiKey.MouseWheelX, owner_id) ImGui.SetKeyOwner(ImGuiKey.MouseWheelY, owner_id) end -- Zoom / Scale window -- FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned if wheel.y ~= 0.0 and g.IO.KeyCtrl and g.IO.FontAllowUserScaling then LockWheelingWindow(mouse_window, wheel.y) local window = mouse_window local new_font_scale = ImClamp(window.FontWindowScale + g.IO.MouseWheel * 0.10, 0.50, 2.50) local scale = new_font_scale / window.FontWindowScale window.FontWindowScale = new_font_scale if window == window.RootWindow then local offset = window.Size * (1.0 - scale) * (g.IO.MousePos - window.Pos) / window.Size ImGui.SetWindowPos(window, window.Pos + offset, 0) -- MarkIniSettingsDirty(window) end return end if g.IO.KeyCtrl then return end -- Mouse wheel scrolling if (g.IO.MouseWheelRequestAxisSwap) then wheel = ImVec2(wheel.y, 0.0) end -- Maintain a rough average of moving magnitude on both axes -- FIXME: should by based on wall clock time rather than frame-counter g.WheelingAxisAvg.x = ImStd.ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30) g.WheelingAxisAvg.y = ImStd.ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30) -- In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now wheel = wheel + g.WheelingWindowWheelRemainder g.WheelingWindowWheelRemainder = ImVec2(0.0, 0.0) if (wheel.x == 0.0 and wheel.y == 0.0) then return end -- Mouse wheel scrolling: find target and apply -- - don't renew lock if axis doesn't apply on the window. -- - select a main axis when both axes are being moved. local window if g.WheelingWindow then window = g.WheelingWindow else window = FindBestWheelingWindow(wheel) end if window then if not (bit32.band(window.Flags, ImGuiWindowFlags.NoScrollWithMouse) ~= 0) and not (bit32.band(window.Flags, ImGuiWindowFlags.NoMouseInputs) ~= 0) then local do_scroll = { wheel.x ~= 0.0 and window.ScrollMax.x ~= 0.0, wheel.y ~= 0.0 and window.ScrollMax.y ~= 0.0 } if do_scroll[ImGuiAxis.X] and do_scroll[ImGuiAxis.Y] then do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) and ImGuiAxis.Y or ImGuiAxis.X] = false end if do_scroll[ImGuiAxis.X] then LockWheelingWindow(window, wheel.x) local max_step = window.InnerRect:GetWidth() * 0.67 local scroll_step = ImTrunc(ImMin(2 * window.FontRefSize, max_step)) ImGui.SetScrollX(window, window.Scroll.x - wheel.x * scroll_step) g.WheelingWindowScrolledFrame = g.FrameCount end if do_scroll[ImGuiAxis.Y] then LockWheelingWindow(window, wheel.y) local max_step = window.InnerRect:GetHeight() * 0.67 local scroll_step = ImTrunc(ImMin(5 * window.FontRefSize, max_step)) ImGui.SetScrollY(window, window.Scroll.y - wheel.y * scroll_step) g.WheelingWindowScrolledFrame = g.FrameCount end end end end local function SetupDrawListSharedData() local g = GImGui local virtual_space = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) for _, viewport in g.Viewports:iter() do virtual_space:Add(viewport:GetMainRect()) end g.DrawListSharedData.ClipRectFullscreen = virtual_space:ToVec4() g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol g.DrawListSharedData:SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError) g.DrawListSharedData.InitialFlags = ImDrawListFlags.None if g.Style.AntiAliasedLines then g.DrawListSharedData.InitialFlags = bit32.bor(g.DrawListSharedData.InitialFlags, ImDrawListFlags.AntiAliasedLines) end if g.Style.AntiAliasedLinesUseTex and not bit32.band(g.IO.Fonts.Flags, ImFontAtlasFlags.NoBakedLines) then g.DrawListSharedData.InitialFlags = bit32.bor(g.DrawListSharedData.InitialFlags, ImDrawListFlags.AntiAliasedLinesUseTex) end if g.Style.AntiAliasedFill then g.DrawListSharedData.InitialFlags = bit32.bor(g.DrawListSharedData.InitialFlags, ImDrawListFlags.AntiAliasedFill) end if bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.RendererHasVtxOffset) then g.DrawListSharedData.InitialFlags = bit32.bor(g.DrawListSharedData.InitialFlags, ImDrawListFlags.AllowVtxOffset) end g.DrawListSharedData.InitialFringeScale = 1.0 end --- @param viewport ImGuiViewportP local function InitViewportDrawData(viewport) local g = GImGui local draw_data = viewport.DrawDataP viewport.DrawData = draw_data viewport.DrawDataBuilder.Layers[1] = draw_data.CmdLists viewport.DrawDataBuilder.Layers[2] = viewport.DrawDataBuilder.LayerData1 viewport.DrawDataBuilder.Layers[1]:resize(0) viewport.DrawDataBuilder.Layers[2]:resize(0) -- When minimized, we report draw_data->DisplaySize as zero to be consistent with non-viewport mode, -- and to allow applications/backends to easily skip rendering. -- FIXME: Note that we however do NOT attempt to report "zero drawlist / vertices" into the ImDrawData structure. -- This is because the work has been done already, and its wasted! We should fix that and add optimizations for -- it earlier in the pipeline, rather than pretend to hide the data at the end of the pipeline. local is_minimized = bit32.band(viewport.Flags, ImGuiViewportFlags.IsMinimized) ~= 0 draw_data.Valid = true draw_data.FrameCount = g.FrameCount draw_data.TotalVtxCount = 0 draw_data.TotalIdxCount = 0 draw_data.DisplayPos = viewport.Pos if is_minimized then draw_data.DisplaySize = ImVec2(0.0, 0.0) else ImVec2_Copy(draw_data.DisplaySize, viewport.Size) end if viewport.FramebufferScale.x ~= 0.0 then draw_data.FramebufferScale = viewport.FramebufferScale else draw_data.FramebufferScale = g.IO.DisplayFramebufferScale end draw_data.OwnerViewport = viewport draw_data.Textures = g.PlatformIO.Textures end -- FIXME-DPI: function ImGui.GetScale() local g = GImGui return g.Style._MainScale end --- @return ImGuiWindow function ImGui.GetCurrentWindowRead() local g = GImGui return g.CurrentWindow end --- @return ImGuiWindow @native function ImGui.GetCurrentWindow() local g = GImGui g.CurrentWindow.WriteAccessed = true return g.CurrentWindow end --- @param clip_rect_min ImVec2 --- @param clip_rect_max ImVec2 --- @param intersect_with_current_clip_rect? bool @native function ImGui.PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect) local window = ImGui.GetCurrentWindow() window.DrawList:PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect) ImRect_CopyFromV4(window.ClipRect, window.DrawList._ClipRectStack:back()) end function ImGui.PopClipRect() local window = ImGui.GetCurrentWindow() window.DrawList:PopClipRect() ImRect_CopyFromV4(window.ClipRect, window.DrawList._ClipRectStack:back()) end --- @param viewport ImGuiViewportP --- @param drawlist_no size_t # background(1), foreground(2) --- @param drawlist_name string --- @return ImDrawList local function GetViewportBgFgDrawList(viewport, drawlist_no, drawlist_name) local g = GImGui IM_ASSERT(drawlist_no <= 2) -- IM_COUNTOF(viewport->BgFgDrawLists) local draw_list = viewport.BgFgDrawLists[drawlist_no] if draw_list == nil then draw_list = ImDrawList(g.DrawListSharedData) draw_list._OwnerName = drawlist_name viewport.BgFgDrawLists[drawlist_no] = draw_list end if viewport.BgFgDrawListsLastTimeActive[drawlist_no] ~= g.Time then draw_list:_ResetForNewFrame() draw_list:PushTexture(g.IO.Fonts.TexRef) draw_list:PushClipRect(viewport.Pos, viewport.Pos + viewport.Size, false) viewport.BgFgDrawListsLastTimeActive[drawlist_no] = g.Time end return draw_list end --- @param viewport? ImGuiViewport function ImGui.GetBackgroundDrawList(viewport) local g = GImGui if (viewport == nil) then viewport = g.CurrentWindow.Viewport end --- @cast viewport ImGuiViewportP return GetViewportBgFgDrawList(viewport, 1, "##Background") end --- @param viewport? ImGuiViewport function ImGui.GetForegroundDrawList(viewport) local g = GImGui if (viewport == nil) then viewport = g.CurrentWindow.Viewport end --- @cast viewport ImGuiViewportP return GetViewportBgFgDrawList(viewport, 2, "##Foreground") end -- FIXME: Add a more explicit sort order in the window structure --- @param lhs ImGuiWindow --- @param rhs ImGuiWindow local function ChildWindowComparer(lhs, rhs) local a, b = lhs, rhs local d = (bit32.band(a.Flags, ImGuiWindowFlags.Popup) ~= 0 and 1 or 0) - (bit32.band(b.Flags, ImGuiWindowFlags.Popup) ~= 0 and 1 or 0) if d ~= 0 then return (d < 0) end d = (bit32.band(a.Flags, ImGuiWindowFlags.Tooltip) ~= 0 and 1 or 0) - (bit32.band(b.Flags, ImGuiWindowFlags.Tooltip) ~= 0 and 1 or 0) if d ~= 0 then return (d < 0) end return (a.BeginOrderWithinParent - b.BeginOrderWithinParent < 0) end --- @param out_sorted_windows ImVector --- @param window ImGuiWindow local function AddWindowToSortBuffer(out_sorted_windows, window) out_sorted_windows:push_back(window) if window.Active then local count = window.DC.ChildWindows.Size ImStd.ImQsort(window.DC.ChildWindows.Data, count, ChildWindowComparer) for i = 1, count do local child = window.DC.ChildWindows[i] if child.Active then AddWindowToSortBuffer(out_sorted_windows, child) end end end end local function AddWindowToDrawData(window, layer) local g = GImGui local viewport = window.Viewport g.IO.MetricsRenderWindows = g.IO.MetricsRenderWindows + 1 if window.DrawList._Splitter._Count > 1 then window.DrawList:ChannelsMerge() -- Merge if user forgot to merge back. Also required for DockNodeHost windows. end ImGui.AddDrawListToDrawDataEx(viewport.DrawDataP, viewport.DrawDataBuilder.Layers[layer], window.DrawList) for _, child in window.DC.ChildWindows:iter() do if (ImGui.IsWindowActiveAndVisible(child)) then -- Clipped children may have been marked not active AddWindowToDrawData(child, layer) end end end --- @param window ImGuiWindow local function GetWindowDisplayLayer(window) return (bit32.band(window.Flags, ImGuiWindowFlags.Tooltip) ~= 0) and 2 or 1 end --- @param window ImGuiWindow local function AddRootWindowToDrawData(window) AddWindowToDrawData(window, GetWindowDisplayLayer(window)) end --- @param builder ImDrawDataBuilder local function FlattenDrawDataIntoSingleLayer(builder) local n = builder.Layers[1].Size local full_size = n for i = 2, #builder.Layers do full_size = full_size + builder.Layers[i].Size end builder.Layers[1]:resize(full_size) for layer_n = 2, #builder.Layers do local layer = builder.Layers[layer_n] if not layer:empty() then for i = 1, layer.Size do builder.Layers[1].Data[n + i] = layer.Data[i] end n = n + layer.Size layer:resize(0) end end end function ImGui.NewFrame() IM_ASSERT(GImGui ~= nil, "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?") local g = GImGui g.ConfigFlagsLastFrame = g.ConfigFlagsCurrFrame g.ConfigFlagsCurrFrame = g.IO.ConfigFlags -- Load settings on first frame, save settings when modified (after a delay) ImGui.UpdateSettings() g.Time = g.Time + g.IO.DeltaTime g.FrameCount = g.FrameCount + 1 g.TooltipOverrideCount = 0 g.WindowsActiveCount = 0 g.MenusIdSubmittedThisFrame:resize(0) -- FIXME: are lines below correct and necessary g.FramerateSecPerFrameAccum = g.FramerateSecPerFrameAccum + (g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]) g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % 60 g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, 60) if g.FramerateSecPerFrameAccum > 0 then g.IO.Framerate = (1.0 / (g.FramerateSecPerFrameAccum / g.FramerateSecPerFrameCount)) else g.IO.Framerate = FLT_MAX end ImGui.UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue) ImGui.UpdateViewportsNewFrame() ImGui.UpdateTexturesNewFrame() SetupDrawListSharedData() ImGui.UpdateFontsNewFrame() g.WithinFrameScope = true -- Mark rendering data as invalid to prevent user who may have a handle on it to use it. for _, viewport in g.Viewports:iter() do viewport.DrawData = nil viewport.DrawDataP.Valid = false end if g.DragDropActive and g.DragDropPayload.SourceId == g.ActiveId then ImGui.KeepAliveID(g.DragDropPayload.SourceId) end if not g.IO.ConfigDebugHighlightIdConflicts or not g.IO.KeyCtrl then g.DebugDrawIdConflictsId = 0 end if g.IO.ConfigDebugHighlightIdConflicts and g.HoveredIdPreviousFrameItemCount > 1 then g.DebugDrawIdConflictsId = g.HoveredIdPreviousFrame end -- Update HoveredId data if not g.HoveredIdPreviousFrame then g.HoveredIdTimer = 0.0 end if not g.HoveredIdPreviousFrame or (g.HoveredId and g.ActiveId == g.HoveredId) then g.HoveredIdNotActiveTimer = 0.0 end if g.HoveredId then g.HoveredIdTimer = g.HoveredIdTimer + g.IO.DeltaTime end if g.HoveredId and g.ActiveId ~= g.HoveredId then g.HoveredIdNotActiveTimer = g.HoveredIdNotActiveTimer + g.IO.DeltaTime end g.HoveredIdPreviousFrame = g.HoveredId g.HoveredIdPreviousFrameItemCount = 0 g.HoveredId = 0 g.HoveredIdAllowOverlap = false g.HoveredIdIsDisabled = false if (g.ActiveId ~= 0 and g.ActiveIdIsAlive ~= g.ActiveId and g.ActiveIdPreviousFrame == g.ActiveId) then IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() 0x%08X because it isn't marked alive anymore!", g.ActiveId) ImGui.ClearActiveID() end -- Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) if g.ActiveId then g.ActiveIdTimer = g.ActiveIdTimer + g.IO.DeltaTime end if g.ActiveId and g.ActiveId == g.LastActiveId then g.LastActiveIdWasSelected = g.ActiveIdWasSelected g.LastActiveIdWasSoleSelected = g.ActiveIdWasSoleSelected end g.LastActiveIdTimer = g.LastActiveIdTimer + g.IO.DeltaTime g.ActiveIdPreviousFrame = g.ActiveId g.ActiveIdIsAlive = 0 g.AnyIdHasBeenEditedThisFrame = false g.ActiveIdHasBeenEditedThisFrame = false g.ActiveIdIsJustActivated = false if g.TempInputId ~= 0 and g.ActiveId ~= g.TempInputId then g.TempInputId = 0 end if g.InputTextReactivateId ~= 0 and g.InputTextReactivateId ~= g.DeactivatedItemData.ID then g.InputTextReactivateId = 0 end if g.ActiveId == 0 then g.ActiveIdUsingNavDirMask = 0x00 g.ActiveIdUsingAllKeyboardKeys = false end if g.DeactivatedItemData.ElapseFrame < g.FrameCount then g.DeactivatedItemData.ID = 0 end g.DeactivatedItemData.IsAlive = false if g.InputTextDeactivatedState.ElapseFrame < g.FrameCount then g.InputTextDeactivatedState.ID = 0 end -- Record when we have been stationary as this state is preserved while over same item. -- FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. -- To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function. if g.HoverItemDelayId ~= 0 and g.MouseStationaryTimer >= g.Style.HoverStationaryDelay then g.HoverItemUnlockedStationaryId = g.HoverItemDelayId elseif g.HoverItemDelayId == 0 then g.HoverItemUnlockedStationaryId = 0 end if g.HoveredWindow ~= nil and g.MouseStationaryTimer >= g.Style.HoverStationaryDelay then g.HoverWindowUnlockedStationaryId = g.HoveredWindow.ID elseif g.HoveredWindow == nil then g.HoverWindowUnlockedStationaryId = 0 end -- Update hover delay for IsItemHovered() with delays and tooltips g.HoverItemDelayIdPreviousFrame = g.HoverItemDelayId if g.HoverItemDelayId ~= 0 then g.HoverItemDelayTimer = g.HoverItemDelayTimer + g.IO.DeltaTime g.HoverItemDelayClearTimer = 0.0 g.HoverItemDelayId = 0 elseif g.HoverItemDelayTimer > 0.0 then -- This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps -- We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle. g.HoverItemDelayClearTimer = g.HoverItemDelayClearTimer + g.IO.DeltaTime if g.HoverItemDelayClearTimer >= ImMax(0.25, g.IO.DeltaTime * 2.0) then -- ~7 frames at 30 Hz + allow for low framerate g.HoverItemDelayTimer = 0.0 g.HoverItemDelayClearTimer = 0.0 -- May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer. end end ImGui.UpdateKeyboardInputs() -- Drag and drop g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr g.DragDropAcceptIdCurr = 0 g.DragDropAcceptFlagsPrev = g.DragDropAcceptFlagsCurr g.DragDropAcceptFlagsCurr = ImGuiDragDropFlags.None g.DragDropAcceptIdCurrRectSurface = FLT_MAX g.DragDropWithinSource = false g.DragDropWithinTarget = false g.DragDropHoldJustPressedId = 0 if g.DragDropActive then local owner_id = (g.ActiveId ~= 0) and g.ActiveId or ImHashStr("##DragDropCancelHandler") if ImGui.Shortcut(ImGuiKey.Escape, ImGuiInputFlags.RouteGlobal, owner_id) then ImGui.ClearActiveID() ImGui.ClearDragDrop() end end g.TooltipPreviousWindow = nil ImGui.NavUpdate() ImGui.UpdateMouseInputs() -- Undocking -- (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame) ImGui.DockContextNewFrameUpdateUndocking(g) IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size) local gc_all = g.GcCompactAll or g.IO.ConfigMemoryCompactTimer < 0.0 local memory_compact_start_time = gc_all and FLT_MAX or (g.Time - g.IO.ConfigMemoryCompactTimer) for _, window in g.Windows:iter() do window.WasActive = window.Active window.Active = false window.WriteAccessed = false window.BeginCountPreviousFrame = window.BeginCount window.BeginCount = 0 if (not window.WasActive or gc_all) and not window.MemoryCompacted and window.LastTimeActive < memory_compact_start_time then ImGui.GcCompactTransientWindowBuffers(window) end end ImGui.UpdateHoveredWindowAndCaptureFlags(g.IO.MousePos) ImGui.UpdateMouseMovingWindowNewFrame() -- Background darkening/whitening if ImGui.GetTopMostPopupModal() ~= nil or (g.NavWindowingTarget ~= nil and g.NavWindowingHighlightAlpha > 0.0) then g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0, 1.0) else g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0, 0.0) end g.MouseCursor = ImGuiMouseCursor.Arrow g.WantCaptureMouseNextFrame = -1 g.WantCaptureKeyboardNextFrame = -1 g.WantTextInputNextFrame = -1 -- Platform IME data: reset for the frame ImGuiPlatformImeData_Copy(g.PlatformImeDataPrev, g.PlatformImeData) g.PlatformImeData.WantVisible = false g.PlatformImeData.WantTextInput = false ImGui.UpdateMouseWheel() -- Garbage collect transient buffers of recently unused tables for i = 1, g.TablesLastTimeActive.Size do if g.TablesLastTimeActive.Data[i] >= 0.0 and g.TablesLastTimeActive.Data[i] < memory_compact_start_time then ImGui.TableGcCompactTransientBuffers(g.Tables:GetByIndex(i - 1)) end end for _, table_temp_data in g.TablesTempData:iter() do table_temp_data.ReconcileColumnsRequests:clear() -- Unusual: clear every frame because this is rarely used. if table_temp_data.LastTimeActive >= 0.0 and table_temp_data.LastTimeActive < memory_compact_start_time then ImGui.TableGcCompactTransientBuffers(table_temp_data) end end if g.GcCompactAll then ImGui.GcCompactTransientMiscBuffers() end g.GcCompactAll = false if (g.NavWindow and not g.NavWindow.WasActive) then ImGui.FocusTopMostWindowUnderOne(nil, nil, nil, ImGuiFocusRequestFlags.RestoreFocusedChild) end g.CurrentWindowStack:resize(0) g.BeginPopupStack:resize(0) g.ItemFlagsStack:resize(0) g.ItemFlagsStack:push_back(ImGuiItemFlags.Default_) g.CurrentItemFlags = g.ItemFlagsStack:back() g.GroupStack:resize(0) -- [DEBUG] ID Stack Tool query ImGui.UpdateDebugToolItemPathQuery() -- Docking ImGui.DockContextNewFrameUpdateDocking(g) g.WithinFrameScopeWithImplicitWindow = true ImGui.SetNextWindowSize(ImVec2(400, 400), ImGuiCond.FirstUseEver) ImGui.Begin("Debug##Default") IM_ASSERT(g.CurrentWindow.IsFallbackWindow == true) -- Store stack sizes g.ErrorCountCurrentFrame = 0 g.StackSizesInNewFrame = g.StackSizesInNewFrame or ImGuiErrorRecoveryState() ImGui.ErrorRecoveryStoreState(g.StackSizesInNewFrame) end function ImGui.EndFrame() local g = GImGui IM_ASSERT(g.Initialized) if g.FrameCountEnded == g.FrameCount then return end IM_ASSERT_USER_ERROR(g.WithinFrameScope, "Forgot to call ImGui::NewFrame()?") -- [EXPERIMENTAL] Recover from errors if g.IO.ConfigErrorRecovery and g.StackSizesInNewFrame then ImGui.ErrorRecoveryTryToRecoverState(g.StackSizesInNewFrame) end ImGui.ErrorCheckEndFrameFinalizeErrorTooltip() -- Notify Platform when our Input Method Editor cursor has moved local ime_data = g.PlatformImeData if g.PlatformIO.Platform_SetImeDataFn ~= nil and not ImGuiPlatformImeData_Compare(ime_data, g.PlatformImeDataPrev) then local viewport = ImGui.FindViewportByID(ime_data.ViewportId) if viewport == nil then viewport = ImGui.GetMainViewport() end -- IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f) for Viewport 0x%08X", ime_data.WantVisible, ime_data.InputPos.x, ime_data.InputPos.y, viewport.ID) g.PlatformIO.Platform_SetImeDataFn(g, viewport, ime_data) end g.WantTextInputNextFrame = ime_data.WantTextInput g.WithinFrameScopeWithImplicitWindow = false if (g.CurrentWindow and g.CurrentWindow.IsFallbackWindow and g.CurrentWindow.WriteAccessed == false) then g.CurrentWindow.Active = false end ImGui.End() -- Update navigation: Ctrl+Tab, wrap-around requests ImGui.NavEndFrame() -- Update docking ImGui.DockContextEndFrame(g) ImGui.SetCurrentViewport(nil, nil) -- Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) if g.DragDropActive then local is_delivered = g.DragDropPayload.Delivery local is_elapsed = (g.DragDropSourceFrameCount + 1 < g.FrameCount) and (bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.PayloadAutoExpire) ~= 0 or g.DragDropMouseButton == -1 or not ImGui.IsMouseDown(g.DragDropMouseButton)) if is_delivered or is_elapsed then ImGui.ClearDragDrop() end end -- Drag and Drop: Fallback for missing source tooltip. This is not ideal but better than nothing. -- If you want to handle source item disappearing: instead of submitting your description tooltip -- in the BeginDragDropSource() block of the dragged item, you can submit them from a safe single spot -- (e.g. end of your item loop, or before EndFrame) by reading payload data. -- In the typical case, the contents of drag tooltip should be possible to infer solely from payload data. if g.DragDropActive and g.DragDropSourceFrameCount + 1 < g.FrameCount and (bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceNoPreviewTooltip) == 0) then g.DragDropWithinSource = true ImGui.SetTooltip("...") g.DragDropWithinSource = false end g.WithinFrameScope = false g.FrameCountEnded = g.FrameCount ImGui.UpdateFontsEndFrame() ImGui.UpdateMouseMovingWindowEndFrame() ImGui.UpdateViewportsEndFrame() g.WindowsTempSortBuffer:resize(0) g.WindowsTempSortBuffer:reserve(g.Windows.Size) for _, window in g.Windows:iter() do repeat if window.Active and bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then -- if a child is active its parent will add it break end AddWindowToSortBuffer(g.WindowsTempSortBuffer, window) until true end IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size) g.Windows:swap(g.WindowsTempSortBuffer) g.IO.MetricsActiveWindows = g.WindowsActiveCount ImGui.UpdateTexturesEndFrame() for _, atlas in g.FontAtlases:iter() do atlas.Locked = false end ImVec2_Copy(g.IO.MousePosPrev, g.IO.MousePos) g.IO.AppFocusLost = false g.IO.MouseWheel = 0.0 g.IO.MouseWheelH = 0.0 g.IO.InputQueueCharacters:resize(0) end -- TODO: function ImGui.Render() local g = GImGui IM_ASSERT(g.Initialized) if g.FrameCountEnded ~= g.FrameCount then ImGui.EndFrame() end if g.FrameCountRendered == g.FrameCount then return end g.FrameCountRendered = g.FrameCount g.IO.MetricsRenderWindows = 0 for _, viewport in g.Viewports:iter() do InitViewportDrawData(viewport) if viewport.BgFgDrawLists[1] ~= nil and viewport.BgFgDrawListsLastTimeActive[1] == g.Time then ImGui.AddDrawListToDrawDataEx(viewport.DrawDataP, viewport.DrawDataBuilder.Layers[1], ImGui.GetBackgroundDrawList(viewport)) end end ImGui.RenderDimmedBackgrounds() local windows_to_render_top_most = {nil, nil} windows_to_render_top_most[1] = (g.NavWindowingTarget and (bit32.band(g.NavWindowingTarget.Flags, ImGuiWindowFlags.NoBringToFrontOnFocus) == 0)) and g.NavWindowingTarget.RootWindowDockTree or nil windows_to_render_top_most[2] = g.NavWindowingTarget and g.NavWindowingListWindow or nil for _, window in g.Windows:iter() do if ImGui.IsWindowActiveAndVisible(window) and (bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0) and window ~= windows_to_render_top_most[1] and window ~= windows_to_render_top_most[2] then AddRootWindowToDrawData(window) end end for n = 1, 2 do if windows_to_render_top_most[n] and ImGui.IsWindowActiveAndVisible(windows_to_render_top_most[n]) then -- NavWindowingTarget is always temporarily displayed as the top-most window AddRootWindowToDrawData(windows_to_render_top_most[n]) end end -- Draw software mouse cursor if requested by io.MouseDrawCursor flag if g.IO.MouseDrawCursor and g.MouseCursor ~= ImGuiMouseCursor.None then ImGui.RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)) end g.IO.MetricsRenderVertices = 0 g.IO.MetricsRenderIndices = 0 for _, viewport in g.Viewports:iter() do FlattenDrawDataIntoSingleLayer(viewport.DrawDataBuilder) if viewport.BgFgDrawLists[2] ~= nil and viewport.BgFgDrawListsLastTimeActive[2] == g.Time then ImGui.AddDrawListToDrawDataEx(viewport.DrawDataP, viewport.DrawDataBuilder.Layers[1], ImGui.GetForegroundDrawList(viewport)) end local draw_data = viewport.DrawDataP for _, draw_list in draw_data.CmdLists:iter() do draw_list:_PopUnusedDrawCmd() end g.IO.MetricsRenderVertices = g.IO.MetricsRenderVertices + draw_data.TotalVtxCount g.IO.MetricsRenderIndices = g.IO.MetricsRenderIndices + draw_data.TotalIdxCount end end --- @param text ImString --- @param text_end? int # Exclusive upper bound --- @param hide_text_after_double_hash? bool --- @param wrap_width? float --- @return ImVec2 @native function ImGui.CalcTextSize(text, text_end, hide_text_after_double_hash, wrap_width) return ImGui.CalcTextSizeEx(text, 1, text_end, hide_text_after_double_hash, wrap_width) end --- @param text ImString --- @param text_begin int --- @param text_end? int # Exclusive upper bound --- @param hide_text_after_double_hash? bool --- @param wrap_width? float --- @return ImVec2 @native function ImGui.CalcTextSizeEx(text, text_begin, text_end, hide_text_after_double_hash, wrap_width) if hide_text_after_double_hash == nil then hide_text_after_double_hash = false end if wrap_width == nil then wrap_width = -1.0 end local g = GImGui local text_display_end if hide_text_after_double_hash then text_display_end = ImGui.FindRenderedTextEnd(text, text_end) else text_display_end = text_end end local font = g.Font local font_size = g.FontSize if text == "" or (text_end and text_end <= text_begin) then return ImVec2(0.0, font_size) end local text_size = font:CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_begin, text_display_end, nil) text_size.x = ImCeilFast(text_size.x) return text_size end function ImGui.GetDrawData() local g = GImGui local viewport = g.Viewports[1] return viewport.DrawDataP.Valid and viewport.DrawDataP or nil end function ImGui.GetTime() return GImGui.Time end function ImGui.Shutdown() local g = GImGui IM_ASSERT_USER_ERROR(g.IO.BackendPlatformUserData == nil, "Forgot to shutdown Platform backend?") IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == nil, "Forgot to shutdown Renderer backend?") for _, viewport in g.Viewports:iter() do -- IM_UNUSED(viewport) IM_ASSERT_USER_ERROR(viewport.RendererUserData == nil and viewport.PlatformUserData == nil and viewport.PlatformHandle == nil, "Backend or app forgot to call DestroyPlatformWindows()?") end for _, atlas in g.FontAtlases:iter() do ImGui.UnregisterFontAtlas(atlas) if atlas.OwnerContext == g then IM_ASSERT(atlas.RefCount == 0, "Destroying context owning a ImFontAtlas which is still used elsewhere!") if atlas.RefCount == 0 then atlas.Locked = false end end end g.DrawListSharedData.TempBuffer:clear() ImGui.DockContextShutdown(g) if not g.Initialized then return end -- TODO: g.MenusIdSubmittedThisFrame:clear() end --- @return string? function ImGui.GetClipboardText() local g = GImGui return g.PlatformIO.Platform_GetClipboardTextFn and g.PlatformIO.Platform_GetClipboardTextFn(g) or nil end --- @param text string function ImGui.SetClipboardText(text) local g = GImGui if g.PlatformIO.Platform_SetClipboardTextFn ~= nil then g.PlatformIO.Platform_SetClipboardTextFn(g, text) end end function ImGui.GetIO() return GImGui.IO end --- @return ImGuiPlatformIO function ImGui.GetPlatformIO() IM_ASSERT(GImGui ~= nil, "No current context. Did you call ImGui.CreateContext() and ImGui.SetCurrentContext()?") return GImGui.PlatformIO end function ImGui.GetMouseCursor() local g = GImGui return g.MouseCursor end --- @param cursor_type ImGuiMouseCursor function ImGui.SetMouseCursor(cursor_type) local g = GImGui g.MouseCursor = cursor_type end --- @param col_a ImU32 --- @param col_b ImU32 --- @return ImU32 function ImStd.ImAlphaBlendColors(col_a, col_b) local t = bit32.band(bit32.rshift(col_b, IM_COL32_A_SHIFT), 0xFF) / 255.0 local r = ImLerp(bit32.band(bit32.rshift(col_a, IM_COL32_R_SHIFT), 0xFF), bit32.band(bit32.rshift(col_b, IM_COL32_R_SHIFT), 0xFF), t) local g = ImLerp(bit32.band(bit32.rshift(col_a, IM_COL32_G_SHIFT), 0xFF), bit32.band(bit32.rshift(col_b, IM_COL32_G_SHIFT), 0xFF), t) local b = ImLerp(bit32.band(bit32.rshift(col_a, IM_COL32_B_SHIFT), 0xFF), bit32.band(bit32.rshift(col_b, IM_COL32_B_SHIFT), 0xFF), t) return IM_COL32(r, g, b, 0xFF) end --- @param in_col ImU32 --- @param out_col ImVec4? --- @return ImVec4? function ImGui.ColorConvertU32ToFloat4(in_col, out_col) local s = 1.0 / 255.0 local r = bit32.band(bit32.rshift(in_col, IM_COL32_R_SHIFT), 0xFF) * s local g = bit32.band(bit32.rshift(in_col, IM_COL32_G_SHIFT), 0xFF) * s local b = bit32.band(bit32.rshift(in_col, IM_COL32_B_SHIFT), 0xFF) * s local a = bit32.band(bit32.rshift(in_col, IM_COL32_A_SHIFT), 0xFF) * s if out_col then out_col[1] = r; out_col[2] = g; out_col[3] = b; out_col[4] = a else return ImVec4(r, g, b, a) end end --- @param in_col ImVec4 --- @return ImU32 local function F32ToU8Sat(v) if v < 0.0 then v = 0.0 elseif v > 1.0 then v = 1.0 end return math.floor(v * 255.0 + 0.5) end @native function ImGui.ColorConvertFloat4ToU32(in_col) return bit32.bor(F32ToU8Sat(in_col.x), bit32.lshift(F32ToU8Sat(in_col.y), 8), bit32.lshift(F32ToU8Sat(in_col.z), 16), bit32.lshift(F32ToU8Sat(in_col.w), 24)) end --- @param r float --- @param g float --- @param b float --- @return float, float, float @native function ImGui.ColorConvertRGBtoHSV(r, g, b) local K = 0.0 if g < b then g, b = b, g K = -1.0 end if r < g then r, g = g, r K = -2.0 / 6.0 - K end local chroma = r - (g < b and g or b) local out_h = ImFabs(K + (g - b) / (6.0 * chroma + 1e-20)) local out_s = chroma / (r + 1e-20) local out_v = r return out_h, out_s, out_v end --- @param h float --- @param s float --- @param v float --- @return float, float, float @native function ImGui.ColorConvertHSVtoRGB(h, s, v) if s == 0.0 then -- gray return v, v, v end h = ImFmod(h, 1.0) / (60.0 / 360.0) local i = math.floor(h) local f = h - i local p = v * (1.0 - s) local q = v * (1.0 - s * f) local t = v * (1.0 - s * (1.0 - f)) if i == 0 then return v, t, p elseif i == 1 then return q, v, p elseif i == 2 then return p, v, t elseif i == 3 then return p, q, v elseif i == 4 then return t, p, v else -- i == 5 or default return v, p, q end end --- @param clip_rect ImRect --- @param pos ImVec2 --- @param items_height float function ImGui.CalcClipRectVisibleItemsY(clip_rect, pos, items_height) local visible_start = ImMax(ImTrunc((clip_rect.Min.y - pos.y) / items_height), 0) local visible_end = ImMax(ImTrunc(ImCeil((clip_rect.Max.y - pos.y) / items_height)), visible_start) return visible_start + 1, visible_end + 1 end --------------------------------------------------------------------------------------- -- [SECTION] STYLING --------------------------------------------------------------------------------------- function ImGui.GetStyle() IM_ASSERT(GImGui ~= nil, "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?") return GImGui.Style end do local c = ImVec4() --- @param col ImGuiCol|ImVec4|ImU32 --- @param alpha_mul? float --- @param col_is_u32? bool # must be truthy if `col` is `ImU32` --- @return ImU32 @native function ImGui.GetColorU32(col, alpha_mul, col_is_u32) if alpha_mul == nil then alpha_mul = 1.0 end local style = GImGui.Style if not col_is_u32 then --- @cast col ImVec4|ImGuiCol local w if type(col) == "number" then col = style.Colors[col] w = col.w * style.Alpha * alpha_mul else --- @cast col ImVec4 w = col.w * style.Alpha end return bit32.bor(F32ToU8Sat(col.x), bit32.lshift(F32ToU8Sat(col.y), 8), bit32.lshift(F32ToU8Sat(col.z), 16), bit32.lshift(F32ToU8Sat(w), 24)) else --- @cast col ImU32 alpha_mul = alpha_mul * style.Alpha if alpha_mul >= 1.0 then return col end local a = bit32.rshift(bit32.band(col, IM_COL32_A_MASK), IM_COL32_A_SHIFT) a = math.floor(a * alpha_mul) -- We don't need to clamp 0..255 because alpha is in 0..1 range. return bit32.bor(bit32.band(col, bit32.bnot(IM_COL32_A_MASK)), bit32.lshift(a, IM_COL32_A_SHIFT)) end end end --- @param idx ImGuiCol --- @param col ImU32|ImVec4 function ImGui.PushStyleColor(idx, col) local g = GImGui local backup = ImGuiColorMod(idx, g.Style.Colors[idx]) g.ColorStack:push_back(backup) if g.DebugFlashStyleColorIdx ~= idx then if type(col) == "number" then ImGui.ColorConvertU32ToFloat4(col, g.Style.Colors[idx]) else --- @cast col ImVec4 ImVec4_Copy(g.Style.Colors[idx], col) end end end --- @param count? int function ImGui.PopStyleColor(count) if count == nil then count = 1 end local g = GImGui if g.ColorStack.Size < count then IM_ASSERT_USER_ERROR(false, "Calling PopStyleColor() too many times!") count = g.ColorStack.Size end while count > 0 do local backup = g.ColorStack:back() ImVec4_Copy(g.Style.Colors[backup.Col], backup.BackupValue) g.ColorStack:pop_back() count = count - 1 end end local GStyleVarsInfo = { ImGuiStyleVarInfo(1, ImGuiDataType.Float, "Alpha"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "DisabledAlpha"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "WindowPadding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "WindowRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "WindowBorderSize"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "WindowMinSize"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "WindowTitleAlign"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ChildRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ChildBorderSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "PopupRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "PopupBorderSize"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "FramePadding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "FrameRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "FrameBorderSize"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "ItemSpacing"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "ItemInnerSpacing"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "IndentSpacing"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "CellPadding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ScrollbarSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ScrollbarRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ScrollbarPadding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "GrabMinSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "GrabRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ImageRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "ImageBorderSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabBorderSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabMinWidthBase"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabMinWidthShrink"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabBarBorderSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TabBarOverlineSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TableAngledHeadersAngle"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "TableAngledHeadersTextAlign"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TreeLinesSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "TreeLinesRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "MenuItemRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "SelectableRounding"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "DragDropTargetRounding"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "ButtonTextAlign"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "SelectableTextAlign"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "SeparatorSize"), ImGuiStyleVarInfo(1, ImGuiDataType.Float, "SeparatorTextBorderSize"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "SeparatorTextAlign"), ImGuiStyleVarInfo(2, ImGuiDataType.Float, "SeparatorTextPadding") } --- @param idx ImGuiStyleVar --- @return ImGuiStyleVarInfo function ImGui.GetStyleVarInfo(idx) IM_ASSERT(idx >= 0 and idx < ImGuiStyleVar.COUNT) -- IM_STATIC_ASSERT(IM_COUNTOF(GStyleVarsInfo) == ImGuiStyleVar_COUNT) return GStyleVarsInfo[idx + 1] end --- @param idx ImGuiStyleVar --- @param val float|ImVec2 function ImGui.PushStyleVar(idx, val) local g = GImGui local var_info = ImGui.GetStyleVarInfo(idx) if type(val) == "number" then IM_ASSERT_USER_ERROR_RET(var_info.DataType == ImGuiDataType.Float and var_info.Count == 1, "Calling PushStyleVar() with wrong type!") else -- ImVec2 IM_ASSERT_USER_ERROR_RET(var_info.DataType == ImGuiDataType.Float and var_info.Count == 2, "Calling PushStyleVar() with wrong type!") end local var = g.Style[var_info.Key] g.StyleVarStack:push_back(ImGuiStyleMod(idx, var)) if type(val) == "number" then g.Style[var_info.Key] = val else -- copy into the style's own ImVec2: storing the caller's vector would alias it into the style forever var.x = val.x; var.y = val.y end end --- @param idx ImGuiStyleVar --- @param val_x float function ImGui.PushStyleVarX(idx, val_x) local g = GImGui local var_info = ImGui.GetStyleVarInfo(idx) IM_ASSERT_USER_ERROR_RET(var_info.DataType == ImGuiDataType.Float and var_info.Count == 2, "Calling PushStyleVarX() with wrong type!") local pvar = g.Style[var_info.Key] g.StyleVarStack:push_back(ImGuiStyleMod(idx, pvar)) pvar.x = val_x end --- @param idx ImGuiStyleVar --- @param val_y float function ImGui.PushStyleVarY(idx, val_y) local g = GImGui local var_info = ImGui.GetStyleVarInfo(idx) IM_ASSERT_USER_ERROR_RET(var_info.DataType == ImGuiDataType.Float and var_info.Count == 2, "Calling PushStyleVarY() with wrong type!") local pvar = g.Style[var_info.Key] g.StyleVarStack:push_back(ImGuiStyleMod(idx, pvar)) pvar.y = val_y end --- @param count? int function ImGui.PopStyleVar(count) if count == nil then count = 1 end local g = GImGui if g.StyleVarStack.Size < count then IM_ASSERT_USER_ERROR(0, "Calling PopStyleVar() too many times!") count = g.StyleVarStack.Size end while count > 0 do local backup = g.StyleVarStack:back() local var_info = ImGui.GetStyleVarInfo(backup.VarIdx) local data = g.Style[var_info.Key] if (var_info.DataType == ImGuiDataType.Float and var_info.Count == 1) then g.Style[var_info.Key] = backup.BackupVal[1] elseif (var_info.DataType == ImGuiDataType.Float and var_info.Count == 2) then data.x = backup.BackupVal[1]; data.y = backup.BackupVal[2] end g.StyleVarStack:pop_back() count = count - 1 end end --- @param wrap_local_pos_x float function ImGui.PushTextWrapPos(wrap_local_pos_x) -- ATTENTION: THIS IS IN LEGACY LOCAL SPACE. local g = GImGui local window = g.CurrentWindow window.DC.TextWrapPosStack:push_back(window.DC.TextWrapPos) window.DC.TextWrapPos = wrap_local_pos_x end function ImGui.PopTextWrapPos() local g = GImGui local window = g.CurrentWindow IM_ASSERT_USER_ERROR_RET(window.DC.TextWrapPosStack.Size > 0, "Calling PopTextWrapPos() too many times!") window.DC.TextWrapPos = window.DC.TextWrapPosStack:back() window.DC.TextWrapPosStack:pop_back() end --- @param window ImGuiWindow --- @param popup_hierarchy bool --- @param dock_hierarchy bool local function GetCombinedRootWindow(window, popup_hierarchy, dock_hierarchy) local last_window = nil while last_window ~= window do last_window = window window = window.RootWindow if popup_hierarchy then window = window.RootWindowPopupTree end if dock_hierarchy then window = window.RootWindowDockTree end end return window end --- @param window ImGuiWindow --- @param potential_parent ImGuiWindow --- @param popup_hierarchy bool --- @param dock_hierarchy bool function ImGui.IsWindowChildOf(window, potential_parent, popup_hierarchy, dock_hierarchy) local window_root = GetCombinedRootWindow(window, popup_hierarchy, dock_hierarchy) if window_root == potential_parent then return true end while window ~= nil do if window == potential_parent then return true end if window == window_root then -- end of chain return false end window = window.ParentWindow end return false end --- @param window ImGuiWindow function ImGui.IsWindowInBeginStack(window) local g = GImGui for n = g.CurrentWindowStack.Size, 1, -1 do if g.CurrentWindowStack.Data[n].Window == window then return true end end return false end --- @param window ImGuiWindow --- @param potential_parent ImGuiWindow function ImGui.IsWindowWithinBeginStackOf(window, potential_parent) if window.RootWindow == potential_parent then return true end while window ~= nil do if window == potential_parent then return true end window = window.ParentWindowInBeginStack end return false end --- @param potential_above ImGuiWindow --- @param potential_below ImGuiWindow --- @return bool function ImGui.IsWindowAbove(potential_above, potential_below) local g = GImGui -- It would be saner to ensure that display layer is always reflected in the g.Windows order, which would likely requires altering all manipulations of that array local display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below) if display_layer_delta ~= 0 then return display_layer_delta > 0 end for i = g.Windows.Size, 1, -1 do local candidate_window = g.Windows.Data[i] if candidate_window == potential_above then return true end if candidate_window == potential_below then return false end end return false end -- Is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags for options. --- @param flags? ImGuiHoveredFlags function ImGui.IsWindowHovered(flags) if flags == nil then flags = 0 end local g = GImGui IM_ASSERT_USER_ERROR(bit32.band(flags, bit32.bnot(ImGuiHoveredFlags.AllowedMaskForIsWindowHovered)) == 0, "Invalid flags for IsWindowHovered()!") local ref_window = g.HoveredWindow local cur_window = g.CurrentWindow if ref_window == nil then return false end if bit32.band(flags, ImGuiHoveredFlags.AnyWindow) == 0 then IM_ASSERT(cur_window) -- Not inside a Begin()/End() local popup_hierarchy = bit32.band(flags, ImGuiHoveredFlags.NoPopupHierarchy) == 0 local dock_hierarchy = bit32.band(flags, ImGuiHoveredFlags.DockHierarchy) ~= 0 if bit32.band(flags, ImGuiHoveredFlags.RootWindow) ~= 0 then cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy) end local result if bit32.band(flags, ImGuiHoveredFlags.ChildWindows) ~= 0 then result = ImGui.IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy) else result = (ref_window == cur_window) end if not result then return false end end if not ImGui.IsWindowContentHoverable(ref_window, flags) then return false end if bit32.band(flags, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) == 0 then if g.ActiveId ~= 0 and not g.ActiveIdAllowOverlap and g.ActiveId ~= ref_window.MoveId then return false end end if bit32.band(flags, ImGuiHoveredFlags.ForTooltip) ~= 0 then flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipMouse) end if bit32.band(flags, ImGuiHoveredFlags.Stationary) ~= 0 and g.HoverWindowUnlockedStationaryId ~= ref_window.ID then return false end return true end -- Similar to IsWindowHovered() --- @param flags? ImGuiFocusedFlags function ImGui.IsWindowFocused(flags) if flags == nil then flags = 0 end local g = GImGui local ref_window = g.NavWindow local cur_window = g.CurrentWindow if ref_window == nil then return false end if bit32.band(flags, ImGuiFocusedFlags.AnyWindow) ~= 0 then return true end IM_ASSERT(cur_window) -- Not inside a Begin()/End() local popup_hierarchy = bit32.band(flags, ImGuiFocusedFlags.NoPopupHierarchy) == 0 local dock_hierarchy = bit32.band(flags, ImGuiFocusedFlags.DockHierarchy) ~= 0 if bit32.band(flags, ImGuiFocusedFlags.RootWindow) ~= 0 then cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy) end if bit32.band(flags, ImGuiFocusedFlags.ChildWindows) ~= 0 then return ImGui.IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy) else return ref_window == cur_window end end --- @param window ImGuiWindow --- @param scale float local function ScaleWindow(window, scale) local origin = window.Viewport.Pos ImVec2_Copy(window.Pos, ImFloor((window.Pos - origin) * scale + origin)) ImVec2_Copy(window.Size, ImTrunc(window.Size * scale)) ImVec2_Copy(window.SizeFull, ImTrunc(window.SizeFull * scale)) ImVec2_Copy(window.ContentSize, ImTrunc(window.ContentSize * scale)) end --- @param viewport ImGuiViewportP --- @param scale float function ImGui.ScaleWindowsInViewport(viewport, scale) local g = GImGui -- IMGUI_DEBUG_LOG_VIEWPORT("[viewport] ScaleWindowsInViewport 0x%08X", viewport.ID) if viewport.Window then ScaleWindow(viewport.Window, scale) else for _, window in g.Windows:iter() do if window.Viewport == viewport then ScaleWindow(window, scale) end end end end --------------------------------------------------------------------------------------- -- [SECTION] SCROLLING --------------------------------------------------------------------------------------- --- @param target float --- @param snap_min float --- @param snap_max float --- @param snap_threshold float --- @param center_ratio float local function CalcScrollEdgeSnap(target, snap_min, snap_max, snap_threshold, center_ratio) if target <= snap_min + snap_threshold then return ImLerp(snap_min, target, center_ratio) end if target >= snap_max - snap_threshold then return ImLerp(target, snap_max, center_ratio) end return target end --- @param window ImGuiWindow function CalcNextScrollFromScrollTargetAndClamp(window) local scroll = ImVec2() ImVec2_Copy(scroll, window.Scroll) local decoration_size = ImVec2(window.DecoOuterSizeX1 + window.DecoInnerSizeX1 + window.DecoOuterSizeX2, window.DecoOuterSizeY1 + window.DecoInnerSizeY1 + window.DecoOuterSizeY2) for axis = ImGuiAxis.X, ImGuiAxis.Y do if window.ScrollTarget[axis] < FLT_MAX then local center_ratio = window.ScrollTargetCenterRatio[axis] local scroll_target = window.ScrollTarget[axis] if window.ScrollTargetEdgeSnapDist[axis] > 0.0 then local snap_min = 0.0 local snap_max = window.ScrollMax[axis] + window.SizeFull[axis] - decoration_size[axis] scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window.ScrollTargetEdgeSnapDist[axis], center_ratio) end scroll[axis] = scroll_target - center_ratio * (window.SizeFull[axis] - decoration_size[axis]) end scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0)) if not window.Collapsed and not window.SkipItems then scroll[axis] = ImMin(scroll[axis], window.ScrollMax[axis]) end end return scroll end --- @param window ImGuiWindow --- @param item_rect ImRect --- @param flags? ImGuiScrollFlags function ImGui.ScrollToRectEx(window, item_rect, flags) if flags == nil then flags = 0 end local g = GImGui local scroll_rect = ImRect(window.InnerRect.Min - ImVec2(1, 1), window.InnerRect.Max + ImVec2(1, 1)) scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window.DecoInnerSizeX1, scroll_rect.Max.x) scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window.DecoInnerSizeY1, scroll_rect.Max.y) IM_ASSERT(bit32.band(flags, ImGuiScrollFlags.MaskX_) == 0 or ImIsPowerOfTwo(bit32.band(flags, ImGuiScrollFlags.MaskX_))) IM_ASSERT(bit32.band(flags, ImGuiScrollFlags.MaskY_) == 0 or ImIsPowerOfTwo(bit32.band(flags, ImGuiScrollFlags.MaskY_))) local in_flags = flags if bit32.band(flags, ImGuiScrollFlags.MaskX_) == 0 and window.ScrollbarX then flags = bit32.bor(flags, ImGuiScrollFlags.KeepVisibleEdgeX) end if bit32.band(flags, ImGuiScrollFlags.MaskY_) == 0 then flags = bit32.bor(flags, window.Appearing and ImGuiScrollFlags.AlwaysCenterY or ImGuiScrollFlags.KeepVisibleEdgeY) end local fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x and item_rect.Max.x <= scroll_rect.Max.x local fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y and item_rect.Max.y <= scroll_rect.Max.y local can_be_fully_visible_x = (item_rect:GetWidth() + g.Style.ItemSpacing.x * 2.0) <= scroll_rect:GetWidth() or (window.AutoFitFramesX > 0) or bit32.band(window.Flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0 local can_be_fully_visible_y = (item_rect:GetHeight() + g.Style.ItemSpacing.y * 2.0) <= scroll_rect:GetHeight() or (window.AutoFitFramesY > 0) or bit32.band(window.Flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0 if bit32.band(flags, ImGuiScrollFlags.KeepVisibleEdgeX) ~= 0 and not fully_visible_x then if item_rect.Min.x < scroll_rect.Min.x or not can_be_fully_visible_x then ImGui.SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window.Pos.x, 0.0) elseif item_rect.Max.x >= scroll_rect.Max.x then ImGui.SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window.Pos.x, 1.0) end elseif (bit32.band(flags, ImGuiScrollFlags.KeepVisibleCenterX) ~= 0 and not fully_visible_x) or bit32.band(flags, ImGuiScrollFlags.AlwaysCenterX) ~= 0 then if can_be_fully_visible_x then ImGui.SetScrollFromPosX(window, ImTrunc((item_rect.Min.x + item_rect.Max.x) * 0.5) - window.Pos.x, 0.5) else ImGui.SetScrollFromPosX(window, item_rect.Min.x - window.Pos.x, 0.0) end end if bit32.band(flags, ImGuiScrollFlags.KeepVisibleEdgeY) ~= 0 and not fully_visible_y then if item_rect.Min.y < scroll_rect.Min.y or not can_be_fully_visible_y then ImGui.SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window.Pos.y, 0.0) elseif item_rect.Max.y >= scroll_rect.Max.y then ImGui.SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window.Pos.y, 1.0) end elseif (bit32.band(flags, ImGuiScrollFlags.KeepVisibleCenterY) ~= 0 and not fully_visible_y) or bit32.band(flags, ImGuiScrollFlags.AlwaysCenterY) ~= 0 then if can_be_fully_visible_y then ImGui.SetScrollFromPosY(window, ImTrunc((item_rect.Min.y + item_rect.Max.y) * 0.5) - window.Pos.y, 0.5) else ImGui.SetScrollFromPosY(window, item_rect.Min.y - window.Pos.y, 0.0) end end local next_scroll = CalcNextScrollFromScrollTargetAndClamp(window) local delta_scroll = next_scroll - window.Scroll if bit32.band(flags, ImGuiScrollFlags.NoScrollParent) == 0 and bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then if bit32.band(in_flags, bit32.bor(ImGuiScrollFlags.AlwaysCenterX, ImGuiScrollFlags.KeepVisibleCenterX)) ~= 0 then in_flags = bit32.bor(bit32.band(in_flags, bit32.bnot(ImGuiScrollFlags.MaskX_)), ImGuiScrollFlags.KeepVisibleEdgeX) end if bit32.band(in_flags, bit32.bor(ImGuiScrollFlags.AlwaysCenterY, ImGuiScrollFlags.KeepVisibleCenterY)) ~= 0 then in_flags = bit32.bor(bit32.band(in_flags, bit32.bnot(ImGuiScrollFlags.MaskY_)), ImGuiScrollFlags.KeepVisibleEdgeY) end local parent_delta = ImGui.ScrollToRectEx(window.ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags) delta_scroll = delta_scroll + parent_delta end return delta_scroll end --- @return float function ImGui.GetScrollMaxY() local window = GImGui.CurrentWindow return window.ScrollMax.y end function ImGui.GetScrollMaxX() return GImGui.CurrentWindow.ScrollMax.x end function ImGui.GetScrollX() return GImGui.CurrentWindow.Scroll.x end function ImGui.GetScrollY() return GImGui.CurrentWindow.Scroll.y end --- @param flags? ImGuiScrollFlags function ImGui.ScrollToItem(flags) local g = GImGui ImGui.ScrollToRectEx(g.CurrentWindow, g.LastItemData.NavRect, flags or 0) end --- @param window ImGuiWindow --- @param item_rect ImRect --- @param flags? ImGuiScrollFlags function ImGui.ScrollToRect(window, item_rect, flags) ImGui.ScrollToRectEx(window, item_rect, flags or 0) end --- @param center_x_ratio? float function ImGui.SetScrollHereX(center_x_ratio) if center_x_ratio == nil then center_x_ratio = 0.5 end local g = GImGui local window = g.CurrentWindow local spacing_x = ImMax(window.WindowPadding.x, g.Style.ItemSpacing.x) local target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio) ImGui.SetScrollFromPosX(window, target_pos_x - window.Pos.x, center_x_ratio) window.ScrollTargetEdgeSnapDist.x = ImMax(0.0, window.WindowPadding.x - spacing_x) end --- @param center_y_ratio? float function ImGui.SetScrollHereY(center_y_ratio) if center_y_ratio == nil then center_y_ratio = 0.5 end local g = GImGui local window = g.CurrentWindow local spacing_y = ImMax(window.WindowPadding.y, g.Style.ItemSpacing.y) local target_pos_y = ImLerp(window.DC.CursorPosPrevLine.y - spacing_y, window.DC.CursorPosPrevLine.y + window.DC.PrevLineSize.y + spacing_y, center_y_ratio) ImGui.SetScrollFromPosY(window, target_pos_y - window.Pos.y, center_y_ratio) window.ScrollTargetEdgeSnapDist.y = ImMax(0.0, window.WindowPadding.y - spacing_y) end -- Overloads: SetScrollX(scroll_x) / SetScrollX(window, scroll_x) --- @param window ImGuiWindow|float --- @param scroll_x float? function ImGui.SetScrollX(window, scroll_x) if type(window) == "number" then window, scroll_x = GImGui.CurrentWindow, window end window.ScrollTarget.x = scroll_x window.ScrollTargetCenterRatio.x = 0.0 window.ScrollTargetEdgeSnapDist.x = 0.0 end --- @param window ImGuiWindow --- @param scroll_y float function ImGui.SetScrollY(window, scroll_y) if type(window) == "number" then window, scroll_y = GImGui.CurrentWindow, window end window.ScrollTarget.y = scroll_y window.ScrollTargetCenterRatio.y = 0.0 window.ScrollTargetEdgeSnapDist.y = 0.0 end --- @param window ImGuiWindow --- @param local_x float --- @param center_x_ratio float function ImGui.SetScrollFromPosX(window, local_x, center_x_ratio) if type(window) == "number" then window, local_x, center_x_ratio = GImGui.CurrentWindow, window, local_x end if center_x_ratio == nil then center_x_ratio = 0.5 end IM_ASSERT(center_x_ratio >= 0.0 and center_x_ratio <= 1.0) window.ScrollTarget.x = IM_TRUNC(local_x - window.DecoOuterSizeX1 - window.DecoInnerSizeX1 + window.Scroll.x) window.ScrollTargetCenterRatio.x = center_x_ratio window.ScrollTargetEdgeSnapDist.x = 0.0 end --- @param window ImGuiWindow --- @param local_y float --- @param center_y_ratio float function ImGui.SetScrollFromPosY(window, local_y, center_y_ratio) if type(window) == "number" then window, local_y, center_y_ratio = GImGui.CurrentWindow, window, local_y end if center_y_ratio == nil then center_y_ratio = 0.5 end IM_ASSERT(center_y_ratio >= 0.0 and center_y_ratio <= 1.0) window.ScrollTarget.y = IM_TRUNC(local_y - window.DecoOuterSizeY1 - window.DecoInnerSizeY1 + window.Scroll.y) window.ScrollTargetCenterRatio.y = center_y_ratio window.ScrollTargetEdgeSnapDist.y = 0.0 end --------------------------------------------------------------------------------------- -- [SECTION] TOOLTIPS --------------------------------------------------------------------------------------- --- @param tooltip_flags ImGuiTooltipFlags --- @param extra_window_flags ImGuiWindowFlags function ImGui.BeginTooltipEx(tooltip_flags, extra_window_flags) local g = GImGui local is_dragdrop_tooltip = g.DragDropWithinSource or g.DragDropWithinTarget if is_dragdrop_tooltip then local is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource.TouchScreen) if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasPos) == 0 then local tooltip_pos if is_touchscreen then tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * g.Style.MouseCursorScale else tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * g.Style.MouseCursorScale end local tooltip_pivot = is_touchscreen and TOOLTIP_DEFAULT_PIVOT_TOUCH or ImVec2(0.0, 0.0) ImGui.SetNextWindowPos(tooltip_pos, ImGuiCond.None, tooltip_pivot) end local bg_alpha = g.Style.Colors[ImGuiCol.PopupBg].w * 0.60 ImGui.SetNextWindowBgAlpha(bg_alpha) tooltip_flags = bit32.bor(tooltip_flags, ImGuiTooltipFlags.OverridePrevious) end if (bit32.band(tooltip_flags, ImGuiTooltipFlags.OverridePrevious) ~= 0) and g.TooltipPreviousWindow ~= nil and g.TooltipPreviousWindow.Active and not ImGui.IsWindowInBeginStack(g.TooltipPreviousWindow) then -- IMGUI_DEBUG_LOG("[tooltip] '%s' already active, using +1 for this frame\n", window_name) ImGui.SetWindowHiddenAndSkipItemsForCurrentFrame(g.TooltipPreviousWindow) g.TooltipOverrideCount = g.TooltipOverrideCount + 1 end local window_name_template = is_dragdrop_tooltip and "##Tooltip_DragDrop_%02d" or "##Tooltip_%02d" local window_name = ImFormatString(window_name_template, g.TooltipOverrideCount) local flags = bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.NoInputs, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.AlwaysAutoResize) ImGui.Begin(window_name, nil, bit32.bor(flags, extra_window_flags)) return true end function ImGui.BeginTooltip() return ImGui.BeginTooltipEx(ImGuiTooltipFlags.None, ImGuiWindowFlags.None) end function ImGui.BeginItemTooltip() if not ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) then return false end return ImGui.BeginTooltipEx(ImGuiTooltipFlags.None, ImGuiWindowFlags.None) end function ImGui.EndTooltip() IM_ASSERT(bit32.band(ImGui.GetCurrentWindowRead().Flags, ImGuiWindowFlags.Tooltip) ~= 0) -- Mismatched BeginTooltip()/EndTooltip() calls ImGui.End() end --- @param fmt string --- @param ... any function ImGui.SetTooltip(fmt, ...) if not ImGui.BeginTooltipEx(ImGuiTooltipFlags.OverridePrevious, ImGuiWindowFlags.None) then return end ImGui.TextV(fmt, ...) ImGui.EndTooltip() end --- @param fmt string --- @param ... any function ImGui.SetItemTooltip(fmt, ...) if ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) then ImGui.SetTooltip(fmt, ...) end end --------------------------------------------------------------------------------------- -- [SECTION] POPUPS --------------------------------------------------------------------------------------- --- @param window? ImGuiWindow function ImGui.FindBlockingModal(window) local g = GImGui if g.OpenPopupStack.Size <= 0 then return nil end for i = 1, g.OpenPopupStack.Size do repeat local popup_data = g.OpenPopupStack.Data[i] local popup_window = popup_data.Window if popup_window == nil or bit32.band(popup_window.Flags, ImGuiWindowFlags.Modal) == 0 then break end if not popup_window.Active and not popup_window.WasActive then break end if window == nil then return popup_window end if ImGui.IsWindowWithinBeginStackOf(window, popup_window) then break end do return popup_window end until true end return nil end --- @param id ImGuiID|string --- @param popup_flags? ImGuiPopupFlags function ImGui.OpenPopup(id, popup_flags) if popup_flags == nil then popup_flags = 0 end if type(id) == "number" then return ImGui.OpenPopupEx(id, popup_flags) else --- @cast id string local g = GImGui local _id = g.CurrentWindow:GetID(id) IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)", id, _id) return ImGui.OpenPopupEx(_id, popup_flags) end end --- @param id ImGuiID --- @param popup_flags ImGuiPopupFlags function ImGui.OpenPopupEx(id, popup_flags) local g = GImGui local parent_window = g.CurrentWindow local current_stack_size = g.BeginPopupStack.Size if bit32.band(popup_flags, ImGuiPopupFlags.NoOpenOverExistingPopup) ~= 0 then if ImGui.IsPopupOpen(0, ImGuiPopupFlags.AnyPopupId) then return false end end local popup_ref = ImGuiPopupData() popup_ref.PopupId = id popup_ref.Window = nil popup_ref.RestoreNavWindow = g.NavWindow -- When popup closes focus may be restored to NavWindow (depend on window type). popup_ref.OpenFrameCount = g.FrameCount popup_ref.OpenParentId = parent_window.IDStack:back() ImVec2_Copy(popup_ref.OpenPopupPos, ImGui.NavCalcPreferredRefPos(ImGuiWindowFlags.Popup)) if ImGui.IsMousePosValid(g.IO.MousePos) then ImVec2_Copy(popup_ref.OpenMousePos, g.IO.MousePos) else ImVec2_Copy(popup_ref.OpenMousePos, popup_ref.OpenPopupPos) end -- IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)", id) if g.OpenPopupStack.Size < current_stack_size + 1 then g.OpenPopupStack:push_back(popup_ref) return true else -- Gently handle the user mistakenly calling OpenPopup() every frames: it is likely a programming mistake! -- However, if we were to run the regular code path, the ui would become completely unusable because the popup will always be -- in hidden-while-calculating-size state _while_ claiming focus. Which is extremely confusing situation for the programmer. -- Instead, for successive frames calls to OpenPopup(), we silently avoid reopening even if ImGuiPopupFlags.NoReopen is not specified. local keep_existing = false if g.OpenPopupStack.Data[current_stack_size + 1].PopupId == id then if (g.OpenPopupStack.Data[current_stack_size + 1].OpenFrameCount == g.FrameCount - 1) or (bit32.band(popup_flags, ImGuiPopupFlags.NoReopen) ~= 0) then keep_existing = true end end if keep_existing then -- No reopen g.OpenPopupStack.Data[current_stack_size + 1].OpenFrameCount = popup_ref.OpenFrameCount else -- Reopen: close child popups if any, then flag popup for open/reopen (set position, focus, init navigation) ImGui.ClosePopupToLevel(current_stack_size, true) g.OpenPopupStack:push_back(popup_ref) end -- When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). -- This is equivalent to what ClosePopupToLevel() does. -- if (g.OpenPopupStack[current_stack_size + 1].PopupId == id) -- FocusWindow(parent_window); return not keep_existing end end -- When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. -- This function closes any popups that are over 'ref_window'. --- @param ref_window? ImGuiWindow --- @param restore_focus_to_window_under_popup bool function ImGui.ClosePopupsOverWindow(ref_window, restore_focus_to_window_under_popup) local g = GImGui if g.OpenPopupStack.Size == 0 then return end -- Don't close our own child popup windows. -- IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\") restore_under=%d", ref_window and ref_window.Name or "", restore_focus_to_window_under_popup) local popup_count_to_keep = 0 if ref_window then -- Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) local ref_window_is_descendent_of_popup local stop_8041 = false while popup_count_to_keep < g.OpenPopupStack.Size do repeat local popup = g.OpenPopupStack.Data[popup_count_to_keep + 1] if not popup.Window then break end IM_ASSERT(bit32.band(popup.Window.Flags, ImGuiWindowFlags.Popup) ~= 0) -- Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow) -- - Clicking/Focusing Window2 won't close Popup1: -- Window -> Popup1 -> Window2(Ref) -- - Clicking/focusing Popup1 will close Popup2 and Popup3: -- Window -> Popup1(Ref) -> Popup2 -> Popup3 -- - Each popups may contain child windows, which is why we compare ->RootWindow! -- Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child -- We step through every popup from bottom to top to validate their position relative to reference window. ref_window_is_descendent_of_popup = false for n = popup_count_to_keep, g.OpenPopupStack.Size - 1 do local popup_window = g.OpenPopupStack.Data[n + 1].Window if popup_window and ImGui.IsWindowWithinBeginStackOf(ref_window, popup_window) then ref_window_is_descendent_of_popup = true break end end if not ref_window_is_descendent_of_popup then stop_8041 = true; break end until true if stop_8041 then break end popup_count_to_keep = popup_count_to_keep + 1 end end if popup_count_to_keep < g.OpenPopupStack.Size then -- This test is not required but it allows to set a convenient breakpoint on the statement below -- IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")", ref_window and ref_window.Name or "") ImGui.ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup) end end --- @param remaining int # 0-based --- @param restore_focus_to_window_under_popup bool function ImGui.ClosePopupToLevel(remaining, restore_focus_to_window_under_popup) local g = GImGui -- IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d", remaining, restore_focus_to_window_under_popup) IM_ASSERT(remaining >= 0 and remaining < g.OpenPopupStack.Size) -- if bit32.band(g.DebugLogFlags, ImGuiDebugLogFlags.EventPopup) ~= 0 then -- for n = remaining + 1, g.OpenPopupStack.Size do -- local popup = g.OpenPopupStack.Data[n] -- IMGUI_DEBUG_LOG_POPUP("[popup] - Closing PopupID 0x%08X Window \"%s\"", popup.PopupId, popup.Window and popup.Window.Name or nil) -- end -- end -- Trim open popup stack -- FIXME: is it safer to full copy here? local prev_popup = g.OpenPopupStack.Data[remaining + 1] g.OpenPopupStack:resize(remaining) -- Restore focus (unless popup window was not yet submitted, and didn't have a chance to take focus anyhow. See #7325 for an edge case) if restore_focus_to_window_under_popup and prev_popup.Window then local popup_window = prev_popup.Window local focus_window if bit32.band(popup_window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then focus_window = popup_window.ParentWindow else focus_window = prev_popup.RestoreNavWindow end if focus_window and not focus_window.WasActive then ImGui.FocusTopMostWindowUnderOne(popup_window, nil, nil, ImGuiFocusRequestFlags.RestoreFocusedChild) -- Fallback else local focus_flags = (g.NavLayer == ImGuiNavLayer.Main) and ImGuiFocusRequestFlags.RestoreFocusedChild or ImGuiFocusRequestFlags.None ImGui.FocusWindow(focus_window, focus_flags) end end end -- Close the popup we have Begin-ed into function ImGui.CloseCurrentPopup() local g = GImGui local popup_idx = g.BeginPopupStack.Size if popup_idx < 1 or popup_idx > g.OpenPopupStack.Size or g.BeginPopupStack.Data[popup_idx].PopupId ~= g.OpenPopupStack.Data[popup_idx].PopupId then return end -- Closing a menu closes its top-most parent popup (unless a modal) while popup_idx > 1 do local popup_window = g.OpenPopupStack.Data[popup_idx].Window local parent_popup_window = g.OpenPopupStack.Data[popup_idx - 1].Window local close_parent = false if popup_window and bit32.band(popup_window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then if parent_popup_window and not (bit32.band(parent_popup_window.Flags, ImGuiWindowFlags.MenuBar) ~= 0) then close_parent = true end end if not close_parent then break end popup_idx = popup_idx - 1 end -- IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size, popup_idx) ImGui.ClosePopupToLevel(popup_idx - 1, true) -- A common pattern is to close a popup when selecting a menu item/selectable that will open another window. -- To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. -- Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. local window = g.NavWindow if window then window.DC.NavHideHighlightOneFrame = true end end --- @param id ImGuiID --- @param extra_window_flags ImGuiWindowFlags function ImGui.BeginPopupEx(id, extra_window_flags) local g = GImGui if not ImGui.IsPopupOpen(id, ImGuiPopupFlags.None) then g.NextWindowData:ClearFlags() return false end IM_ASSERT(bit32.band(extra_window_flags, ImGuiWindowFlags.ChildMenu) == 0) -- Use BeginPopupMenuEx() local name = ImFormatString("##Popup_%08x", id) -- No recycling, so we can close/open during the same frame local is_open _, is_open = ImGui.Begin(name, nil, bit32.bor(extra_window_flags, ImGuiWindowFlags.Popup, ImGuiWindowFlags.NoDocking)) if not is_open then -- NB: Begin can return false when the popup is completely clipped (e.g. zero size display) ImGui.EndPopup() end -- g.CurrentWindow.FocusRouteParentWindow = g.CurrentWindow.ParentWindowInBeginStack return is_open end --- @param id ImGuiID --- @param label any --- @param extra_window_flags ImGuiWindowFlags function ImGui.BeginPopupMenuEx(id, label, extra_window_flags) local g = GImGui if not ImGui.IsPopupOpen(id, ImGuiPopupFlags.None) then g.NextWindowData:ClearFlags() return false end if bit32.band(extra_window_flags, ImGuiWindowFlags.ChildWindow) ~= 0 and bit32.band(extra_window_flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0 then ImGui.SetNextWindowChildFlags(ImGuiChildFlags.AlwaysAutoResize, true) end IM_ASSERT(bit32.band(extra_window_flags, ImGuiWindowFlags.ChildMenu) ~= 0) local name = ImFormatString("%s###Menu_%02d", label, g.BeginMenuDepth) local is_open _, is_open = ImGui.Begin(name, nil, bit32.bor(extra_window_flags, ImGuiWindowFlags.Popup)) if not is_open then ImGui.EndPopup() end return is_open end --- @param str_id string --- @param flags? ImGuiWindowFlags function ImGui.BeginPopup(str_id, flags) if flags == nil then flags = 0 end local g = GImGui if g.OpenPopupStack.Size <= g.BeginPopupStack.Size then -- Early out for performance g.NextWindowData:ClearFlags() -- We behave like Begin() and need to consume those values return false end flags = bit32.bor(flags, ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings) local id = g.CurrentWindow:GetID(str_id) return ImGui.BeginPopupEx(id, flags) end function ImGui.EndPopup() local g = GImGui local window = g.CurrentWindow IM_ASSERT_USER_ERROR_RET((bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0) and (g.BeginPopupStack.Size > 0), "Calling EndPopup() in wrong window!") -- Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) if g.NavWindow == window then ImGui.NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags.LoopY) end -- Child-popups don't need to be laid out local backup_within_end_popup_id = g.WithinEndPopupID local backup_within_end_child_id = g.WithinEndChildID g.WithinEndPopupID = window.ID if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then g.WithinEndChildID = window.ID end ImGui.End() g.WithinEndPopupID = backup_within_end_popup_id g.WithinEndChildID = backup_within_end_child_id end --- @param ref_pos ImVec2 --- @param size ImVec2 --- @param last_dir ImGuiDir --- @param r_outer ImRect --- @param r_avoid ImRect --- @param policy ImGuiPopupPositionPolicy --- @return ImVec2 # Best Window Pos For Popup --- @return int # Updated last_dir --- @nodiscard function ImGui.FindBestWindowPosForPopupEx(ref_pos, size, last_dir, r_outer, r_avoid, policy) local base_pos_clamped -- Combo Box policy (we want a connecting edge) if policy == ImGuiPopupPositionPolicy.ComboBox then local dir_preferred_order = {ImGuiDir.Down, ImGuiDir.Right, ImGuiDir.Left, ImGuiDir.Up} for n = (last_dir ~= ImGuiDir.None) and 0 or 1, ImGuiDir.COUNT do repeat local dir = (n == 0) and last_dir or dir_preferred_order[n] if n ~= 0 and dir == last_dir then -- Already tried this direction? break end local pos if dir == ImGuiDir.Down then pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y) -- Below, Toward Right (default) elseif dir == ImGuiDir.Right then pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y) -- Above, Toward Right elseif dir == ImGuiDir.Left then pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y) -- Below, Toward Left elseif dir == ImGuiDir.Up then pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y) -- Above, Toward Left end if not r_outer:Contains(ImRect(pos, pos + size)) then break end last_dir = dir do return pos, last_dir end until true end end -- Tooltip and Default popup policy -- (Always first try the direction we used on the last frame, if any) if policy == ImGuiPopupPositionPolicy.Tooltip or policy == ImGuiPopupPositionPolicy.Default then local dir_preferred_order = {ImGuiDir.Right, ImGuiDir.Down, ImGuiDir.Up, ImGuiDir.Left} for n = (last_dir ~= ImGuiDir.None) and 0 or 1, ImGuiDir.COUNT do repeat local dir = (n == 0) and last_dir or dir_preferred_order[n] if n ~= 0 and dir == last_dir then break end local avail_w = ((dir == ImGuiDir.Left) and r_avoid.Min.x or r_outer.Max.x) - ((dir == ImGuiDir.Right) and r_avoid.Max.x or r_outer.Min.x) local avail_h = ((dir == ImGuiDir.Up) and r_avoid.Min.y or r_outer.Max.y) - ((dir == ImGuiDir.Down) and r_avoid.Max.y or r_outer.Min.y) -- If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) if avail_w < size.x and (dir == ImGuiDir.Left or dir == ImGuiDir.Right) then break end if avail_h < size.y and (dir == ImGuiDir.Up or dir == ImGuiDir.Down) then break end base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size) local pos = ImVec2() pos.x = (dir == ImGuiDir.Left) and (r_avoid.Min.x - size.x) or ((dir == ImGuiDir.Right) and r_avoid.Max.x or base_pos_clamped.x) pos.y = (dir == ImGuiDir.Up) and (r_avoid.Min.y - size.y) or ((dir == ImGuiDir.Down) and r_avoid.Max.y or base_pos_clamped.y) -- Clamp top-left corner of popup pos.x = ImMax(pos.x, r_outer.Min.x) pos.y = ImMax(pos.y, r_outer.Min.y) last_dir = dir do return pos, last_dir end until true end end -- Fallback when not enough room: last_dir = ImGuiDir.None -- For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. if policy == ImGuiPopupPositionPolicy.Tooltip then return ref_pos + ImVec2(2, 2), last_dir end -- Otherwise try to keep within display local pos = ImVec2(ref_pos.x, ref_pos.y) pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x) pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y) return pos, last_dir end --- @param window ImGuiWindow --- @return ImRect --- @nodiscard function ImGui.GetPopupAllowedExtentRect(window) local g = GImGui local r_screen = ImRect() if window.ViewportAllowPlatformMonitorExtend >= 1 then -- Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here) local monitor = g.PlatformIO.Monitors.Data[window.ViewportAllowPlatformMonitorExtend] ImVec2_Copy(r_screen.Min, monitor.WorkPos) ImVec2_Copy(r_screen.Max, monitor.WorkPos + monitor.WorkSize) else -- Use the full viewport area (not work area) for popups r_screen = window.Viewport:GetMainRect() end local padding = g.Style.DisplaySafeAreaPadding r_screen:Expand(ImVec2((r_screen:GetWidth() > padding.x * 2) and -padding.x or 0.0, (r_screen:GetHeight() > padding.y * 2) and -padding.y or 0.0)) return r_screen end --- @param window ImGuiWindow --- @return ImVec2 --- @nodiscard function ImGui.FindBestWindowPosForPopup(window) local g = GImGui local r_outer = ImGui.GetPopupAllowedExtentRect(window) if bit32.band(window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then -- Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. -- This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. local parent_window = window.ParentWindow local horizontal_overlap = g.Style.ItemInnerSpacing.x -- We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). local r_avoid if parent_window.DC.MenuBarAppending then r_avoid = ImRect(-FLT_MAX, parent_window.ClipRect.Min.y, FLT_MAX, parent_window.ClipRect.Max.y) -- Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field else r_avoid = ImRect(parent_window.Pos.x + horizontal_overlap, -FLT_MAX, parent_window.Pos.x + parent_window.Size.x - horizontal_overlap - parent_window.ScrollbarSizes.x, FLT_MAX) end local pos pos, window.AutoPosLastDirection = ImGui.FindBestWindowPosForPopupEx(window.Pos, window.Size, window.AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy.Default) return pos end if bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 then local pos pos, window.AutoPosLastDirection = ImGui.FindBestWindowPosForPopupEx(window.Pos, window.Size, window.AutoPosLastDirection, r_outer, ImRect(window.Pos, window.Pos), ImGuiPopupPositionPolicy.Default) -- Ideally we'd disable r_avoid here return pos end if bit32.band(window.Flags, ImGuiWindowFlags.Tooltip) ~= 0 then -- Position tooltip (always follows mouse + clamp within outer boundaries) -- FIXME: -- - Too many paths. One problem is that FindBestWindowPosForPopupEx() doesn't allow passing a suggested position (so touch screen path doesn't use it by default). -- - Drag and drop tooltips are not using this path either: BeginTooltipEx() manually sets their position. -- - Require some tidying up. In theory we could handle both cases in same location, but requires a bit of shuffling -- as drag and drop tooltips are calling SetNextWindowPos() leading to 'window_pos_set_by_api' being set in Begin(). IM_ASSERT(g.CurrentWindow == window) local scale = g.Style.MouseCursorScale local ref_pos = ImGui.NavCalcPreferredRefPos(ImGuiWindowFlags.Tooltip) if g.IO.MouseSource == ImGuiMouseSource.TouchScreen and ImGui.NavCalcPreferredRefPosSource(ImGuiWindowFlags.Tooltip) == ImGuiInputSource.Mouse then local tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - TOOLTIP_DEFAULT_PIVOT_TOUCH * window.Size if r_outer:Contains(ImRect(tooltip_pos, tooltip_pos + window.Size)) then return tooltip_pos end end local tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale local r_avoid if g.NavCursorVisible and g.NavHighlightItemUnderNav and not g.IO.ConfigNavMoveSetMousePos then r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8) else r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale) -- FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. end local pos pos, window.AutoPosLastDirection = ImGui.FindBestWindowPosForPopupEx(tooltip_pos, window.Size, window.AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy.Tooltip) return pos end IM_ASSERT(false) return window.Pos end --- @param flags ImGuiPopupFlags --- @return ImGuiMouseButton function ImGui.GetMouseButtonFromPopupFlags(flags) IM_ASSERT(bit32.band(flags, ImGuiPopupFlags.InvalidMask_) == 0) if bit32.band(flags, ImGuiPopupFlags.MouseButtonMask_) ~= 0 then return bit32.rshift(bit32.band(flags, ImGuiPopupFlags.MouseButtonMask_), ImGuiPopupFlags.MouseButtonShift_) - 1 end return ImGuiMouseButton.Right -- Default == 1 end --- @param popup_flags ImGuiPopupFlags --- @param id ImGuiID @native function ImGui.IsPopupOpenRequestForItem(popup_flags, id) local g = GImGui local mouse_button = ImGui.GetMouseButtonFromPopupFlags(popup_flags) if ImGui.IsMouseReleased(mouse_button) and ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByPopup) then return true end if g.NavOpenContextMenuItemId == id and (ImGui.IsItemFocused() or id == g.CurrentWindow.MoveId) then return true end return false end --- @param str_id? string --- @param popup_flags? ImGuiPopupFlags @native function ImGui.OpenPopupOnItemClick(str_id, popup_flags) if popup_flags == nil then popup_flags = 0 end local g = GImGui if ImGui.IsPopupOpenRequestForItem(popup_flags, g.LastItemData.ID) then local window = g.CurrentWindow local id if str_id then id = window:GetID(str_id) else id = g.LastItemData.ID end IM_ASSERT(id ~= 0) return ImGui.OpenPopupEx(id, popup_flags) end return false end --- @param str_id? string --- @param popup_flags? ImGuiPopupFlags --- @return bool function ImGui.BeginPopupContextItem(str_id, popup_flags) if popup_flags == nil then popup_flags = 0 end local g = GImGui local window = g.CurrentWindow if window.SkipItems then return false end local id if str_id then id = window:GetID(str_id) else id = g.LastItemData.ID end IM_ASSERT(id ~= 0) if ImGui.IsPopupOpenRequestForItem(popup_flags, g.LastItemData.ID) then ImGui.OpenPopupEx(id, popup_flags) end return ImGui.BeginPopupEx(id, bit32.bor(ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings)) end --------------------------------------------------------------------------------------- -- [SECTION] NAVIGATION --------------------------------------------------------------------------------------- --- @param id ImGuiID function ImGui.PushFocusScope(id) local g = GImGui local data = ImGuiFocusScopeData() data.ID = id data.WindowID = g.CurrentWindow.ID g.FocusScopeStack:push_back(data) g.CurrentFocusScopeId = id end function ImGui.PopFocusScope() local g = GImGui -- TODO: IM_ASSERT_USER_ERROR_RET(g.FocusScopeStack.Size > g.StackSizesInBeginForCurrentWindow.SizeOfFocusScopeStack, "Calling PopFocusScope() too many times!") g.FocusScopeStack:pop_back() if g.FocusScopeStack.Size > 0 then g.CurrentFocusScopeId = g.FocusScopeStack:back().ID else g.CurrentFocusScopeId = 0 end end --- @param focus_scope_id ImGuiID function ImGui.IsInNavFocusRoute(focus_scope_id) local g = GImGui if g.NavFocusScopeId == focus_scope_id then return true end for _, focus_scope in g.NavFocusRoute:iter() do if focus_scope.ID == focus_scope_id then return true end end return false end --- @param focus_scope_id ImGuiID function ImGui.SetNavFocusScope(focus_scope_id) local g = GImGui g.NavFocusScopeId = focus_scope_id g.NavFocusRoute:resize(0) if focus_scope_id == 0 then return end IM_ASSERT(g.NavWindow ~= nil) if focus_scope_id == g.CurrentFocusScopeId then for n = g.FocusScopeStack.Size, 1, -1 do local data = g.FocusScopeStack.Data[n] if data.WindowID ~= g.CurrentWindow.ID then break end g.NavFocusRoute:push_back(data) end elseif focus_scope_id == g.NavWindow.NavRootFocusScopeId then local data = ImGuiFocusScopeData() data.ID = focus_scope_id data.WindowID = g.NavWindow.ID g.NavFocusRoute:push_back(data) else return end local window = g.NavWindow.ParentWindowForFocusRoute while window ~= nil do local data = ImGuiFocusScopeData() data.ID = window.NavRootFocusScopeId data.WindowID = window.ID g.NavFocusRoute:push_back(data) window = window.ParentWindowForFocusRoute end IM_ASSERT(g.NavFocusRoute.Size < 100) end function ImGui.SetItemDefaultFocus() local g = GImGui local window = g.CurrentWindow if not window.Appearing then return end if g.NavWindow ~= window.RootWindowForNav or (not g.NavInitRequest and g.NavInitResult.ID == 0) or g.NavLayer ~= window.DC.NavLayerCurrent then return end g.NavInitRequest = false ImGui.NavApplyItemToResult(g.NavInitResult) ImGui.NavUpdateAnyRequestFlag() if not window.ClipRect:Contains(g.LastItemData.Rect) then ImGui.ScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags.None) end end function ImGui.SetNavCursorVisibleAfterMove() local g = GImGui if g.NavWindow and (bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0) then g.NavCursorVisible = false elseif g.NavInputSource == ImGuiInputSource.Keyboard and (bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) == 0) then g.NavCursorVisible = false elseif g.NavInputSource == ImGuiInputSource.Gamepad and (bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) == 0) then g.NavCursorVisible = false elseif g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = true end g.NavHighlightItemUnderNav = true g.NavMousePosDirty = true end --- @param window? ImGuiWindow function ImGui.SetNavWindow(window) local g = GImGui if g.NavWindow ~= window then -- IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")", window and window.Name or "") g.NavWindow = window g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid end g.NavInitRequest = false g.NavMoveSubmitted = false g.NavMoveScoringItems = false ImGui.NavUpdateAnyRequestFlag() end --- @param axis ImGuiAxis function ImGui.NavClearPreferredPosForAxis(axis) local g = GImGui g.NavWindow.RootWindowForNav.NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX end --- @param id ImGuiID --- @param nav_layer ImGuiNavLayer --- @param focus_scope_id ImGuiID --- @param rect_rel ImRect function ImGui.SetNavID(id, nav_layer, focus_scope_id, rect_rel) local g = GImGui IM_ASSERT(g.NavWindow ~= nil) IM_ASSERT(nav_layer == ImGuiNavLayer.Main or nav_layer == ImGuiNavLayer.Menu) g.NavId = id g.NavLayer = nav_layer ImGui.SetNavFocusScope(focus_scope_id) g.NavWindow.NavLastIds[nav_layer] = id ImRect_Copy(g.NavWindow.NavRectRel[nav_layer], rect_rel) ImGui.NavClearPreferredPosForAxis(ImGuiAxis.X) ImGui.NavClearPreferredPosForAxis(ImGuiAxis.Y) end --- @param nav_window ImGuiWindow function ImGui.NavSaveLastChildNavWindowIntoParent(nav_window) local parent = nav_window while parent and parent.RootWindow ~= parent and bit32.band(parent.Flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.ChildMenu)) == 0 do parent = parent.ParentWindow end if parent and parent ~= nav_window then parent.NavLastChildNavWindow = nav_window end end --- @param window ImGuiWindow function ImGui.NavRestoreLastChildNavWindow(window) if window.NavLastChildNavWindow and window.NavLastChildNavWindow.WasActive then return window.NavLastChildNavWindow end return window end --- @param layer ImGuiNavLayer function ImGui.NavRestoreLayer(layer) local g = GImGui if layer == ImGuiNavLayer.Main then local prev_nav_window = g.NavWindow g.NavWindow = ImGui.NavRestoreLastChildNavWindow(g.NavWindow) g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid end local window = g.NavWindow if window.NavLastIds[layer] ~= 0 then ImGui.SetNavID(window.NavLastIds[layer], layer, 0, window.NavRectRel[layer]) else g.NavLayer = layer ImGui.NavInitWindow(window, true) end end --- @param id ImGuiID function ImGui.NavHighlightActivated(id) local g = GImGui g.NavHighlightActivatedId = id g.NavHighlightActivatedTimer = NAV_ACTIVATE_HIGHLIGHT_TIMER end function ImGui.NavUpdateAnyRequestFlag() local g = GImGui g.NavAnyRequest = g.NavMoveScoringItems or g.NavInitRequest or (IMGUI_DEBUG_NAV_SCORING and g.NavWindow ~= nil) if g.NavAnyRequest then IM_ASSERT(g.NavWindow ~= nil) end end --- @param window ImGuiWindow --- @param force_reinit bool function ImGui.NavInitWindow(window, force_reinit) local g = GImGui IM_ASSERT(window == g.NavWindow) if bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 then g.NavId = 0 ImGui.SetNavFocusScope(window.NavRootFocusScopeId) return end local init_for_nav = false if window == window.RootWindow or bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 or window.NavLastIds[0] == 0 or force_reinit then init_for_nav = true end -- IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d", init_for_nav, window->Name, g.NavLayer) if init_for_nav then ImGui.SetNavID(0, g.NavLayer, window.NavRootFocusScopeId, ImRect()) g.NavInitRequest = true g.NavInitRequestFromMove = false g.NavInitResult.ID = 0 ImGui.NavUpdateAnyRequestFlag() else g.NavId = window.NavLastIds[0] ImGui.SetNavFocusScope(window.NavRootFocusScopeId) end end --- @param window_type ImGuiWindowFlags --- @return ImGuiInputSource function ImGui.NavCalcPreferredRefPosSource(window_type) local g = GImGui local window = g.NavWindow local activated_shortcut = g.ActiveId ~= 0 and g.ActiveIdFromShortcut and g.ActiveId == g.LastItemData.ID if (bit32.band(window_type, ImGuiWindowFlags.Popup) ~= 0) and activated_shortcut then return ImGuiInputSource.Keyboard end if not g.NavCursorVisible or not g.NavHighlightItemUnderNav or not window then return ImGuiInputSource.Mouse else return ImGuiInputSource.Keyboard -- or Nav in general end end --- @param window_type ImGuiWindowFlags --- @return ImVec2 --- @nodiscard function ImGui.NavCalcPreferredRefPos(window_type) local g = GImGui local window = g.NavWindow local source = ImGui.NavCalcPreferredRefPosSource(window_type) if source == ImGuiInputSource.Mouse then -- Mouse (we need a fallback in case the mouse becomes invalid after being used) -- The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard. -- In theory we could move that +1.0f offset in OpenPopupEx() local p = ImGui.IsMousePosValid(g.IO.MousePos) and g.IO.MousePos or g.MouseLastValidPos return ImVec2(p.x + 1.0, p.y) else -- When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item local activated_shortcut = g.ActiveId ~= 0 and g.ActiveIdFromShortcut and g.ActiveId == g.LastItemData.ID local ref_rect = ImRect() if activated_shortcut and (bit32.band(window_type, ImGuiWindowFlags.Popup) ~= 0) then ImRect_Copy(ref_rect, g.LastItemData.NavRect) elseif window ~= nil then ImRect_Copy(ref_rect, ImGui.WindowRectRelToAbs(window, window.NavRectRel[g.NavLayer])) end -- Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?) if window ~= nil and window.LastFrameActive ~= g.FrameCount and (window.ScrollTarget.x ~= FLT_MAX or window.ScrollTarget.y ~= FLT_MAX) then local next_scroll = CalcNextScrollFromScrollTargetAndClamp(window) ref_rect:Translate(window.Scroll - next_scroll) end local pos = ImVec2(ref_rect.Min.x + ImMin(g.Style.FramePadding.x * 4, ref_rect:GetWidth()), ref_rect.Max.y - ImMin(g.Style.FramePadding.y, ref_rect:GetHeight())) if window ~= nil then local viewport = window.Viewport if viewport then pos = ImClamp(pos, viewport.Pos, viewport.Pos + viewport.Size) end end return ImTrunc(pos) -- ImTrunc() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. end end --- @param axis ImGuiAxis --- @return float function ImGui.GetNavTweakPressedAmount(axis) local g = GImGui local repeat_delay, repeat_rate = ImGui.GetTypematicRepeatRate(ImGuiInputFlags.RepeatRateNavTweak) local key_less, key_more if g.NavInputSource == ImGuiInputSource.Gamepad then key_less = (axis == ImGuiAxis.X) and ImGuiKey.GamepadDpadLeft or ImGuiKey.GamepadDpadUp key_more = (axis == ImGuiAxis.X) and ImGuiKey.GamepadDpadRight or ImGuiKey.GamepadDpadDown else key_less = (axis == ImGuiAxis.X) and ImGuiKey.LeftArrow or ImGuiKey.UpArrow key_more = (axis == ImGuiAxis.X) and ImGuiKey.RightArrow or ImGuiKey.DownArrow end local amount = ImGui.GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - ImGui.GetKeyPressedAmount(key_less, repeat_delay, repeat_rate) if amount ~= 0.0 and ImGui.IsKeyDown(key_less) and ImGui.IsKeyDown(key_more) then -- Cancel when opposite directions are held, regardless of repeat phase amount = 0.0 end return amount end do local nav_gamepad_keys_to_change_source = { ImGuiKey.GamepadFaceRight, ImGuiKey.GamepadFaceLeft, ImGuiKey.GamepadFaceUp, ImGuiKey.GamepadFaceDown, ImGuiKey.GamepadDpadRight, ImGuiKey.GamepadDpadLeft, ImGuiKey.GamepadDpadUp, ImGuiKey.GamepadDpadDown } local nav_keyboard_keys_to_change_source = { ImGuiKey.Space, ImGuiKey.Enter, ImGuiKey.Escape, ImGuiKey.RightArrow, ImGuiKey.LeftArrow, ImGuiKey.UpArrow, ImGuiKey.DownArrow } --- @param focus_change_dir int function ImGui.NavUpdateWindowingTarget(focus_change_dir) local g = GImGui IM_ASSERT(g.NavWindowingTarget) if bit32.band(g.NavWindowingTarget.Flags, ImGuiWindowFlags.Modal) ~= 0 then return end local i_current = ImGui.FindWindowFocusIndex(g.NavWindowingTarget) local window_target = ImGui.FindWindowNavFocusable(i_current + focus_change_dir, 0, focus_change_dir) if window_target == nil then window_target = ImGui.FindWindowNavFocusable((focus_change_dir < 0) and g.WindowsFocusOrder.Size or 1, i_current, focus_change_dir) end if window_target then g.NavWindowingTarget = window_target g.NavWindowingTargetAnim = window_target ImVec2_CopyV(g.NavWindowingAccumDeltaPos, 0.0, 0.0) ImVec2_CopyV(g.NavWindowingAccumDeltaSize, 0.0, 0.0) end g.NavWindowingToggleLayer = false end --- @param apply_focus_window ImGuiWindow function ImGui.NavUpdateWindowingApplyFocus(apply_focus_window) local g = GImGui if g.NavWindow == nil or apply_focus_window ~= g.NavWindow.RootWindow then local previous_viewport = g.NavWindow and g.NavWindow.Viewport or nil ImGui.ClearActiveID() ImGui.SetNavCursorVisibleAfterMove() ImGui.ClosePopupsOverWindow(apply_focus_window, false) ImGui.FocusWindow(apply_focus_window, ImGuiFocusRequestFlags.RestoreFocusedChild) IM_ASSERT(g.NavWindow ~= nil) apply_focus_window = g.NavWindow if apply_focus_window.NavLastIds[ImGuiNavLayer.Main] == 0 then ImGui.NavInitWindow(apply_focus_window, false) end if apply_focus_window.DC.NavLayersActiveMaskNext == bit32.lshift(1, ImGuiNavLayer.Menu) then g.NavLayer = ImGuiNavLayer.Menu end if apply_focus_window.Viewport ~= previous_viewport and g.PlatformIO.Platform_SetWindowFocus then g.PlatformIO.Platform_SetWindowFocus(apply_focus_window.Viewport) end end g.NavWindowingTarget = nil end function ImGui.NavUpdateWindowing() local g = GImGui local io = g.IO local apply_focus_window = nil local apply_toggle_layer = false local modal_window = ImGui.GetTopMostPopupModal() local allow_windowing = (modal_window == nil) if not allow_windowing then g.NavWindowingTarget = nil end if g.NavWindowingTargetAnim and g.NavWindowingTarget == nil then g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0, 0.0) if g.DimBgRatio <= 0.0 and g.NavWindowingHighlightAlpha <= 0.0 then g.NavWindowingTargetAnim = nil end end local owner_id = ImHashStr("##NavUpdateWindowing") local nav_gamepad_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 and bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0 local nav_keyboard_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 local keyboard_next_window = allow_windowing and g.ConfigNavWindowingKeyNext ~= 0 and ImGui.Shortcut(g.ConfigNavWindowingKeyNext, bit32.bor(ImGuiInputFlags.Repeat, ImGuiInputFlags.RouteAlways), owner_id) local keyboard_prev_window = allow_windowing and g.ConfigNavWindowingKeyPrev ~= 0 and ImGui.Shortcut(g.ConfigNavWindowingKeyPrev, bit32.bor(ImGuiInputFlags.Repeat, ImGuiInputFlags.RouteAlways), owner_id) local start_toggling_with_gamepad = nav_gamepad_active and g.NavWindowingTarget == nil and ImGui.Shortcut(ImGuiKey.NavGamepadMenu, ImGuiInputFlags.RouteAlways, owner_id) local start_windowing_with_gamepad = allow_windowing and start_toggling_with_gamepad local start_windowing_with_keyboard = allow_windowing and g.NavWindowingTarget == nil and (keyboard_next_window or keyboard_prev_window) local just_started_windowing_from_null_focus = false if start_toggling_with_gamepad then g.NavWindowingToggleLayer = true g.NavWindowingToggleKey = ImGuiKey.NavGamepadMenu g.NavWindowingInputSource = ImGuiInputSource.Gamepad g.NavInputSource = ImGuiInputSource.Gamepad end if start_windowing_with_gamepad or start_windowing_with_keyboard then local window = (g.NavWindow and ImGui.IsWindowNavFocusable(g.NavWindow)) and g.NavWindow or ImGui.FindWindowNavFocusable(g.WindowsFocusOrder.Size, 0, -1) if window then if start_windowing_with_keyboard or g.ConfigNavWindowingWithGamepad then g.NavWindowingTarget = window.RootWindow g.NavWindowingTargetAnim = window.RootWindow end g.NavWindowingTimer = 0.0 g.NavWindowingHighlightAlpha = 0.0 ImVec2_CopyV(g.NavWindowingAccumDeltaPos, 0.0, 0.0) ImVec2_CopyV(g.NavWindowingAccumDeltaSize, 0.0, 0.0) g.NavWindowingInputSource = start_windowing_with_keyboard and ImGuiInputSource.Keyboard or ImGuiInputSource.Gamepad g.NavInputSource = g.NavWindowingInputSource if g.NavWindow == nil then just_started_windowing_from_null_focus = true end if keyboard_next_window or keyboard_prev_window then ImGui.SetKeyOwnersForKeyChord(bit32.band(bit32.bor(g.ConfigNavWindowingKeyNext, g.ConfigNavWindowingKeyPrev), ImGuiMod_Mask_), owner_id) end end end if (g.NavWindowingTarget or g.NavWindowingToggleLayer) and g.NavWindowingInputSource == ImGuiInputSource.Gamepad then if g.NavWindowingTarget ~= nil then g.NavWindowingTimer = g.NavWindowingTimer + io.DeltaTime g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05)) local focus_change_dir = (ImGui.IsKeyPressedEx(ImGuiKey.GamepadL1, ImGuiInputFlags.None, ImGuiKeyOwner_Any) and 1 or 0) - (ImGui.IsKeyPressedEx(ImGuiKey.GamepadR1, ImGuiInputFlags.None, ImGuiKeyOwner_Any) and 1 or 0) if focus_change_dir ~= 0 and not just_started_windowing_from_null_focus then ImGui.NavUpdateWindowingTarget(focus_change_dir) g.NavWindowingHighlightAlpha = 1.0 end end if not ImGui.IsKeyDown(ImGuiKey.NavGamepadMenu) then g.NavWindowingToggleLayer = g.NavWindowingToggleLayer and (g.NavWindowingHighlightAlpha < 1.0) if g.NavWindowingToggleLayer and g.NavWindow then apply_toggle_layer = true elseif not g.NavWindowingToggleLayer then apply_focus_window = g.NavWindowingTarget end g.NavWindowingTarget = nil g.NavWindowingToggleLayer = false end end if g.NavWindowingTarget and g.NavWindowingInputSource == ImGuiInputSource.Keyboard then local shared_mods = bit32.band( bit32.band((g.ConfigNavWindowingKeyNext ~= 0) and g.ConfigNavWindowingKeyNext or ImGuiMod_Mask_, (g.ConfigNavWindowingKeyPrev ~= 0) and g.ConfigNavWindowingKeyPrev or ImGuiMod_Mask_), ImGuiMod_Mask_) IM_ASSERT(shared_mods ~= 0) g.NavWindowingTimer = g.NavWindowingTimer + io.DeltaTime g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05)) if (keyboard_next_window or keyboard_prev_window) and not just_started_windowing_from_null_focus then ImGui.NavUpdateWindowingTarget(keyboard_next_window and -1 or 1) elseif bit32.band(io.KeyMods, shared_mods) ~= shared_mods then apply_focus_window = g.NavWindowingTarget end end local windowing_toggle_keys = { ImGuiKey.LeftAlt, ImGuiKey.RightAlt } local windowing_toggle_layer_start = false if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) == 0 then for _, windowing_toggle_key in ipairs(windowing_toggle_keys) do if nav_keyboard_active and ImGui.IsKeyPressedEx(windowing_toggle_key, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner) then windowing_toggle_layer_start = true g.NavWindowingToggleLayer = true g.NavWindowingToggleKey = windowing_toggle_key g.NavWindowingInputSource = ImGuiInputSource.Keyboard g.NavInputSource = ImGuiInputSource.Keyboard break end end end if g.NavWindowingToggleLayer and g.NavWindowingInputSource == ImGuiInputSource.Keyboard then if io.InputQueueCharacters.Size > 0 or io.KeyCtrl or io.KeyShift or io.KeySuper then g.NavWindowingToggleLayer = false elseif windowing_toggle_layer_start == false and g.LastKeyboardKeyPressTime == g.Time then g.NavWindowingToggleLayer = false elseif ImGui.TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false or ImGui.TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false then g.NavWindowingToggleLayer = false end if ImGui.IsKeyReleased(g.NavWindowingToggleKey) and g.NavWindowingToggleLayer then if g.ActiveId == 0 or g.ActiveIdAllowOverlap then if ImGui.IsMousePosValid(io.MousePos) == ImGui.IsMousePosValid(io.MousePosPrev) then apply_toggle_layer = true end end end if not ImGui.IsKeyDown(g.NavWindowingToggleKey) then g.NavWindowingToggleLayer = false end end if g.NavWindowingTarget and bit32.band(g.NavWindowingTarget.Flags, ImGuiWindowFlags.NoMove) == 0 then local nav_move_dir if g.NavInputSource == ImGuiInputSource.Keyboard and not io.KeyShift then nav_move_dir = ImGui.GetKeyMagnitude2d(ImGuiKey.LeftArrow, ImGuiKey.RightArrow, ImGuiKey.UpArrow, ImGuiKey.DownArrow) end if g.NavInputSource == ImGuiInputSource.Gamepad then nav_move_dir = ImGui.GetKeyMagnitude2d(ImGuiKey.GamepadLStickLeft, ImGuiKey.GamepadLStickRight, ImGuiKey.GamepadLStickUp, ImGuiKey.GamepadLStickDown) end if nav_move_dir and (nav_move_dir.x ~= 0.0 or nav_move_dir.y ~= 0.0) then local NAV_MOVE_SPEED = 800.0 local move_step = NAV_MOVE_SPEED * io.DeltaTime * ImGui.GetScale() ImVec2_Copy(g.NavWindowingAccumDeltaPos, g.NavWindowingAccumDeltaPos + nav_move_dir * move_step) g.NavHighlightItemUnderNav = true local accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos) if accum_floored.x ~= 0.0 or accum_floored.y ~= 0.0 then local moving_window = g.NavWindowingTarget.RootWindowDockTree ImGui.SetWindowPos(moving_window, moving_window.Pos + accum_floored, ImGuiCond.Always) ImVec2_Copy(g.NavWindowingAccumDeltaPos, g.NavWindowingAccumDeltaPos - accum_floored) end end end if apply_focus_window then ImGui.NavUpdateWindowingApplyFocus(apply_focus_window) end if apply_toggle_layer and g.NavWindow then ImGui.ClearActiveID() local new_nav_window = g.NavWindow while new_nav_window.ParentWindow and bit32.band(new_nav_window.DC.NavLayersActiveMask, bit32.lshift(1, ImGuiNavLayer.Menu)) == 0 and bit32.band(new_nav_window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 and bit32.band(new_nav_window.Flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.ChildMenu)) == 0 do new_nav_window = new_nav_window.ParentWindow end if new_nav_window ~= g.NavWindow then local old_nav_window = g.NavWindow ImGui.FocusWindow(new_nav_window) new_nav_window.NavLastChildNavWindow = old_nav_window end local new_nav_layer = (bit32.band(g.NavWindow.DC.NavLayersActiveMask, bit32.lshift(1, ImGuiNavLayer.Menu)) ~= 0) and bit32.bxor(g.NavLayer, 1) or ImGuiNavLayer.Main if new_nav_layer ~= g.NavLayer then local preserve_layer_1_nav_id = (new_nav_window.DockNodeAsHost ~= nil) if new_nav_layer == ImGuiNavLayer.Menu and not preserve_layer_1_nav_id then g.NavWindow.NavLastIds[new_nav_layer] = 0 end ImGui.NavRestoreLayer(new_nav_layer) ImGui.SetNavCursorVisibleAfterMove() end end end function ImGui.NavUpdateContextMenuRequest() local g = GImGui local io = g.IO g.NavOpenContextMenuItemId = 0 g.NavOpenContextMenuWindowId = 0 local nav_keyboard_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 local nav_gamepad_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 if (not nav_keyboard_active and not nav_gamepad_active) or g.NavWindow == nil then return end local request = false request = request or (nav_keyboard_active and (ImGui.IsKeyReleased(ImGuiKey.Menu, ImGuiKeyOwner_NoOwner) or (ImGui.IsKeyPressedEx(ImGuiKey.F10, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner) and io.KeyMods == ImGuiMod_Shift))) request = request or (nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.NavGamepadContextMenu, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner)) if not request then return end g.NavOpenContextMenuItemId = g.NavId g.NavOpenContextMenuWindowId = g.NavWindow.ID if g.NavId == g.NavWindow:GetID("#CLOSE") or g.NavId == g.NavWindow:GetID("#COLLAPSE") then g.NavOpenContextMenuItemId = g.NavWindow.MoveId end g.NavInputSource = ImGuiInputSource.Keyboard ImGui.SetNavCursorVisibleAfterMove() end --- @param move_dir ImGuiDir --- @param clip_dir ImGuiDir --- @param move_flags ImGuiNavMoveFlags --- @param scroll_flags ImGuiScrollFlags function ImGui.NavMoveRequestSubmit(move_dir, clip_dir, move_flags, scroll_flags) local g = GImGui IM_ASSERT(g.NavWindow ~= nil) if bit32.band(move_flags, ImGuiNavMoveFlags.IsTabbing) ~= 0 then move_flags = bit32.bor(move_flags, ImGuiNavMoveFlags.AllowCurrentNavId) end g.NavMoveSubmitted = true; g.NavMoveScoringItems = true g.NavMoveDir = move_dir g.NavMoveDirForDebug = move_dir g.NavMoveClipDir = clip_dir g.NavMoveFlags = move_flags g.NavMoveScrollFlags = scroll_flags g.NavMoveForwardToNextFrame = false g.NavMoveKeyMods = (bit32.band(move_flags, ImGuiNavMoveFlags.FocusApi) ~= 0) and 0 or g.IO.KeyMods g.NavMoveResultLocal:Clear() g.NavMoveResultLocalVisible:Clear() g.NavMoveResultOther:Clear() g.NavTabbingCounter = 0 g.NavTabbingResultFirst:Clear() ImGui.NavUpdateAnyRequestFlag() end --- @param r ImRect --- @param preferred_pos_rel ImVec2 --- @param move_dir ImGuiDir --- @param move_flags ImGuiNavMoveFlags function ImGui.NavBiasScoringRect(r, preferred_pos_rel, move_dir, move_flags) local g = GImGui local rel_to_abs_offset = g.NavWindow.DC.CursorStartPos if bit32.band(move_flags, ImGuiNavMoveFlags.Forwarded) == 0 then if preferred_pos_rel.x == FLT_MAX then preferred_pos_rel.x = ImMin(r.Min.x + 1.0, r.Max.x) - rel_to_abs_offset.x end if preferred_pos_rel.y == FLT_MAX then preferred_pos_rel.y = r:GetCenter().y - rel_to_abs_offset.y end end if (move_dir == ImGuiDir.Up or move_dir == ImGuiDir.Down) and preferred_pos_rel.x ~= FLT_MAX then local new_x = preferred_pos_rel.x + rel_to_abs_offset.x r.Min.x = new_x; r.Max.x = new_x elseif (move_dir == ImGuiDir.Left or move_dir == ImGuiDir.Right) and preferred_pos_rel.y ~= FLT_MAX then local new_y = preferred_pos_rel.y + rel_to_abs_offset.y r.Min.y = new_y; r.Max.y = new_y end end --- @return float function ImGui.NavUpdatePageUpPageDown() local g = GImGui local window = g.NavWindow if bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 or g.NavWindowingTarget ~= nil then return 0.0 end local page_up_held = ImGui.IsKeyDown(ImGuiKey.PageUp, ImGuiKeyOwner_NoOwner) local page_down_held = ImGui.IsKeyDown(ImGuiKey.PageDown, ImGuiKeyOwner_NoOwner) local home_pressed = ImGui.IsKeyPressedEx(ImGuiKey.Home, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) local end_pressed = ImGui.IsKeyPressedEx(ImGuiKey.End, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) if page_up_held == page_down_held and home_pressed == end_pressed then return 0.0 end if g.NavLayer ~= ImGuiNavLayer.Main then ImGui.NavRestoreLayer(ImGuiNavLayer.Main) end if bit32.band(window.DC.NavLayersActiveMask, bit32.lshift(1, ImGuiNavLayer.Main)) == 0 and window.DC.NavWindowHasScrollY then if ImGui.IsKeyPressedEx(ImGuiKey.PageUp, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) then ImGui.SetScrollY(window, window.Scroll.y - window.InnerRect:GetHeight()) elseif ImGui.IsKeyPressedEx(ImGuiKey.PageDown, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) then ImGui.SetScrollY(window, window.Scroll.y + window.InnerRect:GetHeight()) elseif home_pressed then ImGui.SetScrollY(window, 0.0) elseif end_pressed then ImGui.SetScrollY(window, window.ScrollMax.y) end else local nav_rect_rel = window.NavRectRel[g.NavLayer] local page_offset_y = ImMax(0.0, window.InnerRect:GetHeight() - window.FontRefSize * 1.0 + nav_rect_rel:GetHeight()) local nav_scoring_rect_offset_y = 0.0 if ImGui.IsKeyPressedEx(ImGuiKey.PageUp, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) then nav_scoring_rect_offset_y = -page_offset_y g.NavMoveDir = ImGuiDir.Down g.NavMoveClipDir = ImGuiDir.Up g.NavMoveFlags = bit32.bor(ImGuiNavMoveFlags.AllowCurrentNavId, ImGuiNavMoveFlags.IsPageMove) elseif ImGui.IsKeyPressedEx(ImGuiKey.PageDown, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) then nav_scoring_rect_offset_y = page_offset_y g.NavMoveDir = ImGuiDir.Up g.NavMoveClipDir = ImGuiDir.Down g.NavMoveFlags = bit32.bor(ImGuiNavMoveFlags.AllowCurrentNavId, ImGuiNavMoveFlags.IsPageMove) elseif home_pressed then nav_rect_rel.Min.y = 0.0; nav_rect_rel.Max.y = 0.0 if nav_rect_rel:IsInverted() then nav_rect_rel.Min.x = 0.0; nav_rect_rel.Max.x = 0.0 end g.NavMoveDir = ImGuiDir.Down g.NavMoveFlags = bit32.bor(ImGuiNavMoveFlags.AllowCurrentNavId, ImGuiNavMoveFlags.ScrollToEdgeY) elseif end_pressed then nav_rect_rel.Min.y = window.ContentSize.y; nav_rect_rel.Max.y = window.ContentSize.y if nav_rect_rel:IsInverted() then nav_rect_rel.Min.x = 0.0; nav_rect_rel.Max.x = 0.0 end g.NavMoveDir = ImGuiDir.Up g.NavMoveFlags = bit32.bor(ImGuiNavMoveFlags.AllowCurrentNavId, ImGuiNavMoveFlags.ScrollToEdgeY) end return nav_scoring_rect_offset_y end return 0.0 end function ImGui.NavUpdateCreateMoveRequest() local g = GImGui local io = g.IO local window = g.NavWindow local nav_gamepad_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 and bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0 local nav_keyboard_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 if g.NavMoveForwardToNextFrame and window ~= nil then IM_ASSERT(g.NavMoveDir ~= ImGuiDir.None and g.NavMoveClipDir ~= ImGuiDir.None) IM_ASSERT(bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.Forwarded) ~= 0) else g.NavMoveDir = ImGuiDir.None g.NavMoveFlags = ImGuiNavMoveFlags.None g.NavMoveScrollFlags = ImGuiScrollFlags.None if window and not g.NavWindowingTarget and bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) == 0 then local repeat_mode = bit32.bor(ImGuiInputFlags.Repeat, ImGuiInputFlags.RepeatRateNavMove) if not ImGui.IsActiveIdUsingNavDir(ImGuiDir.Left) and ((nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.GamepadDpadLeft, repeat_mode, ImGuiKeyOwner_NoOwner)) or (nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.LeftArrow, repeat_mode, ImGuiKeyOwner_NoOwner))) then g.NavMoveDir = ImGuiDir.Left end if not ImGui.IsActiveIdUsingNavDir(ImGuiDir.Right) and ((nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.GamepadDpadRight, repeat_mode, ImGuiKeyOwner_NoOwner)) or (nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.RightArrow, repeat_mode, ImGuiKeyOwner_NoOwner))) then g.NavMoveDir = ImGuiDir.Right end if not ImGui.IsActiveIdUsingNavDir(ImGuiDir.Up) and ((nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.GamepadDpadUp, repeat_mode, ImGuiKeyOwner_NoOwner)) or (nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.UpArrow, repeat_mode, ImGuiKeyOwner_NoOwner))) then g.NavMoveDir = ImGuiDir.Up end if not ImGui.IsActiveIdUsingNavDir(ImGuiDir.Down) and ((nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.GamepadDpadDown, repeat_mode, ImGuiKeyOwner_NoOwner)) or (nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.DownArrow, repeat_mode, ImGuiKeyOwner_NoOwner))) then g.NavMoveDir = ImGuiDir.Down end end g.NavMoveClipDir = g.NavMoveDir ImRect_Copy(g.NavScoringNoClipRect, ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX)) end local scoring_page_offset_y = 0.0 if window and g.NavMoveDir == ImGuiDir.None and nav_keyboard_active then scoring_page_offset_y = ImGui.NavUpdatePageUpPageDown() end g.NavMoveForwardToNextFrame = false if g.NavMoveDir ~= ImGuiDir.None then ImGui.NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags) end if g.NavMoveSubmitted and g.NavId == 0 then g.NavInitRequest = true; g.NavInitRequestFromMove = true g.NavInitResult.ID = 0 if g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = true end end if g.NavMoveSubmitted and g.NavInputSource == ImGuiInputSource.Gamepad and g.NavLayer == ImGuiNavLayer.Main and window ~= nil then local clamp_x = bit32.band(g.NavMoveFlags, bit32.bor(ImGuiNavMoveFlags.LoopX, ImGuiNavMoveFlags.WrapX)) == 0 local clamp_y = bit32.band(g.NavMoveFlags, bit32.bor(ImGuiNavMoveFlags.LoopY, ImGuiNavMoveFlags.WrapY)) == 0 local inner_rect_rel = ImGui.WindowRectAbsToRel(window, ImRect(ImVec2(window.InnerRect.Min.x - 1, window.InnerRect.Min.y - 1), ImVec2(window.InnerRect.Max.x + 1, window.InnerRect.Max.y + 1))) local next_scroll = CalcNextScrollFromScrollTargetAndClamp(window) inner_rect_rel:Translate(ImVec2(next_scroll.x - window.Scroll.x, next_scroll.y - window.Scroll.y)) if (clamp_x or clamp_y) and not inner_rect_rel:Contains(window.NavRectRel[g.NavLayer]) then local pad_x = ImMin(inner_rect_rel:GetWidth(), window.FontRefSize * 0.5) local pad_y = ImMin(inner_rect_rel:GetHeight(), window.FontRefSize * 0.5) inner_rect_rel.Min.x = clamp_x and (inner_rect_rel.Min.x + pad_x) or -FLT_MAX inner_rect_rel.Max.x = clamp_x and (inner_rect_rel.Max.x - pad_x) or FLT_MAX inner_rect_rel.Min.y = clamp_y and (inner_rect_rel.Min.y + pad_y) or -FLT_MAX inner_rect_rel.Max.y = clamp_y and (inner_rect_rel.Max.y - pad_y) or FLT_MAX window.NavRectRel[g.NavLayer]:ClipWithFull(inner_rect_rel) g.NavId = 0 end end local scoring_rect = ImRect() if window ~= nil then local nav_rect_rel = ImRect() if not window.NavRectRel[g.NavLayer]:IsInverted() then ImRect_Copy(nav_rect_rel, window.NavRectRel[g.NavLayer]) end scoring_rect = ImGui.WindowRectRelToAbs(window, nav_rect_rel) if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsPageMove) ~= 0 then if window.InnerRect:Contains(scoring_rect) then g.NavMoveFlags = bit32.bor(g.NavMoveFlags, ImGuiNavMoveFlags.AlsoScoreVisibleSet) end ImRect_Copy(g.NavScoringNoClipRect, scoring_rect) scoring_rect:TranslateY(scoring_page_offset_y) g.NavScoringNoClipRect:Add(scoring_rect) end if g.NavMoveSubmitted then ImGui.NavBiasScoringRect(scoring_rect, window.RootWindowForNav.NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags) end IM_ASSERT(not scoring_rect:IsInverted()) end ImRect_Copy(g.NavScoringRect, scoring_rect) end function ImGui.NavUpdateCreateTabbingRequest() local g = GImGui local window = g.NavWindow IM_ASSERT(g.NavMoveDir == ImGuiDir.None) if window == nil or g.NavWindowingTarget ~= nil or bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 or not g.ConfigNavEnableTabbing then return end local tab_pressed = ImGui.IsKeyPressedEx(ImGuiKey.Tab, ImGuiInputFlags.Repeat, ImGuiKeyOwner_NoOwner) and not g.IO.KeyCtrl and not g.IO.KeyAlt if not tab_pressed then return end local nav_keyboard_active = bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 if nav_keyboard_active then g.NavTabbingDir = g.IO.KeyShift and -1 or ((g.NavCursorVisible == false and g.ActiveId == 0) and 0 or 1) else g.NavTabbingDir = g.IO.KeyShift and -1 or ((g.ActiveId == 0) and 0 or 1) end local move_flags = bit32.bor(ImGuiNavMoveFlags.IsTabbing, ImGuiNavMoveFlags.Activate) local scroll_flags = window.Appearing and bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.AlwaysCenterY) or bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleEdgeY) local clip_dir = (g.NavTabbingDir < 0) and ImGuiDir.Up or ImGuiDir.Down ImGui.NavMoveRequestSubmit(ImGuiDir.None, clip_dir, move_flags, scroll_flags) g.NavTabbingCounter = -1 end function ImGui.NavUpdate() local g = GImGui local io = g.IO io.WantSetMousePos = false local nav_gamepad_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 and bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0 if nav_gamepad_active and g.NavInputSource ~= ImGuiInputSource.Gamepad then for _, key in ipairs(nav_gamepad_keys_to_change_source) do if ImGui.IsKeyDown(key) then g.NavInputSource = ImGuiInputSource.Gamepad end end end local nav_keyboard_active = bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 if nav_keyboard_active and g.NavInputSource ~= ImGuiInputSource.Keyboard then for _, key in ipairs(nav_keyboard_keys_to_change_source) do if ImGui.IsKeyDown(key) then g.NavInputSource = ImGuiInputSource.Keyboard end end end g.NavJustMovedToId = 0 g.NavJustMovedToFocusScopeId = 0 g.NavJustMovedFromFocusScopeId = 0 if g.NavInitResult.ID ~= 0 then ImGui.NavInitRequestApplyResult() end g.NavInitRequest = false g.NavInitRequestFromMove = false g.NavInitResult.ID = 0 if g.NavMoveSubmitted then ImGui.NavMoveRequestApplyResult() end g.NavTabbingCounter = 0 g.NavMoveSubmitted = false g.NavMoveScoringItems = false if g.NavCursorHideFrames > 0 then g.NavCursorHideFrames = g.NavCursorHideFrames - 1 if g.NavCursorHideFrames == 0 then g.NavCursorVisible = true end end local set_mouse_pos = false if g.NavMousePosDirty and g.NavIdIsAlive then if g.NavCursorVisible and g.NavHighlightItemUnderNav and g.NavWindow then set_mouse_pos = true end end g.NavMousePosDirty = false IM_ASSERT(g.NavLayer == ImGuiNavLayer.Main or g.NavLayer == ImGuiNavLayer.Menu) if g.NavWindow then ImGui.NavSaveLastChildNavWindowIntoParent(g.NavWindow) end if g.NavWindow and g.NavWindow.NavLastChildNavWindow ~= nil and g.NavLayer == ImGuiNavLayer.Main then g.NavWindow.NavLastChildNavWindow = nil end ImGui.NavUpdateWindowing() io.NavActive = (nav_keyboard_active or nav_gamepad_active) and g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) == 0 io.NavVisible = (io.NavActive and g.NavId ~= 0 and g.NavCursorVisible) or (g.NavWindowingTarget ~= nil) ImGui.NavUpdateCancelRequest() ImGui.NavUpdateContextMenuRequest() g.NavActivateId = 0 g.NavActivateDownId = 0 g.NavActivatePressedId = 0 g.NavActivateFlags = ImGuiActivateFlags.None if g.NavId ~= 0 and g.NavCursorVisible and not g.NavWindowingTarget and g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) == 0 then local activate_down = (nav_keyboard_active and ImGui.IsKeyDown(ImGuiKey.Space, ImGuiKeyOwner_NoOwner)) or (nav_gamepad_active and ImGui.IsKeyDown(ImGuiKey.NavGamepadActivate, ImGuiKeyOwner_NoOwner)) local activate_pressed = activate_down and ((nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.Space, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner)) or (nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.NavGamepadActivate, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner))) local input_pressed_keyboard = nav_keyboard_active and (ImGui.IsKeyPressedEx(ImGuiKey.Enter, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner) or ImGui.IsKeyPressedEx(ImGuiKey.KeypadEnter, ImGuiInputFlags.None, ImGuiKeyOwner_NoOwner)) local input_pressed_gamepad = false if activate_down and nav_gamepad_active and ImGui.IsKeyDown(ImGuiKey.NavGamepadActivate, ImGuiKeyOwner_NoOwner) and bit32.band(g.NavIdItemFlags, ImGuiItemFlags.Inputable) ~= 0 then if ImGui.GetKeyData(g, ImGuiKey.NavGamepadActivate).DownDurationPrev < NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY and ImGui.GetKeyData(g, ImGuiKey.NavGamepadActivate).DownDuration >= NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY then input_pressed_gamepad = true end end if g.ActiveId == 0 and activate_pressed then g.NavActivateId = g.NavId g.NavActivateFlags = ImGuiActivateFlags.PreferTweak end if (g.ActiveId == 0 or g.ActiveId == g.NavId) and (input_pressed_keyboard or input_pressed_gamepad) then g.NavActivateId = g.NavId g.NavActivateFlags = ImGuiActivateFlags.PreferInput end if (g.ActiveId == 0 or g.ActiveId == g.NavId) and (activate_down or input_pressed_keyboard or input_pressed_gamepad) then g.NavActivateDownId = g.NavId end if (g.ActiveId == 0 or g.ActiveId == g.NavId) and (activate_pressed or input_pressed_keyboard or input_pressed_gamepad) then g.NavActivatePressedId = g.NavId ImGui.NavHighlightActivated(g.NavId) end end if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 then g.NavCursorVisible = false elseif g.IO.ConfigNavCursorVisibleAlways and g.NavCursorHideFrames == 0 then g.NavCursorVisible = true end if g.NavActivateId ~= 0 then IM_ASSERT(g.NavActivateDownId == g.NavActivateId) end if g.NavHighlightActivatedTimer > 0.0 then g.NavHighlightActivatedTimer = ImMax(0.0, g.NavHighlightActivatedTimer - io.DeltaTime) end if g.NavHighlightActivatedTimer == 0.0 then g.NavHighlightActivatedId = 0 end if g.NavNextActivateId ~= 0 then g.NavActivateId = g.NavNextActivateId g.NavActivateDownId = g.NavNextActivateId g.NavActivatePressedId = g.NavNextActivateId g.NavActivateFlags = g.NavNextActivateFlags end g.NavNextActivateId = 0 ImGui.NavUpdateCreateMoveRequest() if g.NavMoveDir == ImGuiDir.None then ImGui.NavUpdateCreateTabbingRequest() end ImGui.NavUpdateAnyRequestFlag() g.NavIdIsAlive = false if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) == 0 and not g.NavWindowingTarget then local window = g.NavWindow local scroll_speed = IM_ROUND(window.FontRefSize * 100 * io.DeltaTime) local move_dir = g.NavMoveDir if window.DC.NavLayersActiveMask == 0x00 and window.DC.NavWindowHasScrollY and move_dir ~= ImGuiDir.None then if move_dir == ImGuiDir.Left or move_dir == ImGuiDir.Right then local delta = (move_dir == ImGuiDir.Left) and -1.0 or 1.0 ImGui.SetScrollX(window, ImTrunc(window.Scroll.x + delta * scroll_speed)) end if move_dir == ImGuiDir.Up or move_dir == ImGuiDir.Down then local delta = (move_dir == ImGuiDir.Up) and -1.0 or 1.0 ImGui.SetScrollY(window, ImTrunc(window.Scroll.y + delta * scroll_speed)) end end if nav_gamepad_active then local scroll_dir = ImGui.GetKeyMagnitude2d(ImGuiKey.GamepadLStickLeft, ImGuiKey.GamepadLStickRight, ImGuiKey.GamepadLStickUp, ImGuiKey.GamepadLStickDown) local tweak_factor = 1.0 if ImGui.IsKeyDown(ImGuiKey.NavGamepadTweakSlow) then tweak_factor = 1.0 / 10.0 elseif ImGui.IsKeyDown(ImGuiKey.NavGamepadTweakFast) then tweak_factor = 10.0 end if scroll_dir.x ~= 0.0 and window.ScrollbarX then ImGui.SetScrollX(window, ImTrunc(window.Scroll.x + scroll_dir.x * scroll_speed * tweak_factor)) end if scroll_dir.y ~= 0.0 then ImGui.SetScrollY(window, ImTrunc(window.Scroll.y + scroll_dir.y * scroll_speed * tweak_factor)) end end end if not nav_keyboard_active and not nav_gamepad_active then g.NavCursorVisible = false g.NavHighlightItemUnderNav = false set_mouse_pos = false end if set_mouse_pos and io.ConfigNavMoveSetMousePos and bit32.band(io.BackendFlags, ImGuiBackendFlags.HasSetMousePos) ~= 0 then ImGui.TeleportMousePos(ImGui.NavCalcPreferredRefPos(ImGuiWindowFlags.Popup)) end g.NavScoringDebugCount = 0 end end function ImGui.NavUpdateCancelRequest() local g = GImGui local nav_gamepad_active = bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 and bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0 local nav_keyboard_active = bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 if not (nav_keyboard_active and ImGui.IsKeyPressedEx(ImGuiKey.Escape, 0, ImGuiKeyOwner_NoOwner)) and not (nav_gamepad_active and ImGui.IsKeyPressedEx(ImGuiKey.NavGamepadCancel, 0, ImGuiKeyOwner_NoOwner)) then return end -- IMGUI_DEBUG_LOG_NAV("[nav] NavUpdateCancelRequest()") if g.ActiveId ~= 0 then ImGui.ClearActiveID() elseif g.NavLayer ~= ImGuiNavLayer.Main then ImGui.NavRestoreLayer(ImGuiNavLayer.Main) ImGui.SetNavCursorVisibleAfterMove() elseif g.NavWindow and g.NavWindow ~= g.NavWindow.RootWindow and bit32.band(g.NavWindow.RootWindowForNav.Flags, ImGuiWindowFlags.Popup) == 0 and g.NavWindow.RootWindowForNav.ParentWindow then local child_window = g.NavWindow.RootWindowForNav local parent_window = child_window.ParentWindow IM_ASSERT(child_window.ChildId ~= 0) ImGui.FocusWindow(parent_window) ImGui.SetNavID(child_window.ChildId, ImGuiNavLayer.Main, 0, ImGui.WindowRectAbsToRel(parent_window, child_window:Rect())) ImGui.SetNavCursorVisibleAfterMove() elseif g.OpenPopupStack.Size > 0 and g.OpenPopupStack:back().Window ~= nil and bit32.band(g.OpenPopupStack:back().Window.Flags, ImGuiWindowFlags.Modal) == 0 then ImGui.ClosePopupToLevel(g.OpenPopupStack.Size - 1, true) else if g.IO.ConfigNavEscapeClearFocusItem or g.IO.ConfigNavEscapeClearFocusWindow then if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.Popup) ~= 0 then g.NavWindow.NavLastIds[0] = 0 end end if g.IO.ConfigNavEscapeClearFocusItem or g.IO.ConfigNavEscapeClearFocusWindow then g.NavId = 0 end if g.IO.ConfigNavEscapeClearFocusWindow then ImGui.FocusWindow(nil) end end end function ImGui.NavMoveRequestButNoResultYet() local g = GImGui return g.NavMoveScoringItems and g.NavMoveResultLocal.ID == 0 and g.NavMoveResultOther.ID == 0 end local function ImGetDirQuadrantFromDelta(dx, dy) if ImFabs(dx) > ImFabs(dy) then return (dx > 0.0) and ImGuiDir.Right or ImGuiDir.Left end return (dy > 0.0) and ImGuiDir.Down or ImGuiDir.Up end local function NavScoreItemDistInterval(cand_min, cand_max, curr_min, curr_max) if cand_max < curr_min then return cand_max - curr_min end if curr_max < cand_min then return cand_min - curr_max end return 0.0 end --- @param result ImGuiNavItemData --- @param nav_bb ImRect --- @return bool function ImGui.NavScoreItem(result, nav_bb) local g = GImGui local window = g.CurrentWindow if g.NavLayer ~= window.DC.NavLayerCurrent then return false end local cand = ImRect() ImRect_Copy(cand, nav_bb) local curr = g.NavScoringRect g.NavScoringDebugCount = g.NavScoringDebugCount + 1 if window.ParentWindow == g.NavWindow then IM_ASSERT(bit32.band(bit32.bor(window.ChildFlags, g.NavWindow.ChildFlags), ImGuiChildFlags.NavFlattened) ~= 0) if not window.ClipRect:Overlaps(cand) then return false end cand:ClipWithFull(window.ClipRect) end local dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x) local dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2), ImLerp(cand.Min.y, cand.Max.y, 0.8), ImLerp(curr.Min.y, curr.Max.y, 0.2), ImLerp(curr.Min.y, curr.Max.y, 0.8)) if dby ~= 0.0 and dbx ~= 0.0 then dbx = (dbx / 1000.0) + ((dbx > 0.0) and 1.0 or -1.0) end local dist_box = ImFabs(dbx) + ImFabs(dby) local dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x) local dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y) local dist_center = ImFabs(dcx) + ImFabs(dcy) local quadrant local dax = 0.0 local day = 0.0 local dist_axial = 0.0 if dbx ~= 0.0 or dby ~= 0.0 then dax = dbx day = dby dist_axial = dist_box quadrant = ImGetDirQuadrantFromDelta(dbx, dby) elseif dcx ~= 0.0 or dcy ~= 0.0 then dax = dcx day = dcy dist_axial = dist_center quadrant = ImGetDirQuadrantFromDelta(dcx, dcy) else quadrant = (g.LastItemData.ID < g.NavId) and ImGuiDir.Left or ImGuiDir.Right end local move_dir = g.NavMoveDir local new_best = false if quadrant == move_dir then if dist_box < result.DistBox then result.DistBox = dist_box result.DistCenter = dist_center return true end if dist_box == result.DistBox then if dist_center < result.DistCenter then result.DistCenter = dist_center new_best = true elseif dist_center == result.DistCenter then if (((move_dir == ImGuiDir.Up or move_dir == ImGuiDir.Down) and dby) or dbx) < 0.0 then new_best = true end end end end if result.DistBox == FLT_MAX and dist_axial < result.DistAxial then if g.NavLayer == ImGuiNavLayer.Menu and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.ChildMenu) == 0 then if (move_dir == ImGuiDir.Left and dax < 0.0) or (move_dir == ImGuiDir.Right and dax > 0.0) or (move_dir == ImGuiDir.Up and day < 0.0) or (move_dir == ImGuiDir.Down and day > 0.0) then result.DistAxial = dist_axial new_best = true end end end return new_best end --- @param result ImGuiNavItemData function ImGui.NavApplyItemToResult(result) local g = GImGui local window = g.CurrentWindow result.Window = window result.ID = g.LastItemData.ID result.FocusScopeId = g.CurrentFocusScopeId result.ItemFlags = g.LastItemData.ItemFlags ImRect_Copy(result.RectRel, ImGui.WindowRectAbsToRel(window, g.LastItemData.NavRect)) if bit32.band(result.ItemFlags, ImGuiItemFlags.HasSelectionUserData) ~= 0 then IM_ASSERT(g.NextItemData.SelectionUserData ~= ImGuiSelectionUserData_Invalid) result.SelectionUserData = g.NextItemData.SelectionUserData end end --- @param result ImGuiNavItemData function ImGui.NavMoveRequestResolveWithLastItem(result) local g = GImGui g.NavMoveScoringItems = false ImGui.NavApplyItemToResult(result) ImGui.NavUpdateAnyRequestFlag() end --- @param id ImGuiID --- @param item_flags ImGuiItemFlags --- @param move_flags ImGuiNavMoveFlags function ImGui.NavProcessItemForTabbingRequest(id, item_flags, move_flags) local g = GImGui if bit32.band(move_flags, ImGuiNavMoveFlags.FocusApi) == 0 then if g.NavLayer ~= g.CurrentWindow.DC.NavLayerCurrent then return end if g.NavFocusScopeId ~= g.CurrentFocusScopeId then return end end local can_stop if bit32.band(move_flags, ImGuiNavMoveFlags.FocusApi) ~= 0 then can_stop = true else can_stop = bit32.band(item_flags, ImGuiItemFlags.NoTabStop) == 0 and (bit32.band(g.IO.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 or bit32.band(item_flags, ImGuiItemFlags.Inputable) ~= 0) end local result = g.NavMoveResultLocal if g.NavTabbingDir == 1 then if can_stop and g.NavTabbingResultFirst.ID == 0 then ImGui.NavApplyItemToResult(g.NavTabbingResultFirst) end if can_stop and g.NavTabbingCounter > 0 then g.NavTabbingCounter = g.NavTabbingCounter - 1 if g.NavTabbingCounter == 0 then ImGui.NavMoveRequestResolveWithLastItem(result) end elseif g.NavId == id then g.NavTabbingCounter = 1 end elseif g.NavTabbingDir == -1 then if g.NavId == id then if result.ID ~= 0 then g.NavMoveScoringItems = false ImGui.NavUpdateAnyRequestFlag() end elseif can_stop then ImGui.NavApplyItemToResult(result) end elseif g.NavTabbingDir == 0 then if can_stop and g.NavId == id then ImGui.NavMoveRequestResolveWithLastItem(result) end if can_stop and g.NavTabbingResultFirst.ID == 0 then ImGui.NavApplyItemToResult(g.NavTabbingResultFirst) end end end function ImGui.NavProcessItem() local g = GImGui local window = g.CurrentWindow local id = g.LastItemData.ID local item_flags = g.LastItemData.ItemFlags local nav_bb = ImRect() ImRect_Copy(nav_bb, g.LastItemData.NavRect) if window.DC.NavIsScrollPushableX == false then nav_bb.Min.x = ImClamp(nav_bb.Min.x, window.ClipRect.Min.x, window.ClipRect.Max.x) nav_bb.Max.x = ImClamp(nav_bb.Max.x, window.ClipRect.Min.x, window.ClipRect.Max.x) end if g.NavInitRequest and g.NavLayer == window.DC.NavLayerCurrent and bit32.band(item_flags, ImGuiItemFlags.Disabled) == 0 then local candidate_for_nav_default_focus = bit32.band(item_flags, ImGuiItemFlags.NoNavDefaultFocus) == 0 if candidate_for_nav_default_focus or g.NavInitResult.ID == 0 then ImGui.NavApplyItemToResult(g.NavInitResult) end if candidate_for_nav_default_focus then g.NavInitRequest = false ImGui.NavUpdateAnyRequestFlag() end end if g.NavMoveScoringItems and bit32.band(item_flags, ImGuiItemFlags.Disabled) == 0 then if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.FocusApi) ~= 0 or bit32.band(window.Flags, ImGuiWindowFlags.NoNavInputs) == 0 then local is_tabbing = bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 if is_tabbing then ImGui.NavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags) elseif g.NavId ~= id or bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.AllowCurrentNavId) ~= 0 then local result = (window == g.NavWindow) and g.NavMoveResultLocal or g.NavMoveResultOther if ImGui.NavScoreItem(result, nav_bb) then ImGui.NavApplyItemToResult(result) end local VISIBLE_RATIO = 0.70 if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.AlsoScoreVisibleSet) ~= 0 then local r = window.InnerRect if r:Overlaps(nav_bb) then if ImClamp(nav_bb.Max.y, r.Min.y, r.Max.y) - ImClamp(nav_bb.Min.y, r.Min.y, r.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO then if ImGui.NavScoreItem(g.NavMoveResultLocalVisible, nav_bb) then ImGui.NavApplyItemToResult(g.NavMoveResultLocalVisible) end end end end end end end if g.NavId == id then if g.NavWindow ~= window then ImGui.SetNavWindow(window) end g.NavLayer = window.DC.NavLayerCurrent ImGui.SetNavFocusScope(g.CurrentFocusScopeId) g.NavFocusScopeId = g.CurrentFocusScopeId g.NavIdIsAlive = true g.NavIdItemFlags = item_flags if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.HasSelectionUserData) ~= 0 then IM_ASSERT(g.NextItemData.SelectionUserData ~= ImGuiSelectionUserData_Invalid) g.NavLastValidSelectionUserData = g.NextItemData.SelectionUserData end window.NavRectRel[window.DC.NavLayerCurrent] = ImGui.WindowRectAbsToRel(window, nav_bb) end end function ImGui.NavInitRequestApplyResult() local g = GImGui if not g.NavWindow then return end local result = g.NavInitResult if g.NavId ~= result.ID then g.NavJustMovedFromFocusScopeId = g.NavFocusScopeId g.NavJustMovedToId = result.ID g.NavJustMovedToFocusScopeId = result.FocusScopeId g.NavJustMovedToKeyMods = 0 g.NavJustMovedToIsTabbing = false g.NavJustMovedToHasSelectionData = bit32.band(result.ItemFlags, ImGuiItemFlags.HasSelectionUserData) ~= 0 end ImGui.SetNavID(result.ID, g.NavLayer, result.FocusScopeId, result.RectRel) g.NavIdIsAlive = true if result.SelectionUserData ~= ImGuiSelectionUserData_Invalid then g.NavLastValidSelectionUserData = result.SelectionUserData end if g.NavInitRequestFromMove then ImGui.SetNavCursorVisibleAfterMove() end end function ImGui.NavMoveRequestApplyResult() local g = GImGui local result if g.NavMoveResultLocal.ID ~= 0 then result = g.NavMoveResultLocal elseif g.NavMoveResultOther.ID ~= 0 then result = g.NavMoveResultOther else result = nil end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 and result == nil then if (g.NavTabbingCounter == 1 or g.NavTabbingDir == 0) and g.NavTabbingResultFirst.ID ~= 0 then result = g.NavTabbingResultFirst end end local axis = (g.NavMoveDir == ImGuiDir.Up or g.NavMoveDir == ImGuiDir.Down) and ImGuiAxis.Y or ImGuiAxis.X if result == nil then if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 then g.NavMoveFlags = bit32.bor(g.NavMoveFlags, ImGuiNavMoveFlags.NoSetNavCursorVisible) end if g.NavId ~= 0 and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.NoSetNavCursorVisible) == 0 then ImGui.SetNavCursorVisibleAfterMove() end ImGui.NavClearPreferredPosForAxis(axis) return end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.AlsoScoreVisibleSet) ~= 0 and g.NavMoveResultLocalVisible.ID ~= 0 and g.NavMoveResultLocalVisible.ID ~= g.NavId then result = g.NavMoveResultLocalVisible end if result ~= g.NavMoveResultOther and g.NavMoveResultOther.ID ~= 0 and g.NavMoveResultOther.Window.ParentWindow == g.NavWindow then if g.NavMoveResultOther.DistBox < result.DistBox or (g.NavMoveResultOther.DistBox == result.DistBox and g.NavMoveResultOther.DistCenter < result.DistCenter) then result = g.NavMoveResultOther end end IM_ASSERT(g.NavWindow and result.Window) if g.NavLayer == ImGuiNavLayer.Main then local rect_abs = ImGui.WindowRectRelToAbs(result.Window, result.RectRel) ImGui.ScrollToRectEx(result.Window, rect_abs, g.NavMoveScrollFlags) if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.ScrollToEdgeY) ~= 0 then local scroll_target = (g.NavMoveDir == ImGuiDir.Up) and result.Window.ScrollMax.y or 0.0 ImGui.SetScrollY(result.Window, scroll_target) end end if g.NavWindow ~= result.Window then g.NavWindow = result.Window g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid end if g.ActiveId ~= result.ID and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.NoClearActiveId) == 0 then ImGui.ClearActiveID() end if (g.NavId ~= result.ID or bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsPageMove) ~= 0) and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.NoSelect) == 0 then g.NavJustMovedFromFocusScopeId = g.NavFocusScopeId g.NavJustMovedToId = result.ID g.NavJustMovedToFocusScopeId = result.FocusScopeId g.NavJustMovedToKeyMods = g.NavMoveKeyMods g.NavJustMovedToIsTabbing = bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 g.NavJustMovedToHasSelectionData = bit32.band(result.ItemFlags, ImGuiItemFlags.HasSelectionUserData) ~= 0 end local root_for_nav = g.NavWindow.RootWindowForNav local preferred_scoring_pos_rel = ImVec2() ImVec2_Copy(preferred_scoring_pos_rel, root_for_nav.NavPreferredScoringPosRel[g.NavLayer]) ImGui.SetNavID(result.ID, g.NavLayer, result.FocusScopeId, result.RectRel) if result.SelectionUserData ~= ImGuiSelectionUserData_Invalid then g.NavLastValidSelectionUserData = result.SelectionUserData end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) == 0 then preferred_scoring_pos_rel[axis] = result.RectRel:GetCenter()[axis] ImVec2_Copy(root_for_nav.NavPreferredScoringPosRel[g.NavLayer], preferred_scoring_pos_rel) end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 and bit32.band(result.ItemFlags, ImGuiItemFlags.Inputable) == 0 then g.NavMoveFlags = bit32.band(g.NavMoveFlags, bit32.bnot(ImGuiNavMoveFlags.Activate)) end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.Activate) ~= 0 then g.NavNextActivateId = result.ID g.NavNextActivateFlags = ImGuiActivateFlags.None if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.FocusApi) ~= 0 then g.NavNextActivateFlags = bit32.bor(g.NavNextActivateFlags, ImGuiActivateFlags.FromFocusApi) end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 then g.NavNextActivateFlags = bit32.bor(g.NavNextActivateFlags, ImGuiActivateFlags.PreferInput, ImGuiActivateFlags.TryToPreserveState, ImGuiActivateFlags.FromTabbing) end end if bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.NoSetNavCursorVisible) == 0 then ImGui.SetNavCursorVisibleAfterMove() end end function ImGui.NavUpdateCurrentWindowIsScrollPushableX() local g = GImGui local window = g.CurrentWindow window.DC.NavIsScrollPushableX = (g.CurrentTable == nil and window.DC.CurrentColumns == nil) end --- @param result ImGuiNavItemData --- @param tree_node_data ImGuiTreeNodeStackData function ImGui.NavMoveRequestResolveWithPastTreeNode(result, tree_node_data) local g = GImGui g.NavMoveScoringItems = false g.LastItemData.ID = tree_node_data.ID g.LastItemData.ItemFlags = bit32.band(tree_node_data.ItemFlags, bit32.bnot(ImGuiItemFlags.HasSelectionUserData)) ImRect_Copy(g.LastItemData.NavRect, tree_node_data.NavRect) ImGui.NavApplyItemToResult(result) ImGui.NavClearPreferredPosForAxis(ImGuiAxis.Y) ImGui.NavUpdateAnyRequestFlag() end function ImGui.NavMoveRequestCancel() local g = GImGui g.NavMoveSubmitted = false g.NavMoveScoringItems = false ImGui.NavUpdateAnyRequestFlag() end --- @param move_dir ImGuiDir --- @param clip_dir ImGuiDir --- @param move_flags ImGuiNavMoveFlags --- @param scroll_flags ImGuiScrollFlags function ImGui.NavMoveRequestForward(move_dir, clip_dir, move_flags, scroll_flags) local g = GImGui IM_ASSERT(g.NavMoveForwardToNextFrame == false) ImGui.NavMoveRequestCancel() g.NavMoveForwardToNextFrame = true g.NavMoveDir = move_dir g.NavMoveClipDir = clip_dir g.NavMoveFlags = bit32.bor(move_flags, ImGuiNavMoveFlags.Forwarded) g.NavMoveScrollFlags = scroll_flags end --- @param window ImGuiWindow --- @param wrap_flags ImGuiNavMoveFlags function ImGui.NavMoveRequestTryWrapping(window, wrap_flags) local g = GImGui IM_ASSERT(bit32.band(wrap_flags, ImGuiNavMoveFlags.WrapMask_) ~= 0 and bit32.band(wrap_flags, bit32.bnot(ImGuiNavMoveFlags.WrapMask_)) == 0) if g.NavWindow == window and g.NavMoveScoringItems and g.NavLayer == window.DC.NavLayerCurrent then g.NavMoveFlags = bit32.bor(bit32.band(g.NavMoveFlags, bit32.bnot(ImGuiNavMoveFlags.WrapMask_)), wrap_flags) end end --------------------------------------------------------------------------------------- -- [SECTION] DRAG AND DROP --------------------------------------------------------------------------------------- function ImGui.IsDragDropPayloadBeingAccepted() local g = GImGui return g.DragDropActive and g.DragDropAcceptIdPrev ~= 0 end --------------------------------------------------------------------------------------- -- [SECTION] LOCALIZATION --------------------------------------------------------------------------------------- --- @param entries ImGuiLocEntry[] --- @param count int function ImGui.LocalizeRegisterEntries(entries, count) local g = GImGui for n = 1, count do g.LocalizationTable[entries[n].Key] = entries[n].Text end end --------------------------------------------------------------------------------------- -- [SECTION] VIEWPORTS, PLATFORM WINDOWS --------------------------------------------------------------------------------------- function MT.ImGuiViewport:GetDebugName() local viewport = self return viewport.Window and viewport.Window.Name or "n/a" end function MT.ImGuiPlatformIO:ClearPlatformHandlers() self.Platform_GetClipboardTextFn = nil; self.Platform_SetClipboardTextFn = nil self.Platform_ClipboardUserData = nil self.Platform_OpenInShellFn = nil; self.Platform_OpenInShellUserData = nil self.Platform_SetImeDataFn = nil; self.Platform_ImeUserData = nil self.Platform_CreateWindow = nil; self.Platform_DestroyWindow = nil; self.Platform_ShowWindow = nil self.Platform_SetWindowPos = nil; self.Platform_SetWindowSize = nil self.Platform_GetWindowPos = nil; self.Platform_GetWindowSize = nil; self.Platform_GetWindowFramebufferScale = nil self.Platform_SetWindowFocus = nil; self.Platform_GetWindowFocus = nil; self.Platform_GetWindowMinimized = nil self.Platform_SetWindowTitle = nil; self.Platform_SetWindowAlpha = nil; self.Platform_UpdateWindow = nil self.Platform_RenderWindow = nil; self.Platform_SwapBuffers = nil; self.Platform_GetWindowDpiScale = nil self.Platform_OnChangedViewport = nil; self.Platform_GetWindowWorkAreaInsets = nil; self.Platform_CreateVkSurface = nil end function MT.ImGuiPlatformIO:ClearRendererHandlers() self.Renderer_TextureMaxWidth = 0; self.Renderer_TextureMaxHeight = 0 self.Renderer_RenderState = nil self.Renderer_CreateWindow = nil; self.Renderer_DestroyWindow = nil self.Renderer_SetWindowSize = nil self.Renderer_RenderWindow = nil; self.Renderer_SwapBuffers = nil end --- @return ImGuiViewport function ImGui.GetMainViewport() local g = GImGui return g.Viewports[1] end --- @param viewport_id ImGuiID --- @return ImGuiViewport? function ImGui.FindViewportByID(viewport_id) local g = GImGui for _, viewport in g.Viewports:iter() do if viewport.ID == viewport_id then return viewport end end return nil end --- @param current_window? ImGuiWindow --- @param viewport? ImGuiViewportP function ImGui.SetCurrentViewport(current_window, viewport) local g = GImGui if viewport then viewport.LastFrameActive = g.FrameCount end if g.CurrentViewport == viewport then return end g.CurrentDpiScale = viewport and viewport.DpiScale or 1.0 g.CurrentViewport = viewport IM_ASSERT(g.CurrentDpiScale > 0.0 and g.CurrentDpiScale < 99.0) -- Typical correct values would be between 1.0f and 4.0f -- IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X", current_window and current_window.Name or "NULL", viewport and viewport.ID or 0) if g.IO.ConfigDpiScaleFonts then g.Style.FontScaleDpi = g.CurrentDpiScale end -- Notify platform layer of viewport changes -- FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI if g.CurrentViewport and g.PlatformIO.Platform_OnChangedViewport then g.PlatformIO.Platform_OnChangedViewport(g.CurrentViewport) end end --- @param window ImGuiWindow --- @param viewport ImGuiViewportP function ImGui.SetWindowViewport(window, viewport) -- Abandon viewport if window.ViewportOwned and window.Viewport.Window == window then window.Viewport.Size = ImVec2(0.0, 0.0) end window.Viewport = viewport window.ViewportId = viewport.ID window.ViewportOwned = (viewport.Window == window) end --- @param window ImGuiWindow --- @return bool function ImGui.GetWindowAlwaysWantOwnViewport(window) -- Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protrude and create their own. local g = GImGui if g.IO.ConfigViewportsNoAutoMerge or (bit32.band(window.WindowClass.ViewportFlagsOverrideSet, ImGuiViewportFlags.NoAutoMerge) ~= 0) then if bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) ~= 0 then if not window.DockIsActive then if bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.ChildWindow, ImGuiWindowFlags.ChildMenu, ImGuiWindowFlags.Tooltip)) == 0 then if bit32.band(window.Flags, ImGuiWindowFlags.Popup) == 0 or bit32.band(window.Flags, ImGuiWindowFlags.Modal) ~= 0 then return true end end end end end return false end --- Heuristic, see #8948: depends on how backends handle OS-level parenting. --- Due to how parent viewport stack is layed out, note that IsViewportAbove(a,b) isn't always the same as !IsViewportAbove(b,a). --- @param potential_above ImGuiViewportP --- @param potential_below ImGuiViewportP --- @return bool function ImGui.IsViewportAbove(potential_above, potential_below) -- If ImGuiBackendFlags.HasParentViewport if set, ->ParentViewport chain should be accurate. local g = GImGui if bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.HasParentViewport) ~= 0 then local v = potential_above --[[@as ImGuiViewport]] while v ~= nil and v.ParentViewport do if v.ParentViewport == potential_below then return true end v = v.ParentViewport end else if potential_above.ParentViewport == potential_below then return true end end if potential_above.LastFocusedStampCount > potential_below.LastFocusedStampCount then return true end return false end --- @param window ImGuiWindow --- @param viewport_dst ImGuiViewportP function ImGui.UpdateTryMergeWindowIntoHostViewport(window, viewport_dst) local g = GImGui IM_ASSERT(window == window.RootWindowDockTree) local viewport_src = window.Viewport -- Current viewport if viewport_src == viewport_dst then return false end if bit32.band(viewport_dst.Flags, ImGuiViewportFlags.CanHostOtherWindows) == 0 then return false end if bit32.band(viewport_dst.Flags, ImGuiViewportFlags.IsMinimized) ~= 0 then return false end if not viewport_dst:GetMainRect():Contains(window:Rect()) then return false end if ImGui.GetWindowAlwaysWantOwnViewport(window) then return false end for _, viewport_obstructing in g.Viewports:iter() do repeat if viewport_obstructing == viewport_src or viewport_obstructing == viewport_dst or not viewport_obstructing.PlatformWindowCreated then break end if viewport_obstructing:GetMainRect():Overlaps(window:Rect()) then if ImGui.IsViewportAbove(viewport_obstructing, viewport_dst) then if viewport_src == nil or ImGui.IsViewportAbove(viewport_src, viewport_obstructing) then return false -- viewport_obstructing is between viewport_src and viewport_dst -> Cannot merge. end end end until true end -- Move to the existing viewport, Move child/hosted windows as well (FIXME-OPT: iterate child) IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' merge into Viewport 0X%08X", window.Name, viewport_dst.ID) if window.ViewportOwned then for n = 1, g.Windows.Size do if g.Windows.Data[n].Viewport == viewport_src then ImGui.SetWindowViewport(g.Windows.Data[n], viewport_dst) end end end ImGui.SetWindowViewport(window, viewport_dst) if bit32.band(window.Flags, ImGuiWindowFlags.NoBringToFrontOnFocus) == 0 then ImGui.BringWindowToDisplayFront(window) end return true end -- FIXME: handle 0 to N host viewports --- @param window ImGuiWindow --- @return bool function ImGui.UpdateTryMergeWindowIntoHostViewports(window) local g = GImGui return ImGui.UpdateTryMergeWindowIntoHostViewport(window, g.Viewports.Data[1]) end --- Translate Dear ImGui windows when a Host Viewport has been moved --- (This additionally keeps windows at the same place when ImGuiConfigFlags.ViewportsEnable is toggled!) --- @param viewport ImGuiViewportP --- @param old_pos ImVec2 --- @param new_pos ImVec2 --- @param old_size ImVec2 --- @param new_size ImVec2 function ImGui.TranslateWindowsInViewport(viewport, old_pos, new_pos, old_size, new_size) local g = GImGui -- IMGUI_DEBUG_LOG_VIEWPORT("[viewport] TranslateWindowsInViewport 0x%08X", viewport.ID) IM_ASSERT(viewport.Window == nil and (bit32.band(viewport.Flags, ImGuiViewportFlags.CanHostOtherWindows) ~= 0)) -- 1) We test if ImGuiConfigFlags.ViewportsEnable was just toggled, which allows us to conveniently -- translate imgui windows from OS-window-local to absolute coordinates or vice-versa. -- 2) If it's not going to fit into the new size, keep it at same absolute position. -- One problem with this is that most Win32 applications doesn't update their render while dragging, -- and so the window will appear to teleport when releasing the mouse. local translate_all_windows = (bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) ~= bit32.band(g.ConfigFlagsLastFrame, ImGuiConfigFlags.ViewportsEnable)) local test_still_fit_rect = ImRect(old_pos, old_pos + old_size) local delta_pos = new_pos - old_pos for _, window in g.Windows:iter() do -- FIXME-OPT if translate_all_windows or (window.Viewport == viewport and (old_size == new_size or test_still_fit_rect:Contains(window:Rect()))) then ImGui.TranslateWindow(window, delta_pos) end end end -- If the backend doesn't support ImGuiBackendFlags_HasMouseHoveredViewport or doesn't honor ImGuiViewportFlags_NoInputs for it, we do a search ourselves. -- A) It won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window. -- B) It requires Platform_GetWindowFocus to be implemented by backend. --- @param mouse_platform_pos ImVec2 --- @return ImGuiViewportP? function ImGui.FindHoveredViewportFromPlatformWindowStack(mouse_platform_pos) local g = GImGui local best_candidate = nil for _, viewport in g.Viewports:iter() do if bit32.band(viewport.Flags, bit32.bor(ImGuiViewportFlags.NoInputs, ImGuiViewportFlags.IsMinimized)) == 0 and viewport:GetMainRect():Contains(mouse_platform_pos) then if best_candidate == nil or best_candidate.LastFocusedStampCount < viewport.LastFocusedStampCount then if viewport.PlatformWindowCreated then best_candidate = viewport end end end end return best_candidate end function ImGui.UpdateViewportsNewFrame() local g = GImGui IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size) -- Update Minimized status (we need it first in order to decide if we'll apply Pos/Size of the main viewport) -- Update Focused status local viewports_enabled = (bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) ~= 0) if viewports_enabled then local focused_viewport = nil for i = 1, g.Viewports.Size do local viewport = g.Viewports.Data[i] local platform_funcs_available = viewport.PlatformWindowCreated if g.PlatformIO.Platform_GetWindowMinimized and platform_funcs_available then local is_minimized = g.PlatformIO.Platform_GetWindowMinimized(viewport) if is_minimized then viewport.Flags = bit32.bor(viewport.Flags, ImGuiViewportFlags.IsMinimized) else viewport.Flags = bit32.band(viewport.Flags, bit32.bnot(ImGuiViewportFlags.IsMinimized)) end end -- Update our implicit z-order knowledge of platform windows, which is used when the backend cannot provide io.MouseHoveredViewport. -- When setting Platform_GetWindowFocus, it is expected that the platform backend can handle calls without crashing if it doesn't have data stored. if g.PlatformIO.Platform_GetWindowFocus and platform_funcs_available then local is_focused = g.PlatformIO.Platform_GetWindowFocus(viewport) if is_focused then viewport.Flags = bit32.bor(viewport.Flags, ImGuiViewportFlags.IsFocused) else viewport.Flags = bit32.band(viewport.Flags, bit32.bnot(ImGuiViewportFlags.IsFocused)) end if is_focused then focused_viewport = viewport end end end -- Focused viewport has changed? if focused_viewport and g.PlatformLastFocusedViewportId ~= focused_viewport.ID then IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Focused viewport changed %08X -> %08X '%s', attempting to apply our focus.", g.PlatformLastFocusedViewportId, focused_viewport.ID, focused_viewport.Window and focused_viewport.Window.Name or "n/a") local prev_focused_viewport = ImGui.FindViewportByID(g.PlatformLastFocusedViewportId) local prev_focused_has_been_destroyed = (prev_focused_viewport == nil) or (not prev_focused_viewport.PlatformWindowCreated) -- Store a tag so we can infer z-order easily from all our windows -- We compare PlatformLastFocusedViewportId so newly created viewports with _NoFocusOnAppearing flag -- will keep the front most stamp instead of losing it back to their parent viewport. if focused_viewport.LastFocusedStampCount ~= g.ViewportFocusedStampCount then g.ViewportFocusedStampCount = g.ViewportFocusedStampCount + 1 focused_viewport.LastFocusedStampCount = g.ViewportFocusedStampCount end g.PlatformLastFocusedViewportId = focused_viewport.ID -- Focus associated dear imgui window -- - if focus didn't happen with a click within imgui boundaries, e.g. Clicking platform title bar. (#6299) -- - if focus didn't happen because we destroyed another window (#6462) -- FIXME: perhaps 'FocusTopMostWindowUnderOne()' can handle the 'focused_window.Window ~= nil' case as well. local apply_imgui_focus_on_focused_viewport = not ImGui.IsAnyMouseDown() and not prev_focused_has_been_destroyed if apply_imgui_focus_on_focused_viewport and g.IO.ConfigViewportsPlatformFocusSetsImGuiFocus then focused_viewport.LastFocusedHadNavWindow = focused_viewport.LastFocusedHadNavWindow or (g.NavWindow ~= nil and g.NavWindow.Viewport == focused_viewport) -- Update so a window changing viewport won't lose focus. local focus_request_flags = bit32.bor(ImGuiFocusRequestFlags.UnlessBelowModal, ImGuiFocusRequestFlags.RestoreFocusedChild) if focused_viewport.Window ~= nil then ImGui.FocusWindow(focused_viewport.Window, focus_request_flags) elseif focused_viewport.LastFocusedHadNavWindow then ImGui.FocusTopMostWindowUnderOne(nil, nil, focused_viewport, focus_request_flags) -- Focus top most in viewport else ImGui.FocusWindow(nil, focus_request_flags) -- No window had focus last time viewport was focused end end end if focused_viewport then focused_viewport.LastFocusedHadNavWindow = (g.NavWindow ~= nil) and (g.NavWindow.Viewport == focused_viewport) end end -- Create/update main viewport with current platform position. -- FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent. local main_viewport = g.Viewports.Data[1] IM_ASSERT(main_viewport.ID == IMGUI_VIEWPORT_DEFAULT_ID) IM_ASSERT(main_viewport.Window == nil) local main_viewport_pos if viewports_enabled then main_viewport_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport) else main_viewport_pos = ImVec2(0.0, 0.0) end local main_viewport_size = g.IO.DisplaySize local main_viewport_framebuffer_scale = g.IO.DisplayFramebufferScale if viewports_enabled and (bit32.band(main_viewport.Flags, ImGuiViewportFlags.IsMinimized) ~= 0) then ImVec2_Copy(main_viewport_pos, main_viewport.Pos) -- Preserve last pos/size when minimized (FIXME: We don't do the same for Size outside of the viewport path) ImVec2_Copy(main_viewport_size, main_viewport.Size) main_viewport_framebuffer_scale = main_viewport.FramebufferScale end ImGui.AddUpdateViewport(nil, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_pos, main_viewport_size, bit32.bor(ImGuiViewportFlags.OwnedByApp, ImGuiViewportFlags.CanHostOtherWindows)) local memory_compact_start_time = (g.GcCompactAll or g.IO.ConfigMemoryCompactTimer < 0.0) and FLT_MAX or (g.Time - g.IO.ConfigMemoryCompactTimer) g.CurrentDpiScale = 0.0 g.CurrentViewport = nil g.MouseViewport = nil local n = 1 while n <= g.Viewports.Size do local viewport = g.Viewports.Data[n] viewport.Idx = n -- Erase unused viewports if n > 1 and viewport.LastFrameActive < g.FrameCount - 2 then ImGui.DestroyViewport(viewport) -- n stays the same because we removed an element else local platform_funcs_available = viewport.PlatformWindowCreated if viewports_enabled then -- Update Position and Size (from Platform Window to ImGui) if requested. -- We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities. if (bit32.band(viewport.Flags, ImGuiViewportFlags.IsMinimized) == 0) and platform_funcs_available then -- Viewport->WorkPos and WorkSize will be updated below if viewport.PlatformRequestMove then ImVec2_Copy(viewport.Pos, g.PlatformIO.Platform_GetWindowPos(viewport)) ImVec2_Copy(viewport.LastPlatformPos, viewport.Pos) end if viewport.PlatformRequestResize then viewport.Size = g.PlatformIO.Platform_GetWindowSize(viewport) ImVec2_Copy(viewport.LastPlatformSize, viewport.Size) end if g.PlatformIO.Platform_GetWindowFramebufferScale ~= nil then viewport.FramebufferScale = g.PlatformIO.Platform_GetWindowFramebufferScale(viewport) end end end -- Update/copy monitor info ImGui.UpdateViewportPlatformMonitor(viewport) -- Lock down space taken by menu bars and status bars + query initial insets from backend -- Setup initial value for functions like BeginMainMenuBar(), DockSpaceOverViewport() etc. viewport.WorkInsetMin = viewport.BuildWorkInsetMin viewport.WorkInsetMax = viewport.BuildWorkInsetMax viewport.BuildWorkInsetMin = ImVec2(0.0, 0.0) viewport.BuildWorkInsetMax = ImVec2(0.0, 0.0) if g.PlatformIO.Platform_GetWindowWorkAreaInsets ~= nil and platform_funcs_available then local insets = g.PlatformIO.Platform_GetWindowWorkAreaInsets(viewport) IM_ASSERT(insets.x >= 0.0 and insets.y >= 0.0 and insets.z >= 0.0 and insets.w >= 0.0) viewport.BuildWorkInsetMin = ImVec2(insets.x, insets.y) viewport.BuildWorkInsetMax = ImVec2(insets.z, insets.w) end viewport:UpdateWorkRect() for dl_n = 1, 2 do -- IM_COUNTOF(viewport->BgFgDrawLists) if viewport.BgFgDrawListsLastTimeActive[dl_n] < memory_compact_start_time and viewport.BgFgDrawLists[dl_n] ~= nil then IM_DELETE(viewport.BgFgDrawLists, dl_n) end end -- Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back. viewport.Alpha = 1.0 -- Translate Dear ImGui windows when a Host Viewport has been moved -- (This additionally keeps windows at the same place when ImGuiConfigFlags.ViewportsEnable is toggled!) local viewport_delta_pos = viewport.Pos - viewport.LastPos if (bit32.band(viewport.Flags, ImGuiViewportFlags.CanHostOtherWindows) ~= 0) and (viewport_delta_pos.x ~= 0.0 or viewport_delta_pos.y ~= 0.0) then ImGui.TranslateWindowsInViewport(viewport, viewport.LastPos, viewport.Pos, viewport.LastSize, viewport.Size) end -- Update DPI scale local new_dpi_scale if g.PlatformIO.Platform_GetWindowDpiScale and platform_funcs_available then new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport) elseif viewport.PlatformMonitor ~= -1 then new_dpi_scale = g.PlatformIO.Monitors.Data[viewport.PlatformMonitor].DpiScale else new_dpi_scale = (viewport.DpiScale ~= 0.0) and viewport.DpiScale or 1.0 end IM_ASSERT(new_dpi_scale > 0.0 and new_dpi_scale < 99.0) -- Typical correct values would be between 1.0f and 4.0f if viewport.DpiScale ~= 0.0 and new_dpi_scale ~= viewport.DpiScale then local scale_factor = new_dpi_scale / viewport.DpiScale if g.IO.ConfigDpiScaleViewports then ImGui.ScaleWindowsInViewport(viewport, scale_factor) end -- if viewport == ImGui.GetMainViewport() then -- g.PlatformInterface.SetWindowSize(viewport, viewport.Size * scale_factor) -- end -- Scale our window moving pivot so that the window will rescale roughly around the mouse position. -- FIXME-VIEWPORT: This currently creates a resizing feedback loop when a window is straddling a DPI transition border. -- (Minor: since our sizes do not perfectly linearly scale, deferring the click offset scale until we know the actual window scale ratio may get us slightly more precise mouse positioning.) -- if g.MovingWindow ~= nil and g.MovingWindow.Viewport == viewport then -- g.ActiveIdClickOffset = ImTrunc(g.ActiveIdClickOffset * scale_factor) -- end end viewport.DpiScale = new_dpi_scale n = n + 1 end end -- Update fallback monitor g.PlatformMonitorsFullWorkRect = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) if g.PlatformIO.Monitors.Size == 0 then local monitor = g.FallbackMonitor ImVec2_Copy(monitor.MainPos, main_viewport.Pos) ImVec2_Copy(monitor.MainSize, main_viewport.Size) ImVec2_Copy(monitor.WorkPos, main_viewport.WorkPos) ImVec2_Copy(monitor.WorkSize, main_viewport.WorkSize) monitor.DpiScale = main_viewport.DpiScale g.PlatformMonitorsFullWorkRect:Add(monitor.WorkPos) g.PlatformMonitorsFullWorkRect:Add(monitor.WorkPos + monitor.WorkSize) else g.FallbackMonitor = g.PlatformIO.Monitors.Data[1] end for i = 1, g.PlatformIO.Monitors.Size do local monitor = g.PlatformIO.Monitors.Data[i] g.PlatformMonitorsFullWorkRect:Add(monitor.WorkPos) g.PlatformMonitorsFullWorkRect:Add(monitor.WorkPos + monitor.WorkSize) end if not viewports_enabled then g.MouseViewport = main_viewport return end -- Mouse handling: decide on the actual mouse viewport for this frame between the active/focused viewport and the hovered viewport. -- Note that 'viewport_hovered' should skip over any viewport that has the ImGuiViewportFlags.NoInputs flags set. local viewport_hovered = nil if bit32.band(g.IO.BackendFlags, ImGuiBackendFlags.HasMouseHoveredViewport) ~= 0 then viewport_hovered = g.IO.MouseHoveredViewport and ImGui.FindViewportByID(g.IO.MouseHoveredViewport) or nil if viewport_hovered and (bit32.band(viewport_hovered.Flags, ImGuiViewportFlags.NoInputs) ~= 0) then viewport_hovered = ImGui.FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos) -- Backend failed to handle _NoInputs viewport: revert to our fallback. end else -- If the backend doesn't know how to honor ImGuiViewportFlags.NoInputs, we do a search ourselves. Note that this search: -- A) won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window. -- B) won't take account of how the backend apply parent<>child relationship to secondary viewports, which affects their Z order. -- C) uses LastFocusedStampCount as a flawed replacement for the last time a window was focused (we could/should fix that by introducing Focus functions in PlatformIO) viewport_hovered = ImGui.FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos) end if viewport_hovered ~= nil then g.MouseLastHoveredViewport = viewport_hovered elseif g.MouseLastHoveredViewport == nil then g.MouseLastHoveredViewport = g.Viewports.Data[1] end -- Update mouse reference viewport -- (when moving a window we aim at its viewport, but this will be overwritten below if we go in drag and drop mode) -- (MovingViewport->Viewport will be nil in the rare situation where the window disappared while moving, set UpdateMouseMovingWindowNewFrame() for details) if g.MovingWindow and g.MovingWindow.Viewport then g.MouseViewport = g.MovingWindow.Viewport else g.MouseViewport = g.MouseLastHoveredViewport end -- When dragging something, always refer to the last hovered viewport. -- - when releasing a moving window we will revert to aiming behind (at viewport_hovered) -- - when we are between viewports, our dragged preview will tend to show in the last viewport _even_ if we don't have tooltips in their viewports (when lacking monitor info) -- - consider the case of holding on a menu item to browse child menus: even thou a mouse button is held, there's no active id because menu items only react on mouse release. -- FIXME-VIEWPORT: This is essentially broken, when ImGuiBackendFlags.HasMouseHoveredViewport is set we want to trust when viewport_hovered==nil and use that. local is_mouse_dragging_with_an_expected_destination = g.DragDropActive if is_mouse_dragging_with_an_expected_destination and viewport_hovered == nil then viewport_hovered = g.MouseLastHoveredViewport end if is_mouse_dragging_with_an_expected_destination or g.ActiveId == 0 or not ImGui.IsAnyMouseDown() then if viewport_hovered ~= nil and viewport_hovered ~= g.MouseViewport and (bit32.band(viewport_hovered.Flags, ImGuiViewportFlags.NoInputs) == 0) then g.MouseViewport = viewport_hovered end end IM_ASSERT(g.MouseViewport ~= nil) end function ImGui.UpdateViewportsEndFrame() local g = GImGui g.PlatformIO.Viewports:resize(0) for i = 1, g.Viewports.Size do repeat local viewport = g.Viewports.Data[i] ImVec2_Copy(viewport.LastPos, ImVec2(viewport.Pos.x, viewport.Pos.y)) ImVec2_Copy(viewport.LastSize, ImVec2(viewport.Size.x, viewport.Size.y)) if (viewport.LastFrameActive < g.FrameCount or viewport.Size.x <= 0.0 or viewport.Size.y <= 0.0) and (i > 1) then break end if viewport.Window and not ImGui.IsWindowActiveAndVisible(viewport.Window) then break end if i > 1 then IM_ASSERT(viewport.Window ~= nil) end g.PlatformIO.Viewports:push_back(viewport) until true end g.Viewports.Data[1]:ClearRequestFlags() -- Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called end --- @param window? ImGuiWindow --- @param id ImGuiID --- @param pos ImVec2 --- @param size ImVec2 --- @param flags ImGuiViewportFlags --- @return ImGuiViewportP function ImGui.AddUpdateViewport(window, id, pos, size, flags) local g = GImGui IM_ASSERT(id ~= 0) flags = bit32.bor(flags, ImGuiViewportFlags.IsPlatformWindow) if window ~= nil then local window_can_use_inputs = (bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoNavInputs)) == 0) if g.MovingWindow and g.MovingWindow.RootWindowDockTree == window then flags = bit32.bor(flags, ImGuiViewportFlags.NoInputs, ImGuiViewportFlags.NoFocusOnAppearing) end if not window_can_use_inputs then flags = bit32.bor(flags, ImGuiViewportFlags.NoInputs) end if bit32.band(window.Flags, ImGuiWindowFlags.NoFocusOnAppearing) ~= 0 then flags = bit32.bor(flags, ImGuiViewportFlags.NoFocusOnAppearing) end end local viewport = ImGui.FindViewportByID(id) if viewport then --- @cast viewport ImGuiViewportP -- Always update for main viewport as we are already pulling correct platform pos/size (see #4900) local prev_pos = ImVec2(viewport.Pos.x, viewport.Pos.y) local prev_size = ImVec2(viewport.Size.x, viewport.Size.y) if not viewport.PlatformRequestMove or viewport.ID == IMGUI_VIEWPORT_DEFAULT_ID then ImVec2_Copy(viewport.Pos, pos) end if not viewport.PlatformRequestResize or viewport.ID == IMGUI_VIEWPORT_DEFAULT_ID then ImVec2_Copy(viewport.Size, size) end -- Preserve existing flags viewport.Flags = bit32.bor(flags, bit32.band(viewport.Flags, bit32.bor(ImGuiViewportFlags.IsMinimized, ImGuiViewportFlags.IsFocused))) if prev_pos.x ~= viewport.Pos.x or prev_pos.y ~= viewport.Pos.y or prev_size.x ~= viewport.Size.x or prev_size.y ~= viewport.Size.y then ImGui.UpdateViewportPlatformMonitor(viewport) end else -- New viewport viewport = ImGuiViewportP() viewport.ID = id viewport.Idx = g.Viewports.Size ImVec2_Copy(viewport.Pos, pos) ImVec2_Copy(viewport.LastPos, pos) ImVec2_Copy(viewport.Size, size) ImVec2_Copy(viewport.LastSize, size) viewport.Flags = flags ImGui.UpdateViewportPlatformMonitor(viewport) g.Viewports:push_back(viewport) g.ViewportCreatedCount = g.ViewportCreatedCount + 1 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Add Viewport %08X '%s'", id, window and window.Name or "") -- We assume the window becomes front-most (even when ImGuiViewportFlags.NoFocusOnAppearing is used). -- This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available. g.ViewportFocusedStampCount = g.ViewportFocusedStampCount + 1 viewport.LastFocusedStampCount = g.ViewportFocusedStampCount -- We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport. -- We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame g.DrawListSharedData.ClipRectFullscreen.x = ImMin(g.DrawListSharedData.ClipRectFullscreen.x, viewport.Pos.x) g.DrawListSharedData.ClipRectFullscreen.y = ImMin(g.DrawListSharedData.ClipRectFullscreen.y, viewport.Pos.y) g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport.Pos.x + viewport.Size.x) g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport.Pos.y + viewport.Size.y) -- Store initial DpiScale before the OS platform window creation, based on expected monitor data. -- This is so we can select an appropriate font size on the first frame of our window lifetime viewport.DpiScale = ImGui.GetViewportPlatformMonitor(viewport).DpiScale end viewport.Window = window viewport.LastFrameActive = g.FrameCount viewport:UpdateWorkRect() IM_ASSERT(window == nil or viewport.ID == window.ID) if window ~= nil then window.ViewportOwned = true end return viewport end --- @param viewport ImGuiViewportP function ImGui.DestroyViewport(viewport) -- Clear references to this viewport in windows (window->ViewportId becomes the master data) local g = GImGui for i = 1, g.Windows.Size do local window = g.Windows.Data[i] if window.Viewport == viewport then window.Viewport = nil window.ViewportOwned = false end end if viewport == g.MouseLastHoveredViewport then g.MouseLastHoveredViewport = nil end -- Destroy IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Delete Viewport %08X '%s'", viewport.ID, viewport.Window and viewport.Window.Name or "n/a") ImGui.DestroyPlatformWindow(viewport) -- In most circumstances the platform window will already be destroyed here. IM_ASSERT(not g.PlatformIO.Viewports:contains(viewport)) IM_ASSERT(g.Viewports.Data[viewport.Idx] == viewport) g.Viewports:erase(viewport.Idx) -- IM_DELETE(viewport) end --- @param window ImGuiWindow function ImGui.WindowSelectViewport(window) local g = GImGui local flags = window.Flags window.ViewportAllowPlatformMonitorExtend = -1 -- Restore main viewport if multi-viewport is not supported by the backend local main_viewport = ImGui.GetMainViewport() --[[@as ImGuiViewportP]] if bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) == 0 then ImGui.SetWindowViewport(window, main_viewport) return end window.ViewportOwned = false -- Appearing popups reset their viewport so they can inherit again if bit32.band(flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0 and window.Appearing then window.Viewport = nil window.ViewportId = 0 end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasViewport) == 0 then -- By default inherit from parent window if window.Viewport == nil and window.ParentWindow and (not window.ParentWindow.IsFallbackWindow or window.ParentWindow.WasActive) then window.Viewport = window.ParentWindow.Viewport end -- Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file if window.Viewport == nil and window.ViewportId ~= 0 then window.Viewport = ImGui.FindViewportByID(window.ViewportId) --[[@as ImGuiViewportP]] if window.Viewport == nil and window.ViewportPos.x ~= FLT_MAX and window.ViewportPos.y ~= FLT_MAX then window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.ViewportPos, window.Size, ImGuiViewportFlags.None) end end end local lock_viewport = false if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasViewport) ~= 0 then -- Code explicitly request a viewport window.Viewport = ImGui.FindViewportByID(g.NextWindowData.ViewportId) --[[@as ImGuiViewportP]] window.ViewportId = g.NextWindowData.ViewportId -- Store ID even if Viewport isn't resolved yet. if window.Viewport and bit32.band(window.Flags, ImGuiWindowFlags.DockNodeHost) ~= 0 and window.Viewport.Window ~= nil then window.Viewport.Window = window window.Viewport.ID = window.ID window.ViewportId = window.ID -- Overwrite ID (always owned by node) end lock_viewport = true elseif bit32.band(flags, ImGuiWindowFlags.ChildWindow) ~= 0 or bit32.band(flags, ImGuiWindowFlags.ChildMenu) ~= 0 then -- Always inherit viewport from parent window if window.DockNode and window.DockNode.HostWindow then IM_ASSERT(window.DockNode.HostWindow.Viewport == window.ParentWindow.Viewport) end window.Viewport = window.ParentWindow.Viewport elseif window.DockNode and window.DockNode.HostWindow then -- This covers the "always inherit viewport from parent window" case for when a window reattach to a node that was just created mid-frame window.Viewport = window.DockNode.HostWindow.Viewport elseif bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0 then window.Viewport = g.MouseViewport elseif ImGui.GetWindowAlwaysWantOwnViewport(window) then window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.Pos, window.Size, ImGuiViewportFlags.None) elseif g.MovingWindow and g.MovingWindow.RootWindowDockTree == window and ImGui.IsMousePosValid() then if window.Viewport ~= nil and window.Viewport.Window == window then window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.Pos, window.Size, ImGuiViewportFlags.None) end else -- Merge into host viewport? -- We cannot test window->ViewportOwned as it set lower in the function. -- Testing (g.ActiveId == 0 || g.ActiveIdAllowOverlap) to avoid merging during a short-term widget interaction. Main intent was to avoid during resize (see #4212) local try_to_merge_into_host_viewport = (window.Viewport and window == window.Viewport.Window and (g.ActiveId == 0 or g.ActiveIdAllowOverlap)) if try_to_merge_into_host_viewport then ImGui.UpdateTryMergeWindowIntoHostViewports(window) end end -- Fallback: merge in default viewport if z-order matches, otherwise create a new viewport if window.Viewport == nil then --- @cast main_viewport ImGuiViewportP if not ImGui.UpdateTryMergeWindowIntoHostViewport(window, main_viewport) then window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.Pos, window.Size, ImGuiViewportFlags.None) end end -- Mark window as allowed to protrude outside of its viewport and into the current monitor if not lock_viewport then if bit32.band(flags, bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.Popup)) ~= 0 then -- We need to take account of the possibility that mouse may become invalid. -- Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds. local mouse_ref = bit32.band(flags, ImGuiWindowFlags.Tooltip) ~= 0 and g.IO.MousePos or g.BeginPopupStack.Data[g.BeginPopupStack.Size].OpenMousePos local use_mouse_ref = not g.NavCursorVisible or not g.NavHighlightItemUnderNav or not g.NavWindow local mouse_valid = ImGui.IsMousePosValid(mouse_ref) if (window.Appearing or bit32.band(flags, bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.ChildMenu)) ~= 0) and (not use_mouse_ref or mouse_valid) then local pos_to_use = (use_mouse_ref and mouse_valid) and mouse_ref or ImGui.NavCalcPreferredRefPos(window.Flags) window.ViewportAllowPlatformMonitorExtend = ImGui.FindPlatformMonitorForPos(pos_to_use) else window.ViewportAllowPlatformMonitorExtend = window.Viewport.PlatformMonitor end elseif window.Viewport and window ~= window.Viewport.Window and window.Viewport.Window and bit32.band(flags, ImGuiWindowFlags.ChildWindow) == 0 and window.DockNode == nil then -- When called from Begin() we don't have access to a proper version of the Hidden flag yet, so we replicate this code. local will_be_visible = (window.DockIsActive and not window.DockTabIsVisible) and false or true if bit32.band(window.Flags, ImGuiWindowFlags.DockNodeHost) ~= 0 and window.Viewport.LastFrameActive < g.FrameCount and will_be_visible then -- Steal/transfer ownership IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' steal Viewport %08X from Window '%s'", window.Name, window.Viewport.ID, window.Viewport.Window.Name) window.Viewport.Window = window window.Viewport.ID = window.ID window.Viewport.LastNameHash = 0 elseif not ImGui.UpdateTryMergeWindowIntoHostViewports(window) then -- Merge? -- New viewport window.Viewport = ImGui.AddUpdateViewport(window, window.ID, window.Pos, window.Size, ImGuiViewportFlags.NoFocusOnAppearing) end elseif window.ViewportAllowPlatformMonitorExtend < 0 and bit32.band(flags, ImGuiWindowFlags.ChildWindow) == 0 then -- Regular (non-child, non-popup) windows by default are also allowed to protrude -- Child windows are kept contained within their parent. window.ViewportAllowPlatformMonitorExtend = window.Viewport.PlatformMonitor end end -- Update flags window.ViewportOwned = (window == window.Viewport.Window) window.ViewportId = window.Viewport.ID -- If the OS window has a title bar, hide our imgui title bar -- if window.ViewportOwned and bit32.band(window.Viewport.Flags, ImGuiViewportFlags.NoDecoration) == 0 then -- window.Flags = bit32.bor(window.Flags, ImGuiWindowFlags.NoTitleBar) -- end end --- @param window ImGuiWindow --- @param parent_window_in_stack? ImGuiWindow function ImGui.WindowSyncOwnedViewport(window, parent_window_in_stack) local g = GImGui local viewport_rect_changed = false -- Synchronize window --> viewport in most situations -- Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM if window.Viewport.PlatformRequestMove then ImVec2_Copy(window.Pos, window.Viewport.Pos) -- ImGui.MarkIniSettingsDirty(window) elseif window.Viewport.Pos.x ~= window.Pos.x or window.Viewport.Pos.y ~= window.Pos.y then viewport_rect_changed = true ImVec2_Copy(window.Viewport.Pos, window.Pos) end if window.Viewport.PlatformRequestResize then ImVec2_Copy(window.Size, window.Viewport.Size) ImVec2_Copy(window.SizeFull, window.Viewport.Size) -- ImGui.MarkIniSettingsDirty(window) elseif window.Viewport.Size.x ~= window.Size.x or window.Viewport.Size.y ~= window.Size.y then viewport_rect_changed = true ImVec2_Copy(window.Viewport.Size, window.Size) end window.Viewport:UpdateWorkRect() -- The viewport may have changed monitor since the global update in UpdateViewportsNewFrame() -- Either a SetNextWindowPos() call in the current frame or a SetWindowPos() call in the previous frame may have this effect. if viewport_rect_changed then ImGui.UpdateViewportPlatformMonitor(window.Viewport) end -- Update common viewport flags local viewport_flags_to_clear = bit32.bor(ImGuiViewportFlags.TopMost, ImGuiViewportFlags.NoTaskBarIcon, ImGuiViewportFlags.NoDecoration, ImGuiViewportFlags.NoRendererClear) local viewport_flags = bit32.band(window.Viewport.Flags, bit32.bnot(viewport_flags_to_clear)) local window_flags = window.Flags local is_modal = bit32.band(window_flags, ImGuiWindowFlags.Modal) ~= 0 local is_short_lived_floating_window = bit32.band(window_flags, bit32.bor(ImGuiWindowFlags.ChildMenu, ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.Popup)) ~= 0 if bit32.band(window_flags, ImGuiWindowFlags.Tooltip) ~= 0 then viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.TopMost) end if (g.IO.ConfigViewportsNoTaskBarIcon or is_short_lived_floating_window) and not is_modal then viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.NoTaskBarIcon) end if g.IO.ConfigViewportsNoDecoration or is_short_lived_floating_window then viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.NoDecoration) end -- Not correct to set modal as topmost because: -- - Because other popups can be stacked above a modal (e.g. combo box in a modal) -- - ImGuiViewportFlags.TopMost is currently handled different in backends -- if bit32.band(window_flags, ImGuiWindowFlags.Modal) ~= 0 then -- viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.TopMost) -- end -- For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them -- won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration). -- Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app, -- but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere. if is_short_lived_floating_window and not is_modal then viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.NoFocusOnAppearing, ImGuiViewportFlags.NoFocusOnClick) end -- We can overwrite viewport flags using ImGuiWindowClass (advanced users) if window.WindowClass.ViewportFlagsOverrideSet ~= 0 then viewport_flags = bit32.bor(viewport_flags, window.WindowClass.ViewportFlagsOverrideSet) end if window.WindowClass.ViewportFlagsOverrideClear ~= 0 then viewport_flags = bit32.band(viewport_flags, bit32.bnot(window.WindowClass.ViewportFlagsOverrideClear)) end -- We can also tell the backend that clearing the platform window won't be necessary, -- as our window background is filling the viewport and we have disabled BgAlpha. -- FIXME: Work on support for per-viewport transparency (#2766) if bit32.band(window_flags, ImGuiWindowFlags.NoBackground) == 0 then viewport_flags = bit32.bor(viewport_flags, ImGuiViewportFlags.NoRendererClear) end window.Viewport.Flags = viewport_flags -- Update parent viewport ID -- (the !IsFallbackWindow test mimic the one done in WindowSelectViewport()) if window.WindowClass.ParentViewportId ~= 0xFFFFFFFF then local old_parent_viewport_id = window.Viewport.ParentViewportId window.Viewport.ParentViewportId = window.WindowClass.ParentViewportId if window.Viewport.ParentViewportId ~= old_parent_viewport_id then window.Viewport.ParentViewport = ImGui.FindViewportByID(window.Viewport.ParentViewportId) --[[@as ImGuiViewport]] end elseif bit32.band(window_flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.Tooltip)) ~= 0 and parent_window_in_stack and (not parent_window_in_stack.IsFallbackWindow or parent_window_in_stack.WasActive) then window.Viewport.ParentViewport = parent_window_in_stack.Viewport window.Viewport.ParentViewportId = parent_window_in_stack.Viewport.ID else if g.IO.ConfigViewportsNoDefaultParent then window.Viewport.ParentViewport = nil else window.Viewport.ParentViewport = ImGui.GetMainViewport() end window.Viewport.ParentViewportId = g.IO.ConfigViewportsNoDefaultParent and 0 or IMGUI_VIEWPORT_DEFAULT_ID end end function ImGui.UpdatePlatformWindows() local g = GImGui IM_ASSERT(g.FrameCountEnded == g.FrameCount, "Forgot to call Render() or EndFrame() before UpdatePlatformWindows()?") IM_ASSERT(g.FrameCountPlatformEnded < g.FrameCount) g.FrameCountPlatformEnded = g.FrameCount if bit32.band(g.ConfigFlagsCurrFrame, ImGuiConfigFlags.ViewportsEnable) == 0 then return end -- Create/resize/destroy platform windows to match each active viewport. -- Skip the main viewport (index 0), which is always fully handled by the application! for i = 2, g.Viewports.Size do repeat local viewport = g.Viewports.Data[i] -- Destroy platform window if the viewport hasn't been submitted or if it is hosting a hidden window -- (the implicit/fallback Debug##Default window will be registering its viewport then be disabled, causing a dummy DestroyPlatformWindow to be made each frame) local destroy_platform_window = false destroy_platform_window = destroy_platform_window or (viewport.LastFrameActive < g.FrameCount - 1) destroy_platform_window = destroy_platform_window or (viewport.Window and not ImGui.IsWindowActiveAndVisible(viewport.Window)) --[[@as bool]] if destroy_platform_window then ImGui.DestroyPlatformWindow(viewport) break end -- New windows that appears directly in a new viewport won't always have a size on their first frame if viewport.LastFrameActive < g.FrameCount or viewport.Size.x <= 0 or viewport.Size.y <= 0 then break end -- Create window local is_new_platform_window = not viewport.PlatformWindowCreated if is_new_platform_window then IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Create Platform Window %08X '%s'", viewport.ID, viewport.Window and viewport.Window.Name or "n/a") g.PlatformIO.Platform_CreateWindow(viewport) if g.PlatformIO.Renderer_CreateWindow ~= nil then g.PlatformIO.Renderer_CreateWindow(viewport) end g.PlatformWindowsCreatedCount = g.PlatformWindowsCreatedCount + 1 viewport.LastNameHash = 0 ImVec2_CopyV(viewport.LastPlatformPos, FLT_MAX, FLT_MAX) ImVec2_CopyV(viewport.LastPlatformSize, FLT_MAX, FLT_MAX) -- By clearing those we'll enforce a call to Platform_SetWindowPos/Size below, before Platform_ShowWindow (FIXME: Is that necessary?) ImVec2_Copy(viewport.LastRendererSize, viewport.Size) -- We don't need to call Renderer_SetWindowSize() as it is expected Renderer_CreateWindow() already did it. viewport.PlatformWindowCreated = true end -- Apply Position and Size (from ImGui to Platform/Renderer backends) if (viewport.LastPlatformPos.x ~= viewport.Pos.x or viewport.LastPlatformPos.y ~= viewport.Pos.y) and not viewport.PlatformRequestMove then g.PlatformIO.Platform_SetWindowPos(viewport, viewport.Pos) end if (viewport.LastPlatformSize.x ~= viewport.Size.x or viewport.LastPlatformSize.y ~= viewport.Size.y) and not viewport.PlatformRequestResize then g.PlatformIO.Platform_SetWindowSize(viewport, viewport.Size) end if (viewport.LastRendererSize.x ~= viewport.Size.x or viewport.LastRendererSize.y ~= viewport.Size.y) and g.PlatformIO.Renderer_SetWindowSize ~= nil then g.PlatformIO.Renderer_SetWindowSize(viewport, viewport.Size) end ImVec2_Copy(viewport.LastPlatformPos, viewport.Pos) ImVec2_Copy(viewport.LastPlatformSize, viewport.Size) ImVec2_Copy(viewport.LastRendererSize, viewport.Size) -- Update title bar (if it changed) local window_for_title = GetWindowForTitleDisplay(viewport.Window) if window_for_title ~= nil then local title = window_for_title.Name local title_begin = 1 local title_end = ImGui.FindRenderedTextEnd(title) local title_hash = ImHashStr(title, title_end - title_begin) if viewport.LastNameHash ~= title_hash then -- This still creates new strings g.PlatformIO.Platform_SetWindowTitle(viewport, string.sub(title, title_begin, title_end - 1)) viewport.LastNameHash = title_hash end end -- Update alpha (if it changed) if viewport.LastAlpha ~= viewport.Alpha and g.PlatformIO.Platform_SetWindowAlpha ~= nil then g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport.Alpha) end viewport.LastAlpha = viewport.Alpha -- Optional, general purpose call to allow the backend to perform general book-keeping even if things haven't changed. if g.PlatformIO.Platform_UpdateWindow ~= nil then g.PlatformIO.Platform_UpdateWindow(viewport) end if is_new_platform_window then -- On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late) if g.FrameCount < 3 then viewport.Flags = bit32.bor(viewport.Flags, ImGuiViewportFlags.NoFocusOnAppearing) end -- Show window g.PlatformIO.Platform_ShowWindow(viewport) end -- Clear request flags viewport:ClearRequestFlags() until true end end -- This is a default/basic function for performing the rendering/swap of multiple Platform Windows. -- Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves. -- The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself: -- -- local platform_io = ImGui.GetPlatformIO() -- for i = 2, platform_io.Viewports.Size do -- if bit32.band(platform_io.Viewports.Data[i].Flags, ImGuiViewportFlags.IsMinimized) == 0 then -- MyRenderFunction(platform_io.Viewports.Data[i], my_args) -- end -- end -- for i = 2, platform_io.Viewports.Size do -- if bit32.band(platform_io.Viewports.Data[i].Flags, ImGuiViewportFlags.IsMinimized) == 0 then -- MySwapBufferFunction(platform_io.Viewports.Data[i], my_args) -- end -- end -- function ImGui.RenderPlatformWindowsDefault(platform_render_arg, renderer_render_arg) -- Skip the main viewport (index 1 in Lua), which is always fully handled by the application! local platform_io = ImGui.GetPlatformIO() -- First pass: render all windows for i = 2, platform_io.Viewports.Size do local viewport = platform_io.Viewports.Data[i] if bit32.band(viewport.Flags, ImGuiViewportFlags.IsMinimized) == 0 then if platform_io.Platform_RenderWindow then platform_io.Platform_RenderWindow(viewport, platform_render_arg) end if platform_io.Renderer_RenderWindow then platform_io.Renderer_RenderWindow(viewport, renderer_render_arg) end end end -- Second pass: swap buffers for all windows for i = 2, platform_io.Viewports.Size do local viewport = platform_io.Viewports.Data[i] if bit32.band(viewport.Flags, ImGuiViewportFlags.IsMinimized) == 0 then if platform_io.Platform_SwapBuffers then platform_io.Platform_SwapBuffers(viewport, platform_render_arg) end if platform_io.Renderer_SwapBuffers then platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg) end end end end --- @param pos ImVec2 function ImGui.FindPlatformMonitorForPos(pos) local g = GImGui for monitor_n = 1, g.PlatformIO.Monitors.Size do local monitor = g.PlatformIO.Monitors.Data[monitor_n] if ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize):Contains(pos) then return monitor_n end end return -1 end --- @param rect ImRect --- @return int function ImGui.FindPlatformMonitorForRect(rect) local g = GImGui local monitor_count = g.PlatformIO.Monitors.Size if monitor_count <= 1 then return monitor_count end -- Use a minimum threshold of 1.0f so a zero-sized rect won't false positive, and will still find the correct monitor given its position. -- This is necessary for tooltips which always resize down to zero at first. local surface_threshold = math.max(rect:GetWidth() * rect:GetHeight() * 0.5, 1.0) local best_monitor_n = 1 -- Default to the first monitor as fallback local best_monitor_surface = 0.001 for monitor_n = 1, g.PlatformIO.Monitors.Size do if best_monitor_surface >= surface_threshold then break end local monitor = g.PlatformIO.Monitors.Data[monitor_n] local monitor_rect = ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize) if monitor_rect:Contains(rect) then return monitor_n end local overlapping_rect = ImRect(rect.Min.x, rect.Min.y, rect.Max.x, rect.Max.y) overlapping_rect:ClipWithFull(monitor_rect) local overlapping_surface = overlapping_rect:GetWidth() * overlapping_rect:GetHeight() if overlapping_surface > best_monitor_surface then best_monitor_surface = overlapping_surface best_monitor_n = monitor_n end end return best_monitor_n end --- @param viewport ImGuiViewportP function ImGui.UpdateViewportPlatformMonitor(viewport) viewport.PlatformMonitor = ImGui.FindPlatformMonitorForRect(viewport:GetMainRect()) end --- @param viewport_p ImGuiViewport --- @return ImGuiPlatformMonitor function ImGui.GetViewportPlatformMonitor(viewport_p) local g = GImGui local viewport = viewport_p --- @cast viewport ImGuiViewportP local monitor_idx = viewport.PlatformMonitor if monitor_idx >= 1 and monitor_idx <= g.PlatformIO.Monitors.Size then return g.PlatformIO.Monitors.Data[monitor_idx] end return g.FallbackMonitor end --- @param viewport ImGuiViewportP function ImGui.DestroyPlatformWindow(viewport) local g = GImGui if viewport.PlatformWindowCreated then IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Destroy Platform Window %08X '%s'", viewport.ID, viewport.Window and viewport.Window.Name or "n/a") if g.PlatformIO.Renderer_DestroyWindow then g.PlatformIO.Renderer_DestroyWindow(viewport) end if g.PlatformIO.Platform_DestroyWindow then g.PlatformIO.Platform_DestroyWindow(viewport) end IM_ASSERT(viewport.RendererUserData == nil and viewport.PlatformUserData == nil) -- Don't clear PlatformWindowCreated for the main viewport, as we initially set that up to true in Initialize() -- The righter way may be to leave it to the backend to set this flag all-together, and made the flag public. if viewport.ID ~= IMGUI_VIEWPORT_DEFAULT_ID then viewport.PlatformWindowCreated = false end else IM_ASSERT(viewport.RendererUserData == nil and viewport.PlatformUserData == nil and viewport.PlatformHandle == nil) end viewport.RendererUserData = nil viewport.PlatformUserData = nil viewport.PlatformHandle = nil viewport:ClearRequestFlags() end function ImGui.DestroyPlatformWindows() local g = GImGui for _, viewport in g.Viewports:iter() do ImGui.DestroyPlatformWindow(viewport) end end --------------------------------------------------------------------------------------- -- [SECTION] METRICS/DEBUGGER WINDOW --------------------------------------------------------------------------------------- --- @param draw_list ImDrawList --- @param viewport ImGuiViewport --- @param bb ImRect function ImGui.DebugRenderViewportThumbnail(draw_list, viewport, bb) local g = GImGui local window = g.CurrentWindow local scale = bb:GetSize() / viewport.Size local off = bb.Min - viewport.Pos * scale local alpha_mul = (bit32.band(viewport.Flags, ImGuiViewportFlags.IsMinimized) ~= 0) and 0.30 or 1.00 window.DrawList:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Border, alpha_mul * 0.40)) for _, thumb_window in g.Windows:iter() do repeat if not thumb_window.WasActive or bit32.band(thumb_window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then break end if thumb_window.Viewport ~= viewport then break end local thumb_r = thumb_window:Rect() local title_r = thumb_window:TitleBarRect() thumb_r = ImRect(ImTrunc(off + thumb_r.Min * scale), ImTrunc(off + thumb_r.Max * scale)) title_r = ImRect(ImTrunc(off + title_r.Min * scale), ImTrunc(off + ImVec2(title_r.Max.x, title_r.Min.y + title_r:GetHeight() * 3.0) * scale)) thumb_r:ClipWithFull(bb) title_r:ClipWithFull(bb) local window_is_focused = g.NavWindow and thumb_window.RootWindowForTitleBarHighlight == g.NavWindow.RootWindowForTitleBarHighlight window.DrawList:AddRectFilled(thumb_r.Min, thumb_r.Max, ImGui.GetColorU32(ImGuiCol.WindowBg, alpha_mul)) window.DrawList:AddRectFilled(title_r.Min, title_r.Max, ImGui.GetColorU32(window_is_focused and ImGuiCol.TitleBgActive or ImGuiCol.TitleBg, alpha_mul)) window.DrawList:AddRect(thumb_r.Min, thumb_r.Max, ImGui.GetColorU32(ImGuiCol.Border, alpha_mul)) window.DrawList:AddText(g.Font, g.FontSize * 1.0, title_r.Min, ImGui.GetColorU32(ImGuiCol.Text, alpha_mul), thumb_window.Name, 1, ImGui.FindRenderedTextEnd(thumb_window.Name)) until true end draw_list:AddRect(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Border, alpha_mul)) if viewport.ID == g.DebugMetricsConfig.HighlightViewportID then window.DrawList:AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)) end end function ImGui.RenderViewportsThumbnails() local g = GImGui local window = g.CurrentWindow local SCALE = 1.0 / 8.0 local bb_full = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) for _, monitor in g.PlatformIO.Monitors:iter() do bb_full:Add(ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize)) end local p = window.DC.CursorPos local off = p - bb_full.Min * SCALE for _, monitor in g.PlatformIO.Monitors:iter() do local monitor_draw_bb = ImRect(off + monitor.MainPos * SCALE, off + (monitor.MainPos + monitor.MainSize) * SCALE) window.DrawList:AddRect(monitor_draw_bb.Min, monitor_draw_bb.Max, (g.DebugMetricsConfig.HighlightMonitorIdx == g.PlatformIO.Monitors:index_from_ptr(monitor)) and IM_COL32(255, 255, 0, 255) or ImGui.GetColorU32(ImGuiCol.Border), 4.0) window.DrawList:AddRectFilled(monitor_draw_bb.Min, monitor_draw_bb.Max, ImGui.GetColorU32(ImGuiCol.Border, 0.10), 4.0) end for _, viewport in g.Viewports:iter() do local viewport_draw_bb = ImRect(off + viewport.Pos * SCALE, off + (viewport.Pos + viewport.Size) * SCALE) ImGui.DebugRenderViewportThumbnail(window.DrawList, viewport, viewport_draw_bb) end ImGui.Dummy(bb_full:GetSize() * SCALE) end --- @param idx ImGuiCol --- @return ImVec4 # live reference to the style color (like upstream's const&) function ImGui.GetStyleColorVec4(idx) return GImGui.Style.Colors[idx] end function ImGui.ErrorCheckUsingSetCursorPosToExtendParentBoundaries() local g = GImGui local window = g.CurrentWindow IM_ASSERT(window.DC.IsSetPos) window.DC.IsSetPos = false if window.DC.CursorPos.x <= window.DC.CursorMaxPos.x and window.DC.CursorPos.y <= window.DC.CursorMaxPos.y then return end if window.SkipItems then return end -- Upstream asserts (user error): "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. -- Please submit an item e.g. Dummy() afterwards". We keep the old, tolerant behavior instead of erroring. window.DC.CursorMaxPos = ImMax(window.DC.CursorMaxPos, window.DC.CursorPos) end --------------------------------------------------------------------------------------- -- [SECTION] POPUPS: modals, context popups, dimming --------------------------------------------------------------------------------------- local function GetWindowDisplayLayer(window) return (bit32.band(window.Flags, ImGuiWindowFlags.Tooltip) ~= 0) and 1 or 0 end --- @return int # 0-based display index (like upstream), -1 if not found function ImGui.FindWindowDisplayIndex(window) local g = GImGui local i = g.Windows:find_index(window) return i and (i - 1) or -1 end function ImGui.BringWindowToDisplayBack(window) local g = GImGui if g.Windows.Data[1] == window then return end local i = g.Windows:find_index(window) if i then table.remove(g.Windows.Data, i) table.insert(g.Windows.Data, 1, window) end end function ImGui.FindBottomMostVisibleWindowWithinBeginStack(parent_window) local g = GImGui local bottom_most_visible_window = parent_window for i = ImGui.FindWindowDisplayIndex(parent_window), 0, -1 do local window = g.Windows.Data[i + 1] if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0 then if not ImGui.IsWindowWithinBeginStackOf(window, parent_window) then break end if ImGui.IsWindowActiveAndVisible(window) and GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window) then bottom_most_visible_window = window end end end return bottom_most_visible_window end function ImGui.GetTopMostAndVisiblePopupModal() local g = GImGui for n = g.OpenPopupStack.Size, 1, -1 do local popup = g.OpenPopupStack.Data[n].Window if popup and bit32.band(popup.Flags, ImGuiWindowFlags.Modal) ~= 0 and ImGui.IsWindowActiveAndVisible(popup) then return popup end end return nil end function ImGui.RenderDimmedBackgroundBehindWindow(window, col) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end local viewport = window.Viewport local viewport_rect = viewport:GetMainRect() -- Draw behind window by moving the draw command at the FRONT of the draw list local draw_list = (window.RootWindowDockTree or window.RootWindow).DrawList draw_list:ChannelsMerge() if draw_list.CmdBuffer.Size == 0 then draw_list:AddDrawCmd() end draw_list:PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false) draw_list:AddRectFilled(viewport_rect.Min, viewport_rect.Max, col) local cmd = draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size] draw_list.CmdBuffer:pop_back() draw_list.CmdBuffer:push_front(cmd) draw_list:AddDrawCmd() draw_list:PopClipRect() end function ImGui.RenderDimmedBackgrounds() local g = GImGui local modal_window = ImGui.GetTopMostAndVisiblePopupModal() if g.DimBgRatio <= 0.0 and g.NavWindowingHighlightAlpha <= 0.0 then return end local dim_bg_for_modal = (modal_window ~= nil) local dim_bg_for_window_list = (g.NavWindowingTargetAnim ~= nil and g.NavWindowingTargetAnim.Active) if not dim_bg_for_modal and not dim_bg_for_window_list then return end if dim_bg_for_modal then local dim_behind_window = ImGui.FindBottomMostVisibleWindowWithinBeginStack(modal_window) ImGui.RenderDimmedBackgroundBehindWindow(dim_behind_window, ImGui.GetColorU32(modal_window.DC.ModalDimBgColor, g.DimBgRatio, true)) elseif dim_bg_for_window_list then ImGui.RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, ImGui.GetColorU32(ImGuiCol.NavWindowingDimBg, g.DimBgRatio)) if g.NavWindowingListWindow ~= nil and g.NavWindowingListWindow.Active and g.NavWindowingListWindow.Viewport and g.NavWindowingListWindow.Viewport ~= g.NavWindowingTargetAnim.Viewport then ImGui.RenderDimmedBackgroundBehindWindow(g.NavWindowingListWindow, ImGui.GetColorU32(ImGuiCol.NavWindowingDimBg, g.DimBgRatio)) end -- Draw border around Ctrl+Tab target window local window = g.NavWindowingTargetAnim local viewport = window.Viewport local distance = g.FontSize local bb = window:Rect() bb:Expand(distance) if bb:GetWidth() >= viewport.Size.x and bb:GetHeight() >= viewport.Size.y then bb:Expand(-distance - 1.0) end window.DrawList:ChannelsMerge() if window.DrawList.CmdBuffer.Size == 0 then window.DrawList:AddDrawCmd() end window.DrawList:PushClipRect(viewport.Pos, viewport.Pos + viewport.Size) window.DrawList:AddRect(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.NavWindowingHighlight, g.NavWindowingHighlightAlpha), window.WindowRounding, 0, 3.0) window.DrawList:PopClipRect() end end function ImGui.ClosePopupsExceptModals() local g = GImGui local popup_count_to_keep = g.OpenPopupStack.Size while popup_count_to_keep > 0 do local window = g.OpenPopupStack.Data[popup_count_to_keep].Window if not window or bit32.band(window.Flags, ImGuiWindowFlags.Modal) ~= 0 then break end popup_count_to_keep = popup_count_to_keep - 1 end if popup_count_to_keep < g.OpenPopupStack.Size then ImGui.ClosePopupToLevel(popup_count_to_keep, true) end end --- @return bool visible, bool? p_open # p_open is the updated value of the optional close button flag function ImGui.BeginPopupModal(name, p_open, flags) if flags == nil then flags = 0 end local g = GImGui local window = g.CurrentWindow local id = window:GetID(name) if not ImGui.IsPopupOpen(id, ImGuiPopupFlags.None) then g.NextWindowData:ClearFlags() if p_open then p_open = false end return false, p_open end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasPos) == 0 then local viewport = window.WasActive and window.Viewport or ImGui.GetMainViewport() ImGui.SetNextWindowPos(viewport:GetCenter(), ImGuiCond.FirstUseEver, ImVec2(0.5, 0.5)) end flags = bit32.bor(flags, ImGuiWindowFlags.Popup, ImGuiWindowFlags.Modal, ImGuiWindowFlags.NoCollapse, ImGuiWindowFlags.NoDocking) local is_open p_open, is_open = ImGui.Begin(name, p_open, flags) if not is_open or (p_open ~= nil and not p_open) then ImGui.EndPopup() if is_open then ImGui.ClosePopupToLevel(g.BeginPopupStack.Size, true) end return false, p_open end return is_open, p_open end function ImGui.IsPopupOpenRequestForWindow(popup_flags) local g = GImGui local mouse_button = ImGui.GetMouseButtonFromPopupFlags(popup_flags) if ImGui.IsMouseReleased(mouse_button, ImGuiKeyOwner_NoOwner) and ImGui.IsWindowHovered(ImGuiHoveredFlags.AllowWhenBlockedByPopup) then if bit32.band(popup_flags, ImGuiPopupFlags.NoOpenOverItems) == 0 or not ImGui.IsAnyItemHovered() then return true end end if g.NavOpenContextMenuWindowId and g.NavOpenContextMenuWindowId ~= 0 and g.CurrentWindow.ID ~= 0 then if ImGui.IsWindowChildOf(g.NavWindow, g.CurrentWindow, false, false) then return true end end return false end function ImGui.BeginPopupContextWindow(str_id, popup_flags) if popup_flags == nil then popup_flags = 0 end local g = GImGui local window = g.CurrentWindow if not str_id then str_id = "window_context" end local id = window:GetID(str_id) if ImGui.IsPopupOpenRequestForWindow(popup_flags) then ImGui.OpenPopupEx(id, popup_flags) end return ImGui.BeginPopupEx(id, bit32.bor(ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings)) end function ImGui.BeginPopupContextVoid(str_id, popup_flags) if popup_flags == nil then popup_flags = 0 end local g = GImGui local window = g.CurrentWindow if not str_id then str_id = "void_context" end local id = window:GetID(str_id) local mouse_button = ImGui.GetMouseButtonFromPopupFlags(popup_flags) if ImGui.IsMouseReleased(mouse_button, id) and not ImGui.IsWindowHovered(ImGuiHoveredFlags.AnyWindow) then if ImGui.GetTopMostPopupModal() == nil then ImGui.OpenPopupEx(id, popup_flags) end end return ImGui.BeginPopupEx(id, bit32.bor(ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings)) end function ImGui.BeginTooltipHidden() local g = GImGui local _, ret = ImGui.Begin("##Tooltip_Hidden", nil, bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.NoInputs, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.AlwaysAutoResize)) ImGui.SetWindowHiddenAndSkipItemsForCurrentFrame(g.CurrentWindow) return ret end -- [SECTION] MISC GETTERS/SETTERS, FOCUS function ImGui.NavMoveRequestResolveWithLastItem(result) local g = GImGui g.NavMoveScoringItems = false -- Ensure request doesn't need more processing ImGui.NavApplyItemToResult(result) ImGui.NavUpdateAnyRequestFlag() end function ImGui.SetKeyboardFocusHere(offset) if offset == nil then offset = 0 end local g = GImGui local window = g.CurrentWindow IM_ASSERT(offset >= -1) -- -1 is allowed but not below if g.DragDropActive or g.MovingWindow ~= nil then return end ImGui.SetNavWindow(window) local move_flags = bit32.bor(ImGuiNavMoveFlags.IsTabbing, ImGuiNavMoveFlags.Activate, ImGuiNavMoveFlags.FocusApi, ImGuiNavMoveFlags.NoSetNavCursorVisible) local scroll_flags = window.Appearing and bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.AlwaysCenterY) or bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleEdgeY) ImGui.NavMoveRequestSubmit(ImGuiDir.None, (offset < 0) and ImGuiDir.Up or ImGuiDir.Down, move_flags, scroll_flags) if offset == -1 then ImGui.NavMoveRequestResolveWithLastItem(g.NavMoveResultLocal) else g.NavTabbingDir = 1 g.NavTabbingCounter = offset + 1 end end function ImGui.FocusItem() local g = GImGui local window = g.CurrentWindow if g.DragDropActive or g.MovingWindow ~= nil then return end local move_flags = bit32.bor(ImGuiNavMoveFlags.IsTabbing, ImGuiNavMoveFlags.FocusApi, ImGuiNavMoveFlags.NoSetNavCursorVisible, ImGuiNavMoveFlags.NoSelect) local scroll_flags = window.Appearing and bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.AlwaysCenterY) or bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleEdgeY) ImGui.SetNavWindow(window) ImGui.NavMoveRequestSubmit(ImGuiDir.None, ImGuiDir.Up, move_flags, scroll_flags) ImGui.NavMoveRequestResolveWithLastItem(g.NavMoveResultLocal) end function ImGui.ActivateItemByID(id) local g = GImGui g.NavNextActivateId = id g.NavNextActivateFlags = ImGuiActivateFlags.None end function ImGui.SetNavCursorVisible(visible) local g = GImGui if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 then visible = false elseif g.IO.ConfigNavCursorVisibleAlways then visible = true end g.NavCursorVisible = visible end function ImGui.GetFrameCount() return GImGui.FrameCount end function ImGui.GetStateStorage() return GImGui.CurrentWindow.DC.StateStorage end function ImGui.SetStateStorage(tree) local window = GImGui.CurrentWindow window.DC.StateStorage = tree or window.StateStorage end function ImGui.SetNextFrameWantCaptureKeyboard(want) GImGui.WantCaptureKeyboardNextFrame = want and 1 or 0 end function ImGui.SetNextFrameWantCaptureMouse(want) GImGui.WantCaptureMouseNextFrame = want and 1 or 0 end function ImGui.GetVersion() return IMGUI_VERSION end local StyleColorNames = nil function ImGui.GetStyleColorName(idx) if StyleColorNames == nil then StyleColorNames = {} for k, v in pairs(ImGuiCol) do if k ~= "COUNT" then StyleColorNames[v] = k end end end return StyleColorNames[idx] or "Unknown" end -- [SECTION] NAV END FRAME local NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15 local function GetFallbackWindowNameForWindowingList(window) if bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 then return "(Popup)" end if bit32.band(window.Flags, ImGuiWindowFlags.MenuBar) ~= 0 and window.Name == "##MainMenuBar" then return "(Main menu bar)" end if window.DockNodeAsHost then return "(Dock node)" end return "(Untitled)" end function ImGui.NavUpdateWindowingOverlay() local g = GImGui IM_ASSERT(g.NavWindowingTarget ~= nil) if g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY then return end local viewport = ImGui.GetMainViewport() ImGui.SetNextWindowSizeConstraints(ImVec2(viewport.Size.x * 0.20, viewport.Size.y * 0.20), ImVec2(FLT_MAX, FLT_MAX)) ImGui.SetNextWindowPos(viewport:GetCenter(), ImGuiCond.Always, ImVec2(0.5, 0.5)) ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, g.Style.WindowPadding * 2.0) ImGui.Begin("##NavWindowingOverlay", nil, bit32.bor(ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoFocusOnAppearing, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoInputs, ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoSavedSettings)) g.NavWindowingListWindow = g.CurrentWindow for n = g.WindowsFocusOrder.Size, 1, -1 do local window = g.WindowsFocusOrder.Data[n] IM_ASSERT(window ~= nil) if ImGui.IsWindowNavFocusable(window) then local label = window.Name if ImGui.FindRenderedTextEnd(label) == 1 then label = GetFallbackWindowNameForWindowingList(window) end ImGui.Selectable(label, g.NavWindowingTarget == window) end end ImGui.End() ImGui.PopStyleVar() end local function NavUpdateCreateWrappingRequest() local g = GImGui local window = g.NavWindow local do_forward = false local src = window.NavRectRel[g.NavLayer] local bb_rel = ImRect(src.Min.x, src.Min.y, src.Max.x, src.Max.y) local clip_dir = g.NavMoveDir local move_flags = g.NavMoveFlags local wrap_size = (g.NavLayer == ImGuiNavLayer.Menu) and window.Size or (window.ContentSize + window.WindowPadding) if g.NavMoveDir == ImGuiDir.Left and bit32.band(move_flags, bit32.bor(ImGuiNavMoveFlags.WrapX, ImGuiNavMoveFlags.LoopX)) ~= 0 then bb_rel.Min.x = wrap_size.x; bb_rel.Max.x = wrap_size.x if bit32.band(move_flags, ImGuiNavMoveFlags.WrapX) ~= 0 then bb_rel:TranslateY(-bb_rel:GetHeight()) clip_dir = ImGuiDir.Up end do_forward = true end if g.NavMoveDir == ImGuiDir.Right and bit32.band(move_flags, bit32.bor(ImGuiNavMoveFlags.WrapX, ImGuiNavMoveFlags.LoopX)) ~= 0 then bb_rel.Min.x = -window.WindowPadding.x; bb_rel.Max.x = -window.WindowPadding.x if bit32.band(move_flags, ImGuiNavMoveFlags.WrapX) ~= 0 then bb_rel:TranslateY(bb_rel:GetHeight()) clip_dir = ImGuiDir.Down end do_forward = true end if g.NavMoveDir == ImGuiDir.Up and bit32.band(move_flags, bit32.bor(ImGuiNavMoveFlags.WrapY, ImGuiNavMoveFlags.LoopY)) ~= 0 then bb_rel.Min.y = wrap_size.y; bb_rel.Max.y = wrap_size.y if bit32.band(move_flags, ImGuiNavMoveFlags.WrapY) ~= 0 then bb_rel:TranslateX(-bb_rel:GetWidth()) clip_dir = ImGuiDir.Left end do_forward = true end if g.NavMoveDir == ImGuiDir.Down and bit32.band(move_flags, bit32.bor(ImGuiNavMoveFlags.WrapY, ImGuiNavMoveFlags.LoopY)) ~= 0 then bb_rel.Min.y = -window.WindowPadding.y; bb_rel.Max.y = -window.WindowPadding.y if bit32.band(move_flags, ImGuiNavMoveFlags.WrapY) ~= 0 then bb_rel:TranslateX(bb_rel:GetWidth()) clip_dir = ImGuiDir.Right end do_forward = true end if not do_forward then return end window.NavRectRel[g.NavLayer] = bb_rel ImGui.NavClearPreferredPosForAxis(ImGuiAxis.X) ImGui.NavClearPreferredPosForAxis(ImGuiAxis.Y) ImGui.NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags) end function ImGui.NavEndFrame() local g = GImGui if g.NavWindowingTarget ~= nil then ImGui.NavUpdateWindowingOverlay() end if g.NavWindow and ImGui.NavMoveRequestButNoResultYet() and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.WrapMask_) ~= 0 and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.Forwarded) == 0 then NavUpdateCreateWrappingRequest() end end -- [SECTION] ImGuiTextFilter --- @class ImGuiTextFilter MT.ImGuiTextFilter = {} MT.ImGuiTextFilter.__index = MT.ImGuiTextFilter --- @param default_filter? string function ImGuiTextFilter(default_filter) local this = setmetatable({ InputBuf = {}, _CountExclude = 0, _Items = ImVector() }, MT.ImGuiTextFilter) for i = 1, 256 do this.InputBuf[i] = 0 end if default_filter and default_filter ~= "" then for i = 1, ImMin(#default_filter, 255) do this.InputBuf[i] = string.byte(default_filter, i) end this:Build() end return this end function MT.ImGuiTextFilter:Draw(label, width) if label == nil then label = "Filter (inc,-exc)" end if width ~= nil and width ~= 0.0 then ImGui.SetNextItemWidth(width) end return self:DrawWithHint(label, "incl -excl") end function MT.ImGuiTextFilter:DrawWithHint(label, hint) if label == nil then label = "Filter" end if hint == nil then hint = "incl -excl" end local value_changed = ImGui.InputTextWithHint(label, hint, self.InputBuf, 256) if value_changed then self:Build() end return value_changed end function MT.ImGuiTextFilter:Clear() self.InputBuf[1] = 0; self:Build() end function MT.ImGuiTextFilter:IsActive() return self._Items.Size ~= 0 end -- Items are { Text = string (lowercased), CountInclude = int } function MT.ImGuiTextFilter:Build() local items = self._Items items:resize(0) self._CountExclude = 0 local n = 0 while self.InputBuf[n + 1] ~= nil and self.InputBuf[n + 1] ~= 0 do n = n + 1 end local buf = ImGui._ByteArrayToString(self.InputBuf, 1, n + 1) local buf_e = n + 1 -- exclusive, 1-based local word_b = 1 local seq_start_idx = -1 -- 1-based index into items, -1 = none while word_b < buf_e do while word_b < buf_e and ImCharIsBlankA(string.byte(buf, word_b)) do word_b = word_b + 1 end local is_excl = word_b < buf_e and string.byte(buf, word_b) == 45 -- '-' if is_excl then word_b = word_b + 1 end local is_quote = word_b < buf_e and string.byte(buf, word_b) == 34 -- '"' local word_e if is_quote then word_b = word_b + 1 word_e = string.find(buf, '"', word_b, true) or buf_e if word_e > buf_e then word_e = buf_e end else word_e = word_b while word_e < buf_e do local c = string.byte(buf, word_e) if c == 32 or c == 44 then break end word_e = word_e + 1 end end if word_e - word_b > 0 then local item = { Text = string.lower(string.sub(buf, word_b, word_e - 1)), CountInclude = 0 } if is_excl then items:insert(self._CountExclude + 1, item) self._CountExclude = self._CountExclude + 1 if seq_start_idx ~= -1 then seq_start_idx = seq_start_idx + 1 end else if seq_start_idx == -1 then seq_start_idx = items.Size + 1 end items:push_back(item) items.Data[seq_start_idx].CountInclude = items.Data[seq_start_idx].CountInclude + 1 end end if word_e < buf_e and string.byte(buf, word_e) == 44 then -- ',' seq_start_idx = -1 end word_b = word_e + 1 end end --- @param text string? --- @param text_end? int # exclusive, 1-based function MT.ImGuiTextFilter:PassFilter(text, text_end) local items = self._Items if items.Size == 0 then return true end if text == nil then text = "" end if text_end ~= nil then text = string.sub(text, 1, text_end - 1) end text = string.lower(text) local seq = 1 local seq_excl_end = self._CountExclude + 1 while seq < seq_excl_end do if string.find(text, items.Data[seq].Text, 1, true) then return false end seq = seq + 1 end local seq_end = items.Size + 1 if seq == seq_end then return true end while seq < seq_end do local seq_incl_end = seq + items.Data[seq].CountInclude while seq < seq_incl_end do if not string.find(text, items.Data[seq].Text, 1, true) then break end seq = seq + 1 end if seq == seq_incl_end then return true end seq = seq_incl_end end return false end -- [SECTION] ImGuiListClipper ImGuiListClipperFlags = ImGuiListClipperFlags or { None = 0, NoSetTableRowCounters = bit32.lshift(1, 0) } local function GetSkipItemForListClipping() local g = GImGui if g.CurrentTable then return g.CurrentTable.HostSkipItems end return g.CurrentWindow.SkipItems end local function ClipperRangeFromIndices(min, max) return { Min = min, Max = max, PosToIndexConvert = false, PosToIndexOffsetMin = 0, PosToIndexOffsetMax = 0 } end local function ClipperRangeFromPositions(y1, y2, off_min, off_max) return { Min = y1, Max = y2, PosToIndexConvert = true, PosToIndexOffsetMin = off_min, PosToIndexOffsetMax = off_max } end -- `offset` is a 0-based count of leading ranges to leave alone local function ImGuiListClipper_SortAndFuseRanges(ranges, offset) if offset == nil then offset = 0 end if ranges.Size - offset <= 1 then return end local d = ranges.Data for sort_end = ranges.Size - offset - 1, 1, -1 do for i = offset + 1, sort_end + offset do if d[i].Min > d[i + 1].Min then d[i], d[i + 1] = d[i + 1], d[i] end end end local i = 2 + offset while i <= ranges.Size do IM_ASSERT(not d[i].PosToIndexConvert and not d[i - 1].PosToIndexConvert) if d[i - 1].Max < d[i].Min then i = i + 1 else d[i - 1].Min = ImMin(d[i - 1].Min, d[i].Min) d[i - 1].Max = ImMax(d[i - 1].Max, d[i].Max) ranges:erase(i) end end end local function ImGuiListClipper_SeekCursorAndSetupPrevLine(clipper, pos_y, line_height) local g = GImGui local window = g.CurrentWindow local off_y = pos_y - window.DC.CursorPos.y window.DC.CursorPos.y = pos_y window.DC.CursorMaxPos.y = ImMax(window.DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y) window.DC.CursorPosPrevLine.y = window.DC.CursorPos.y - line_height window.DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y) local columns = window.DC.CurrentColumns if columns then columns.LineMinY = window.DC.CursorPos.y end local tbl = g.CurrentTable if tbl then if tbl.IsInsideRow then ImGui.TableEndRow(tbl) end local row_increase = math.floor((off_y / line_height) + 0.5) if row_increase > 0 and bit32.band(clipper.Flags, ImGuiListClipperFlags.NoSetTableRowCounters) == 0 then tbl.CurrentRow = tbl.CurrentRow + row_increase tbl.RowBgColorCounter = tbl.RowBgColorCounter + row_increase end tbl.RowPosY2 = window.DC.CursorPos.y end end --- @class ImGuiListClipper MT.ImGuiListClipper = {} MT.ImGuiListClipper.__index = MT.ImGuiListClipper function ImGuiListClipper() return setmetatable({ DisplayStart = 0, DisplayEnd = 0, UserIndex = 0, ItemsCount = 0, ItemsHeight = 0.0, Flags = 0, StartPosY = 0.0, StartSeekOffsetY = 0.0, Ctx = nil, TempData = nil }, MT.ImGuiListClipper) end --- @param items_count int --- @param items_height? float function MT.ImGuiListClipper:Begin(items_count, items_height) if items_height == nil then items_height = -1.0 end self.Ctx = ImGui.GetCurrentContext() local g = self.Ctx local window = g.CurrentWindow local tbl = g.CurrentTable if tbl and tbl.IsInsideRow then ImGui.TableEndRow(tbl) end self.StartPosY = window.DC.CursorPos.y self.ItemsHeight = items_height self.ItemsCount = items_count self.DisplayStart = -1 self.DisplayEnd = 0 g.ClipperTempDataStacked = g.ClipperTempDataStacked + 1 while g.ClipperTempDataStacked > g.ClipperTempData.Size do g.ClipperTempData:push_back({ ListClipper = nil, LossynessOffset = 0.0, StepNo = 0, ItemsFrozen = 0, Ranges = ImVector() }) end local data = g.ClipperTempData.Data[g.ClipperTempDataStacked] data.ListClipper = self; data.StepNo = 0; data.ItemsFrozen = 0; data.Ranges:resize(0) data.LossynessOffset = window.DC.CursorStartPosLossyness.y self.TempData = data self.StartSeekOffsetY = data.LossynessOffset end function MT.ImGuiListClipper:End() local data = self.TempData if data then local g = self.Ctx if self.ItemsCount >= 0 and self.ItemsCount < INT_MAX and self.DisplayStart >= 0 then self:SeekCursorForItem(self.ItemsCount) end IM_ASSERT(data.ListClipper == self) data.StepNo = data.Ranges.Size g.ClipperTempDataStacked = g.ClipperTempDataStacked - 1 if g.ClipperTempDataStacked > 0 then data = g.ClipperTempData.Data[g.ClipperTempDataStacked] data.ListClipper.TempData = data end self.TempData = nil end self.DisplayStart = self.ItemsCount self.DisplayEnd = self.ItemsCount self.ItemsCount = -1 end function MT.ImGuiListClipper:IncludeItemByIndex(item_index) self:IncludeItemsByIndex(item_index, item_index + 1) end function MT.ImGuiListClipper:IncludeItemsByIndex(item_begin, item_end) local data = self.TempData IM_ASSERT(self.DisplayStart < 0) IM_ASSERT(item_begin <= item_end) if item_begin < item_end then data.Ranges:push_back(ClipperRangeFromIndices(item_begin, item_end)) end end function MT.ImGuiListClipper:SeekCursorForItem(item_n) local pos_y = self.StartPosY + self.StartSeekOffsetY + item_n * self.ItemsHeight ImGuiListClipper_SeekCursorAndSetupPrevLine(self, pos_y, self.ItemsHeight) end local function ImGuiListClipper_StepInternal(clipper) local g = clipper.Ctx local window = g.CurrentWindow local data = clipper.TempData IM_ASSERT(data ~= nil, "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?") local tbl = g.CurrentTable if tbl and tbl.IsInsideRow then ImGui.TableEndRow(tbl) end if clipper.ItemsCount == 0 or GetSkipItemForListClipping() then return false end if data.StepNo == 0 and tbl ~= nil and not tbl.IsUnfrozenRows then clipper.DisplayStart = data.ItemsFrozen clipper.DisplayEnd = ImMin(data.ItemsFrozen + 1, clipper.ItemsCount) if clipper.DisplayStart < clipper.DisplayEnd then data.ItemsFrozen = data.ItemsFrozen + 1 end return true end local calc_clipping = false if data.StepNo == 0 then clipper.StartPosY = window.DC.CursorPos.y if clipper.ItemsHeight <= 0.0 then data.Ranges:push_front(ClipperRangeFromIndices(data.ItemsFrozen, data.ItemsFrozen + 1)) clipper.DisplayStart = ImMax(data.Ranges.Data[1].Min, data.ItemsFrozen) clipper.DisplayEnd = ImMin(data.Ranges.Data[1].Max, clipper.ItemsCount) data.StepNo = 1 return true end calc_clipping = true end if clipper.ItemsHeight <= 0.0 then IM_ASSERT(data.StepNo == 1) -- (no float precision mitigation needed: Luau numbers are doubles) clipper.ItemsHeight = (window.DC.CursorPos.y - clipper.StartPosY) / (clipper.DisplayEnd - clipper.DisplayStart) if clipper.ItemsHeight == 0.0 and clipper.ItemsCount == INT_MAX then return false end if clipper.ItemsHeight <= 0.0 then IM_ASSERT_USER_ERROR(clipper.ItemsHeight > 0.0, "ImGuiListClipper: Failed to calculate item height! First item hasn't been submitted by user code, or has not moved the cursor vertically!") return false end calc_clipping = true end local already_submitted = clipper.DisplayEnd if calc_clipping then clipper.StartSeekOffsetY = data.LossynessOffset - data.ItemsFrozen * clipper.ItemsHeight if g.LogEnabled then data.Ranges:push_back(ClipperRangeFromIndices(0, clipper.ItemsCount)) else local is_nav_request = (g.NavMoveScoringItems and g.NavWindow and g.NavWindow.RootWindowForNav == window.RootWindowForNav) and true or false local nav_off_min = (is_nav_request and g.NavMoveClipDir == ImGuiDir.Up) and -1 or 0 local nav_off_max = (is_nav_request and g.NavMoveClipDir == ImGuiDir.Down) and 1 or 0 if is_nav_request then data.Ranges:push_back(ClipperRangeFromPositions(g.NavScoringRect.Min.y, g.NavScoringRect.Max.y, nav_off_min, nav_off_max)) if not g.NavScoringNoClipRect:IsInverted() then data.Ranges:push_back(ClipperRangeFromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, nav_off_min, nav_off_max)) end end if is_nav_request and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.IsTabbing) ~= 0 and g.NavTabbingDir == -1 then data.Ranges:push_back(ClipperRangeFromIndices(clipper.ItemsCount - 1, clipper.ItemsCount)) end local nav_rect_abs = ImGui.WindowRectRelToAbs(window, window.NavRectRel[0]) if g.NavId ~= 0 and window.NavLastIds[0] == g.NavId then data.Ranges:push_back(ClipperRangeFromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0)) end local min_y = window.ClipRect.Min.y local max_y = window.ClipRect.Max.y local bs = g.BoxSelectState if bs and bs.IsActive and bs.Window == window then local pad_y = g.Style.ItemSpacing.y min_y = min_y - pad_y max_y = max_y + pad_y if bs.UnclipMode then data.Ranges:push_back(ClipperRangeFromPositions(bs.UnclipRect.Min.y - pad_y, bs.UnclipRect.Max.y + pad_y, 0, 0)) end end data.Ranges:push_back(ClipperRangeFromPositions(min_y, max_y, nav_off_min, nav_off_max)) end for _, range in data.Ranges:iter() do if range.PosToIndexConvert then local m1 = ImTrunc((range.Min - window.DC.CursorPos.y - data.LossynessOffset) / clipper.ItemsHeight) local m2 = ImTrunc(((range.Max - window.DC.CursorPos.y - data.LossynessOffset) / clipper.ItemsHeight) + 0.999999) range.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper.ItemsCount - 1) range.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper.ItemsCount) range.PosToIndexConvert = false end end ImGuiListClipper_SortAndFuseRanges(data.Ranges, data.StepNo) end while data.StepNo < data.Ranges.Size do local r = data.Ranges.Data[data.StepNo + 1] clipper.DisplayStart = ImMax(r.Min, already_submitted) clipper.DisplayEnd = ImMin(r.Max, clipper.ItemsCount) data.StepNo = data.StepNo + 1 if clipper.DisplayStart < clipper.DisplayEnd then if clipper.DisplayStart > already_submitted then clipper:SeekCursorForItem(clipper.DisplayStart) end return true end end if clipper.ItemsCount < INT_MAX then clipper:SeekCursorForItem(clipper.ItemsCount) end return false end function MT.ImGuiListClipper:Step() local ret = ImGuiListClipper_StepInternal(self) if ret and (self.DisplayStart >= self.DisplayEnd) then ret = false end if not ret then self:End() end return ret end function ImGui.CalcClipRectVisibleItemsY(clip_rect, pos, items_height) local out_visible_start = ImMax(ImTrunc((clip_rect.Min.y - pos.y) / items_height), 0) local out_visible_end = ImMax(ImTrunc(ImCeil((clip_rect.Max.y - pos.y) / items_height)), out_visible_start) return out_visible_start, out_visible_end end -- [SECTION] ERROR CHECKING, STATE RECOVERY function ImGuiErrorRecoveryState() return { SizeOfWindowStack = 0, SizeOfIDStack = 0, SizeOfTreeStack = 0, SizeOfColorStack = 0, SizeOfStyleVarStack = 0, SizeOfFontStack = 0, SizeOfFocusScopeStack = 0, SizeOfGroupStack = 0, SizeOfItemFlagsStack = 0, SizeOfBeginPopupStack = 0, SizeOfDisabledStack = 0 } end function ImGui.ErrorRecoveryStoreState(state_out) local g = GImGui state_out.SizeOfWindowStack = g.CurrentWindowStack.Size state_out.SizeOfIDStack = g.CurrentWindow.IDStack.Size state_out.SizeOfTreeStack = g.CurrentWindow.DC.TreeDepth -- NOT g.TreeNodeStack.Size which is a partial stack! state_out.SizeOfColorStack = g.ColorStack.Size state_out.SizeOfStyleVarStack = g.StyleVarStack.Size state_out.SizeOfFontStack = g.FontStack.Size state_out.SizeOfFocusScopeStack = g.FocusScopeStack.Size state_out.SizeOfGroupStack = g.GroupStack.Size state_out.SizeOfItemFlagsStack = g.ItemFlagsStack.Size state_out.SizeOfBeginPopupStack = g.BeginPopupStack.Size state_out.SizeOfDisabledStack = g.DisabledStackSize end function ImGui.ErrorRecoveryTryToRecoverState(state_in) local g = GImGui while g.CurrentWindowStack.Size > state_in.SizeOfWindowStack do local window = g.CurrentWindow if bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0 then if g.CurrentTable ~= nil and g.CurrentTable.InnerWindow == g.CurrentWindow then IM_ASSERT_USER_ERROR(false, "Missing EndTable()") ImGui.EndTable() else IM_ASSERT_USER_ERROR(false, "Missing EndChild()") ImGui.EndChild() end else IM_ASSERT_USER_ERROR(false, "Missing End()") ImGui.End() end end if g.CurrentWindowStack.Size == state_in.SizeOfWindowStack then ImGui.ErrorRecoveryTryToRecoverWindowState(state_in) end end function ImGui.ErrorRecoveryTryToRecoverWindowState(state_in) local g = GImGui while g.CurrentTable ~= nil and g.CurrentTable.InnerWindow == g.CurrentWindow do IM_ASSERT_USER_ERROR(false, "Missing EndTable()") ImGui.EndTable() end local window = g.CurrentWindow -- FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. while g.CurrentTabBar ~= nil and g.CurrentTabBar.Window == window do IM_ASSERT_USER_ERROR(false, "Missing EndTabBar()") ImGui.EndTabBar() end while g.CurrentMultiSelect ~= nil and g.CurrentMultiSelect.Storage.Window == window and ImGui.EndMultiSelect do IM_ASSERT_USER_ERROR(false, "Missing EndMultiSelect()") ImGui.EndMultiSelect() end if window.DC.MenuBarAppending then IM_ASSERT_USER_ERROR(false, "Missing EndMenuBar()") ImGui.EndMenuBar() end while window.DC.TreeDepth > state_in.SizeOfTreeStack do IM_ASSERT_USER_ERROR(false, "Missing TreePop()") ImGui.TreePop() end while g.GroupStack.Size > state_in.SizeOfGroupStack do IM_ASSERT_USER_ERROR(false, "Missing EndGroup()") ImGui.EndGroup() end IM_ASSERT(g.GroupStack.Size == state_in.SizeOfGroupStack) while window.IDStack.Size > state_in.SizeOfIDStack do IM_ASSERT_USER_ERROR(false, "Missing PopID()") ImGui.PopID() end while g.DisabledStackSize > state_in.SizeOfDisabledStack do IM_ASSERT_USER_ERROR(false, "Missing EndDisabled()") if bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0 then ImGui.EndDisabled() else ImGui.EndDisabledOverrideReenable() g.CurrentWindowStack:back().DisabledOverrideReenable = false end end IM_ASSERT(g.DisabledStackSize == state_in.SizeOfDisabledStack) while g.ColorStack.Size > state_in.SizeOfColorStack do IM_ASSERT_USER_ERROR(false, "Missing PopStyleColor()") ImGui.PopStyleColor() end while g.ItemFlagsStack.Size > state_in.SizeOfItemFlagsStack do IM_ASSERT_USER_ERROR(false, "Missing PopItemFlag()") ImGui.PopItemFlag() end while g.StyleVarStack.Size > state_in.SizeOfStyleVarStack do IM_ASSERT_USER_ERROR(false, "Missing PopStyleVar()") ImGui.PopStyleVar() end while g.FontStack.Size > state_in.SizeOfFontStack do IM_ASSERT_USER_ERROR(false, "Missing PopFont()") ImGui.PopFont() end while g.FocusScopeStack.Size > state_in.SizeOfFocusScopeStack do IM_ASSERT_USER_ERROR(false, "Missing PopFocusScope()") ImGui.PopFocusScope() end end -- Lines are stored in g.DebugLogBuf (one chunk per call) function ImGui.DebugLog(fmt, ...) local g = GImGui g.DebugLogBuf = g.DebugLogBuf or ImGuiTextBuffer() local str = string.format("[%05d] ", g.FrameCount) .. ((select("#", ...) > 0) and string.format(fmt, ...) or fmt) g.DebugLogBuf:append(str) -- Line index (upstream: g.DebugLogIndex). Lines are complete strings without '\n'. local lines = g.DebugLogLines if lines == nil then lines = { "" }; g.DebugLogLines = lines end for part, nl in string.gmatch(str, "([^\n]*)(\n?)") do lines[#lines] = lines[#lines] .. part if nl ~= "" then lines[#lines + 1] = "" end if part == "" and nl == "" then break end end if bit32.band(g.DebugLogFlags, ImGuiDebugLogFlags.OutputToTTY) ~= 0 then print((string.gsub(str, "\n$", ""))) end end --- @return bool should_assert function ImGui.ErrorLog(msg) local g = GImGui if g == nil then return true end local window = g.CurrentWindow if g.IO.ConfigErrorRecoveryEnableDebugLog then if g.ErrorFirst then ImGui.DebugLog(string.format("[imgui-error] (current settings: Assert=%d, Log=%d, Tooltip=%d)\n", g.IO.ConfigErrorRecoveryEnableAssert and 1 or 0, g.IO.ConfigErrorRecoveryEnableDebugLog and 1 or 0, g.IO.ConfigErrorRecoveryEnableTooltip and 1 or 0)) end ImGui.DebugLog(string.format("[imgui-error] In window '%s': %s\n", window and window.Name or "NULL", tostring(msg))) end g.ErrorFirst = false if g.IO.ConfigErrorRecoveryEnableTooltip then if g.WithinFrameScope and ImGui.BeginErrorTooltip() then if g.ErrorCountCurrentFrame < 20 then ImGui.Text("In window '%s': %s", window and window.Name or "NULL", tostring(msg)) if window and (not window.IsFallbackWindow or window.WasActive) then ImGui.GetForegroundDrawList(window.Viewport):AddRect(window.Pos, window.Pos + window.Size, IM_COL32(255, 0, 0, 255)) end end if g.ErrorCountCurrentFrame == 20 then ImGui.Text("(and more errors)") end ImGui.EndErrorTooltip() end g.ErrorCountCurrentFrame = g.ErrorCountCurrentFrame + 1 end if g.ErrorCallback ~= nil then g.ErrorCallback(g, g.ErrorCallbackUserData, msg) end return g.IO.ConfigErrorRecoveryEnableAssert end function ImGui.ErrorCheckEndFrameFinalizeErrorTooltip() local g = GImGui if g.DebugDrawIdConflictsId ~= 0 and g.IO.KeyCtrl == false then g.DebugDrawIdConflictsCount = g.HoveredIdPreviousFrameItemCount end if g.DebugDrawIdConflictsId ~= 0 and not g.DebugItemPickerActive and ImGui.BeginErrorTooltip() then ImGui.Text("Programmer error: %d visible items with conflicting ID!", g.DebugDrawIdConflictsCount) ImGui.BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!") ImGui.BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!") ImGui.BulletText("Set io.ConfigDebugHighlightIdConflicts=false to disable this warning in non-programmers builds.") ImGui.Separator() ImGui.Text("(Hold Ctrl to: ") ImGui.SameLine(0.0, 0.0) ImGui.TextLinkOpenURL("read FAQ \"About ID Stack System\"", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage") ImGui.SameLine(0.0, 0.0) ImGui.Text(")") ImGui.EndErrorTooltip() end if g.ErrorCountCurrentFrame > 0 and ImGui.BeginErrorTooltip() then ImGui.Separator() ImGui.Text("(Hold Ctrl to: ") ImGui.SameLine(0.0, 0.0) if ImGui.SmallButton("Enable Asserts") then g.IO.ConfigErrorRecoveryEnableAssert = true end ImGui.SameLine(0, 0) ImGui.Text(")") ImGui.EndErrorTooltip() end end function ImGui.BeginErrorTooltip() local g = GImGui local window = ImGui.FindWindowByName("##Tooltip_Error") local use_locked_pos = g.IO.KeyCtrl and window ~= nil and window.WasActive local c = g.Style.Colors[ImGuiCol.PopupBg] ImGui.PushStyleColor(ImGuiCol.PopupBg, ImVec4(ImLerp(c.x, 1.0, 0.15), ImLerp(c.y, 0.0, 0.15), ImLerp(c.z, 0.0, 0.15), ImLerp(c.w, 1.0, 0.15))) if use_locked_pos then ImGui.SetNextWindowPos(g.ErrorTooltipLockedPos) end local _, is_visible = ImGui.Begin("##Tooltip_Error", nil, bit32.bor(ImGuiWindowFlags.Tooltip, ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.AlwaysAutoResize)) ImGui.PopStyleColor() if is_visible and g.CurrentWindow.BeginCount == 1 then ImGui.SeparatorText("MESSAGE FROM DEAR IMGUI") ImGui.BringWindowToDisplayFront(g.CurrentWindow) ImGui.BringWindowToFocusFront(g.CurrentWindow) g.ErrorTooltipLockedPos = ImGui.GetWindowPos() elseif not is_visible then ImGui.End() end return is_visible end function ImGui.EndErrorTooltip() ImGui.End() end do --[[ [SECTION] METRICS/DEBUGGER WINDOW, DEBUG LOG, ID STACK TOOL, FONT DEBUG ]] ---------------------------------------------------------------- -- [SECTION] Font atlas / font debugging ---------------------------------------------------------------- -- byte buffers for InputText (same as the demo's DemoBuf/DemoBufStr; kept here so the library doesn't need the demo) local 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 local 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 local function MetricsHelpMarker(desc) ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0) ImGui.TextUnformatted(desc) ImGui.PopTextWrapPos() ImGui.EndTooltip() end end ImGui.MetricsHelpMarker = MetricsHelpMarker local function U8(c) return (c and c > 0) and utf8.char(c) or "" end function ImGui.ShowFontSelector(label) local io = ImGui.GetIO() local font_current = ImGui.GetFont() if ImGui.BeginCombo(label, font_current:GetDebugName()) then for i, font in io.Fonts.Fonts:iter() do ImGui.PushID(i) if ImGui.Selectable(font:GetDebugName(), font == font_current, ImGuiSelectableFlags.SelectOnNav) then io.FontDefault = font end if font == font_current then ImGui.SetItemDefaultFocus() end ImGui.PopID() end ImGui.EndCombo() end ImGui.SameLine() MetricsHelpMarker("- Load additional fonts with io.Fonts->AddFontXXX() functions.\n- On Roblox: register the .ttf bytes with ImGui_ImplRoblox.AddFile() first.\n- Read FAQ and docs/FONTS.md for more details.") end function ImGui.DebugNodeFontGlyph(font, glyph) ImGui.Text("Codepoint: U+%04X", glyph.Codepoint) ImGui.Separator() ImGui.Text("Visible: %d", glyph.Visible and 1 or 0) ImGui.Text("AdvanceX: %.1f", glyph.AdvanceX) ImGui.Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph.X0, glyph.Y0, glyph.X1, glyph.Y1) ImGui.Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph.U0, glyph.V0, glyph.U1, glyph.V1) if glyph.PackId >= 0 then local r = { uv0 = ImVec2(), uv1 = ImVec2() } if font.OwnerAtlas:GetCustomRect(glyph.PackId, r) then ImGui.Text("PackId: 0x%X (%dx%d rect at %d,%d)", glyph.PackId, r.w, r.h, r.x, r.y) end end ImGui.Text("SourceIdx: %d", glyph.SourceIdx) end function ImGui.DebugNodeFontGlyphsForSrcMask(font, baked, src_mask) local draw_list = ImGui.GetWindowDrawList() local glyph_col = ImGui.GetColorU32(ImGuiCol.Text) local cell_size = baked.Size * 1 local cell_spacing = ImGui.GetStyle().ItemSpacing.y -- [port] only scans loaded codepoints (IndexLookup range) instead of the whole 0..0xFFFF range local max_c = baked.IndexLookup.Size - 1 local base = 0 while base <= max_c do local count = 0 for n = 0, 255 do local c = base + n if baked:IsGlyphLoaded(c) then local glyph = baked:FindGlyphNoFallback(c) if glyph and bit32.band(src_mask, bit32.lshift(1, glyph.SourceIdx)) ~= 0 then count = count + 1 end end end if count > 0 and ImGui.TreeNode(base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, (count > 1) and "glyphs" or "glyph") then local base_pos = ImGui.GetCursorScreenPos() for n = 0, 255 do local c = base + n local cell_p1 = ImVec2(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + math.floor(n / 16) * (cell_size + cell_spacing)) local cell_p2 = ImVec2(cell_p1.x + cell_size, cell_p1.y + cell_size) local glyph = baked:IsGlyphLoaded(c) and baked:FindGlyphNoFallback(c) or nil draw_list:AddRect(cell_p1, cell_p2, glyph and IM_COL32(255, 255, 255, 100) or IM_COL32(255, 255, 255, 50)) if glyph and bit32.band(src_mask, bit32.lshift(1, glyph.SourceIdx)) ~= 0 then font:RenderChar(draw_list, cell_size, cell_p1, glyph_col, c) if ImGui.IsMouseHoveringRect(cell_p1, cell_p2) and ImGui.BeginTooltip() then ImGui.DebugNodeFontGlyph(font, glyph) ImGui.EndTooltip() end end end ImGui.Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)) ImGui.TreePop() end base = base + 256 end end function ImGui.DebugNodeFont(font) local g = ImGui.GetCurrentContext() local cfg = g.DebugMetricsConfig local atlas = font.OwnerAtlas local opened = ImGui.TreeNode(tostring(font), "Font: \"%s\": %d sources(s)", font:GetDebugName(), font.Sources.Size) if not opened then ImGui.Indent() end ImGui.Indent() if cfg.ShowFontPreview then ImGui.PushFont(font, 0.0) ImGui.Text("The quick brown fox jumps over the lazy dog") ImGui.PopFont() end if not opened then ImGui.Unindent() ImGui.Unindent() return end if ImGui.SmallButton("Set as default") then ImGui.GetIO().FontDefault = font end ImGui.SameLine() ImGui.BeginDisabled(atlas.Fonts.Size <= 1 or atlas.Locked == true or atlas.RemoveFont == nil) if ImGui.SmallButton("Remove") and atlas.RemoveFont then atlas:RemoveFont(font) end ImGui.EndDisabled() ImGui.SameLine() if ImGui.SmallButton("Clear bakes") then ImFontAtlasFontDiscardBakes(atlas, font, 0) end ImGui.SameLine() if ImGui.SmallButton("Clear unused") then ImFontAtlasFontDiscardBakes(atlas, font, 2) end ImGui.Text("Fallback character: '%s' (U+%04X)", U8(font.FallbackChar), font.FallbackChar or 0) ImGui.Text("Ellipsis character: '%s' (U+%04X)", U8(font.EllipsisChar), font.EllipsisChar or 0) for src_n, src in font.Sources:iter() do if ImGui.TreeNode(tostring(src), "Input %d: '%s' [%d], Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", src_n - 1, src.Name or "", src.FontNo or 0, src.OversampleH or 0, src.OversampleV or 0, src.PixelSnapH and 1 or 0, src.GlyphOffset.x, src.GlyphOffset.y) then local loader = src.FontLoader or atlas.FontLoader ImGui.Text("Loader: '%s'", (loader and loader.Name) or "N/A") ImGui.TreePop() end end local builder = atlas.Builder if builder then for _, baked in builder.BakedPool:iter() do if baked.OwnerFont == font then ImGui.PushID(baked.BakedId) if ImGui.TreeNode("Glyphs", "Baked at { %.2fpx, d.%.2f }: %d glyphs%s", baked.Size, baked.RasterizerDensity, baked.Glyphs.Size, (baked.LastUsedFrame < (builder.FrameCount or 0) - 1) and " *Unused*" or "") then if ImGui.SmallButton("Load all") then for c = 0, 0x7F do baked:FindGlyph(c) end -- [port] ASCII only: loading the whole BMP in Luau stalls for seconds end local surface_sqrt = math.floor(math.sqrt(baked.MetricsTotalSurface)) ImGui.Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked.Ascent, baked.Descent, baked.Ascent - baked.Descent) ImGui.Text("Texture Area: about %d px ~%dx%d px", baked.MetricsTotalSurface, surface_sqrt, surface_sqrt) for src_n, src in font.Sources:iter() do ImGui.BulletText("Input %d: '%s', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", src_n - 1, src.Name or "", src.OversampleH or 0, src.OversampleV or 0, src.PixelSnapH and 1 or 0, src.GlyphOffset.x, src.GlyphOffset.y) end ImGui.DebugNodeFontGlyphsForSrcMask(font, baked, bit32.bnot(0)) ImGui.TreePop() end ImGui.PopID() end end end ImGui.TreePop() ImGui.Unindent() end local StatusNames = { [0] = "OK", "Destroyed", "WantCreate", "WantUpdates", "WantDestroy" } local FormatNames = { [0] = "RGBA32", "Alpha8" } function ImGui.DebugNodeTexture(tex, int_id, highlight_rect) local g = ImGui.GetCurrentContext() ImGui.PushID(int_id) if ImGui.TreeNode("", "Texture #%03d (%dx%d pixels)", tex.UniqueID or 0, tex.Width, tex.Height) then local cfg = g.DebugMetricsConfig _, cfg.ShowTextureUsedRect = ImGui.Checkbox("Show used rect", cfg.ShowTextureUsedRect) ImGui.PushStyleVar(ImGuiStyleVar.ImageBorderSize, math.max(1.0, g.Style.ImageBorderSize)) local p = ImGui.GetCursorScreenPos() if tex.Status == ImTextureStatus.WantDestroy or tex.Status == ImTextureStatus.Destroyed then ImGui.Dummy(ImVec2(tex.Width, tex.Height)) else local ref = ImTextureRef(); ref._TexData = tex ImGui.ImageWithBg(ref, ImVec2(tex.Width, tex.Height), ImVec2(0.0, 0.0), ImVec2(1.0, 1.0), ImVec4(0.0, 0.0, 0.0, 1.0)) end if cfg.ShowTextureUsedRect and tex.UsedRect then local u = tex.UsedRect ImGui.GetWindowDrawList():AddRect(ImVec2(p.x + u.x, p.y + u.y), ImVec2(p.x + u.x + u.w, p.y + u.y + u.h), IM_COL32(255, 0, 255, 255)) end if highlight_rect ~= nil then local r_outer = ImRect(p.x, p.y, p.x + tex.Width, p.y + tex.Height) local r_inner = ImRect(p.x + highlight_rect.x, p.y + highlight_rect.y, p.x + highlight_rect.x + highlight_rect.w, p.y + highlight_rect.y + highlight_rect.h) ImGui.RenderRectFilledWithHole(ImGui.GetWindowDrawList(), r_outer, r_inner, IM_COL32(0, 0, 0, 100), 0.0) ImGui.GetWindowDrawList():AddRect(r_inner.Min - ImVec2(1, 1), r_inner.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255)) end ImGui.PopStyleVar() ImGui.Text("Status = %s (%d), Format = %s (%d), UseColors = %d", StatusNames[tex.Status] or "?", tex.Status, FormatNames[tex.Format] or "?", tex.Format, tex.UseColors and 1 or 0) ImGui.Text("TexID = %s", tostring(tex.TexID)) ImGui.TreePop() end ImGui.PopID() end function ImGui.ShowFontAtlas(atlas) local g = ImGui.GetCurrentContext() local io = g.IO local style = g.Style ImGui.BeginDisabled() ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", io.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ImGui.EndDisabled() ImGui.ShowFontSelector("Font") 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 ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) ImGui.SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later.") style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) ImGui.BulletText("Load a nice font for better results!") ImGui.BulletText("Please submit feedback:") ImGui.SameLine(); ImGui.TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465") ImGui.BulletText("Read FAQ for more details:") ImGui.SameLine(); ImGui.TextLinkOpenURL("dearimgui.com/faq", "https://www.dearimgui.com/faq/") ImGui.SeparatorText("Font List") local cfg = g.DebugMetricsConfig _, cfg.ShowFontPreview = ImGui.Checkbox("Show font preview", cfg.ShowFontPreview == true) if ImGui.TreeNode("Loader", "Loader: '%s'", atlas.FontLoaderName or "NULL") then ImGui.BeginDisabled() ImGui.RadioButtonEx("stb_truetype", true) ImGui.SameLine() ImGui.RadioButtonEx("FreeType", false) ImGui.SetItemTooltip("Not available on Roblox.") ImGui.EndDisabled() ImGui.TreePop() end for i, font in atlas.Fonts:iter() do ImGui.PushID(i) ImGui.DebugNodeFont(font) ImGui.PopID() end ImGui.SeparatorText("Font Atlas") if ImGui.Button("Compact") then atlas:CompactCache() end ImGui.SameLine() if ImGui.Button("Grow") then ImFontAtlasTextureGrow(atlas) end ImGui.SameLine() if ImGui.Button("Clear All") then ImFontAtlasBuildClear(atlas) end ImGui.SetItemTooltip("Destroy cache and custom rectangles.") for tex_n, tex in atlas.TexList:iter() do if tex_n > 1 then ImGui.SameLine() end ImGui.Text("Tex: %dx%d", tex.Width, tex.Height) end local b = atlas.Builder if b then local packed_sqrt = math.floor(math.sqrt(b.RectsPackedSurface or 0)) local discarded_sqrt = math.floor(math.sqrt(b.RectsDiscardedSurface or 0)) ImGui.Text("Packed rects: %d, area: about %d px ~%dx%d px", b.RectsPackedCount or 0, b.RectsPackedSurface or 0, packed_sqrt, packed_sqrt) ImGui.Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", b.RectsDiscardedCount or 0, b.RectsDiscardedSurface or 0, discarded_sqrt, discarded_sqrt) end for tex_n, tex in atlas.TexList:iter() do if tex_n == atlas.TexList.Size then ImGui.SetNextItemOpen(true, ImGuiCond.Once) end ImGui.DebugNodeTexture(tex, atlas.TexList.Size - tex_n, nil) end end ---------------------------------------------------------------- -- [SECTION] Debug Log window ---------------------------------------------------------------- local function SameLineOrWrap(size) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local pos = ImVec2(window.DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window.DC.CursorPosPrevLine.y) if window.WorkRect:Contains(ImRect(pos, pos + size)) then ImGui.SameLine() end end local function ShowDebugLogFlag(name, flags) local g = ImGui.GetCurrentContext() local size = ImVec2(ImGui.GetFrameHeight() + g.Style.ItemInnerSpacing.x + ImGui.CalcTextSize(name).x, ImGui.GetFrameHeight()) SameLineOrWrap(size) local pressed pressed, g.DebugLogFlags = ImGui.CheckboxFlags(name, g.DebugLogFlags, flags) if pressed and g.IO.KeyShift and bit32.band(g.DebugLogFlags, flags) ~= 0 then g.DebugLogAutoDisableFrames = 2 g.DebugLogAutoDisableFlags = bit32.bor(g.DebugLogAutoDisableFlags or 0, flags) end ImGui.SetItemTooltip("Hold Shift when clicking to enable for 2 frames only (useful for spammy log entries)") end function ImGui.ShowDebugLogWindow(p_open) local g = ImGui.GetCurrentContext() if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) == 0 then ImGui.SetNextWindowSize(ImVec2(0.0, ImGui.GetFontSize() * 12.0), ImGuiCond.FirstUseEver) end local visible p_open, visible = ImGui.Begin("Dear ImGui Debug Log", p_open) if not visible or ImGui.GetCurrentWindow().BeginCount > 1 then ImGui.End() return p_open end local L = ImGuiDebugLogFlags local all_enable_flags = bit32.band(L.EventMask_, bit32.bnot(L.EventInputRouting)) _, g.DebugLogFlags = ImGui.CheckboxFlags("All", g.DebugLogFlags, all_enable_flags) ImGui.SetItemTooltip("(except InputRouting which is spammy)") for _, e in ipairs({ { "Errors", L.EventError }, { "ActiveId", L.EventActiveId }, { "Clipper", L.EventClipper }, { "Docking", L.EventDocking }, { "Focus", L.EventFocus }, { "IO", L.EventIO }, { "Font", L.EventFont }, { "Nav", L.EventNav }, { "Popup", L.EventPopup }, { "Selection", L.EventSelection }, { "Table", L.EventTable }, { "Viewport", L.EventViewport }, { "InputRouting", L.EventInputRouting } }) do ShowDebugLogFlag(e[1], e[2]) end if ImGui.SmallButton("Clear") then if g.DebugLogBuf then g.DebugLogBuf:clear() end g.DebugLogLines = { "" } end ImGui.SameLine() if ImGui.SmallButton("Copy") then ImGui.SetClipboardText(g.DebugLogBuf and g.DebugLogBuf:c_str() or "") end ImGui.SameLine() if ImGui.SmallButton("Configure Outputs..") then ImGui.OpenPopup("Outputs") end if ImGui.BeginPopup("Outputs") then _, g.DebugLogFlags = ImGui.CheckboxFlags("OutputToTTY", g.DebugLogFlags, L.OutputToTTY) ImGui.BeginDisabled() _, g.DebugLogFlags = ImGui.CheckboxFlags("OutputToDebugger", g.DebugLogFlags, L.OutputToDebugger) _, g.DebugLogFlags = ImGui.CheckboxFlags("OutputToTestEngine", g.DebugLogFlags, L.OutputToTestEngine) ImGui.EndDisabled() ImGui.EndPopup() end ImGui.BeginChild("##log", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, bit32.bor(ImGuiWindowFlags.AlwaysVerticalScrollbar, ImGuiWindowFlags.AlwaysHorizontalScrollbar)) local backup_log_flags = g.DebugLogFlags g.DebugLogFlags = bit32.band(g.DebugLogFlags, bit32.bnot(L.EventClipper)) local lines = g.DebugLogLines or { "" } local count = #lines if lines[count] == "" then count = count - 1 end -- trailing partial line local clipper = ImGuiListClipper() clipper:Begin(count) while clipper:Step() do for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.TextUnformatted(lines[line_no + 1]) end end g.DebugLogFlags = backup_log_flags if ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then ImGui.SetScrollHereY(1.0) end ImGui.EndChild() ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] ID Stack Tool ---------------------------------------------------------------- local function PathQuery(g) local q = g.DebugItemPathQuery if q == nil then q = { MainID = 0, Active = false, Complete = false, Step = -1, Results = {} } g.DebugItemPathQuery = q g.DebugIDStackTool = { LastActiveFrame = -1, OptHexEncodeNonAsciiChars = true, OptCopyToClipboardOnCtrlC = false, CopyToClipboardLastTime = -FLT_MAX } end return q end -- Update queries. The steps are: -1: query Stack, >= 0: query each stack item local function DebugItemPathQuery_UpdateAndGetHookId(query, id) if query.MainID ~= id then query.MainID = id query.Step = -1 query.Complete = false query.Results = {} end query.Active = false if id == 0 then return 0 end local res = query.Results if query.Step >= 0 and query.Step < #res then if res[query.Step + 1].QuerySuccess or res[query.Step + 1].QueryFrameCount > 2 then query.Step = query.Step + 1 end end query.Complete = (query.Step == #res) if query.Step == -1 then query.Active = true return id elseif query.Step >= 0 and query.Step < #res then res[query.Step + 1].QueryFrameCount = res[query.Step + 1].QueryFrameCount + 1 query.Active = true return res[query.Step + 1].ID end return 0 end function ImGui.UpdateDebugToolItemPathQuery() local g = ImGui.GetCurrentContext() local q = PathQuery(g) local id = 0 if g.DebugIDStackTool.LastActiveFrame + 1 == g.FrameCount then id = (g.HoveredIdPreviousFrame ~= 0 and g.HoveredIdPreviousFrame) or g.ActiveId end g.DebugHookIdInfoId = DebugItemPathQuery_UpdateAndGetHookId(q, id) end -- Hooks called by GetID() family functions. `data_id` is the string/number that was hashed. function ImGui.DebugHookIdInfo(id, data_type, data_id) local g = ImGui.GetCurrentContext() local query = PathQuery(g) if not query.Active then return end local window = g.CurrentWindow if query.Step == -1 then query.Step = 0 query.Results = {} for n = 0, window.IDStack.Size do query.Results[n + 1] = { ID = (n < window.IDStack.Size) and window.IDStack.Data[n + 1] or id, QueryFrameCount = 0, QuerySuccess = false, DataType = -1, Desc = nil } end return end if query.Step ~= window.IDStack.Size then return end local info = query.Results[query.Step + 1] if info == nil or info.ID ~= id then return end if info.Desc == nil then if data_type == ImGuiDataType.S32 then info.Desc = string.format("%d", data_id) elseif data_type == ImGuiDataType.String then info.Desc = tostring(data_id) else info.Desc = string.format("0x%08X [override]", id) end end info.QuerySuccess = true if info.DataType == -1 then info.DataType = data_type end end local function SkipUncontributingPrefix(label) local p = string.find(label, "###", 1, true) if p then return string.sub(label, p) end return label end local function FormatLevelInfo(g, query, n, format_for_ui) local info = query.Results[n + 1] local window = (info.Desc == nil and n == 0) and ImGui.FindWindowByID(info.ID) or nil if window then return string.format(format_for_ui and "\"%s\" [window]" or "%s", SkipUncontributingPrefix(window.Name)) end if info.QuerySuccess then return string.format((format_for_ui and info.DataType == ImGuiDataType.String) and "\"%s\"" or "%s", SkipUncontributingPrefix(info.Desc)) end if query.Step < #query.Results then return "" end return "???" end local function GetResultAsPath(g, query, hex_encode_non_ascii_chars) local out = {} for n = 0, #query.Results - 1 do local desc = FormatLevelInfo(g, query, n, false) out[#out + 1] = (n == 0) and "//" or "/" desc = string.gsub(desc, "/", "\\/") if hex_encode_non_ascii_chars then desc = string.gsub(desc, "[\128-\255]", function(c) return string.format("\\x%02x", string.byte(c)) end) end out[#out + 1] = desc end return table.concat(out) end function ImGui.ShowIDStackToolWindow(p_open) local g = ImGui.GetCurrentContext() if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) == 0 then ImGui.SetNextWindowSize(ImVec2(0.0, ImGui.GetFontSize() * 8.0), ImGuiCond.FirstUseEver) end local visible p_open, visible = ImGui.Begin("Dear ImGui ID Stack Tool", p_open) if not visible or ImGui.GetCurrentWindow().BeginCount > 1 then ImGui.End() return p_open end local query = PathQuery(g) local tool = g.DebugIDStackTool tool.LastActiveFrame = g.FrameCount local result_path = GetResultAsPath(g, query, tool.OptHexEncodeNonAsciiChars) ImGui.Text("0x%08X", query.MainID) ImGui.SameLine() MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.") local time_since_copy = g.Time - tool.CopyToClipboardLastTime ImGui.PushStyleVarY(ImGuiStyleVar.FramePadding, 0.0) _, tool.OptHexEncodeNonAsciiChars = ImGui.Checkbox("Hex-encode non-ASCII", tool.OptHexEncodeNonAsciiChars) ImGui.SameLine() _, tool.OptCopyToClipboardOnCtrlC = ImGui.Checkbox("Ctrl+C: copy path", tool.OptCopyToClipboardOnCtrlC) ImGui.PopStyleVar() ImGui.SameLine() ImGui.TextColored((time_since_copy >= 0.0 and time_since_copy < 0.75 and math.fmod(time_since_copy, 0.25) < 0.25 * 0.5) and ImVec4(1.0, 1.0, 0.3, 1.0) or ImVec4(), "*COPIED*") if tool.OptCopyToClipboardOnCtrlC and ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.C), bit32.bor(ImGuiInputFlags.RouteGlobal, ImGuiInputFlags.RouteOverFocused)) then tool.CopyToClipboardLastTime = g.Time ImGui.SetClipboardText(result_path) end ImGui.Text("- Path \"%s\"", query.Complete and result_path or "") ImGui.Separator() if #query.Results > 0 and ImGui.BeginTable("##table", 3, ImGuiTableFlags.Borders) then local id_width = ImGui.CalcTextSize("0xDDDDDDDD").x ImGui.TableSetupColumn("Seed", ImGuiTableColumnFlags.WidthFixed, id_width) ImGui.TableSetupColumn("PushID", ImGuiTableColumnFlags.WidthStretch) ImGui.TableSetupColumn("Result", ImGuiTableColumnFlags.WidthFixed, id_width) ImGui.TableHeadersRow() for n = 0, #query.Results - 1 do local info = query.Results[n + 1] ImGui.TableNextColumn() ImGui.Text("0x%08X", (n > 0) and query.Results[n].ID or 0) ImGui.TableNextColumn() ImGui.TextUnformatted(FormatLevelInfo(g, query, n, true)) ImGui.TableNextColumn() ImGui.Text("0x%08X", info.ID) if n == #query.Results - 1 then ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(ImGuiCol.Header)) end end ImGui.EndTable() end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Metrics/Debugger window ---------------------------------------------------------------- local function B(v) return v and 1 or 0 end local function FG(window) return ImGui.GetForegroundDrawList(window and window.Viewport or ImGui.GetMainViewport()) end local function YellowRect(window, min, max) FG(window):AddRect(min, max, IM_COL32(255, 255, 0, 255)) end function ImGui.DebugNodeColumns(columns) if not ImGui.TreeNode(columns.ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns.ID, columns.Count, columns.Flags) then return end ImGui.BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns.OffMaxX - columns.OffMinX, columns.OffMinX, columns.OffMaxX) for i, column in columns.Columns:iter() do ImGui.BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", i - 1, column.OffsetNorm, ImGui.GetColumnOffsetFromNorm(columns, column.OffsetNorm)) end ImGui.TreePop() end function ImGui.DebugNodeStorage(storage, label) local n = 0 for _ in pairs(storage) do n = n + 1 end if not ImGui.TreeNode(label, "%s: %d entries", label, n) then return end for k, v in pairs(storage) do ImGui.BulletText("Key 0x%08X Value { %s }", tonumber(k) or 0, tostring(v)) end ImGui.TreePop() end function ImGui.DebugNodeDrawList(window, viewport, draw_list, label) local g = ImGui.GetCurrentContext() local cfg = g.DebugMetricsConfig local cmd_count = draw_list.CmdBuffer.Size if cmd_count > 0 and draw_list.CmdBuffer.Data[cmd_count].ElemCount == 0 and draw_list.CmdBuffer.Data[cmd_count].UserCallback == nil then cmd_count = cmd_count - 1 end local node_open = ImGui.TreeNode(tostring(draw_list), "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list._OwnerName or "", draw_list.VtxBuffer.Size, draw_list.IdxBuffer.Size, cmd_count) if draw_list == ImGui.GetWindowDrawList() then ImGui.SameLine() ImGui.TextColored(ImVec4(1.0, 0.4, 0.4, 1.0), "CURRENTLY APPENDING") if node_open then ImGui.TreePop() end return end local fg_draw_list = viewport and ImGui.GetForegroundDrawList(viewport) or nil if window and ImGui.IsItemHovered() and fg_draw_list then fg_draw_list:AddRect(window.Pos, window.Pos + window.Size, IM_COL32(255, 255, 0, 255)) end if not node_open then return end if window and not window.WasActive then ImGui.TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!") end local vtx, idx = draw_list.VtxBuffer.Buf, draw_list.IdxBuffer.Data for cmd_n = 1, cmd_count do local pcmd = draw_list.CmdBuffer.Data[cmd_n] if pcmd.UserCallback then ImGui.BulletText("Callback %s", tostring(pcmd.UserCallback)) else local cr = pcmd.ClipRect local open = ImGui.TreeNode(cmd_n, "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", math.floor(pcmd.ElemCount / 3), tostring(pcmd.TexRef and (pcmd.TexRef._TexID or pcmd.TexRef._TexData)), cr.x, cr.y, cr.z, cr.w) local function ShowMesh(show_mesh, show_aabb) if not fg_draw_list then return end local clip_rect = ImRect(cr.x, cr.y, cr.z, cr.w) local vtxs_rect = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) local base = pcmd.IdxOffset for i = base, base + pcmd.ElemCount - 1, 3 do local tri = {} for n = 0, 2 do local vi = idx[i + n + 1] + pcmd.VtxOffset if vi > draw_list.VtxBuffer.Size then return end tri[n + 1] = ImVec2(ImDrawVtx_Pos(vtx, vi)) vtxs_rect:Add(tri[n + 1]) end if show_mesh then fg_draw_list:AddPolyline(tri, 3, IM_COL32(255, 255, 0, 255), 1.0, ImDrawFlags.Closed) end end if show_aabb then fg_draw_list:AddRect(ImTrunc(clip_rect.Min), ImTrunc(clip_rect.Max), IM_COL32(255, 0, 255, 255)) fg_draw_list:AddRect(ImTrunc(vtxs_rect.Min), ImTrunc(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)) end end if ImGui.IsItemHovered() and (cfg.ShowDrawCmdMesh or cfg.ShowDrawCmdBoundingBoxes) then ShowMesh(cfg.ShowDrawCmdMesh, cfg.ShowDrawCmdBoundingBoxes) end if open then ImGui.Selectable(string.format("Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d", pcmd.ElemCount, pcmd.VtxOffset, pcmd.IdxOffset)) if ImGui.IsItemHovered() then ShowMesh(true, false) end ImGui.TreePop() end end end ImGui.TreePop() end function ImGui.DebugNodeTabBar(tab_bar, label) local g = ImGui.GetCurrentContext() local is_active = (tab_bar.PrevFrameVisible >= ImGui.GetFrameCount() - 2) local names = {} for tab_n = 1, math.min(tab_bar.Tabs.Size, 3) do local tab = tab_bar.Tabs.Data[tab_n] names[#names + 1] = "'" .. (ImGui.TabBarGetTabName and ImGui.TabBarGetTabName(tab_bar, tab) or "?") .. "'" end local buf = string.format("%s 0x%08X (%d tabs)%s { %s%s", label, tab_bar.ID, tab_bar.Tabs.Size, is_active and "" or " *Inactive*", table.concat(names, ", "), (tab_bar.Tabs.Size > 3) and " ... }" or " } ") if not is_active then ImGui.PushStyleColor(ImGuiCol.Text, g.Style.Colors[ImGuiCol.TextDisabled]) end local open = ImGui.TreeNode(label, "%s", buf) if not is_active then ImGui.PopStyleColor() end if is_active and ImGui.IsItemHovered() then local dl = FG(tab_bar.Window) dl:AddRect(tab_bar.BarRect.Min, tab_bar.BarRect.Max, IM_COL32(255, 255, 0, 255)) dl:AddLine(ImVec2(tab_bar.ScrollingRectMinX, tab_bar.BarRect.Min.y), ImVec2(tab_bar.ScrollingRectMinX, tab_bar.BarRect.Max.y), IM_COL32(0, 255, 0, 255)) dl:AddLine(ImVec2(tab_bar.ScrollingRectMaxX, tab_bar.BarRect.Min.y), ImVec2(tab_bar.ScrollingRectMaxX, tab_bar.BarRect.Max.y), IM_COL32(0, 255, 0, 255)) end if open then for tab_n, tab in tab_bar.Tabs:iter() do ImGui.PushID(tab_n) if ImGui.SmallButton("<") and ImGui.TabBarQueueReorder then ImGui.TabBarQueueReorder(tab_bar, tab, -1) end ImGui.SameLine(0, 2) if ImGui.SmallButton(">") and ImGui.TabBarQueueReorder then ImGui.TabBarQueueReorder(tab_bar, tab, 1) end ImGui.SameLine() ImGui.Text("%02d%s Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f", tab_n - 1, (tab.ID == tab_bar.SelectedTabId) and "*" or " ", tab.ID, ImGui.TabBarGetTabName and ImGui.TabBarGetTabName(tab_bar, tab) or "?", tab.Offset, tab.Width, tab.ContentWidth) ImGui.PopID() end ImGui.TreePop() end end local function SizingDesc(f) local TF = ImGuiTableFlags f = bit32.band(f, TF.SizingMask_) if f == TF.SizingFixedFit then return "FixedFit" elseif f == TF.SizingFixedSame then return "FixedSame" elseif f == TF.SizingStretchProp then return "StretchProp" elseif f == TF.SizingStretchSame then return "StretchSame" end return "N/A" end function ImGui.DebugNodeTableSettings(settings, tbl) local open = ImGui.TreeNode(tostring(settings), "Settings 0x%08X (%d columns)", settings.ID, settings.ColumnsCount) local hovered = ImGui.IsItemHovered() if hovered and tbl == nil and settings.ID ~= 0 then tbl = ImGui.TableFindByID(settings.ID) end if hovered and tbl ~= nil then YellowRect(tbl.OuterWindow, tbl.OuterRect.Min, tbl.OuterRect.Max) end if open then ImGui.BulletText("SaveFlags: 0x%08X", settings.SaveFlags) ImGui.BulletText("ColumnsCount: %d (max %d)", settings.ColumnsCount, settings.ColumnsCountMax) for n = 0, settings.ColumnsCount - 1 do local c = settings.Columns[n] local dir = (c.SortOrder ~= -1) and c.SortDirection or ImGuiSortDirection.None ImGui.BulletText("Column %d Order %d SortOrder %2d %s Vis %d %s %7.3f ID 0x%08X", n, c.DisplayOrder, c.SortOrder, (dir == ImGuiSortDirection.Ascending) and "Asc" or ((dir == ImGuiSortDirection.Descending) and "Des" or "---"), c.IsEnabled, (c.IsStretch ~= 0) and "Weight" or "Width ", c.WidthOrWeight, c.ID) end ImGui.TreePop() end end function ImGui.DebugNodeTable(tbl) local g = ImGui.GetCurrentContext() local is_active = (tbl.LastFrameActive >= g.FrameCount - 2) if not is_active then ImGui.PushStyleColor(ImGuiCol.Text, g.Style.Colors[ImGuiCol.TextDisabled]) end local open = ImGui.TreeNode(tostring(tbl), "Table 0x%08X (%d columns, in '%s')%s", tbl.ID, tbl.ColumnsCount, tbl.OuterWindow and tbl.OuterWindow.Name or "?", is_active and "" or " *Inactive*") if not is_active then ImGui.PopStyleColor() end if ImGui.IsItemHovered() then YellowRect(tbl.OuterWindow, tbl.OuterRect.Min, tbl.OuterRect.Max) end if not open then return end if tbl.InstanceCurrent > 0 then ImGui.Text("** %d instances of same table! Some data below will refer to last instance.", tbl.InstanceCurrent + 1) end local clear_settings = ImGui.SmallButton("Clear settings") ImGui.BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", tbl.OuterRect.Min.x, tbl.OuterRect.Min.y, tbl.OuterRect:GetWidth(), tbl.OuterRect:GetHeight(), SizingDesc(tbl.Flags)) ImGui.BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", tbl.ColumnsGivenWidth, tbl.ColumnsAutoFitWidth, tbl.InnerWidth, (tbl.InnerWidth == 0.0) and " (auto)" or "") ImGui.BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", tbl.CellPaddingX, tbl.CellSpacingX1, tbl.CellSpacingX2, tbl.OuterPaddingX) ImGui.BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", tbl.HoveredColumnBody, tbl.HoveredColumnBorder) ImGui.BulletText("ResizedColumn: %d, HeldHeaderColumn: %d, ReorderColumn: %d", tbl.LastResizedColumn, tbl.LastHeldHeaderColumn, tbl.ReorderColumn) for n = 0, tbl.InstanceCurrent do local inst = ImGui.TableGetInstanceData(tbl, n) ImGui.BulletText("Instance %d: HoveredRow: %d, LastOuterHeight: %.2f", n, inst.HoveredRowLast, inst.LastOuterHeight) end local sum_weights = 0.0 for n = 0, tbl.ColumnsCount - 1 do if bit32.band(tbl.Columns[n].Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then sum_weights = sum_weights + tbl.Columns[n].StretchWeight end end for n = 0, tbl.ColumnsCount - 1 do local c = tbl.Columns[n] local CF = ImGuiTableColumnFlags local buf = string.format( "Column %d order %d '%s': offset %+.2f to %+.2f%s\nEnabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n" .. "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\nMinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n" .. "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\nSort: %d%s, UserData: 0x%08X, Flags: 0x%04X: %s%s%s..", n, c.DisplayOrder, ImGui.TableGetColumnName(tbl, n) or "", c.MinX - tbl.WorkRect.Min.x, c.MaxX - tbl.WorkRect.Min.x, (n < tbl.FreezeColumnsRequest) and " (Frozen)" or "", B(c.IsEnabled), B(c.IsVisibleX), B(c.IsVisibleY), B(c.IsRequestOutput), B(c.IsSkipItems), c.DrawChannelFrozen, c.DrawChannelUnfrozen, c.WidthGiven, c.WidthRequest, c.WidthAuto, c.StretchWeight, (c.StretchWeight > 0.0 and sum_weights > 0) and (c.StretchWeight / sum_weights) * 100.0 or 0.0, c.MinX, c.MaxX, c.MaxX - c.MinX, c.ClipRect.Min.x, c.ClipRect.Max.x, c.ClipRect.Max.x - c.ClipRect.Min.x, c.ContentMaxXFrozen - c.WorkMinX, c.ContentMaxXUnfrozen - c.WorkMinX, c.ContentMaxXHeadersUsed - c.WorkMinX, c.ContentMaxXHeadersIdeal - c.WorkMinX, c.SortOrder, (c.SortDirection == ImGuiSortDirection.Ascending) and " (Asc)" or ((c.SortDirection == ImGuiSortDirection.Descending) and " (Des)" or ""), tonumber(c.UserData) or 0, c.Flags, (bit32.band(c.Flags, CF.WidthStretch) ~= 0) and "WidthStretch " or "", (bit32.band(c.Flags, CF.WidthFixed) ~= 0) and "WidthFixed " or "", (bit32.band(c.Flags, CF.NoResize) ~= 0) and "NoResize " or "") ImGui.Bullet() ImGui.Selectable(buf) if ImGui.IsItemHovered() then YellowRect(tbl.OuterWindow, ImVec2(c.MinX, tbl.OuterRect.Min.y), ImVec2(c.MaxX, tbl.OuterRect.Max.y)) end end local settings = ImGui.TableGetBoundSettings(tbl) if settings then ImGui.DebugNodeTableSettings(settings, tbl) end if clear_settings then tbl.IsResetAllRequest = true end ImGui.TreePop() end local function DebugNodeDockNodeFlags(flags, label, enabled) local D = ImGuiDockNodeFlags ImGui.PushID(label) ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0.0, 0.0)) ImGui.Text("%s:", label) if not enabled then ImGui.BeginDisabled() end for _, n in ipairs({ "NoResize", "NoResizeX", "NoResizeY", "NoTabBar", "HiddenTabBar", "NoWindowMenuButton", "NoCloseButton", "DockedWindowsInFocusRoute", "NoDocking", "NoDockingSplit", "NoDockingSplitOther", "NoDockingOverMe", "NoDockingOverOther", "NoDockingOverEmpty", "NoUndocking" }) do if D[n] then _, flags = ImGui.CheckboxFlags(n, flags, D[n]) end end if not enabled then ImGui.EndDisabled() end ImGui.PopStyleVar() ImGui.PopID() return flags end function ImGui.DebugNodeDockNode(node, label) local g = ImGui.GetCurrentContext() local is_alive = (g.FrameCount - node.LastFrameAlive < 2) local is_active = (g.FrameCount - node.LastFrameActive < 2) if not is_alive then ImGui.PushStyleColor(ImGuiCol.Text, g.Style.Colors[ImGuiCol.TextDisabled]) end local tree_node_flags = node.IsFocused and ImGuiTreeNodeFlags.Selected or ImGuiTreeNodeFlags.None local open if node.Windows.Size > 0 then open = ImGui.TreeNodeEx(node.ID, tree_node_flags, "%s 0x%04X%s: %d windows (vis: '%s')", label, node.ID, node.IsVisible and "" or " (hidden)", node.Windows.Size, node.VisibleWindow and node.VisibleWindow.Name or "NULL") else local kind = (node.SplitAxis == ImGuiAxis.X) and "horizontal split" or ((node.SplitAxis == ImGuiAxis.Y) and "vertical split" or "empty") open = ImGui.TreeNodeEx(node.ID, tree_node_flags, "%s 0x%04X%s: %s (vis: '%s')", label, node.ID, node.IsVisible and "" or " (hidden)", kind, node.VisibleWindow and node.VisibleWindow.Name or "NULL") end if not is_alive then ImGui.PopStyleColor() end if is_active and ImGui.IsItemHovered() then local window = node.HostWindow or node.VisibleWindow if window then YellowRect(window, node.Pos, node.Pos + node.Size) end end if open then ImGui.BulletText("Pos (%.0f,%.0f), Size (%.0f, %.0f) Ref (%.0f, %.0f)", node.Pos.x, node.Pos.y, node.Size.x, node.Size.y, node.SizeRef.x, node.SizeRef.y) ImGui.DebugNodeWindow(node.HostWindow, "HostWindow") ImGui.DebugNodeWindow(node.VisibleWindow, "VisibleWindow") ImGui.BulletText("SelectedTabID: 0x%08X, LastFocusedNodeID: 0x%08X", node.SelectedTabId, node.LastFocusedNodeId) ImGui.BulletText("Misc:%s%s%s%s%s%s%s", node:IsDockSpace() and " IsDockSpace" or "", node:IsCentralNode() and " IsCentralNode" or "", is_alive and " IsAlive" or "", is_active and " IsActive" or "", node.IsFocused and " IsFocused" or "", node.WantLockSizeOnce and " WantLockSizeOnce" or "", node.HasCentralNodeChild and " HasCentralNodeChild" or "") if ImGui.TreeNode("flags", "Flags Merged: 0x%04X, Local: 0x%04X, InWindows: 0x%04X, Shared: 0x%04X", node.MergedFlags, node.LocalFlags, node.LocalFlagsInWindows, node.SharedFlags) then if ImGui.BeginTable("flags", 4) then ImGui.TableNextColumn(); DebugNodeDockNodeFlags(node.MergedFlags, "MergedFlags", false) ImGui.TableNextColumn(); node.LocalFlags = DebugNodeDockNodeFlags(node.LocalFlags, "LocalFlags", true) ImGui.TableNextColumn(); DebugNodeDockNodeFlags(node.LocalFlagsInWindows, "LocalFlagsInWindows", false) ImGui.TableNextColumn(); node.SharedFlags = DebugNodeDockNodeFlags(node.SharedFlags, "SharedFlags", true) ImGui.EndTable() end ImGui.TreePop() end if node.ParentNode then ImGui.DebugNodeDockNode(node.ParentNode, "ParentNode") end if node.ChildNodes[0] then ImGui.DebugNodeDockNode(node.ChildNodes[0], "Child[0]") end if node.ChildNodes[1] then ImGui.DebugNodeDockNode(node.ChildNodes[1], "Child[1]") end if node.TabBar then ImGui.DebugNodeTabBar(node.TabBar, "TabBar") end ImGui.DebugNodeWindowsList(node.Windows, "Windows") ImGui.TreePop() end end function ImGui.DebugNodeWindow(window, label) if window == nil then ImGui.BulletText("%s: NULL", label) return end local g = ImGui.GetCurrentContext() local is_active = window.WasActive local tree_node_flags = (window == g.NavWindow) and ImGuiTreeNodeFlags.Selected or ImGuiTreeNodeFlags.None if not is_active then ImGui.PushStyleColor(ImGuiCol.Text, g.Style.Colors[ImGuiCol.TextDisabled]) end local open = ImGui.TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window.Name, is_active and "" or " *Inactive*") if not is_active then ImGui.PopStyleColor() end if ImGui.IsItemHovered() and is_active then YellowRect(window, window.Pos, window.Pos + window.Size) end if not open then return end if window.MemoryCompacted then ImGui.TextDisabled("Note: some memory buffers have been compacted/freed.") end local W = ImGuiWindowFlags local flags = window.Flags local function F(f, s) return (bit32.band(flags, f) ~= 0) and s or "" end ImGui.DebugNodeDrawList(window, window.Viewport, window.DrawList, "DrawList") ImGui.BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window.Pos.x, window.Pos.y, window.Size.x, window.Size.y, window.ContentSize.x, window.ContentSize.y, window.ContentSizeIdeal.x, window.ContentSizeIdeal.y) ImGui.BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, F(W.ChildWindow, "Child "), F(W.Tooltip, "Tooltip "), F(W.Popup, "Popup "), F(W.Modal, "Modal "), F(W.ChildMenu, "ChildMenu "), F(W.NoSavedSettings, "NoSavedSettings "), F(W.NoMouseInputs, "NoMouseInputs"), F(W.NoNavInputs, "NoNavInputs"), F(W.AlwaysAutoResize, "AlwaysAutoResize")) if bit32.band(flags, W.ChildWindow) ~= 0 then local cf = window.ChildFlags or 0 local C = ImGuiChildFlags ImGui.BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", cf, (bit32.band(cf, C.Borders) ~= 0) and "Borders " or "", (bit32.band(cf, C.ResizeX) ~= 0) and "ResizeX " or "", (bit32.band(cf, C.ResizeY) ~= 0) and "ResizeY " or "", (bit32.band(cf, C.NavFlattened) ~= 0) and "NavFlattened " or "") end ImGui.BulletText("WindowClassId: 0x%08X", window.WindowClass and window.WindowClass.ClassId or 0) ImGui.BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window.Scroll.x, window.ScrollMax.x, window.Scroll.y, window.ScrollMax.y, window.ScrollbarX and "X" or "", window.ScrollbarY and "Y" or "") ImGui.BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", B(window.Active), B(window.WasActive), B(window.WriteAccessed), (window.Active or window.WasActive) and window.BeginOrderWithinContext or -1) ImGui.BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", B(window.Appearing), B(window.Hidden), window.HiddenFramesCanSkipItems, window.HiddenFramesCannotSkipItems, B(window.SkipItems)) for layer = 0, 1 do local r = window.NavRectRel[layer] if r.Min.x >= r.Max.x and r.Min.y >= r.Max.y then ImGui.BulletText("NavLastIds[%d]: 0x%08X", layer, window.NavLastIds[layer]) else ImGui.BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window.NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y) end end ImGui.BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window.DC.NavLayersActiveMask, window.NavLastChildNavWindow and window.NavLastChildNavWindow.Name or "NULL") ImGui.BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window.Viewport and (window.Viewport.Idx or 0) or -1, window.ViewportOwned and " (Owned)" or "", window.ViewportId or 0, window.ViewportPos.x, window.ViewportPos.y) ImGui.BulletText("DockId: 0x%04X, DockOrder: %d, Act: %d, Vis: %d", window.DockId or 0, window.DockOrder or -1, B(window.DockIsActive), B(window.DockTabIsVisible)) if window.DockNode or window.DockNodeAsHost then ImGui.DebugNodeDockNode(window.DockNodeAsHost or window.DockNode, window.DockNodeAsHost and "DockNodeAsHost" or "DockNode") end if window.RootWindow ~= window then ImGui.DebugNodeWindow(window.RootWindow, "RootWindow") end if window.RootWindowDockTree and window.RootWindowDockTree ~= window.RootWindow then ImGui.DebugNodeWindow(window.RootWindowDockTree, "RootWindowDockTree") end if window.ParentWindow ~= nil then ImGui.DebugNodeWindow(window.ParentWindow, "ParentWindow") end if window.ParentWindowForFocusRoute ~= nil then ImGui.DebugNodeWindow(window.ParentWindowForFocusRoute, "ParentWindowForFocusRoute") end if window.DC.ChildWindows.Size > 0 then ImGui.DebugNodeWindowsList(window.DC.ChildWindows, "ChildWindows") end if window.ColumnsStorage.Size > 0 and ImGui.TreeNode("Columns", "Columns sets (%d)", window.ColumnsStorage.Size) then for _, columns in window.ColumnsStorage:iter() do ImGui.DebugNodeColumns(columns) end ImGui.TreePop() end ImGui.DebugNodeStorage(window.StateStorage, "Storage") ImGui.TreePop() end function ImGui.DebugNodeWindowSettings(settings) if settings.WantDelete then ImGui.BeginDisabled() end ImGui.BulletText("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", settings.ID, settings.Name or "", settings.Pos.x, settings.Pos.y, settings.Size.x, settings.Size.y, B(settings.Collapsed)) if settings.WantDelete then ImGui.EndDisabled() end end function ImGui.DebugNodeWindowsList(windows, label) if not ImGui.TreeNode(label, "%s (%d)", label, windows.Size) then return end for i = windows.Size, 1, -1 do ImGui.PushID(tostring(windows.Data[i])) ImGui.DebugNodeWindow(windows.Data[i], "Window") ImGui.PopID() end ImGui.TreePop() end function ImGui.DebugNodeWindowsListByBeginStackParent(windows, first, last, parent_in_begin_stack) for i = first, last do local window = windows[i] if window.ParentWindowInBeginStack == parent_in_begin_stack then local buf = string.format("[%04d] Window", window.BeginOrderWithinContext) ImGui.DebugNodeWindow(window, buf) ImGui.TreePush(buf) ImGui.DebugNodeWindowsListByBeginStackParent(windows, i + 1, last, window) ImGui.TreePop() end end end function ImGui.DebugNodeViewport(viewport) local g = ImGui.GetCurrentContext() ImGui.SetNextItemOpen(true, ImGuiCond.Once) local open = ImGui.TreeNode(viewport.ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport.Idx or 0, viewport.ID, viewport.ParentViewportId or 0, viewport.Window and viewport.Window.Name or "N/A") if ImGui.IsItemHovered() then g.DebugMetricsConfig.HighlightViewportID = viewport.ID end if open then ImGui.BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nFrameBufferScale: (%.2f,%.2f)\nWorkArea Inset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%", viewport.Pos.x, viewport.Pos.y, viewport.Size.x, viewport.Size.y, viewport.FramebufferScale and viewport.FramebufferScale.x or 1, viewport.FramebufferScale and viewport.FramebufferScale.y or 1, viewport.WorkInsetMin.x, viewport.WorkInsetMin.y, viewport.WorkInsetMax.x, viewport.WorkInsetMax.y, viewport.PlatformMonitor or 0, (viewport.DpiScale or 1) * 100.0) ImGui.BulletText("Flags: 0x%04X", viewport.Flags or 0) if viewport.DrawDataP then for _, draw_list in viewport.DrawDataP.CmdLists:iter() do ImGui.DebugNodeDrawList(nil, viewport, draw_list, "DrawList") end end ImGui.TreePop() end end function ImGui.DebugTextEncoding(str) ImGui.Text("Text: \"%s\"", str) if not ImGui.BeginTable("##DebugTextEncoding", 4, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.Resizable)) then return end ImGui.TableSetupColumn("Offset") ImGui.TableSetupColumn("UTF-8") ImGui.TableSetupColumn("Glyph") ImGui.TableSetupColumn("Codepoint") ImGui.TableHeadersRow() for pos, c in utf8.codes(str) do local nxt = utf8.offset(str, 2, pos) or (#str + 1) ImGui.TableNextColumn() ImGui.Text("%d", pos - 1) ImGui.TableNextColumn() for b = pos, nxt - 1 do if b > pos then ImGui.SameLine() end ImGui.Text("0x%02X", string.byte(str, b)) end ImGui.TableNextColumn() ImGui.TextUnformatted(string.sub(str, pos, nxt - 1)) ImGui.TableNextColumn() ImGui.Text("U+%04X", c) end ImGui.EndTable() end local WRT_Names = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" } local TRT_Names = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" } local TRT_ColumnsRect = 6 local function GetWindowRect(window, t) if t == 0 then return window:Rect() elseif t == 1 then return window.OuterRectClipped elseif t == 2 then return window.InnerRect elseif t == 3 then return window.InnerClipRect elseif t == 4 then return window.WorkRect elseif t == 5 then local m = window.InnerRect.Min - window.Scroll + window.WindowPadding; return ImRect(m, m + window.ContentSize) elseif t == 6 then local m = window.InnerRect.Min - window.Scroll + window.WindowPadding; return ImRect(m, m + window.ContentSizeIdeal) else return window.ContentRegionRect end end local function GetTableRect(tbl, t, n) local inst = ImGui.TableGetInstanceData(tbl, tbl.InstanceCurrent) if t == 0 then return tbl.OuterRect elseif t == 1 then return tbl.InnerRect elseif t == 2 then return tbl.WorkRect elseif t == 3 then return tbl.HostClipRect elseif t == 4 then return tbl.InnerClipRect elseif t == 5 then return tbl.BgClipRect end local c = tbl.Columns[n] if t == 6 then return ImRect(c.MinX, tbl.InnerClipRect.Min.y, c.MaxX, tbl.InnerClipRect.Min.y + inst.LastOuterHeight) elseif t == 7 then return ImRect(c.WorkMinX, tbl.WorkRect.Min.y, c.WorkMaxX, tbl.WorkRect.Max.y) elseif t == 8 then return c.ClipRect elseif t == 9 then return ImRect(c.WorkMinX, tbl.InnerClipRect.Min.y, c.ContentMaxXHeadersUsed, tbl.InnerClipRect.Min.y + inst.LastTopHeadersRowHeight) elseif t == 10 then return ImRect(c.WorkMinX, tbl.InnerClipRect.Min.y, c.ContentMaxXHeadersIdeal, tbl.InnerClipRect.Min.y + inst.LastTopHeadersRowHeight) elseif t == 11 then return ImRect(c.WorkMinX, tbl.InnerClipRect.Min.y, c.ContentMaxXFrozen, tbl.InnerClipRect.Min.y + inst.LastFrozenHeight) else return ImRect(c.WorkMinX, tbl.InnerClipRect.Min.y + inst.LastFrozenHeight, c.ContentMaxXUnfrozen, tbl.InnerClipRect.Max.y) end end local function ForEachTable(g, fn) for i = 0, g.Tables:GetMapSize() - 1 do local t = g.Tables:GetByIndex(i) if t then fn(t) end end end local MetricsEncodingBuf = nil local MetricsDockRootOnly = true function ImGui.ShowMetricsWindow(p_open) local g = ImGui.GetCurrentContext() local io = g.IO local cfg = g.DebugMetricsConfig if cfg.ShowDebugLog then cfg.ShowDebugLog = ImGui.ShowDebugLogWindow(cfg.ShowDebugLog) end if cfg.ShowIDStackTool then cfg.ShowIDStackTool = ImGui.ShowIDStackToolWindow(cfg.ShowIDStackTool) end local visible p_open, visible = ImGui.Begin("Dear ImGui Metrics/Debugger", p_open) if not visible or ImGui.GetCurrentWindow().BeginCount > 1 then ImGui.End() return p_open end ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) ImGui.Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / math.max(io.Framerate, 0.0001), io.Framerate) ImGui.Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, math.floor(io.MetricsRenderIndices / 3)) ImGui.Text("%d visible windows, %d current allocations", io.MetricsRenderWindows, g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount) ImGui.Separator() if cfg.ShowWindowsRectsType == nil or cfg.ShowWindowsRectsType < 0 then cfg.ShowWindowsRectsType = 4 end if cfg.ShowTablesRectsType == nil or cfg.ShowTablesRectsType < 0 then cfg.ShowTablesRectsType = 2 end -- Tools if ImGui.TreeNode("Tools") then ImGui.SeparatorText("Visualize") _, cfg.ShowDebugLog = ImGui.Checkbox("Show Debug Log", cfg.ShowDebugLog == true) ImGui.SameLine(); MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code.") _, cfg.ShowIDStackTool = ImGui.Checkbox("Show ID Stack Tool", cfg.ShowIDStackTool == true) ImGui.SameLine(); MetricsHelpMarker("You can also call ImGui::ShowIDStackToolWindow() from your code.") _, cfg.ShowWindowsBeginOrder = ImGui.Checkbox("Show windows begin order", cfg.ShowWindowsBeginOrder == true) _, cfg.ShowWindowsRects = ImGui.Checkbox("Show windows rectangles", cfg.ShowWindowsRects == true) ImGui.SameLine() ImGui.SetNextItemWidth(ImGui.GetFontSize() * 12) local changed cfg.ShowWindowsRectsType, changed = ImGui.Combo("##show_windows_rect_type", cfg.ShowWindowsRectsType, WRT_Names, #WRT_Names, #WRT_Names) cfg.ShowWindowsRects = cfg.ShowWindowsRects or changed if cfg.ShowWindowsRects and g.NavWindow ~= nil then ImGui.BulletText("'%s':", g.NavWindow.Name) ImGui.Indent() for rect_n = 0, #WRT_Names - 1 do local r = GetWindowRect(g.NavWindow, rect_n) ImGui.Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r:GetWidth(), r:GetHeight(), WRT_Names[rect_n + 1]) end ImGui.Unindent() end _, cfg.ShowTablesRects = ImGui.Checkbox("Show tables rectangles", cfg.ShowTablesRects == true) ImGui.SameLine() ImGui.SetNextItemWidth(ImGui.GetFontSize() * 12) cfg.ShowTablesRectsType, changed = ImGui.Combo("##show_table_rects_type", cfg.ShowTablesRectsType, TRT_Names, #TRT_Names, #TRT_Names) cfg.ShowTablesRects = cfg.ShowTablesRects or changed _, g.DebugShowGroupRects = ImGui.Checkbox("Show groups rectangles", g.DebugShowGroupRects == true) ImGui.SeparatorText("Validate") _, io.ConfigDebugBeginReturnValueLoop = ImGui.Checkbox("Debug Begin/BeginChild return value", io.ConfigDebugBeginReturnValueLoop == true) ImGui.SameLine(); MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") _, cfg.ShowTextEncodingViewer = ImGui.Checkbox("UTF-8 Encoding viewer", cfg.ShowTextEncodingViewer == true) ImGui.SameLine(); MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.") if cfg.ShowTextEncodingViewer then MetricsEncodingBuf = MetricsEncodingBuf or DemoBuf("", 64) ImGui.SetNextItemWidth(-FLT_MIN) ImGui.InputText("##DebugTextEncodingBuf", MetricsEncodingBuf, 64) local str = DemoBufStr(MetricsEncodingBuf) if str ~= "" then ImGui.DebugTextEncoding(str) end end ImGui.TreePop() end -- Windows if ImGui.TreeNode("Windows", "Windows (%d)", g.Windows.Size) then ImGui.DebugNodeWindowsList(g.Windows, "By display order") ImGui.DebugNodeWindowsList(g.WindowsFocusOrder, "By focus order (root windows)") if ImGui.TreeNode("By submission order (begin stack)") then local tmp = {} for _, window in g.Windows:iter() do if window.LastFrameActive + 1 >= g.FrameCount then tmp[#tmp + 1] = window end end table.sort(tmp, function(a, b) return a.BeginOrderWithinContext < b.BeginOrderWithinContext end) ImGui.DebugNodeWindowsListByBeginStackParent(tmp, 1, #tmp, nil) ImGui.TreePop() end ImGui.TreePop() end -- DrawLists local drawlist_count = 0 for _, viewport in g.Viewports:iter() do drawlist_count = drawlist_count + viewport.DrawDataP.CmdLists.Size end if ImGui.TreeNode("DrawLists", "DrawLists (%d)", drawlist_count) then _, cfg.ShowDrawCmdMesh = ImGui.Checkbox("Show ImDrawCmd mesh when hovering", cfg.ShowDrawCmdMesh ~= false) _, cfg.ShowDrawCmdBoundingBoxes = ImGui.Checkbox("Show ImDrawCmd bounding boxes when hovering", cfg.ShowDrawCmdBoundingBoxes ~= false) for _, viewport in g.Viewports:iter() do local has = false for _, draw_list in viewport.DrawDataP.CmdLists:iter() do if not has then ImGui.Text("Active DrawLists in Viewport #%d, ID: 0x%08X", viewport.Idx or 0, viewport.ID) end has = true ImGui.DebugNodeDrawList(nil, viewport, draw_list, "DrawList") end end ImGui.TreePop() end -- Viewports if ImGui.TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size) then ImGui.SetNextItemOpen(true, ImGuiCond.Once) if ImGui.TreeNode("Windows Minimap") then ImGui.RenderViewportsThumbnails() ImGui.TreePop() end cfg.HighlightViewportID = 0 for _, viewport in g.Viewports:iter() do ImGui.DebugNodeViewport(viewport) end ImGui.TreePop() end -- Fonts for i, atlas in g.FontAtlases:iter() do if ImGui.TreeNode(tostring(atlas), "Fonts (%d), Textures (%d)", atlas.Fonts.Size, atlas.TexList.Size) then ImGui.ShowFontAtlas(atlas) ImGui.TreePop() end end -- Popups if ImGui.TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size) then for _, popup_data in g.OpenPopupStack:iter() do local window = popup_data.Window local W = ImGuiWindowFlags ImGui.BulletText("PopupID: %08x, Window: '%s' (%s%s), RestoreNavWindow '%s', ParentWindow '%s'", popup_data.PopupId, window and window.Name or "NULL", (window and bit32.band(window.Flags, W.ChildWindow) ~= 0) and "Child;" or "", (window and bit32.band(window.Flags, W.ChildMenu) ~= 0) and "Menu;" or "", popup_data.RestoreNavWindow and popup_data.RestoreNavWindow.Name or "NULL", (window and window.ParentWindow) and window.ParentWindow.Name or "NULL") end ImGui.TreePop() end -- TabBars if ImGui.TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.AliveCount) then for n = 0, g.TabBars:GetMapSize() - 1 do local tab_bar = g.TabBars:GetByIndex(n) if tab_bar then ImGui.PushID(n) ImGui.DebugNodeTabBar(tab_bar, "TabBar") ImGui.PopID() end end ImGui.TreePop() end -- Tables if ImGui.TreeNode("Tables", "Tables (%d)", g.Tables.AliveCount) then ForEachTable(g, ImGui.DebugNodeTable) ImGui.TreePop() end -- Docking if ImGui.TreeNode("Docking") then local dc = g.DockContext _, MetricsDockRootOnly = ImGui.Checkbox("List root nodes", MetricsDockRootOnly) _, cfg.ShowDockingNodes = ImGui.Checkbox("Ctrl shows window dock info", cfg.ShowDockingNodes == true) if ImGui.SmallButton("Clear nodes") then ImGui.DockContextClearNodes(g, 0, true) end ImGui.SameLine() if ImGui.SmallButton("Rebuild all") then dc.WantFullRebuild = true end local ids = {} for id in pairs(dc.Nodes) do ids[#ids + 1] = id end table.sort(ids) for _, id in ipairs(ids) do local node = dc.Nodes[id] if node and (not MetricsDockRootOnly or node:IsRootNode()) then ImGui.DebugNodeDockNode(node, "Node") end end ImGui.TreePop() end -- Settings if ImGui.TreeNode("Settings") then if ImGui.SmallButton("Clear") then ImGui.ClearIniSettings() end ImGui.SameLine() if ImGui.SmallButton("Save to memory") then ImGui.SaveIniSettingsToMemory() end ImGui.SameLine() ImGui.TextUnformatted(io.IniFilename and ("\"" .. io.IniFilename .. "\"") or "") ImGui.Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer) if ImGui.TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size) then for _, handler in g.SettingsHandlers:iter() do ImGui.BulletText("\"%s\"", handler.TypeName) end ImGui.TreePop() end if ImGui.TreeNode("SettingsWindows", "Settings packed data: Windows: %d entries", g.SettingsWindows.Size) then for _, settings in g.SettingsWindows:iter() do ImGui.DebugNodeWindowSettings(settings) end ImGui.TreePop() end if ImGui.TreeNode("SettingsTables", "Settings packed data: Tables: %d entries", g.SettingsTables.Size) then for _, settings in g.SettingsTables:iter() do ImGui.DebugNodeTableSettings(settings, nil) end ImGui.TreePop() end if ImGui.TreeNode("SettingsDocking", "Settings packed data: Docking") then local dc = g.DockContext ImGui.Text("In SettingsWindows:") for _, settings in g.SettingsWindows:iter() do if (settings.DockId or 0) ~= 0 then ImGui.BulletText("Window '%s' -> DockId %08X DockOrder=%d", settings.Name or "", settings.DockId, settings.DockOrder or -1) end end ImGui.Text("In SettingsNodes:") for _, settings in dc.NodesSettings:iter() do local selected_tab_name = nil if (settings.SelectedTabId or 0) ~= 0 then local window = ImGui.FindWindowByID(settings.SelectedTabId) selected_tab_name = window and window.Name or nil end ImGui.BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings.ID, settings.ParentNodeId or 0, settings.SelectedTabId or 0, selected_tab_name or ((settings.SelectedTabId or 0) ~= 0 and "N/A" or "")) end ImGui.TreePop() end local ini = g.SettingsIniData or "" if ImGui.TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", #ini) then ImGui.InputTextMultiline("##Ini", DemoBuf(ini, #ini + 1), #ini + 1, ImVec2(-FLT_MIN, ImGui.GetTextLineHeight() * 20), ImGuiInputTextFlags.ReadOnly) ImGui.TreePop() end ImGui.TreePop() end -- Inputs if ImGui.TreeNode("Inputs") then ImGui.Text("KEYBOARD/GAMEPAD/MOUSE KEYS") ImGui.Indent() ImGui.Text("Keys down:") for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do if ImGui.IsKeyDown(key) then ImGui.SameLine(); ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) end end ImGui.Text("Keys pressed:") for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do if ImGui.IsKeyPressed(key) then ImGui.SameLine(); ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) end end ImGui.Text("Keys released:") for key = ImGuiKey.NamedKey_BEGIN, ImGuiKey.NamedKey_END - 1 do if ImGui.IsKeyReleased(key) then ImGui.SameLine(); ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) end 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.Unindent() ImGui.Text("MOUSE STATE") ImGui.Indent() 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 ImGui.Text("Mouse clicked:") for i = 0, 2 do if ImGui.IsMouseClicked(i) then ImGui.SameLine(); ImGui.Text("b%d (%d)", i, io.MouseClickedCount[i]) end end ImGui.Text("Mouse released:") for i = 0, 2 do if ImGui.IsMouseReleased(i) then ImGui.SameLine(); ImGui.Text("b%d", i) end end ImGui.Text("Mouse wheel: %.1f", io.MouseWheel) ImGui.Text("MouseStationaryTimer: %.2f", g.MouseStationaryTimer) ImGui.Unindent() ImGui.Text("MOUSE WHEELING") ImGui.Indent() ImGui.Text("WheelingWindow: '%s'", g.WheelingWindow and g.WheelingWindow.Name or "NULL") ImGui.Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer or 0) ImGui.Text("WheelingAxisAvg[] = { %.3f, %.3f }", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y) ImGui.Unindent() ImGui.TreePop() end -- Internal state if ImGui.TreeNode("Internal state") then local function N(w) return w and w.Name or "NULL" end ImGui.Text("WINDOWING") ImGui.Indent() ImGui.Text("HoveredWindow: '%s'", N(g.HoveredWindow)) ImGui.Text("HoveredWindow->Root: '%s'", g.HoveredWindow and N(g.HoveredWindow.RootWindowDockTree) or "NULL") ImGui.Text("HoveredWindowUnderMovingWindow: '%s'", N(g.HoveredWindowUnderMovingWindow)) ImGui.Text("HoveredDockNode: 0x%08X", g.DebugHoveredDockNode and g.DebugHoveredDockNode.ID or 0) ImGui.Text("MovingWindow: '%s'", N(g.MovingWindow)) ImGui.Unindent() ImGui.Text("ITEMS") ImGui.Indent() ImGui.Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, B(g.ActiveIdAllowOverlap)) ImGui.Text("ActiveIdWindow: '%s'", N(g.ActiveIdWindow)) ImGui.Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, B(g.HoveredIdAllowOverlap)) ImGui.Text("HoverItemDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverItemDelayId or 0, g.HoverItemDelayTimer or 0, g.HoverItemDelayClearTimer or 0) ImGui.Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\"", B(g.DragDropActive), g.DragDropPayload.SourceId or 0, tostring(g.DragDropPayload.DataType or "")) ImGui.Unindent() ImGui.Text("NAV,FOCUS") ImGui.Indent() ImGui.Text("NavWindow: '%s'", N(g.NavWindow)) ImGui.Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer) ImGui.Text("NavActive: %d, NavVisible: %d", B(io.NavActive), B(io.NavVisible)) ImGui.Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId or 0, g.NavActivatePressedId or 0) ImGui.Text("NavActivateFlags: %04X", g.NavActivateFlags or 0) ImGui.Text("NavCursorVisible: %d, NavHighlightItemUnderNav: %d", B(g.NavCursorVisible), B(g.NavHighlightItemUnderNav)) ImGui.Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId or 0) ImGui.Text("NavWindowingTarget: '%s'", N(g.NavWindowingTarget)) ImGui.Unindent() ImGui.TreePop() end -- Overlays if cfg.ShowWindowsRects or cfg.ShowWindowsBeginOrder then for _, window in g.Windows:iter() do if window.WasActive then local draw_list = FG(window) if cfg.ShowWindowsRects then local r = GetWindowRect(window, cfg.ShowWindowsRectsType) draw_list:AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)) end if cfg.ShowWindowsBeginOrder and bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) == 0 then local font_size = ImGui.GetFontSize() draw_list:AddRectFilled(window.Pos, window.Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)) draw_list:AddText(window.Pos, IM_COL32(255, 255, 255, 255), tostring(window.BeginOrderWithinContext)) end end end end if cfg.ShowTablesRects then ForEachTable(g, function(tbl) if tbl.LastFrameActive < g.FrameCount - 1 then return end local draw_list = FG(tbl.OuterWindow) if cfg.ShowTablesRectsType >= TRT_ColumnsRect then for column_n = 0, tbl.ColumnsCount - 1 do local r = GetTableRect(tbl, cfg.ShowTablesRectsType, column_n) local hot = (tbl.HoveredColumnBody == column_n) draw_list:AddRect(r.Min, r.Max, hot and IM_COL32(255, 255, 128, 255) or IM_COL32(255, 0, 128, 255), 0.0, hot and 3.0 or 1.0) end else local r = GetTableRect(tbl, cfg.ShowTablesRectsType, -1) draw_list:AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)) end end) end ImGui.End() return p_open end end --[[ [SECTION] METRICS/DEBUGGER WINDOW, DEBUG LOG, ID STACK TOOL, FONT DEBUG ]] return true -- [Roblox] ModuleScripts must return exactly one value 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 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): local _ ---------------------------------------------------------------- -- Shared helpers (globals) ---------------------------------------------------------------- function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here --- Helper to display a little (?) mark which shows a tooltip when hovered. function HelpMarker(desc) ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0) ImGui.TextUnformatted(desc) ImGui.PopTextWrapPos() ImGui.EndTooltip() end end function ShowDockingDisabledMessage() local io = ImGui.GetIO() ImGui.Text("ERROR: Docking is not enabled! See Demo > Configuration.") ImGui.Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ") ImGui.SameLine(0.0, 0.0) if ImGui.SmallButton("click here") then io.ConfigFlags = bit32.bor(io.ConfigFlags, ImGuiConfigFlags.DockingEnable) 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 --- `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 ---------------------------------------------------------------- -- [SECTION] Demo Window data ---------------------------------------------------------------- --- Data to be shared across different functions of the demo. function ImGuiDemoWindowData() return { -- Examples Apps (accessible from the "Examples" menu) ShowMainMenuBar = false, ShowAppAssetsBrowser = false, ShowAppConsole = false, ShowAppCustomRendering = false, ShowAppDocuments = false, ShowAppDockSpace = false, ShowAppImageViewer = false, ShowAppLog = false, ShowAppLayout = false, ShowAppPropertyEditor = false, ShowAppSimpleOverlay = false, ShowAppAutoResize = false, ShowAppConstrainedResize = false, ShowAppFullscreen = false, ShowAppLongText = false, ShowAppWindowTitles = false, -- Dear ImGui Tools (accessible from the "Tools" menu) ShowMetrics = false, ShowDebugLog = false, ShowIDStackTool = false, ShowStyleEditor = false, ShowAbout = false, -- Other data DisableSections = false, LiveEditOverride = false, LiveEditFlags = ImGuiItemFlags.LiveEditOnInputText or 0, DemoTree = nil, } end ---------------------------------------------------------------- -- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) ---------------------------------------------------------------- function ExampleTreeNode() return { -- Tree structure Name = "", UID = 0, Parent = nil, Childs = {}, -- 1-based IndexInParent = 0, -- 0-based -- Leaf Data HasData = false, -- All leaves have data DataMyBool = true, DataMyInt = 128, DataMyVec2 = ImVec2(0.0, 3.141592), } end function ExampleTree_CreateNode(name, uid, parent) local node = ExampleTreeNode() node.Name = string.sub(name, 1, 27) node.UID = uid node.Parent = parent node.IndexInParent = parent and #parent.Childs or 0 if parent then parent.Childs[#parent.Childs + 1] = node end return node end function ExampleTree_DestroyNode(node) end -- GC --- Create example tree data function ExampleTree_CreateDemoTree() local ROOT_ITEMS_COUNT = 20 local category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" } local category_count = #category_names 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[idx_L0 // (ROOT_ITEMS_COUNT // category_count) + 1], idx_L0 % (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 uid = uid + 1 local node_L2 = ExampleTree_CreateNode(string.format("Child %d", idx_L1), uid, node_L1) node_L2.HasData = true if idx_L1 == 0 then uid = uid + 1 local node_L3 = ExampleTree_CreateNode(string.format("Sub-child %d", 0), uid, node_L2) node_L3.HasData = true end end end return node_L0 end ---------------------------------------------------------------- -- [SECTION] Helpers: ExampleImageViewer ---------------------------------------------------------------- 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, } end function ExampleImageViewer_DrawOptions(data) ImGui.SetNextItemShortcut(ImGuiKey.G, ImGuiInputFlags.Tooltip) _, data.GridEnabled = ImGui.Checkbox("Grid", data.GridEnabled) ImGui.SameLine() ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10.0) local zoom_100 = data.Zoom * 100.0 local changed zoom_100, changed = ImGui.DragFloat("##Zoom", zoom_100, 5.0, data.ZoomMin * 100.0, data.ZoomMax * 100.0, "%.0f%%", ImGuiSliderFlags.AlwaysClamp) if changed then data.Zoom = zoom_100 / 100.0 end end function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w, image_h) local io = ImGui.GetIO() local platform_io = ImGui.GetPlatformIO() local draw_list = ImGui.GetWindowDrawList() IM_ASSERT(canvas_size.x >= 0.0 and canvas_size.y >= 0.0) -- Layout canvas ImGui.InvisibleButton("##Canvas", canvas_size) local canvas_min = ImGui.GetItemRectMin() local canvas_max = ImGui.GetItemRectMax() if data.ViewReset then data.ViewOffset = ImVec2((canvas_size.x * 0.5 / data.Zoom) - 0.5, (canvas_size.y * 0.5 / data.Zoom) - 0.5) -- Add half a pixel padding end data.ViewReset = false -- 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) end end local zoom = data.Zoom if ImGui.IsItemActive() and ImGui.IsMouseDragging(0) then data.ViewOffset.x = data.ViewOffset.x - io.MouseDelta.x / zoom data.ViewOffset.y = data.ViewOffset.y - io.MouseDelta.y / zoom 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) 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) if platform_io.DrawCallback_SetSamplerNearest ~= nil then draw_list:AddCallback(platform_io.DrawCallback_SetSamplerNearest) end draw_list:AddImage(image_tex_ref, image_min, image_max) if platform_io.DrawCallback_SetSamplerLinear ~= nil then draw_list:AddCallback(ImGui.GetPlatformIO().DrawCallback_SetSamplerLinear) end -- 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 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 draw_list:AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data.GridColor, 1.0) end end draw_list:PopClipRect() end ---------------------------------------------------------------- -- [SECTION] Demo Window / ShowDemoWindow() ---------------------------------------------------------------- local demo_data = ImGuiDemoWindowData() 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.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 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") 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.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 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) 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() 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() end 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.") 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.") ImGui.SeparatorText("Settings") CB("io.ConfigIniSettingsSaveLastUsedDate", "ConfigIniSettingsSaveLastUsedDate") -- 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 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.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. 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) 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.") if ImGui.LogButtons then ImGui.LogButtons() else DemoNotPorted("LogButtons") 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 end end ImGui.TreePop() end end --- Demonstrate most Dear ImGui features (this is big function!) --- @param p_open? bool --- @return bool? p_open function ImGui.ShowDemoWindow(p_open) IM_ASSERT(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") local data = demo_data -- Examples Apps (accessible from the "Examples" menu) if data.ShowMainMenuBar then if ShowExampleAppMainMenuBar then ShowExampleAppMainMenuBar() end 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 -- 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() 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 -- We specify a default position/size in case there's no data in the .ini file. 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 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. 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. -- 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() end 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 of ShowDemoWindow() ImGui.PopItemWidth() ImGui.End() return p_open 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) if not ImGui.CollapsingHeader("Widgets") then return end -- 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 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)) end Sub(DemoWindowWidgetsBasic, "Basic") Sub(DemoWindowWidgetsBullets, "Bullets") Sub(DemoWindowWidgetsCollapsingHeaders, "Collapsing Headers") Sub(DemoWindowWidgetsComboBoxes, "Combo") Sub(DemoWindowWidgetsColorAndPickers, "Color/Picker Widgets") Sub(DemoWindowWidgetsDataTypes, "Data Types") if disable_all then ImGui.EndDisabled() end Sub(DemoWindowWidgetsDisableBlocks, "Disable Blocks", 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") if override_liveedit then ImGui.PopItemFlag() ImGui.PopItemFlag() end if disable_all then ImGui.EndDisabled() 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, ...) 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, 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, 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() end ImGui.SameLine() -- 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() 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 -- 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.") 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) 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) end end ImGui.EndChild() end ImGui.SeparatorText("Misc/Advanced") 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 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 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", 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) 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) 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.Indent() SL.f = ImGui.DragFloat(l2, SL.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. 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") end ImGui.PopID() 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 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 end 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.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 -- 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..") 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") 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() 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 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 for i = 0, 5 do ImGui.BulletText("Item %d..", i) end ImGui.TreePop() 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() end ImGui.AlignTextToFramePadding() local node_open = ImGui.TreeNode("Node##3") ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") if node_open then for i = 0, 5 do ImGui.BulletText("Item %d..", i) end ImGui.TreePop() end -- 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 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) _, SL.show_tree_nodes = ImGui.Checkbox("Tree nodes", SL.show_tree_nodes) _, SL.show_text_wrapped = ImGui.Checkbox("Text wrapped", SL.show_text_wrapped) _, SL.show_columns = ImGui.Checkbox("Columns", SL.show_columns) _, SL.show_tab_bar = ImGui.Checkbox("Tab bar", SL.show_tab_bar) _, SL.show_child = ImGui.Checkbox("Child", SL.show_child) _, 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") 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) 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() end ImGui.Columns(1) else NotPorted("Columns") 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") 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 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]) 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() end if scroll_to_off then ImGui.SetScrollY(SL.scroll_to_off_px) 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) 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 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 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) end end end local scroll_x = ImGui.GetScrollX() local scroll_max_x = ImGui.GetScrollMaxX() ImGui.EndChild() ImGui.SameLine() ImGui.Text("%s\n%.0f/%.0f", hnames[i + 1], scroll_x, scroll_max_x) 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 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) 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("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 BeginChild("scrolling") ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) ImGui.EndChild() end ImGui.Spacing() _, 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() 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 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) 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() end ImGui.Button("Button 1", ImVec2(80, 80)) ImGui.SetCursorScreenPos(button2_pos) ImGui.Button("Button 2", ImVec2(80, 80)) 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 }, } 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 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.") -- Example 1 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 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 ImGui.Text("(2) Or right-click this text") ImGui.OpenPopupOnItemClick("my popup", ImGuiPopupFlags.MouseButtonRight) if ImGui.Button("(3) Or click this button") then ImGui.OpenPopup("my popup") end end -- Example 3 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() 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 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() if not ImGui.CollapsingHeader("Popups & Modal windows") then return end if ImGui.TreeNode("Popups") then DemoWindowPopups_Popups(); ImGui.TreePop() end if ImGui.TreeNode("Context menus") then DemoWindowPopups_ContextMenus(); ImGui.TreePop() end if ImGui.TreeNode("Modals") then if ImGui.BeginPopupModal then DemoWindowPopups_Modals() else NotPorted("BeginPopupModal") end ImGui.TreePop() end if ImGui.TreeNode("Menus inside a regular window") then IMGUI_DEMO_MARKER("Popups/Menus inside a regular window") ImGui.TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!") ImGui.Separator() ImGui.MenuItem("Menu item", "Ctrl+M") if ImGui.BeginMenu("Menu inside a regular window") then DemoMenuFile() ImGui.EndMenu() end ImGui.Separator() ImGui.TreePop() end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowTables() ------------------------------------------------------------------------------- -- MyItemColumnID local MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Action, MyItemColumnID_Quantity, MyItemColumnID_Description = 0, 1, 2, 3, 4 local 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 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 end 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) end end -- Make the UI compact because there are so many fields local 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() ImGui.PopStyleVar(2) end local table_sizing_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." }, } 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 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 "" 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) end end ImGui.EndCombo() end ImGui.SameLine() ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 50.0) for m = 1, #policies do ImGui.Separator() ImGui.Text("%s:", policies[m].Name) ImGui.Separator() ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().IndentSpacing * 0.5) ImGui.TextUnformatted(policies[m].Tooltip) end ImGui.PopTextWrapPos() ImGui.EndTooltip() end return 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 end local 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 }) local ST = {} -- statics for DemoWindowTables (one sub-table per section) local TEXT_BASE_WIDTH, TEXT_BASE_HEIGHT = 0, 0 local function Tables_Basic() IMGUI_DEMO_MARKER("Tables/Basic") -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. 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() end -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). 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() end -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), 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") 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 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") 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") 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 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 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") 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 } 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 end end ImGui.EndTable() end -- Second example: set style.CellPadding to (0.0) or a custom value. 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]) 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") 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.") 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() 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() end end 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() 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, 2 do ImGui.TableSetColumnIndex(column) ImGui.Text("Hello %d,%d", column, row) end end 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() 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 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") 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 } } 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 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 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 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") 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() 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)) 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 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 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 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 if ST.column_selected == nil then ST.column_selected = { false, false, false } end local column_selected = ST.column_selected 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 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 } 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) 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() end end ImGui.PopID() end ImGui.EndTable() end end 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 PushStyleCompact() _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, TF.ContextMenuInBody) PopStyleCompact() 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 end ImGui.EndTable() end 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") -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. ImGui.TableHeadersRow() for row = 0, 3 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 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() end ImGui.EndTable() ImGui.Text("Hovered column: %d", hovered_column) end end 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.") 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") 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 end 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") 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 end local items = s.items 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() if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then local CF = ImGuiTableColumnFlags 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() -- 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 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() 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) 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 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 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 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 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 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 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).") 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 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 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 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 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 -- 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)) else table.insert(selection, 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(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 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 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 end local DCS = { selected = -1, h_borders = true, v_borders = true, columns_count = 4, foo = 1.0, bar = 1.0 } local function 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!") if not open then return end -- Basic columns 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.Separator() for n = 0, 13 do local label = string.format("Item %d", n) if ImGui.Selectable(label) then end ImGui.NextColumn() end ImGui.Columns(1) ImGui.Separator() ImGui.Text("With border:") ImGui.Columns(4, "mycolumns") -- 4-ways, with border ImGui.Separator() ImGui.Text("ID"); ImGui.NextColumn() ImGui.Text("Name"); ImGui.NextColumn() ImGui.Text("Path"); ImGui.NextColumn() ImGui.Text("Hovered"); ImGui.NextColumn() ImGui.Separator() local names = { "One", "Two", "Three" } 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 end local hovered = ImGui.IsItemHovered() ImGui.NextColumn() ImGui.Text(names[i + 1]); ImGui.NextColumn() ImGui.Text(paths[i + 1]); ImGui.NextColumn() ImGui.Text("%d", hovered and 1 or 0); ImGui.NextColumn() end ImGui.Columns(1) ImGui.Separator() ImGui.TreePop() end if ImGui.TreeNode("Borders") then IMGUI_DEMO_MARKER("Columns (legacy API)/Borders") -- 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 end ImGui.SameLine() _, DCS.h_borders = ImGui.Checkbox("horizontal", DCS.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 ImGui.Separator() end ImGui.PushID(i) local c = string.char(string.byte("a") + i) ImGui.Text("%s%s%s", c, c, c) ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) ImGui.Text("Offset %.2f", ImGui.GetColumnOffset()) ImGui.Text("Long text that is likely to clip") ImGui.Button("Button", ImVec2(-FLT_MIN, 0.0)) ImGui.PopID() ImGui.NextColumn() end ImGui.Columns(1) if DCS.h_borders then ImGui.Separator() end ImGui.TreePop() end -- Create multiple items in a same cell before switching to next column if ImGui.TreeNode("Mixed items") then IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items") ImGui.Columns(3, "mixed") ImGui.Separator() ImGui.Text("Hello") ImGui.Button("Banana") ImGui.NextColumn() ImGui.Text("ImGui") ImGui.Button("Apple") DCS.foo = ImGui.InputFloat("red", DCS.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") ImGui.NextColumn() if ImGui.CollapsingHeader("Category A") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() if ImGui.CollapsingHeader("Category B") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() if ImGui.CollapsingHeader("Category C") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() ImGui.Columns(1) ImGui.Separator() ImGui.TreePop() end -- Word wrapping if ImGui.TreeNode("Word-wrapping") then IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping") ImGui.Columns(2, "word-wrapping") ImGui.Separator() ImGui.TextWrapped("The quick brown fox jumps over the lazy dog.") ImGui.TextWrapped("Hello Left") ImGui.NextColumn() ImGui.TextWrapped("The quick brown fox jumps over the lazy dog.") ImGui.TextWrapped("Hello Right") ImGui.Columns(1) ImGui.Separator() ImGui.TreePop() end if ImGui.TreeNode("Horizontal Scrolling") then IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling") ImGui.SetNextWindowContentSize(ImVec2(1500.0, 0.0)) local child_size = ImVec2(0, ImGui.GetFontSize() * 20.0) ImGui.BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags.None, ImGuiWindowFlags.HorizontalScrollbar) ImGui.Columns(10) -- Also demonstrate using clipper for large vertical lists local ITEMS_COUNT = 2000 local clipper = ImGuiListClipper() clipper:Begin(ITEMS_COUNT) while clipper:Step() do for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do for j = 0, 9 do ImGui.Text("Line %d Column %d...", i, j) ImGui.NextColumn() end end end ImGui.Columns(1) ImGui.EndChild() ImGui.TreePop() end if ImGui.TreeNode("Tree") then IMGUI_DEMO_MARKER("Columns (legacy API)/Tree") ImGui.Columns(2, "tree", true) for x = 0, 2 do local open1 = ImGui.TreeNode(x, "Node%d", x) ImGui.NextColumn() ImGui.Text("Node contents") ImGui.NextColumn() if open1 then for y = 0, 2 do local open2 = ImGui.TreeNode(y, "Node%d.%d", x, y) ImGui.NextColumn() ImGui.Text("Node contents") if open2 then ImGui.Text("Even more contents") if ImGui.TreeNode("Tree in column") then ImGui.Text("The quick brown fox jumps over the lazy dog") ImGui.TreePop() end end ImGui.NextColumn() if open2 then ImGui.TreePop() end end ImGui.TreePop() end end ImGui.Columns(1) ImGui.TreePop() end 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 }, } function DemoWindowTables() if not ImGui.CollapsingHeader("Tables & Columns") then return 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() 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 -- Demos for _, sec in ipairs(tables_sections) do if open_action ~= -1 then ImGui.SetNextItemOpen(open_action ~= 0) end if ImGui.TreeNode(sec[1]) then sec[2]() ImGui.TreePop() end end ImGui.PopID() DemoWindowColumns() if disable_indent then ImGui.PopStyleVar() 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 local function BufSet(buf, str) for i = 1, #str do buf[i] = string.byte(str, i) end buf[#str + 1] = 0 end ---------------------------------------------------------------- -- [SECTION] Example App: Debug Console / ShowExampleAppConsole() ---------------------------------------------------------------- local Console = nil local function ConsoleNew() 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, ...) 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.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 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 self.ScrollToBottom = true end function c:TextEditCallback(data) if data.EventFlag == ImGuiInputTextFlags.CallbackCompletion then -- 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 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 self:AddLog("No match for \"%s\"!\n", word) elseif #candidates == 1 then data:DeleteChars(word_start, word_end - word_start) data:InsertChars(data.CursorPos, candidates[1]) data:InsertChars(data.CursorPos, " ") else 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 self:AddLog("Possible matches:\n") for i = 1, #candidates do self:AddLog("- %s\n", candidates[i]) end end elseif data.EventFlag == ImGuiInputTextFlags.CallbackHistory then 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 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 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.") 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") ImGui.Separator() if ImGui.BeginPopup("Options") then _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) ImGui.EndPopup() end 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() 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 ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(4, 1)) if copy_to_clipboard then ImGui.LogToClipboard() end for _, item in ipairs(self.Items) do if self.Filter:PassFilter(item) then 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 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() 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 ImGui.SetItemDefaultFocus() if reclaim_focus then ImGui.SetKeyboardFocusHere(-1) end ImGui.End() return p_open end c:AddLog("Welcome to Dear ImGui!") return c end function ShowExampleAppConsole(p_open) Console = Console or ConsoleNew() return Console:Draw("Example: Console", p_open) end ---------------------------------------------------------------- -- [SECTION] Example App: Debug Log / ShowExampleAppLog() ---------------------------------------------------------------- -- Lines are stored as a Lua array (equivalent of Buf + LineOffsets) local function ExampleAppLog() local l = { Lines = { "" }, Filter = ImGuiTextFilter(), AutoScroll = true } 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 end 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 if ImGui.BeginPopup("Options") then _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) ImGui.EndPopup() end 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 for line_no = 1, #lines do if self.Filter:PassFilter(lines[line_no]) then ImGui.TextUnformatted(lines[line_no]) end end else 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 if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then ImGui.SetScrollHereY(1.0) end end ImGui.EndChild() ImGui.End() return p_open end return l end local AppLog, AppLogCounter = nil, 0 function ShowExampleAppLog(p_open) AppLog = AppLog or ExampleAppLog() ImGui.SetNextWindowSize(ImVec2(500, 400), ImGuiCond.FirstUseEver) p_open = ImGui.Begin("Example: Log", p_open) 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 end end ImGui.End() return AppLog:Draw("Example: Log", p_open) end ---------------------------------------------------------------- -- [SECTION] Example App: Simple Layout / ShowExampleAppLayout() ---------------------------------------------------------------- local LayoutSelected = 0 function ShowExampleAppLayout(p_open) ImGui.SetNextWindowSize(ImVec2(500, 440), ImGuiCond.FirstUseEver) local visible p_open, visible = ImGui.Begin("Example: Simple layout", p_open, ImGuiWindowFlags.MenuBar) if visible then if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then if ImGui.MenuItem("Close", "Ctrl+W") then p_open = false end ImGui.EndMenu() end ImGui.EndMenuBar() end 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 end ImGui.EndChild() ImGui.SameLine() ImGui.BeginGroup() ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) 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() end if ImGui.BeginTabItem("Details") then ImGui.Text("ID: 0123456789") ImGui.EndTabItem() end ImGui.EndTabBar() 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 end ---------------------------------------------------------------- -- [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() ---------------------------------------------------------------- -- 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" }) } function PropEd:IsNodePassingFilter(node) return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) end function PropEd:DrawTreeNode(node) local TN = ImGuiTreeNodeFlags ImGui.TableNextRow() ImGui.TableNextColumn() 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 if #node.Childs == 0 then tree_flags = bit32.bor(tree_flags, TN.Leaf, TN.Bullet, TN.NoTreePushOnOpen) end if node.DataMyBool == false then ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetStyle().Colors[ImGuiCol.TextDisabled]) end ImGui.SetNextItemStorageID(node.UID) 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 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 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 if is_open then return node.Childs[1] end end 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 function PropEd:DrawClippedTree(root_node) local node = root_node.Childs[1] 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 while node ~= nil do node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) end clipper:SeekCursorForItem(clipper.UserIndex) end function PropEd:Draw(root_node) self.Filter = self.Filter or ImGuiTextFilter() if ImGui.BeginChild("##tree", ImVec2(300, 0), bit32.bor(ImGuiChildFlags.ResizeX, ImGuiChildFlags.Borders, ImGuiChildFlags.NavFlattened)) then ImGui.PushItemFlag(ImGuiItemFlags.NoNavDefaultFocus, true) _, self.UseClipper = ImGui.Checkbox("Use Clipper", self.UseClipper) ImGui.SameLine() ImGui.Text("(%d root nodes)", #root_node.Childs) ImGui.SetNextItemWidth(-FLT_MIN) ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.F), ImGuiInputFlags.Tooltip) if ImGui.InputTextWithHint("##Filter", "incl -excl", self.Filter.InputBuf, 256, ImGuiInputTextFlags.EscapeClearsAll) then 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 ImGui.EndTable() end end ImGui.EndChild() ImGui.SameLine() ImGui.BeginGroup() local node = self.SelectedNode if node then ImGui.Text("%s", node.Name) ImGui.TextDisabled("UID: 0x%08X", node.UID) ImGui.Separator() if ImGui.BeginTable("##properties", 2, bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.ScrollY)) then ImGui.PushID(node.UID) ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed) ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthStretch, 2.0) if node.HasData then for _, field_desc in ipairs(ExampleTreeNodeMemberInfos) do ImGui.TableNextRow() ImGui.PushID(field_desc.Name) ImGui.TableNextColumn() 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 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 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 end ImGui.PopID() end end ImGui.PopID() ImGui.EndTable() end end ImGui.EndGroup() end local DemoTree = nil function ShowExampleAppPropertyEditor(p_open, demo_data) 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) ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Long Text / ShowExampleAppLongText() ---------------------------------------------------------------- local LT = { test_type = 0, log = {}, lines = 0, bytes = 0 } function ShowExampleAppLongText(p_open) 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 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 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 end LT.lines = LT.lines + 1000 LT.text = nil end ImGui.BeginChild("Log") if LT.test_type == 0 then LT.text = LT.text or table.concat(LT.log) ImGui.TextUnformatted(LT.text) elseif LT.test_type == 1 then ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(0, 0)) local clipper = ImGuiListClipper() clipper:Begin(LT.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 end ImGui.PopStyleVar() else 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 ImGui.PopStyleVar() end ImGui.EndChild() ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() ---------------------------------------------------------------- local AutoResizeLines = 10 function ShowExampleAppAutoResize(p_open) 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 ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() ---------------------------------------------------------------- local CR = { auto_resize = false, window_padding = true, type = 6, display_lines = 10 } function ShowExampleAppConstrainedResize(p_open) 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 t = CR.type if t == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end if t == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)) end if t == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)) end if t == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)) end if t == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end if t == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)) end if t == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), AspectRatio, 16.0 / 9.0) end if t == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), Square) end if t == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), Step, 100.0) end 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 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 window_open then if ImGui.GetIO().KeyShift then local avail_size = ImGui.GetContentRegionAvail() local pos = ImGui.GetCursorScreenPos() ImGui.ColorButton("viewport", ImVec4(0.5, 0.2, 0.5, 1.0), bit32.bor(ImGuiColorEditFlags.NoTooltip, ImGuiColorEditFlags.NoDragDrop), avail_size) ImGui.SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10)) 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.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) 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 end end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() ---------------------------------------------------------------- local OverlayLocation = 0 function ShowExampleAppSimpleOverlay(p_open) 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 PAD = 10.0 local viewport = ImGui.GetMainViewport() local work_pos, work_size = viewport.WorkPos, viewport.WorkSize 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) 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 ImGui.SetNextWindowPos(ImGui.GetMainViewport():GetCenter(), ImGuiCond.Always, ImVec2(0.5, 0.5)) window_flags = bit32.bor(window_flags, W.NoMove) end ImGui.SetNextWindowBgAlpha(0.35) 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.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.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 p_open ~= nil and ImGui.MenuItem("Close") then p_open = false end ImGui.EndPopup() end end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() ---------------------------------------------------------------- local FS = { use_work_area = true, flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings) } function ShowExampleAppFullscreen(p_open) 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) local visible p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, FS.flags) if visible then _, FS.use_work_area = ImGui.Checkbox("Use work area instead of main area", FS.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) 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) ImGui.Unindent() if p_open ~= nil and ImGui.Button("Close this window") then p_open = false end end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() ---------------------------------------------------------------- function ShowExampleAppWindowTitles(p_open) local viewport = ImGui.GetMainViewport() local base_pos = viewport.Pos ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond.FirstUseEver) ImGui.Begin("Same title as another window##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.Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.") ImGui.End() 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()) ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond.FirstUseEver) ImGui.Begin(buf) ImGui.Text("This window has a changing title.") ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() ---------------------------------------------------------------- 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() 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) 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 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) } 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 } } 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 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 draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x = x + step draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding); x = x + step draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br); x = x + step draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step 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) Shape(concave_shape, x, y); draw_list:PathFillConcave(col); x = x + step Shape(zigzag_shape, x, y); draw_list:PathFillConcave(col); x = x + step 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) 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 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 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 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 draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step 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 draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th); x = x + step draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x = x + step draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x = x + step draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step 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) Shape(concave_shape, x, y); draw_list:PathStroke(col, th, ImDrawFlags.Closed); x = x + step Shape(zigzag_shape, x, y); draw_list:PathStroke(col, th, ImDrawFlags.Closed); x = x + step 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) 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 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 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 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.") local canvas_p0 = ImGui.GetCursorScreenPos() local canvas_sz = ImGui.GetContentRegionAvail() 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) 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)) ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(ImGuiButtonFlags.MouseButtonLeft, ImGuiButtonFlags.MouseButtonRight)) local is_hovered = ImGui.IsItemHovered() local is_active = ImGui.IsItemActive() local origin = ImVec2(canvas_p0.x + s.scrolling.x, canvas_p0.y + s.scrolling.y) local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) local points = s.points 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 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 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_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 function ShowExampleAppCustomRendering(p_open) 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 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("BG/FG draw lists") then _, 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_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 ImGui.EndTabItem() end if ImGui.BeginTabItem("Draw Channels") then 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)) draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) ImGui.Dummy(ImVec2(75, 75)) 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() 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)) 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)) draw_list:ChannelsMerge() ImGui.Dummy(ImVec2(75, 75)) ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") ImGui.EndTabItem() end ImGui.EndTabBar() end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() ---------------------------------------------------------------- local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0, opt_demo_mode = 0, opt_demo_mode_changed = false } local function ShowExampleAppDockSpaceAdvanced(args, p_open) local dockspace_flags = args.DockSpaceFlags local W = ImGuiWindowFlags local window_flags = W.NoDocking if args.IsFullscreen then 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) else dockspace_flags = bit32.band(dockspace_flags, bit32.bnot(ImGuiDockNodeFlags.PassthruCentralNode)) 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 args.IsFullscreen then ImGui.PopStyleVar(2) end local dockspace_id = ImGui.GetID("MyDockSpace") ImGui.DockSpace(dockspace_id, ImVec2(0.0, 0.0), dockspace_flags) ImGui.End() return p_open end function ShowExampleAppDockSpace(p_open) local args = DSA if args.opt_demo_mode == 0 then ImGui.DockSpaceOverViewport(0, nil, args.DockSpaceFlags) else p_open = ShowExampleAppDockSpaceAdvanced(args, p_open) end if args.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 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) _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) else _, 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) 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 end 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.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.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()") ImGui.EndMenu() end ImGui.EndMenuBar() end ImGui.End() return p_open end ---------------------------------------------------------------- -- [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() ---------------------------------------------------------------- local 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 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 function app:GetTabName(doc) return string.format("%s###doc%d", doc:Name(), doc.UID) end 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() 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) ImGui.PopID() end 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() end 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 end end return app end function ShowExampleAppDocuments(p_open) Docs = Docs or DocsInit() local app = Docs local Target_Tab, Target_DockSpaceAndWindow = 1, 2 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 ImGui.End() return p_open end 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 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 end if ImGui.MenuItem("Exit") and p_open ~= nil then p_open = false end ImGui.EndMenu() end ImGui.EndMenuBar() end for doc_n, doc in ipairs(app.Documents) do if doc_n > 1 then ImGui.SameLine() end ImGui.PushID("doc" .. doc.UID) local pressed pressed, doc.Open = ImGui.Checkbox(doc:Name(), doc.Open) if pressed and not doc.Open then doc:DoForceClose() end ImGui.PopID() end ImGui.PushItemWidth(ImGui.GetFontSize() * 12) app.opt_target = ImGui.Combo("Output", app.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 ImGui.Separator() 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 ImGui.BeginTabBar("##tabs", tab_bar_flags) then if app.opt_reorderable then app:NotifyOfDocumentsClosedElsewhere() end for _, doc in ipairs(app.Documents) do if doc.Open then local tab_flags = doc.Dirty and ImGuiTabItemFlags.UnsavedDocument or 0 local visible visible, doc.Open = ImGui.BeginTabItem(app:GetTabName(doc), doc.Open, tab_flags) 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 end end ImGui.EndTabBar() end elseif app.opt_target == Target_DockSpaceAndWindow then if bit32.band(ImGui.GetIO().ConfigFlags, ImGuiConfigFlags.DockingEnable) ~= 0 then app:NotifyOfDocumentsClosedElsewhere() local dockspace_id = ImGui.GetID("MyDockSpace") ImGui.DockSpace(dockspace_id) 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) 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() end end else ShowDockingDisabledMessage() end end if not window_contents_visible then ImGui.End() return p_open end if app.RenamingDoc ~= nil then 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 ImGui.CloseCurrentPopup() app.RenamingDoc = nil end if app.RenamingStarted then ImGui.SetKeyboardFocusHere(-1) end ImGui.EndPopup() else app.RenamingDoc = nil end app.RenamingStarted = false end if #app.CloseQueue > 0 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 if close_queue_unsaved_documents == 0 then for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end app.CloseQueue = {} else 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 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 doc:DoForceClose() end app.CloseQueue = {} ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("No", button_size) then for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end app.CloseQueue = {} ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("Cancel", button_size) then app.CloseQueue = {} 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" } 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") 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 ImGui.AlignTextToFramePadding() ImGui.Text("Hold to repeat:") ImGui.SameLine() 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.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) 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) 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) 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.") 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 } 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 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 ImGui.TreePop() end 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:") 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 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() 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 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 if s.display_mode == 2 then flags = bit32.bor(flags, CE.DisplayRGB) end 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 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() 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 S.combo = { flags = 0, sel = 0, filter = nil, c2 = 0, c3 = -1, c4 = 0 } function DemoWindowWidgetsComboBoxes() if not ImGui.TreeNode("Combo") then return end local s = S.combo local CF = ImGuiComboFlags local p _, 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 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 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 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 local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } 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 if is_selected then ImGui.SetItemDefaultFocus() end end ImGui.EndCombo() end 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.") s.c2 = ImGui.Combo("combo 3 (one-liner)", s.c2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") s.c3 = ImGui.Combo("combo 4 (array)", s.c3, items, #items) s.c4 = ImGui.Combo("combo 5 (function)", s.c4, function(data, n) return data[n + 1] end, items, #items) ImGui.TreePop() end 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 -- ponytail: Luau numbers are doubles, so S64/U64 are shown with S32/Double here (no 64-bit integer type) 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 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 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 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)) if ImGui.BeginDragDropSource(ImGuiDragDropFlags.None) then ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) 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 ImGui.PushItemFlag(ImGuiItemFlags.AllowDuplicateId, true) 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 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 if n == 0 then ImGui.ColorButton("drag me", s.col4) end end ImGui.TreePop() end ImGui.TreePop() end 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 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 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) 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) 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) ImGui.TreePop() end function DemoWindowWidgetsFonts() if not ImGui.TreeNode("Fonts") then return end if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end ImGui.TreePop() end 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!") local atlas = io.Fonts local my_tex_id = atlas.TexRef local my_tex_w = atlas.TexData and atlas.TexData.Width or 0 local my_tex_h = atlas.TexData and atlas.TexData.Height or 0 ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) 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)) ImGui.PopStyleVar() 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 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) local uv0 = ImVec2(0.0, 0.0) local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) 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 S.lb = { sel = 0, highlight = false } function DemoWindowWidgetsListBoxes() if not ImGui.TreeNode("List Boxes") then return end 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 _, 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 if is_selected then ImGui.SetItemDefaultFocus() end end ImGui.EndListBox() end ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") 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 if is_selected then ImGui.SetItemDefaultFocus() end end ImGui.EndListBox() end ImGui.TreePop() end 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 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 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] 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() ImGui.SeparatorText("Others Widgets") ImGui.Text("(note: edits are not applied in this demo)") 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) 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 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 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 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) 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)) 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 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 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)) -- 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 S.pb = { accum = 0.0, dir = 1.0 } function DemoWindowWidgetsProgressBars() if not ImGui.TreeNode("Progress Bars") then return end 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) 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)) 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 -- 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 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 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 if t == 1 then ret = ImGui.Button("ITEM: Button") end if t == 2 then ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end if t == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end if t == 4 then s.col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", s.col4f[1], 0.0, 1.0) end if t == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end if t == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end if t == 7 then s.col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", s.col4f[1], 1.0) end if t == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", s.col4f) end if t == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", s.col4f) end if t == 10 then ret = ImGui.Selectable("ITEM: Selectable") end if t == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end if t == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end if t == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.NoTreePushOnOpen)) end 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) 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 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))) 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 _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) if s.test_window then s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) if ImGui.BeginPopupContextItem() then 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 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() if not ImGui.TreeNode("Selectables") then return end local s = S.sel 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 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") 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]) 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 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 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 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 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 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) ImGui.AlignTextToFramePadding() ImGui.Text("Opened:") local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } for n = 1, 4 do ImGui.SameLine() _, s.opened[n] = ImGui.Checkbox(names[n], s.opened[n]) end 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 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 _, 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) s.tib_flags = EditTabBarFittingPolicyFlags(s.tib_flags) if ImGui.BeginTabBar("MyTabBar", s.tib_flags) then 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 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 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 end end 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 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 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) 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.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_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.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 S.tf = { filter = nil } function DemoWindowWidgetsTextFilter() if not ImGui.TreeNode("Text Filter") then return end 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 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 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") local function FilterCasingSwap(data) local c = data.EventChar if c >= a and c <= z then data.EventChar = c - (a - A) elseif c >= A and c <= Z then data.EventChar = c + (a - A) end return 0 end 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) ImGui.InputText("\"imgui\"", f[7], 32, IT.CallbackCharFilter, FilterImGuiLetters) 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 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 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 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 ImGui.SeparatorText("General") 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") _, 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.") 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 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 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 if ImGui.TreeNode("Basic Trees") then for i = 0, 4 do if i == 0 then ImGui.SetNextItemOpen(true, ImGuiCond.Once) end 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.") local node_clicked_idx = -1 for node_n = 0, 5 do 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 if ImGui.GetIO().KeyCtrl then s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) else s.selection_mask = bit32.lshift(1, node_clicked_idx) 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 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 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 node_flags = bit32.bor(node_flags, TN.Leaf, TN.NoTreePushOnOpen) 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 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() ---------------------------------------------------------------- S.menu = { enabled = true, f = 0.5, n = 0, b = true } 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) if ImGui.BeginMenu("Options") then _, s.b = ImGui.Checkbox("SomeOption", s.b) ImGui.EndMenu() end if ImGui.BeginMenu("Disabled", false) then IM_ASSERT(false) end if ImGui.MenuItem("Checked", nil, true) then end ImGui.Separator() if ImGui.MenuItem("Quit", "Alt+F4") then end end 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 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() ---------------------------------------------------------------- -- 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 } function ImGui.ShowStyleSelector(label) 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) local se = S.se local style = ImGui.GetStyle() if se.ref_saved_style == nil then se.ref_saved_style = {} end 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 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) 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 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() style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") if changed then style.GrabRounding = style.FrameRounding end 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 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) 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") _, 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 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 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() 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)) 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") 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() ---------------------------------------------------------------- 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") 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 ImGui.End() return p_open end end --[[ About window ]] return true end __FILES['imgui_draw.lua'] = function() --- Dear ImGui WIP -- (Draw Code) FONT_ATLAS_DEFAULT_TEX_DATA_W = 122 FONT_ATLAS_DEFAULT_TEX_DATA_H = 27 local IM_DRAWLIST_TEX_LINES_WIDTH_MAX = 32 local writef64, writeu32, readf64, readu32 = buffer.writef64, buffer.writeu32, buffer.readf64, buffer.readu32 -- Write vertex i (1-based) of a VtxBuffer.Buf local function WV(b, i, x, y, u, v, col) local o = (i - 1) * 36 writef64(b, o, x); writef64(b, o + 8, y); writef64(b, o + 16, u); writef64(b, o + 24, v); writeu32(b, o + 32, col) end local function WVP(b, i, p, uv, col) WV(b, i, p.x, p.y, uv.x, uv.y, col) end local IM_FONTGLYPH_INDEX_UNUSED = 0xFFFF local IM_FONTGLYPH_INDEX_NOT_FOUND = 0xFFFE --- @param str string --- @return table --- @nodiscard --- @package local function str_to_table(str) local t = {} for i = 1, #str do t[i] = string.sub(str, i, i) end return t end --- @param buf char[] # 1-based --- @param base int # 1-based start index --- @param u32 ImU32 local function write_u32(buf, base, u32) buf[base + 0] = bit32.band(u32, 0xFF) buf[base + 1] = bit32.band(bit32.rshift(u32, 8), 0xFF) buf[base + 2] = bit32.band(bit32.rshift(u32, 16), 0xFF) buf[base + 3] = bit32.band(bit32.rshift(u32, 24), 0xFF) end --- Original ImGui pixel art! local FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS = str_to_table( "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " .. "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" .. "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" .. "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " .. "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " .. "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " .. "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " .. "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " .. "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " .. "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " .. "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " .. "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " .. "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" .. "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" .. "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " .. "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" .. "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " .. "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " .. "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " .. "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " .. " X..X - - X...X - X...X - X..X X..X - - X........X - " .. " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " .. "------------- - X - X -X.....................X- ------------------- " .. " ----------------------------------- X...XXXXXXXXXXXXX...X - " .. " - X..X X..X - " .. " - X.X X.X - " .. " - XX XX - " ) local FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA = { -- Pos .......... Size ......... Offset ....... { ImVec2( 0, 3), ImVec2(12, 19), ImVec2( 0, 0) }, -- ImGuiMouseCursor.Arrow { ImVec2( 13, 0), ImVec2( 7, 16), ImVec2( 1, 8) }, -- ImGuiMouseCursor.TextInput { ImVec2( 31, 0), ImVec2(23, 23), ImVec2(11, 11) }, -- ImGuiMouseCursor.ResizeAll { ImVec2( 21, 0), ImVec2( 9, 23), ImVec2( 4, 11) }, -- ImGuiMouseCursor.ResizeNS { ImVec2( 55, 18), ImVec2(23, 9), ImVec2(11, 4) }, -- ImGuiMouseCursor.ResizeEW { ImVec2( 73, 0), ImVec2(17, 17), ImVec2( 8, 8) }, -- ImGuiMouseCursor.ResizeNESW { ImVec2( 55, 0), ImVec2(17, 17), ImVec2( 8, 8) }, -- ImGuiMouseCursor.ResizeNWSE { ImVec2( 91, 0), ImVec2(17, 22), ImVec2( 5, 0) }, -- ImGuiMouseCursor.Hand { ImVec2( 0, 3), ImVec2(12, 19), ImVec2( 0, 0) }, -- ImGuiMouseCursor.Wait -- Arrow + custom code in ImGui.RenderMouseCursor() { ImVec2( 0, 3), ImVec2(12, 19), ImVec2( 0, 0) }, -- ImGuiMouseCursor.Progress -- Arrow + custom code in ImGui.RenderMouseCursor() { ImVec2(109, 0), ImVec2(13, 15), ImVec2( 6, 7) }, -- ImGuiMouseCursor.NotAllowed } local MT = ImGui.GetMetatables() --- @module "imstb_rectpack" local stbrp = IM_INCLUDE("imstb_rectpack.lua") --- @module "imstb_truetype" local stbtt = IM_INCLUDE("imstb_truetype.lua") --------------------------------------------------------------------------------------- -- [SECTION] STYLE FUNCTIONS --------------------------------------------------------------------------------------- --- @param a ImVec4 --- @param b ImVec4 --- @param t float local function ImLerpV4V4F(a, b, t) return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t) end --- @param dst? ImGuiStyle function ImGui.StyleColorsDark(dst) local style = dst and dst or ImGui.GetStyle() local colors = style.Colors colors[ImGuiCol.Text] = ImVec4(1.00, 1.00, 1.00, 1.00) colors[ImGuiCol.TextDisabled] = ImVec4(0.50, 0.50, 0.50, 1.00) colors[ImGuiCol.WindowBg] = ImVec4(0.06, 0.06, 0.06, 0.94) colors[ImGuiCol.ChildBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.PopupBg] = ImVec4(0.08, 0.08, 0.08, 0.94) colors[ImGuiCol.Border] = ImVec4(0.43, 0.43, 0.50, 0.50) colors[ImGuiCol.BorderShadow] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.FrameBg] = ImVec4(0.16, 0.29, 0.48, 0.54) colors[ImGuiCol.FrameBgHovered] = ImVec4(0.26, 0.59, 0.98, 0.40) colors[ImGuiCol.FrameBgActive] = ImVec4(0.26, 0.59, 0.98, 0.67) colors[ImGuiCol.TitleBg] = ImVec4(0.04, 0.04, 0.04, 1.00) colors[ImGuiCol.TitleBgActive] = ImVec4(0.16, 0.29, 0.48, 1.00) colors[ImGuiCol.TitleBgCollapsed] = ImVec4(0.00, 0.00, 0.00, 0.51) colors[ImGuiCol.MenuBarBg] = ImVec4(0.14, 0.14, 0.14, 1.00) colors[ImGuiCol.ScrollbarBg] = ImVec4(0.02, 0.02, 0.02, 0.53) colors[ImGuiCol.ScrollbarGrab] = ImVec4(0.31, 0.31, 0.31, 1.00) colors[ImGuiCol.ScrollbarGrabHovered] = ImVec4(0.41, 0.41, 0.41, 1.00) colors[ImGuiCol.ScrollbarGrabActive] = ImVec4(0.51, 0.51, 0.51, 1.00) colors[ImGuiCol.CheckMark] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.CheckboxSelectedBg] = ImLerpV4V4F(colors[ImGuiCol.FrameBg], colors[ImGuiCol.FrameBgHovered], 0.65) colors[ImGuiCol.SliderGrab] = ImVec4(0.24, 0.52, 0.88, 1.00) colors[ImGuiCol.SliderGrabActive] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.Button] = ImVec4(0.26, 0.59, 0.98, 0.40) colors[ImGuiCol.ButtonHovered] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.ButtonActive] = ImVec4(0.06, 0.53, 0.98, 1.00) colors[ImGuiCol.Header] = ImVec4(0.26, 0.59, 0.98, 0.31) colors[ImGuiCol.HeaderHovered] = ImVec4(0.26, 0.59, 0.98, 0.80) colors[ImGuiCol.HeaderActive] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.Separator] = colors[ImGuiCol.Border] colors[ImGuiCol.SeparatorHovered] = ImVec4(0.10, 0.40, 0.75, 0.78) colors[ImGuiCol.SeparatorActive] = ImVec4(0.10, 0.40, 0.75, 1.00) colors[ImGuiCol.ResizeGrip] = ImVec4(0.26, 0.59, 0.98, 0.20) colors[ImGuiCol.ResizeGripHovered] = ImVec4(0.26, 0.59, 0.98, 0.67) colors[ImGuiCol.ResizeGripActive] = ImVec4(0.26, 0.59, 0.98, 0.95) colors[ImGuiCol.InputTextCursor] = colors[ImGuiCol.Text] colors[ImGuiCol.TabHovered] = colors[ImGuiCol.HeaderHovered] colors[ImGuiCol.Tab] = ImLerpV4V4F(colors[ImGuiCol.Header], colors[ImGuiCol.TitleBgActive], 0.80) colors[ImGuiCol.TabSelected] = ImLerpV4V4F(colors[ImGuiCol.HeaderActive], colors[ImGuiCol.TitleBgActive], 0.60) colors[ImGuiCol.TabSelectedOverline] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TabDimmed] = ImLerpV4V4F(colors[ImGuiCol.Tab], colors[ImGuiCol.TitleBg], 0.80) colors[ImGuiCol.TabDimmedSelected] = ImLerpV4V4F(colors[ImGuiCol.TabSelected], colors[ImGuiCol.TitleBg], 0.40) colors[ImGuiCol.TabDimmedSelectedOverline] = ImVec4(0.50, 0.50, 0.50, 0.00) colors[ImGuiCol.DockingPreview] = ImVec4(colors[ImGuiCol.HeaderActive].x, colors[ImGuiCol.HeaderActive].y, colors[ImGuiCol.HeaderActive].z, colors[ImGuiCol.HeaderActive].w * 0.7) colors[ImGuiCol.DockingEmptyBg] = ImVec4(0.20, 0.20, 0.20, 1.00) colors[ImGuiCol.PlotLines] = ImVec4(0.61, 0.61, 0.61, 1.00) colors[ImGuiCol.PlotLinesHovered] = ImVec4(1.00, 0.43, 0.35, 1.00) colors[ImGuiCol.PlotHistogram] = ImVec4(0.90, 0.70, 0.00, 1.00) colors[ImGuiCol.PlotHistogramHovered] = ImVec4(1.00, 0.60, 0.00, 1.00) colors[ImGuiCol.TableHeaderBg] = ImVec4(0.19, 0.19, 0.20, 1.00) colors[ImGuiCol.TableBorderStrong] = ImVec4(0.31, 0.31, 0.35, 1.00) colors[ImGuiCol.TableBorderLight] = ImVec4(0.23, 0.23, 0.25, 1.00) colors[ImGuiCol.TableRowBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.TableRowBgAlt] = ImVec4(1.00, 1.00, 1.00, 0.06) colors[ImGuiCol.TextLink] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TextSelectedBg] = ImVec4(0.26, 0.59, 0.98, 0.35) colors[ImGuiCol.TreeLines] = colors[ImGuiCol.Border] colors[ImGuiCol.DragDropTarget] = ImVec4(1.00, 1.00, 0.00, 0.90) colors[ImGuiCol.DragDropTargetBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.UnsavedMarker] = ImVec4(1.00, 1.00, 1.00, 1.00) colors[ImGuiCol.NavCursor] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.NavWindowingHighlight] = ImVec4(1.00, 1.00, 1.00, 0.70) colors[ImGuiCol.NavWindowingDimBg] = ImVec4(0.80, 0.80, 0.80, 0.20) colors[ImGuiCol.ModalWindowDimBg] = ImVec4(0.80, 0.80, 0.80, 0.35) end --- @param dst? ImGuiStyle function ImGui.StyleColorsClassic(dst) local style = dst and dst or ImGui.GetStyle() local colors = style.Colors colors[ImGuiCol.Text] = ImVec4(0.90, 0.90, 0.90, 1.00) colors[ImGuiCol.TextDisabled] = ImVec4(0.60, 0.60, 0.60, 1.00) colors[ImGuiCol.WindowBg] = ImVec4(0.00, 0.00, 0.00, 0.85) colors[ImGuiCol.ChildBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.PopupBg] = ImVec4(0.11, 0.11, 0.14, 0.92) colors[ImGuiCol.Border] = ImVec4(0.50, 0.50, 0.50, 0.50) colors[ImGuiCol.BorderShadow] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.FrameBg] = ImVec4(0.43, 0.43, 0.43, 0.39) colors[ImGuiCol.FrameBgHovered] = ImVec4(0.47, 0.47, 0.69, 0.40) colors[ImGuiCol.FrameBgActive] = ImVec4(0.42, 0.41, 0.64, 0.69) colors[ImGuiCol.TitleBg] = ImVec4(0.27, 0.27, 0.54, 0.83) colors[ImGuiCol.TitleBgActive] = ImVec4(0.32, 0.32, 0.63, 0.87) colors[ImGuiCol.TitleBgCollapsed] = ImVec4(0.40, 0.40, 0.80, 0.20) colors[ImGuiCol.MenuBarBg] = ImVec4(0.40, 0.40, 0.55, 0.80) colors[ImGuiCol.ScrollbarBg] = ImVec4(0.20, 0.25, 0.30, 0.60) colors[ImGuiCol.ScrollbarGrab] = ImVec4(0.40, 0.40, 0.80, 0.30) colors[ImGuiCol.ScrollbarGrabHovered] = ImVec4(0.40, 0.40, 0.80, 0.40) colors[ImGuiCol.ScrollbarGrabActive] = ImVec4(0.41, 0.39, 0.80, 0.60) colors[ImGuiCol.CheckMark] = ImVec4(0.90, 0.90, 0.90, 0.50) colors[ImGuiCol.CheckboxSelectedBg] = ImLerpV4V4F(colors[ImGuiCol.FrameBg], colors[ImGuiCol.FrameBgActive], 0.65) colors[ImGuiCol.SliderGrab] = ImVec4(1.00, 1.00, 1.00, 0.30) colors[ImGuiCol.SliderGrabActive] = ImVec4(0.41, 0.39, 0.80, 0.60) colors[ImGuiCol.Button] = ImVec4(0.35, 0.40, 0.61, 0.62) colors[ImGuiCol.ButtonHovered] = ImVec4(0.40, 0.48, 0.71, 0.79) colors[ImGuiCol.ButtonActive] = ImVec4(0.46, 0.54, 0.80, 1.00) colors[ImGuiCol.Header] = ImVec4(0.40, 0.40, 0.90, 0.45) colors[ImGuiCol.HeaderHovered] = ImVec4(0.45, 0.45, 0.90, 0.80) colors[ImGuiCol.HeaderActive] = ImVec4(0.53, 0.53, 0.87, 0.80) colors[ImGuiCol.Separator] = ImVec4(0.50, 0.50, 0.50, 0.60) colors[ImGuiCol.SeparatorHovered] = ImVec4(0.60, 0.60, 0.70, 1.00) colors[ImGuiCol.SeparatorActive] = ImVec4(0.70, 0.70, 0.90, 1.00) colors[ImGuiCol.ResizeGrip] = ImVec4(1.00, 1.00, 1.00, 0.10) colors[ImGuiCol.ResizeGripHovered] = ImVec4(0.78, 0.82, 1.00, 0.60) colors[ImGuiCol.ResizeGripActive] = ImVec4(0.78, 0.82, 1.00, 0.90) colors[ImGuiCol.InputTextCursor] = colors[ImGuiCol.Text] colors[ImGuiCol.TabHovered] = colors[ImGuiCol.HeaderHovered] colors[ImGuiCol.Tab] = ImLerpV4V4F(colors[ImGuiCol.Header], colors[ImGuiCol.TitleBgActive], 0.80) colors[ImGuiCol.TabSelected] = ImLerpV4V4F(colors[ImGuiCol.HeaderActive], colors[ImGuiCol.TitleBgActive], 0.60) colors[ImGuiCol.TabSelectedOverline] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TabDimmed] = ImLerpV4V4F(colors[ImGuiCol.Tab], colors[ImGuiCol.TitleBg], 0.80) colors[ImGuiCol.TabDimmedSelected] = ImLerpV4V4F(colors[ImGuiCol.TabSelected], colors[ImGuiCol.TitleBg], 0.40) colors[ImGuiCol.TabDimmedSelectedOverline] = ImVec4(0.53, 0.53, 0.87, 0.00) colors[ImGuiCol.DockingPreview] = ImVec4(colors[ImGuiCol.Header].x, colors[ImGuiCol.Header].y, colors[ImGuiCol.Header].z, colors[ImGuiCol.Header].w * 0.7) colors[ImGuiCol.DockingEmptyBg] = ImVec4(0.20, 0.20, 0.20, 1.00) colors[ImGuiCol.PlotLines] = ImVec4(1.00, 1.00, 1.00, 1.00) colors[ImGuiCol.PlotLinesHovered] = ImVec4(0.90, 0.70, 0.00, 1.00) colors[ImGuiCol.PlotHistogram] = ImVec4(0.90, 0.70, 0.00, 1.00) colors[ImGuiCol.PlotHistogramHovered] = ImVec4(1.00, 0.60, 0.00, 1.00) colors[ImGuiCol.TableHeaderBg] = ImVec4(0.27, 0.27, 0.38, 1.00) colors[ImGuiCol.TableBorderStrong] = ImVec4(0.31, 0.31, 0.45, 1.00) colors[ImGuiCol.TableBorderLight] = ImVec4(0.26, 0.26, 0.28, 1.00) colors[ImGuiCol.TableRowBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.TableRowBgAlt] = ImVec4(1.00, 1.00, 1.00, 0.07) colors[ImGuiCol.TextLink] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TextSelectedBg] = ImVec4(0.00, 0.00, 1.00, 0.35) colors[ImGuiCol.TreeLines] = colors[ImGuiCol.Border] colors[ImGuiCol.DragDropTarget] = ImVec4(1.00, 1.00, 0.00, 0.90) colors[ImGuiCol.DragDropTargetBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.UnsavedMarker] = ImVec4(0.90, 0.90, 0.90, 1.00) colors[ImGuiCol.NavCursor] = colors[ImGuiCol.HeaderHovered] colors[ImGuiCol.NavWindowingHighlight] = ImVec4(1.00, 1.00, 1.00, 0.70) colors[ImGuiCol.NavWindowingDimBg] = ImVec4(0.80, 0.80, 0.80, 0.20) colors[ImGuiCol.ModalWindowDimBg] = ImVec4(0.20, 0.20, 0.20, 0.35) end -- Those light colors are better suited with a thicker font than the default one + FrameBorder --- @param dst? ImGuiStyle function ImGui.StyleColorsLight(dst) local style = dst and dst or ImGui.GetStyle() local colors = style.Colors colors[ImGuiCol.Text] = ImVec4(0.00, 0.00, 0.00, 1.00) colors[ImGuiCol.TextDisabled] = ImVec4(0.60, 0.60, 0.60, 1.00) colors[ImGuiCol.WindowBg] = ImVec4(0.94, 0.94, 0.94, 1.00) colors[ImGuiCol.ChildBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.PopupBg] = ImVec4(1.00, 1.00, 1.00, 0.98) colors[ImGuiCol.Border] = ImVec4(0.00, 0.00, 0.00, 0.30) colors[ImGuiCol.BorderShadow] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.FrameBg] = ImVec4(1.00, 1.00, 1.00, 1.00) colors[ImGuiCol.FrameBgHovered] = ImVec4(0.26, 0.59, 0.98, 0.40) colors[ImGuiCol.FrameBgActive] = ImVec4(0.26, 0.59, 0.98, 0.67) colors[ImGuiCol.TitleBg] = ImVec4(0.96, 0.96, 0.96, 1.00) colors[ImGuiCol.TitleBgActive] = ImVec4(0.82, 0.82, 0.82, 1.00) colors[ImGuiCol.TitleBgCollapsed] = ImVec4(1.00, 1.00, 1.00, 0.51) colors[ImGuiCol.MenuBarBg] = ImVec4(0.86, 0.86, 0.86, 1.00) colors[ImGuiCol.ScrollbarBg] = ImVec4(0.98, 0.98, 0.98, 0.53) colors[ImGuiCol.ScrollbarGrab] = ImVec4(0.69, 0.69, 0.69, 0.80) colors[ImGuiCol.ScrollbarGrabHovered] = ImVec4(0.49, 0.49, 0.49, 0.80) colors[ImGuiCol.ScrollbarGrabActive] = ImVec4(0.49, 0.49, 0.49, 1.00) colors[ImGuiCol.CheckMark] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.CheckboxSelectedBg] = ImVec4(0.95, 0.97, 1.00, 1.00) colors[ImGuiCol.SliderGrab] = ImVec4(0.26, 0.59, 0.98, 0.78) colors[ImGuiCol.SliderGrabActive] = ImVec4(0.46, 0.54, 0.80, 0.60) colors[ImGuiCol.Button] = ImVec4(0.26, 0.59, 0.98, 0.40) colors[ImGuiCol.ButtonHovered] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.ButtonActive] = ImVec4(0.06, 0.53, 0.98, 1.00) colors[ImGuiCol.Header] = ImVec4(0.26, 0.59, 0.98, 0.31) colors[ImGuiCol.HeaderHovered] = ImVec4(0.26, 0.59, 0.98, 0.80) colors[ImGuiCol.HeaderActive] = ImVec4(0.26, 0.59, 0.98, 1.00) colors[ImGuiCol.Separator] = ImVec4(0.39, 0.39, 0.39, 0.62) colors[ImGuiCol.SeparatorHovered] = ImVec4(0.14, 0.44, 0.80, 0.78) colors[ImGuiCol.SeparatorActive] = ImVec4(0.14, 0.44, 0.80, 1.00) colors[ImGuiCol.ResizeGrip] = ImVec4(0.35, 0.35, 0.35, 0.17) colors[ImGuiCol.ResizeGripHovered] = ImVec4(0.26, 0.59, 0.98, 0.67) colors[ImGuiCol.ResizeGripActive] = ImVec4(0.26, 0.59, 0.98, 0.95) colors[ImGuiCol.InputTextCursor] = colors[ImGuiCol.Text] colors[ImGuiCol.TabHovered] = colors[ImGuiCol.HeaderHovered] colors[ImGuiCol.Tab] = ImLerpV4V4F(colors[ImGuiCol.Header], colors[ImGuiCol.TitleBgActive], 0.90) colors[ImGuiCol.TabSelected] = ImLerpV4V4F(colors[ImGuiCol.HeaderActive], colors[ImGuiCol.TitleBgActive], 0.60) colors[ImGuiCol.TabSelectedOverline] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TabDimmed] = ImLerpV4V4F(colors[ImGuiCol.Tab], colors[ImGuiCol.TitleBg], 0.80) colors[ImGuiCol.TabDimmedSelected] = ImLerpV4V4F(colors[ImGuiCol.TabSelected], colors[ImGuiCol.TitleBg], 0.40) colors[ImGuiCol.TabDimmedSelectedOverline] = ImVec4(0.26, 0.59, 1.00, 0.00) colors[ImGuiCol.DockingPreview] = ImVec4(colors[ImGuiCol.Header].x, colors[ImGuiCol.Header].y, colors[ImGuiCol.Header].z, colors[ImGuiCol.Header].w * 0.7) colors[ImGuiCol.DockingEmptyBg] = ImVec4(0.68, 0.69, 0.73, 1.00) colors[ImGuiCol.PlotLines] = ImVec4(0.39, 0.39, 0.39, 1.00) colors[ImGuiCol.PlotLinesHovered] = ImVec4(1.00, 0.43, 0.35, 1.00) colors[ImGuiCol.PlotHistogram] = ImVec4(0.90, 0.70, 0.00, 1.00) colors[ImGuiCol.PlotHistogramHovered] = ImVec4(1.00, 0.45, 0.00, 1.00) colors[ImGuiCol.TableHeaderBg] = ImVec4(0.78, 0.87, 0.98, 1.00) colors[ImGuiCol.TableBorderStrong] = ImVec4(0.57, 0.57, 0.64, 1.00) colors[ImGuiCol.TableBorderLight] = ImVec4(0.68, 0.68, 0.74, 1.00) colors[ImGuiCol.TableRowBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.TableRowBgAlt] = ImVec4(0.30, 0.30, 0.30, 0.09) colors[ImGuiCol.TextLink] = colors[ImGuiCol.HeaderActive] colors[ImGuiCol.TextSelectedBg] = ImVec4(0.26, 0.59, 0.98, 0.35) colors[ImGuiCol.TreeLines] = colors[ImGuiCol.Border] colors[ImGuiCol.DragDropTarget] = ImVec4(0.26, 0.59, 0.98, 0.95) colors[ImGuiCol.DragDropTargetBg] = ImVec4(0.00, 0.00, 0.00, 0.00) colors[ImGuiCol.UnsavedMarker] = ImVec4(0.00, 0.00, 0.00, 1.00) colors[ImGuiCol.NavCursor] = colors[ImGuiCol.HeaderHovered] colors[ImGuiCol.NavWindowingHighlight] = ImVec4(0.70, 0.70, 0.70, 0.70) colors[ImGuiCol.NavWindowingDimBg] = ImVec4(0.20, 0.20, 0.20, 0.20) colors[ImGuiCol.ModalWindowDimBg] = ImVec4(0.20, 0.20, 0.20, 0.35) end --- @param draw_list ImDrawList --- @param vert_start_idx int --- @param vert_end_idx int --- @param gradient_p0 ImVec2 --- @param gradient_p1 ImVec2 --- @param col0 ImU32 --- @param col1 ImU32 function ImGui.ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col0, col1) local gradient_extent = gradient_p1 - gradient_p0 local gradient_inv_length2 = 1.0 / ImLengthSqr(gradient_extent) local col0_r = bit32.band(bit32.rshift(col0, IM_COL32_R_SHIFT), 0xFF) local col0_g = bit32.band(bit32.rshift(col0, IM_COL32_G_SHIFT), 0xFF) local col0_b = bit32.band(bit32.rshift(col0, IM_COL32_B_SHIFT), 0xFF) local col_delta_r = bit32.band(bit32.rshift(col1, IM_COL32_R_SHIFT), 0xFF) - col0_r local col_delta_g = bit32.band(bit32.rshift(col1, IM_COL32_G_SHIFT), 0xFF) - col0_g local col_delta_b = bit32.band(bit32.rshift(col1, IM_COL32_B_SHIFT), 0xFF) - col0_b for vert_idx = vert_start_idx, vert_end_idx - 1 do local vb = draw_list.VtxBuffer.Buf local o = (vert_idx - 1) * 36 local d = (readf64(vb, o) - gradient_p0.x) * gradient_extent.x + (readf64(vb, o + 8) - gradient_p0.y) * gradient_extent.y local t = ImClamp(d * gradient_inv_length2, 0.0, 1.0) local r = math.floor(col0_r + col_delta_r * t) local g = math.floor(col0_g + col_delta_g * t) local b = math.floor(col0_b + col_delta_b * t) writeu32(vb, o + 32, bit32.bor(bit32.lshift(r, IM_COL32_R_SHIFT), bit32.lshift(g, IM_COL32_G_SHIFT), bit32.lshift(b, IM_COL32_B_SHIFT), bit32.band(readu32(vb, o + 32), IM_COL32_A_MASK))) end end -- Rotate and translate vertices [vert_start_idx, vert_end_idx) (1-based, like _VtxCurrentIdx) function ImGui.ShadeVertsTransformPos(draw_list, vert_start_idx, vert_end_idx, pivot_in, cos_a, sin_a, pivot_out) local data = draw_list.VtxBuffer.Buf local pix, piy, pox, poy = pivot_in.x, pivot_in.y, pivot_out.x, pivot_out.y for i = vert_start_idx, vert_end_idx - 1 do local o = (i - 1) * 36 local x, y = readf64(data, o) - pix, readf64(data, o + 8) - piy writef64(data, o, x * cos_a - y * sin_a + pox) writef64(data, o + 8, x * sin_a + y * cos_a + poy) end end -- Distribute UV over (a, b) rectangle --- @param draw_list ImDrawList --- @param vert_start_idx int --- @param vert_end_idx int --- @param a ImVec2 --- @param b ImVec2 --- @param uv_a ImVec2 --- @param uv_b ImVec2 --- @param clamp bool function ImGui.ShadeVertsLinearUV(draw_list, vert_start_idx, vert_end_idx, a, b, uv_a, uv_b, clamp) local size = b - a local uv_size = uv_b - uv_a local scale = ImVec2( (size.x ~= 0.0) and (uv_size.x / size.x) or 0.0, (size.y ~= 0.0) and (uv_size.y / size.y) or 0.0 ) local vertex local verts = draw_list.VtxBuffer.Buf if clamp then local min = ImMin(uv_a, uv_b) local max = ImMax(uv_a, uv_b) for vert_idx = vert_start_idx, vert_end_idx - 1 do local o = (vert_idx - 1) * 36 local uv = ImClamp(uv_a + ImMul(ImVec2(readf64(verts, o), readf64(verts, o + 8)) - a, scale), min, max) writef64(verts, o + 16, uv.x); writef64(verts, o + 24, uv.y) end else for vert_idx = vert_start_idx, vert_end_idx - 1 do local o = (vert_idx - 1) * 36 local uv = uv_a + ImMul(ImVec2(readf64(verts, o), readf64(verts, o + 8)) - a, scale) writef64(verts, o + 16, uv.x); writef64(verts, o + 24, uv.y) end end end --- Forward Declarations local ImFontAtlasTextureAdd local ImFontAtlasTextureGrow local ImFontAtlasTextureGetSizeEstimate local ImFontAtlasTextureBlockCopy local ImFontAtlasTextureBlockConvert local ImFontAtlasTextureBlockPostProcess local ImFontAtlasTextureBlockPostProcessMultiply local ImFontAtlasTextureBlockQueueUpload local ImFontAtlasTextureCompact local ImFontAtlasPackInit local ImFontAtlasPackAddRect local ImFontAtlasPackGetRect local ImFontAtlasPackGetRectSafe local ImFontAtlasBakedAdd local ImFontAtlasBakedAddFontGlyph local ImFontAtlasBakedAddFontGlyphAdvancedX local ImFontAtlasBakedDiscard local ImFontAtlasBakedGetOrAdd local ImFontAtlasBakedGetId local ImFontAtlasBakedGetClosestMatch local ImFontAtlasBuildInit local ImFontAtlasBuildSetTexture local ImFontAtlasBuildUpdateTexDataLines local ImFontAtlasBuildUpdateTexDataBasic local ImFontAtlasBuildSetupFontLoader local ImFontAtlasBuildSetupFontSpecialGlyphs local ImFontAtlasBuildSetupFontBakedBlanks local ImFontAtlasBuildSetupFontBakedEllipsis local ImFontAtlasBuildSetupFontBakedFallback local ImFontAtlasBuildDestroy local ImFontAtlasBuildAcceptCodepointForSource local ImFontAtlasBuildNotifySetFont local ImFontAtlasBuildRenderBitmapFromString local ImFontAtlasFontSourceInit local ImFontAtlasFontSourceAddToFont local ImFontAtlasFontDestroySourceData local ImFontAtlasFontDestroyOutput local ImFontBaked_BuildGrowIndex local ImFontBaked_BuildLoadGlyph local ImFontBaked_BuildLoadGlyphAdvanceX local ImTextInitClassifiers local ImTextClassifierGet local ImTextClassifierClear local ImTextClassifierSetCharClass local ImTextClassifierSetCharClassFromStr local ImTextureDataGetFormatBytesPerPixel function MT.ImFontAtlas:Clear() IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas:Clear()") local backup_renderer_has_textures = self.RendererHasTextures self.RendererHasTextures = false self:ClearFonts() self:ClearTexData() self.RendererHasTextures = backup_renderer_has_textures end function MT.ImFontAtlas:SetFontLoader(font_loader) ImFontAtlasBuildSetupFontLoader(self, font_loader) end function MT.ImFontAtlas:ClearInputData() IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") for _, font in self.Fonts:iter() do ImFontAtlasFontDestroyOutput(self, font) end for _, font_cfg in self.Sources:iter() do ImFontAtlasFontDestroySourceData(self, font_cfg) end for _, font in self.Fonts:iter() do font.Sources:clear() font.Flags = bit32.bor(font.Flags, ImFontFlags.NoLoadGlyphs) end self.Sources:clear() end function MT.ImFontAtlas:ClearTexData() IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") IM_ASSERT(self.RendererHasTextures == false, "Not supported for dynamic atlases, but you may call Clear().") for _, tex in self.TexList:iter() do tex:DestroyPixels() end end function MT.ImFontAtlas:CompactCache() ImFontAtlasTextureCompact(self) end function MT.ImFontAtlas:ClearFonts() IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas:ClearFonts()") IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") for _, font in self.Fonts:iter() do ImFontAtlasBuildNotifySetFont(self, font, nil) end ImFontAtlasBuildDestroy(self) self:ClearInputData() self.Fonts:clear_delete() self.TexIsBuilt = false for _, shared_data in self.DrawListSharedDatas:iter() do if shared_data.FontAtlas == self then shared_data.Font = nil shared_data.FontSize = 0.0 shared_data.FontScale = 0.0 end end end --- @param tex ImTextureData function ImTextureDataUpdateNewFrame(tex) local remove_from_list = false if tex.Status == ImTextureStatus.OK then tex.Updates:resize(0) tex.UpdateRect.x = 65535 tex.UpdateRect.y = 65535 tex.UpdateRect.w = 0 tex.UpdateRect.h = 0 end if (tex.WantDestroyNextFrame and tex.Status ~= ImTextureStatus.Destroyed and tex.Status ~= ImTextureStatus.WantDestroy) then IM_ASSERT(tex.Status == ImTextureStatus.OK or tex.Status == ImTextureStatus.WantCreate or tex.Status == ImTextureStatus.WantUpdates) tex.Status = ImTextureStatus.WantDestroy end if (tex.Status == ImTextureStatus.WantDestroy and tex.TexID == ImTextureID_Invalid and tex.BackendUserData == nil and tex.QueueUserData == nil) then tex.Status = ImTextureStatus.Destroyed end if (tex.Status == ImTextureStatus.Destroyed) then IM_ASSERT(tex.TexID == ImTextureID_Invalid and tex.BackendUserData == nil, "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!") IM_ASSERT(tex.QueueUserData == nil, "Texture queue set Status to Destroyed but did not clear QueueUserData!") if (tex.WantDestroyNextFrame) then remove_from_list = true else tex.Status = ImTextureStatus.WantCreate end end if (tex.Status == ImTextureStatus.WantDestroy) then tex.UnusedFrames = tex.UnusedFrames + 1 end return remove_from_list end --- @param atlas ImFontAtlas --- @param frame_count int --- @param renderer_has_textures any function ImFontAtlasUpdateNewFrame(atlas, frame_count, renderer_has_textures) IM_ASSERT(atlas.Builder == nil or atlas.Builder.FrameCount < frame_count) atlas.RendererHasTextures = renderer_has_textures local tex_n = 1 while tex_n <= atlas.TexList.Size do local tex = atlas.TexList.Data[tex_n] if (tex.Status == ImTextureStatus.WantCreate and atlas.RendererHasTextures) then IM_ASSERT(tex.TexID == ImTextureID_Invalid and tex.BackendUserData == nil, "Backend set texture's TexID/BackendUserData but did not update Status to OK.") end local remove_from_list = ImTextureDataUpdateNewFrame(tex) if remove_from_list then IM_ASSERT(atlas.TexData ~= tex) tex:DestroyPixels() atlas.TexList:erase(tex_n) tex_n = tex_n - 1 end tex_n = tex_n + 1 end if (atlas.RendererHasTextures) then atlas.TexIsBuilt = true if (atlas.Builder == nil) then ImFontAtlasBuildMain(atlas) end end if (not atlas.RendererHasTextures) then IM_ASSERT_USER_ERROR(atlas.TexIsBuilt, "Backend does not support ImGuiBackendFlags.RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().") end if (atlas.TexIsBuilt and atlas.Builder.PreloadedAllGlyphsRanges) then IM_ASSERT_USER_ERROR(atlas.RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags.RendererHasTextures got set! With new backends: you don't need to call Build().") end local builder = atlas.Builder builder.FrameCount = frame_count for _, font in atlas.Fonts:iter() do font.LastBaked = nil end if builder.BakedDiscardedCount > 0 then local dst_n = 1 for src_n = 1, builder.BakedPool.Size do repeat local p_src = builder.BakedPool.Data[src_n] if p_src.WantDestroy then break end local p_dst = builder.BakedPool.Data[dst_n] dst_n = dst_n + 1 if p_dst == p_src then break end builder.BakedPool.Data[dst_n - 1] = p_src builder.BakedMap[p_src.BakedId] = p_src until true end IM_ASSERT(dst_n - 1 + builder.BakedDiscardedCount == builder.BakedPool.Size) builder.BakedPool.Size = builder.BakedPool.Size - builder.BakedDiscardedCount builder.BakedDiscardedCount = 0 end end --- @param src_pixels unsigned_char[] --- @param src_fmt ImTextureFormat --- @param src_pitch int --- @param dst_pixels unsigned_char[] --- @param dst_pixels_base int --- @param dst_fmt ImTextureFormat --- @param dst_pitch int --- @param w int --- @param h int function ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, dst_pixels, dst_pixels_base, dst_fmt, dst_pitch, w, h) IM_ASSERT(src_pixels ~= nil and dst_pixels ~= nil) local src_pixels_base = 1 if src_fmt == dst_fmt then local line_sz = w * ImTextureDataGetFormatBytesPerPixel(src_fmt) for ny = h, 1, -1 do ImStd.memmove(dst_pixels, dst_pixels_base, src_pixels, src_pixels_base, line_sz) src_pixels_base = src_pixels_base + src_pitch dst_pixels_base = dst_pixels_base + dst_pitch end elseif src_fmt == ImTextureFormat.Alpha8 and dst_fmt == ImTextureFormat.RGBA32 then for ny = h, 1, -1 do for nx = w, 1, -1 do local alpha = src_pixels[src_pixels_base + 0] src_pixels_base = src_pixels_base + 1 write_u32(dst_pixels, dst_pixels_base, IM_COL32(255, 255, 255, alpha)) dst_pixels_base = dst_pixels_base + 4 end src_pixels_base = src_pixels_base + (src_pitch - w) dst_pixels_base = dst_pixels_base + (dst_pitch - w * 4) end elseif src_fmt == ImTextureFormat.RGBA32 and dst_fmt == ImTextureFormat.Alpha8 then for ny = h, 1, -1 do for nx = w, 1, -1 do local alpha = src_pixels[src_pixels_base + 3] src_pixels_base = src_pixels_base + 4 dst_pixels[dst_pixels_base + 0] = alpha dst_pixels_base = dst_pixels_base + 1 end src_pixels_base = src_pixels_base + (src_pitch - w * 4) dst_pixels_base = dst_pixels_base + (dst_pitch - w) end else IM_ASSERT(false) end end --- @param data ImFontAtlasPostProcessData function ImFontAtlasTextureBlockPostProcess(data) if data.FontSrc.RasterizerMultiply ~= 1.0 then ImFontAtlasTextureBlockPostProcessMultiply(data, data.FontSrc.RasterizerMultiply) end end --- @param data ImFontAtlasPostProcessData --- @param multiply_factor float function ImFontAtlasTextureBlockPostProcessMultiply(data, multiply_factor) local pixels, pixels_base = data.Pixels, data._PixelsBase local pitch = data.Pitch if data.Format == ImTextureFormat.Alpha8 then for ny = data.Height, 1, -1 do local p = pixels_base for nx = data.Width, 1, -1 do local v = ImMin(ImFloor(pixels[p + 0] * multiply_factor), 255) pixels[p + 0] = v p = p + 1 end pixels_base = pixels_base + pitch end elseif data.Format == ImTextureFormat.RGBA32 then for ny = data.Height, 1, -1 do local p = pixels_base for nx = data.Width, 1, -1 do local a = ImMin(ImFloor(pixels[p + 3] * multiply_factor), 255) write_u32(pixels, p, IM_COL32(pixels[p + 0], pixels[p + 1], pixels[p + 2], a)) p = p + 4 end pixels_base = pixels_base + pitch end else IM_ASSERT(false) end end --- @param src_tex ImTextureData --- @param src_x int --- @param src_y int --- @param dst_tex ImTextureData --- @param dst_x int --- @param dst_y int --- @param w int --- @param h int function ImFontAtlasTextureBlockCopy(src_tex, src_x, src_y, dst_tex, dst_x, dst_y, w, h) IM_ASSERT(src_tex.Pixels ~= nil and dst_tex.Pixels ~= nil) IM_ASSERT(src_tex.Format == dst_tex.Format) IM_ASSERT(src_x >= 0 and src_x + w <= src_tex.Width) IM_ASSERT(src_y >= 0 and src_y + h <= src_tex.Height) IM_ASSERT(dst_x >= 0 and dst_x + w <= dst_tex.Width) IM_ASSERT(dst_y >= 0 and dst_y + h <= dst_tex.Height) for y = 0, h - 1 do local dst, dst_base = dst_tex:GetPixelsAt(dst_x, dst_y + y) local src, src_base = src_tex:GetPixelsAt(src_x, src_y + y) ImStd.memmove(dst, dst_base, src, src_base, w * dst_tex.BytesPerPixel) end end --- @param tex ImTextureData --- @param x int --- @param y int --- @param w int --- @param h int local function ImTextureDataQueueUpload(tex, x, y, w, h) IM_ASSERT(tex.Status ~= ImTextureStatus.WantDestroy and tex.Status ~= ImTextureStatus.Destroyed) IM_ASSERT(x >= 0 and x <= 0xFFFF and y >= 0 and y <= 0xFFFF and w >= 0 and x + w <= 0x10000 and h >= 0 and y + h <= 0x10000) local req = ImTextureRect(x, y, w, h) -- (unsigned short) local new_x1 = ImMax(tex.UpdateRect.w == 0 and 0 or tex.UpdateRect.x + tex.UpdateRect.w, req.x + req.w) local new_y1 = ImMax(tex.UpdateRect.h == 0 and 0 or tex.UpdateRect.y + tex.UpdateRect.h, req.y + req.h) tex.UpdateRect.x = ImMin(tex.UpdateRect.x, req.x) tex.UpdateRect.y = ImMin(tex.UpdateRect.y, req.y) tex.UpdateRect.w = (new_x1 - tex.UpdateRect.x) -- (unsigned short) tex.UpdateRect.h = (new_y1 - tex.UpdateRect.y) -- (unsigned short) tex.UsedRect.x = ImMin(tex.UsedRect.x, req.x) tex.UsedRect.y = ImMin(tex.UsedRect.y, req.y) tex.UsedRect.w = (ImMax(tex.UsedRect.x + tex.UsedRect.w, req.x + req.w) - tex.UsedRect.x) -- (unsigned short) tex.UsedRect.h = (ImMax(tex.UsedRect.y + tex.UsedRect.h, req.y + req.h) - tex.UsedRect.y) -- (unsigned short) if (tex.Status == ImTextureStatus.OK or tex.Status == ImTextureStatus.WantUpdates) then tex.Status = ImTextureStatus.WantUpdates tex.Updates:push_back(req) end end --- @param atlas ImFontAtlas --- @param tex ImTextureData --- @param x int --- @param y int --- @param w int --- @param h int function ImFontAtlasTextureBlockQueueUpload(atlas, tex, x, y, w, h) ImTextureDataQueueUpload(tex, x, y, w, h) atlas.TexIsBuilt = false end --- @param atlas ImFontAtlas --- @param baked ImFontBaked --- @param src ImFontConfig --- @param glyph ImFontGlyph --- @param r ImTextureRect --- @param src_pixels unsigned_char[] --- @param src_fmt ImTextureFormat --- @param src_pitch int local function ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, glyph, r, src_pixels, src_fmt, src_pitch) local tex = atlas.TexData IM_ASSERT(r.x + r.w <= tex.Width and r.y + r.h <= tex.Height) local out_p, out_p_base = tex:GetPixelsAt(r.x, r.y) IM_ASSERT(out_p ~= nil) ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, out_p, out_p_base, tex.Format, tex:GetPitch(), r.w, r.h) local pp_data = ImFontAtlasPostProcessData(atlas, baked.OwnerFont, src, baked, glyph, out_p, out_p_base, tex.Format, tex:GetPitch(), r.w, r.h) ImFontAtlasTextureBlockPostProcess(pp_data) ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h) end local function ImFontAtlasBuildGetOversampleFactors(src, baked) local raster_size = baked.Size * baked.RasterizerDensity * src.RasterizerDensity local out_oversample_h if src.OversampleH ~= 0 then out_oversample_h = src.OversampleH elseif raster_size > 36.0 or src.PixelSnapH then out_oversample_h = 1 else out_oversample_h = 2 end local out_oversample_v = (src.OversampleV ~= 0) and src.OversampleV or 1 return out_oversample_h, out_oversample_v end local function ImFontAtlasBuildDiscardBakes(atlas, unused_frames) local builder = atlas.Builder for baked_n = 1, builder.BakedPool.Size do repeat local baked = builder.BakedPool[baked_n] if (baked.LastUsedFrame + unused_frames > atlas.Builder.FrameCount) then break end if (baked.WantDestroy or (bit32.band(baked.OwnerFont.Flags, ImFontFlags.LockBakedSizes) ~= 0)) then break end ImFontAtlasBakedDiscard(atlas, baked.OwnerFont, baked) until true end end --- @param atlas ImFontAtlas --- @param data ImDrawListSharedData function ImFontAtlasAddDrawListSharedData(atlas, data) IM_ASSERT(not atlas.DrawListSharedDatas:contains(data)) atlas.DrawListSharedDatas:push_back(data) end --- @param atlas ImFontAtlas --- @param data ImDrawListSharedData function ImFontAtlasRemoveDrawListSharedData(atlas, data) IM_ASSERT(atlas.DrawListSharedDatas:contains(data)) atlas.DrawListSharedDatas:find_erase(data) end --- @param atlas ImFontAtlas --- @param w int --- @param h int local function ImFontAtlasTextureRepack(atlas, w, h) local builder = atlas.Builder builder.LockDisableResize = true local old_tex = atlas.TexData local new_tex = ImFontAtlasTextureAdd(atlas, w, h) new_tex.UseColors = old_tex.UseColors IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d", old_tex.UniqueID, old_tex.Width, old_tex.Height, new_tex.UniqueID, new_tex.Width, new_tex.Height) ImFontAtlasPackInit(atlas) local old_rects = ImVector() local old_index = builder.RectsIndex:copy() old_rects:swap(builder.Rects) for _, index_entry in builder.RectsIndex:iter() do repeat if index_entry.IsUsed == false then break end local old_r = old_rects[index_entry.TargetIndex + 1] if (old_r.w == 0 and old_r.h == 0) then break end local new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, index_entry) if new_r_id == ImFontAtlasRectId_Invalid then IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize failed. Will grow.", new_tex.UniqueID) new_tex.WantDestroyNextFrame = true builder.Rects:swap(old_rects) builder.RectsIndex = old_index ImFontAtlasBuildSetTexture(atlas, old_tex) ImFontAtlasTextureGrow(atlas, w, h) return end IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder.RectsIndex:index_from_ptr(index_entry)) local new_r = ImFontAtlasPackGetRect(atlas, new_r_id) ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r.x, new_r.y, new_r.w, new_r.h) until true end IM_ASSERT(old_rects.Size == builder.Rects.Size + builder.RectsDiscardedCount) builder.RectsDiscardedCount = 0 builder.RectsDiscardedSurface = 0 for baked_n = 1, builder.BakedPool.Size do for _, glyph in builder.BakedPool[baked_n].Glyphs:iter() do if (glyph.PackId ~= ImFontAtlasRectId_Invalid) then local r = ImFontAtlasPackGetRect(atlas, glyph.PackId) glyph.U0 = (r.x) * atlas.TexUvScale.x glyph.V0 = (r.y) * atlas.TexUvScale.y glyph.U1 = (r.x + r.w) * atlas.TexUvScale.x glyph.V1 = (r.y + r.h) * atlas.TexUvScale.y end end end ImFontAtlasBuildUpdateTexData(atlas) builder.LockDisableResize = false ImFontAtlasUpdateDrawListsSharedData(atlas) -- ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack"); end function ImFontAtlasTextureGrow(atlas, old_tex_w, old_tex_h) local builder = atlas.Builder old_tex_w = old_tex_w or -1 old_tex_h = old_tex_h or -1 if (old_tex_w == -1) then old_tex_w = atlas.TexData.Width end if (old_tex_h == -1) then old_tex_h = atlas.TexData.Height end IM_ASSERT(ImIsPowerOfTwo(old_tex_w) and ImIsPowerOfTwo(old_tex_h)) IM_ASSERT(ImIsPowerOfTwo(atlas.TexMinWidth) and ImIsPowerOfTwo(atlas.TexMaxWidth) and ImIsPowerOfTwo(atlas.TexMinHeight) and ImIsPowerOfTwo(atlas.TexMaxHeight)) local new_tex_w = (old_tex_h <= old_tex_w) and old_tex_w or old_tex_w * 2 local new_tex_h = (old_tex_h <= old_tex_w) and old_tex_h * 2 or old_tex_h local pack_padding = atlas.TexGlyphPadding new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder.MaxRectSize.x + pack_padding)) new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder.MaxRectSize.y + pack_padding)) new_tex_w = ImClamp(new_tex_w, atlas.TexMinWidth, atlas.TexMaxWidth) new_tex_h = ImClamp(new_tex_h, atlas.TexMinHeight, atlas.TexMaxHeight) if (new_tex_w == old_tex_w and new_tex_h == old_tex_h) then return end ImFontAtlasTextureRepack(atlas, new_tex_w, new_tex_h) end --- @param atlas ImFontAtlas local function ImFontAtlasTextureMakeSpace(atlas) local builder = atlas.Builder ImFontAtlasBuildDiscardBakes(atlas, 2) if (builder.RectsDiscardedSurface < builder.RectsPackedSurface * 0.20) then ImFontAtlasTextureGrow(atlas) else ImFontAtlasTextureRepack(atlas, atlas.TexData.Width, atlas.TexData.Height) end end --- @param atlas ImFontAtlas --- @param rect_idx ImFontAtlasRectId local function ImFontAtlasPackAllocRectEntry(atlas, rect_idx) local builder = atlas.Builder local index_idx, index_entry if builder.RectsIndexFreeListStart < 0 then builder.RectsIndex:resize(builder.RectsIndex.Size + 1) index_idx = builder.RectsIndex.Size - 1 index_entry = ImFontAtlasRectEntry() builder.RectsIndex.Data[builder.RectsIndex.Size] = index_entry else index_idx = builder.RectsIndexFreeListStart index_entry = builder.RectsIndex[index_idx + 1] IM_ASSERT(index_entry.IsUsed == false and index_entry.Generation > 0) builder.RectsIndexFreeListStart = index_entry.TargetIndex end index_entry.TargetIndex = rect_idx index_entry.IsUsed = true return ImFontAtlasRectId_Make(index_idx, index_entry.Generation) end --- @param atlas ImFontAtlas --- @param index_entry ImFontAtlasRectEntry local function ImFontAtlasPackReuseRectEntry(atlas, index_entry) IM_ASSERT(index_entry.IsUsed) index_entry.TargetIndex = atlas.Builder.Rects.Size - 1 local index_idx = atlas.Builder.RectsIndex:index_from_ptr(index_entry) return ImFontAtlasRectId_Make(index_idx, index_entry.Generation) end --- @param atlas ImFontAtlas --- @param id ImFontAtlasRectId function ImFontAtlasPackDiscardRect(atlas, id) IM_ASSERT(id ~= ImFontAtlasRectId_Invalid) local rect = ImFontAtlasPackGetRect(atlas, id) if (rect == nil) then return end local builder = atlas.Builder local index_idx = ImFontAtlasRectId_GetIndex(id) local index_entry = builder.RectsIndex.Data[index_idx + 1] IM_ASSERT(index_entry.IsUsed and index_entry.TargetIndex >= 0) index_entry.IsUsed = false index_entry.TargetIndex = builder.RectsIndexFreeListStart index_entry.Generation = index_entry.Generation + 1 if (index_entry.Generation == 0) then index_entry.Generation = index_entry.Generation + 1 end local pack_padding = atlas.TexGlyphPadding builder.RectsIndexFreeListStart = index_idx builder.RectsDiscardedCount = builder.RectsDiscardedCount + 1 builder.RectsDiscardedSurface = builder.RectsDiscardedSurface + ((rect.w + pack_padding) * (rect.h + pack_padding)) rect.w = 0 rect.h = 0 end function ImFontAtlasPackAddRect(atlas, w, h, overwrite_entry) IM_ASSERT(w > 0 and w <= 0xFFFF) IM_ASSERT(h > 0 and h <= 0xFFFF) local builder = atlas.Builder local pack_padding = atlas.TexGlyphPadding builder.MaxRectSize.x = ImMax(builder.MaxRectSize.x, w) builder.MaxRectSize.y = ImMax(builder.MaxRectSize.y, h) local r = ImTextureRect(0, 0, w, h) for attempts_remaining = 3, 0, -1 do local pack_r = stbrp.rect() pack_r.w = w + pack_padding pack_r.h = h + pack_padding stbrp.pack_rects(builder.PackContext, {pack_r}, 1) r.x = pack_r.x -- (unsigned short) r.y = pack_r.y -- (unsigned short) if pack_r.was_packed == 1 then break end if (attempts_remaining == 0 or builder.LockDisableResize) then IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.", w, h) return ImFontAtlasRectId_Invalid end ImFontAtlasTextureMakeSpace(atlas) end builder.MaxRectBounds.x = ImMax(builder.MaxRectBounds.x, r.x + r.w + pack_padding) builder.MaxRectBounds.y = ImMax(builder.MaxRectBounds.y, r.y + r.h + pack_padding) builder.RectsPackedCount = builder.RectsPackedCount + 1 builder.RectsPackedSurface = builder.RectsPackedSurface + (w + pack_padding) * (h + pack_padding) builder.Rects:push_back(r) if (overwrite_entry ~= nil) then return ImFontAtlasPackReuseRectEntry(atlas, overwrite_entry) else return ImFontAtlasPackAllocRectEntry(atlas, builder.Rects.Size - 1) end end --- @param atlas ImFontAtlas --- @param id ImFontAtlasRectId --- @return ImTextureRect function ImFontAtlasPackGetRect(atlas, id) IM_ASSERT(id ~= ImFontAtlasRectId_Invalid) local index_idx = ImFontAtlasRectId_GetIndex(id) local builder = atlas.Builder local index_entry = builder.RectsIndex.Data[index_idx + 1] IM_ASSERT(index_entry.Generation == ImFontAtlasRectId_GetGeneration(id)) IM_ASSERT(index_entry.IsUsed) --- @type ImTextureRect return builder.Rects.Data[index_entry.TargetIndex + 1] end --- @param atlas ImFontAtlas --- @param id ImFontAtlasRectId function ImFontAtlasPackGetRectSafe(atlas, id) if id == ImFontAtlasRectId_Invalid then return nil end local index_idx = ImFontAtlasRectId_GetIndex(id) if atlas.Builder == nil then ImFontAtlasBuildInit(atlas) end local builder = atlas.Builder if index_idx >= builder.RectsIndex.Size then return nil end local index_entry = builder.RectsIndex.Data[index_idx + 1] if (index_entry.Generation ~= ImFontAtlasRectId_GetGeneration(id) or not index_entry.IsUsed) then return nil end return builder.Rects.Data[index_entry.TargetIndex + 1] end --- @param src ImFontConfig --- @param codepoint ImWchar --- @return bool function ImFontAtlasBuildAcceptCodepointForSource(src, codepoint) local exclude_list = src.GlyphExcludeRanges if exclude_list then local i = 1 while exclude_list[i] ~= 0 do if codepoint >= exclude_list[i] and codepoint <= exclude_list[i + 1] then return false end i = i + 2 end end return true end --- @param baked ImFontBaked --- @param new_size int function ImFontBaked_BuildGrowIndex(baked, new_size) IM_ASSERT(baked.IndexAdvanceX.Size == baked.IndexLookup.Size) if (new_size <= baked.IndexLookup.Size) then return end baked.IndexAdvanceX:resize(new_size, -1.0) baked.IndexLookup:resize(new_size, IM_FONTGLYPH_INDEX_UNUSED) end --- @class ImGui_ImplStbTrueType_FontSrcData --- @field FontInfo stbtt_fontinfo --- @field ScaleFactor float --- @return ImGui_ImplStbTrueType_FontSrcData --- @nodiscard local function ImGui_ImplStbTrueType_FontSrcData() return { FontInfo = stbtt.fontinfo(), ScaleFactor = nil } end -- Need this in Lua since I don't want to include 'stbrp' just for context constructor -- in ImFontAtlasBuilder def code. The cpp code has 'stbrp_context_opaque' which I don't/can't have here --- @param atlas ImFontAtlas local function ImGui_ImplStbTrueType_LoaderInit(atlas) atlas.Builder.PackContext = atlas.Builder.PackContext or stbrp.context() end local function ImGui_ImplStbTrueType_FontSrcInit(atlas, src) -- IM_UNUSED(atlas) --- @type ImGui_ImplStbTrueType_FontSrcData? local bd_font_data = ImGui_ImplStbTrueType_FontSrcData() IM_ASSERT(src.FontLoaderData == nil) local font_offset = stbtt.GetFontOffsetForIndex(src.FontData, src.FontNo) if font_offset < 0 then bd_font_data = nil IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found.") return false end if (not stbtt.InitFont(bd_font_data.FontInfo, src.FontData, font_offset)) then bd_font_data = nil IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.") return false end src.FontLoaderData = bd_font_data local ref_size = src.DstFont.Sources[1].SizePixels if (src.MergeMode and src.SizePixels == 0.0) then src.SizePixels = ref_size end bd_font_data.ScaleFactor = stbtt.ScaleForPixelHeight(bd_font_data.FontInfo, 1.0) if (src.MergeMode and src.SizePixels ~= 0.0 and ref_size ~= 0.0) then bd_font_data.ScaleFactor = bd_font_data.ScaleFactor * (src.SizePixels / ref_size) end bd_font_data.ScaleFactor = bd_font_data.ScaleFactor * src.ExtraSizeScale return true end local function ImGui_ImplStbTrueType_FontSrcDestroy(atlas, src) -- IM_UNUSED(atlas) src.FontLoaderData = nil end local function ImGui_ImplStbTrueType_FontSrcContainsGlyph(atlas, src, codepoint) -- IM_UNUSED(atlas) local bd_font_data = src.FontLoaderData IM_ASSERT(bd_font_data ~= nil) local glyph_index = stbtt.FindGlyphIndex(bd_font_data.FontInfo, codepoint) return (glyph_index ~= 0) end local function ImGui_ImplStbTrueType_FontBakedInit(atlas, src, baked) -- IM_UNUSED(atlas) local bd_font_data = src.FontLoaderData if (src.MergeMode == false) then local scale_for_layout = bd_font_data.ScaleFactor * baked.Size / src.ExtraSizeScale local unscaled_ascent, unscaled_descent, unscaled_line_gap = stbtt.GetFontVMetrics(bd_font_data.FontInfo) baked.Ascent = ImCeil(unscaled_ascent * scale_for_layout) baked.Descent = ImFloor(unscaled_descent * scale_for_layout) end return true end --- @param atlas ImFontAtlas --- @param src ImFontConfig --- @param baked ImFontBaked --- @param _ any --- @param codepoint ImWchar --- @param out_glyph ImFontGlyph --- @param advance_x? float --- @return bool --- @return float? out_advance_x # Updated `advance_x` local function ImGui_ImplStbTrueType_FontBakedLoadGlyph(atlas, src, baked, _, codepoint, out_glyph, advance_x) local bd_font_data = src.FontLoaderData IM_ASSERT(bd_font_data ~= nil) local glyph_index = stbtt.FindGlyphIndex(bd_font_data.FontInfo, codepoint) if (glyph_index == 0) then return false, advance_x end local oversample_h, oversample_v = ImFontAtlasBuildGetOversampleFactors(src, baked) local scale_for_layout = bd_font_data.ScaleFactor * baked.Size local rasterizer_density = src.RasterizerDensity * baked.RasterizerDensity local scale_for_raster_x = bd_font_data.ScaleFactor * baked.Size * rasterizer_density * oversample_h local scale_for_raster_y = bd_font_data.ScaleFactor * baked.Size * rasterizer_density * oversample_v local x0, y0, x1, y1 = stbtt.GetGlyphBitmapBoxSubpixel(bd_font_data.FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0) local advance, lsb = stbtt.GetGlyphHMetrics(bd_font_data.FontInfo, glyph_index) if (advance_x ~= nil) then IM_ASSERT(out_glyph == nil) advance_x = advance * scale_for_layout return true, advance_x end out_glyph.Codepoint = codepoint out_glyph.AdvanceX = advance * scale_for_layout local is_visible = (x0 ~= x1 and y0 ~= y1) if is_visible then local w = (x1 - x0 + oversample_h - 1) local h = (y1 - y0 + oversample_v - 1) local pack_id = ImFontAtlasPackAddRect(atlas, w, h) if (pack_id == ImFontAtlasRectId_Invalid) then -- Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) IM_ASSERT(pack_id ~= ImFontAtlasRectId_Invalid, "Out of texture memory.") return false, advance_x end local r = ImFontAtlasPackGetRect(atlas, pack_id) x0, y0, x1, y1 = stbtt.GetGlyphBitmapBox(bd_font_data.FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y) local builder = atlas.Builder builder.TempBuffer:resize(w * h * 1) local bitmap_pixels = builder.TempBuffer.Data ImStd.memset(bitmap_pixels, 0, w * h * 1) local sub_x, sub_y = stbtt.MakeGlyphBitmapSubpixelPrefilter(bd_font_data.FontInfo, bitmap_pixels, w, h, w, scale_for_raster_x, scale_for_raster_y, 0, 0, oversample_h, oversample_v, glyph_index) local ref_size = baked.OwnerFont.Sources[1].SizePixels local offsets_scale = (ref_size ~= 0.0) and (baked.Size / ref_size) or 1.0 local font_off_x = ImFloor(src.GlyphOffset.x * offsets_scale + 0.5) local font_off_y = ImFloor(src.GlyphOffset.y * offsets_scale + 0.5) font_off_x = font_off_x + sub_x font_off_y = font_off_y + (sub_y + IM_ROUND(baked.Ascent)) local recip_h = 1.0 / (oversample_h * rasterizer_density) local recip_v = 1.0 / (oversample_v * rasterizer_density) out_glyph.X0 = x0 * recip_h + font_off_x out_glyph.Y0 = y0 * recip_v + font_off_y out_glyph.X1 = (x0 + r.w) * recip_h + font_off_x out_glyph.Y1 = (y0 + r.h) * recip_v + font_off_y out_glyph.Visible = true out_glyph.PackId = pack_id ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, out_glyph, r, bitmap_pixels, ImTextureFormat.Alpha8, w) end return true, advance_x end local function ImFontAtlasGetFontLoaderForStbTruetype() local loader = ImFontLoader() loader.Name = "stb_truetype" loader.LoaderInit = ImGui_ImplStbTrueType_LoaderInit loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit loader.FontBakedDestroy = nil loader.FontBakedLoadGlyph = ImGui_ImplStbTrueType_FontBakedLoadGlyph return loader end --- @param atlas ImFontAtlas --- @param baked ImFontBaked function ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked) local space_glyph = baked:FindGlyphNoFallback(32) if space_glyph ~= nil then space_glyph.Visible = false end if baked:FindGlyphNoFallback(9) == nil and space_glyph ~= nil then local tab_glyph = ImFontGlyph() tab_glyph.Codepoint = 9 tab_glyph.AdvanceX = space_glyph.AdvanceX * IM_TABSIZE ImFontAtlasBakedAddFontGlyph(atlas, baked, nil, tab_glyph) end end --- @param atlas ImFontAtlas --- @param font ImFont --- @param font_size float --- @param font_rasterizer_density float --- @param baked_id ImGuiID --- @return ImFontBaked? function ImFontAtlasBakedAdd(atlas, font, font_size, font_rasterizer_density, baked_id) IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx", font_size) local baked = atlas.Builder.BakedPool:push_back(ImFontBaked()) baked.Size = font_size baked.RasterizerDensity = font_rasterizer_density baked.BakedId = baked_id baked.OwnerFont = font baked.LastUsedFrame = atlas.Builder.FrameCount local loader_data_size = 0 for _, src in font.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader loader_data_size = loader_data_size + loader.FontBakedSrcLoaderDataSize end -- baked.FontLoaderDatas = (loader_data_size > 0) and IM_ALLOC(loader_data_size) or nil -- local loader_data_p = baked->FontLoaderDatas for _, src in font.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader if (loader.FontBakedInit) then loader.FontBakedInit(atlas, src, baked--[[, loader_data_p--]]) end -- loader_data_p += loader->FontBakedSrcLoaderDataSize end ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked) return baked end --- @param atlas ImFontAtlas --- @param font ImFont --- @param font_size float --- @param font_rasterizer_density float --- @return ImFontBaked? function ImFontAtlasBakedGetClosestMatch(atlas, font, font_size, font_rasterizer_density) local builder = atlas.Builder for step_n = 0, 1 do local closest_larger_match local closest_smaller_match for baked_n = 1, builder.BakedPool.Size do repeat local baked = builder.BakedPool[baked_n] if (baked.OwnerFont ~= font or baked.WantDestroy) then break end if (step_n == 0 and baked.RasterizerDensity ~= font_rasterizer_density) then break end if (baked.Size > font_size and (closest_larger_match == nil or baked.Size < closest_larger_match.Size)) then closest_larger_match = baked end if (baked.Size < font_size and (closest_smaller_match == nil or baked.Size > closest_smaller_match.Size)) then closest_smaller_match = baked end until true end if (closest_larger_match) then if (closest_smaller_match == nil or (closest_larger_match.Size >= font_size * 2.0 and closest_smaller_match.Size > font_size * 0.5)) then return closest_larger_match end end if (closest_smaller_match) then return closest_smaller_match end end return nil end --- @param atlas ImFontAtlas --- @param font ImFont --- @param baked ImFontBaked function ImFontAtlasBakedDiscard(atlas, font, baked) local builder = atlas.Builder for _, glyph in baked.Glyphs:iter() do if glyph.PackId ~= ImFontAtlasRectId_Invalid then ImFontAtlasPackDiscardRect(atlas, glyph.PackId) end end -- char* loader_data_p = (char*)baked->FontLoaderDatas for _, src in font.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader if loader.FontBakedDestroy then loader.FontBakedDestroy(atlas, src, baked) end end if baked.FontLoaderDatas then baked.FontLoaderDatas = nil end builder.BakedMap[baked.BakedId] = nil builder.BakedDiscardedCount = builder.BakedDiscardedCount + 1 baked:ClearOutputData() baked.WantDestroy = true font.LastBaked = nil end function ImFontAtlasFontDiscardBakes(atlas, font, unused_frames) local builder = atlas.Builder if builder then for baked_n = 1, builder.BakedPool.Size do repeat local baked = builder.BakedPool[baked_n] if baked.LastUsedFrame + unused_frames > atlas.Builder.FrameCount then break end if (baked.OwnerFont ~= font) or baked.WantDestroy then break end ImFontAtlasBakedDiscard(atlas, font, baked) until true end end end function ImFontAtlasFontInitOutput(atlas, font) local ret = true for _, src in font.Sources:iter() do if not ImFontAtlasFontSourceInit(atlas, src) then ret = false end end IM_ASSERT(ret) return ret end function ImFontAtlasFontDestroyOutput(atlas, font) font:ClearOutputData() for _, src in font.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader if loader and loader.FontSrcDestroy ~= nil then loader.FontSrcDestroy(atlas, src) end end end --- @param atlas ImFontAtlas --- @param src ImFontConfig --- @return boolean function ImFontAtlasFontSourceInit(atlas, src) local loader = (src.FontLoader) and src.FontLoader or atlas.FontLoader if (loader.FontSrcInit ~= nil and not loader.FontSrcInit(atlas, src)) then return false end return true end --- @param atlas ImFontAtlas --- @param font ImFont --- @param src ImFontConfig function ImFontAtlasFontSourceAddToFont(atlas, font, src) if src.MergeMode == false then font:ClearOutputData() font.OwnerAtlas = atlas IM_ASSERT(font.Sources[1] == src) end atlas.TexIsBuilt = false ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src) end --- @param atlas ImFontAtlas --- @param src ImFontConfig function ImFontAtlasFontDestroySourceData(atlas, src) -- IM_UNUSED(atlas) -- if src.FontDataOwnedByAtlas then -- IM_FREE(src.FontData) -- end src.FontData = nil -- if src.GlyphExcludeRanges then -- IM_FREE(src.GlyphExcludeRanges) -- end src.GlyphExcludeRanges = nil end --- @param atlas ImFontAtlas --- @param font ImFont --- @param src ImFontConfig function ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src) -- IM_UNUSED(atlas) IM_ASSERT(font.Sources:contains(src)) --- @type ImWchar[] local fallback_chars = {font.FallbackChar, IM_UNICODE_CODEPOINT_INVALID, 63, 32} if font.FallbackChar == 0 then for _, candidate_char in ipairs(fallback_chars) do if candidate_char ~= 0 and font:IsGlyphInFont(candidate_char) then font.FallbackChar = candidate_char break end end end --- @type ImWchar[] local ellipsis_chars = {src.EllipsisChar, 0x2026, 0x0085} if font.EllipsisChar == 0 then for _, candidate_char in ipairs(ellipsis_chars) do if candidate_char ~= 0 and font:IsGlyphInFont(candidate_char) then font.EllipsisChar = candidate_char break end end end if font.EllipsisChar == 0 then font.EllipsisChar = 0x0085 font.EllipsisAutoBake = true end end --- @param atlas ImFontAtlas --- @param baked ImFontBaked --- @return ImFontGlyph? function ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked) local font = baked.OwnerFont IM_ASSERT(font.EllipsisChar ~= 0) local dot_glyph = baked:FindGlyphNoFallback(46) -- '.' if (dot_glyph == nil) then dot_glyph = baked:FindGlyphNoFallback(0xFF0E) end if (dot_glyph == nil) then return nil end local dot_r_id = dot_glyph.PackId local dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id) local dot_spacing = 1 local dot_step = (dot_glyph.X1 - dot_glyph.X0) + dot_spacing local pack_id = ImFontAtlasPackAddRect(atlas, (dot_r.w * 3 + dot_spacing * 2), dot_r.h) local r = ImFontAtlasPackGetRect(atlas, pack_id) local glyph = ImFontGlyph() glyph.Codepoint = font.EllipsisChar glyph.AdvanceX = ImMax(dot_glyph.AdvanceX, dot_glyph.X0 + dot_step * 3.0 - dot_spacing) glyph.X0 = dot_glyph.X0 glyph.Y0 = dot_glyph.Y0 glyph.X1 = dot_glyph.X0 + dot_step * 3 - dot_spacing glyph.Y1 = dot_glyph.Y1 glyph.Visible = true glyph.PackId = pack_id glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, nil, glyph) dot_glyph = nil dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id) local tex = atlas.TexData for n = 0, 2 do ImFontAtlasTextureBlockCopy(tex, dot_r.x, dot_r.y, tex, r.x + (dot_r.w + dot_spacing) * n, r.y, dot_r.w, dot_r.h) end ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h) return glyph end --- @param baked ImFontBaked function ImFontAtlasBuildSetupFontBakedFallback(baked) IM_ASSERT(baked.FallbackGlyphIndex == -1) IM_ASSERT(baked.FallbackAdvanceX == 0.0) local font = baked.OwnerFont local fallback_glyph if (font.FallbackChar ~= 0) then fallback_glyph = baked:FindGlyphNoFallback(font.FallbackChar) end if (fallback_glyph == nil) then local space_glyph = baked:FindGlyphNoFallback(32) -- ' ' local glyph = ImFontGlyph() glyph.Codepoint = 0 glyph.AdvanceX = space_glyph and space_glyph.AdvanceX or IM_ROUND(baked.Size * 0.40) fallback_glyph = ImFontAtlasBakedAddFontGlyph(font.OwnerAtlas, baked, nil, glyph) end baked.FallbackGlyphIndex = baked.Glyphs:index_from_ptr(fallback_glyph) + 1 baked.FallbackAdvanceX = fallback_glyph.AdvanceX end function ImFontAtlasBuildSetupFontLoader(atlas, font_loader) if atlas.FontLoader == font_loader then return end IM_ASSERT(not atlas.Locked, "Cannot modify a locked ImFontAtlas!") for _, font in atlas.Fonts:iter() do ImFontAtlasFontDestroyOutput(atlas, font) end if atlas.Builder and atlas.FontLoader and atlas.FontLoader.LoaderShutdown then atlas.FontLoader.LoaderShutdown(atlas) end atlas.FontLoader = font_loader atlas.FontLoaderName = font_loader and font_loader.Name or "NULL" IM_ASSERT(atlas.FontLoaderData == nil) if atlas.Builder and atlas.FontLoader and atlas.FontLoader.LoaderInit then atlas.FontLoader.LoaderInit(atlas) end for _, font in atlas.Fonts:iter() do ImFontAtlasFontInitOutput(atlas, font) end for _, font in atlas.Fonts:iter() do for _, src in font.Sources:iter() do ImFontAtlasFontSourceAddToFont(atlas, font, src) end end end local function ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas) for _, shared_data in atlas.DrawListSharedDatas:iter() do local imgui_ctx = shared_data.Context if (imgui_ctx) then atlas.RendererHasTextures = bit32.band(imgui_ctx.IO.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ~= 0 break end end end local function ImFontAtlasBuildUpdatePointers(atlas) -- for _, font in atlas.Fonts:iter() do -- font.Sources:resize(0) -- end -- for _, src in atlas.Sources:iter() do -- src.DstFont.Sources:push_back(src) -- end end --- @param atlas ImFontAtlas --- @param old_tex ImTextureRef --- @param new_tex ImTextureRef local function ImFontAtlasUpdateDrawListsTextures(atlas, old_tex, new_tex) for _, shared_data in atlas.DrawListSharedDatas:iter() do repeat if (shared_data.Context and not shared_data.Context.WithinFrameScope) then break end for _, draw_list in shared_data.DrawLists:iter() do if (draw_list.CmdBuffer.Size > 0 and draw_list._CmdHeader.TexRef == old_tex) then draw_list:_SetTexture(new_tex) end for i, stacked_tex in draw_list._TextureStack:iter() do if (stacked_tex == old_tex) then draw_list._TextureStack.Data[i] = new_tex end end end until true end end function ImFontAtlasBuildSetTexture(atlas, tex) local old_tex_ref = atlas.TexRef atlas.TexData = tex atlas.TexUvScale = ImVec2(1.0 / tex.Width, 1.0 / tex.Height) atlas.TexRef._TexData = tex -- atlas->TexRef._TexID = tex->TexID; <-- We intentionally don't do that. It would be misleading and betray promise that both fields aren't set. ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas.TexRef) end --- @param atlas ImFontAtlas function ImFontAtlasBuildUpdateTexData(atlas) ImFontAtlasBuildUpdateTexDataLines(atlas) ImFontAtlasBuildUpdateTexDataBasic(atlas) end function ImFontAtlasTextureAdd(atlas, w, h) local old_tex = atlas.TexData local new_tex -- FIXME: Cannot reuse texture because old UV may have been used already (unless we remap UV). new_tex = ImTextureData() new_tex.UniqueID = atlas.TexNextUniqueID atlas.TexNextUniqueID = atlas.TexNextUniqueID + 1 atlas.TexList:push_back(new_tex) if old_tex ~= nil then old_tex.WantDestroyNextFrame = true IM_ASSERT(old_tex.Status == ImTextureStatus.OK or old_tex.Status == ImTextureStatus.WantCreate or old_tex.Status == ImTextureStatus.WantUpdates) end new_tex:Create(atlas.TexDesiredFormat, w, h) atlas.TexIsBuilt = false ImFontAtlasBuildSetTexture(atlas, new_tex) return new_tex end --- @param atlas ImFontAtlas --- @return ImVec2 function ImFontAtlasTextureGetSizeEstimate(atlas) local min_w = ImUpperPowerOfTwo(atlas.TexMinWidth) local min_h = ImUpperPowerOfTwo(atlas.TexMinHeight) if (atlas.Builder == nil or atlas.TexData == nil or atlas.TexData.Status == ImTextureStatus.WantDestroy) then return ImVec2(min_w, min_h) -- ImVec2i end local builder = atlas.Builder min_w = ImMax(ImUpperPowerOfTwo(builder.MaxRectSize.x), min_w) min_h = ImMax(ImUpperPowerOfTwo(builder.MaxRectSize.y), min_h) local surface_approx = builder.RectsPackedSurface - builder.RectsDiscardedSurface local surface_sqrt = ImFloor(ImSqrt(surface_approx)) local new_tex_w local new_tex_h if (min_w >= min_h) then new_tex_w = ImMax(min_w, ImUpperPowerOfTwo(surface_sqrt)) new_tex_h = ImMax(min_h, ImFloor((surface_approx + new_tex_w - 1) / new_tex_w)) if (bit32.band(atlas.Flags, ImFontAtlasFlags.NoPowerOfTwoHeight) == 0) then new_tex_h = ImUpperPowerOfTwo(new_tex_h) end else new_tex_h = ImMax(min_h, ImUpperPowerOfTwo(surface_sqrt)) if (bit32.band(atlas.Flags, ImFontAtlasFlags.NoPowerOfTwoHeight) == 0) then new_tex_h = ImUpperPowerOfTwo(new_tex_h) end new_tex_w = ImMax(min_w, ImFloor((surface_approx + new_tex_h - 1) / new_tex_h)) end IM_ASSERT(ImIsPowerOfTwo(new_tex_w) and ImIsPowerOfTwo(new_tex_h)) return ImVec2(new_tex_w, new_tex_h) -- ImVec2i end --- @param atlas ImFontAtlas function ImFontAtlasBuildClear(atlas) local new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas) -- ImVec2i ImFontAtlasBuildDestroy(atlas) ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y) ImFontAtlasBuildInit(atlas) for _, src in atlas.Sources:iter() do ImFontAtlasFontSourceInit(atlas, src) end for _, font in atlas.Fonts:iter() do for _, src in font.Sources:iter() do ImFontAtlasFontSourceAddToFont(atlas, font, src) end end end --- @param atlas ImFontAtlas function ImFontAtlasTextureCompact(atlas) local builder = atlas.Builder ImFontAtlasBuildDiscardBakes(atlas, 1) local old_tex = atlas.TexData local old_tex_size = ImVec2(old_tex.Width, old_tex.Height) local new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas) if (builder.RectsDiscardedCount == 0 and new_tex_size.x == old_tex_size.x and new_tex_size.y == old_tex_size.y) then return end ImFontAtlasTextureRepack(atlas, new_tex_size.x, new_tex_size.y) end --- @param atlas ImFontAtlas function ImFontAtlasPackInit(atlas) local tex = atlas.TexData local builder = atlas.Builder local pack_node_count = ImFloor(tex.Width / 2) builder.PackNodes:resize(pack_node_count) for i = 1, builder.PackNodes.Size do builder.PackNodes.Data[i] = stbrp.node() end stbrp.init_target(builder.PackContext, tex.Width, tex.Height, builder.PackNodes.Data, builder.PackNodes.Size) builder.RectsPackedCount = 0 builder.RectsPackedSurface = 0 builder.MaxRectSize = ImVec2(0, 0) -- ImVec2i builder.MaxRectBounds = ImVec2(0, 0) -- ImVec2i end --- @param atlas ImFontAtlas function ImFontAtlasBuildUpdateTexDataLines(atlas) if bit32.band(atlas.Flags, ImFontAtlasFlags.NoBakedLines) ~= 0 then return end local tex = atlas.TexData local builder = atlas.Builder local r = ImFontAtlasRect() local add_and_draw = (atlas:GetCustomRect(builder.PackIdLinesTexData, r) == false) if add_and_draw then local pack_size = ImVec2(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1) -- ImVec2i builder.PackIdLinesTexData = atlas:AddCustomRect(pack_size.x, pack_size.y, r) IM_ASSERT(builder.PackIdLinesTexData ~= ImFontAtlasRectId_Invalid) end for n = 0, IM_DRAWLIST_TEX_LINES_WIDTH_MAX do local y = n local line_width = n --- @type int # If not floored, will cause black and purple horizontal stripes appearing on the right of the arrow(triangle) in the upper-left most area of the atlas local pad_left = math.floor((r.w - line_width) / 2) --- @type int local pad_right = r.w - (pad_left + line_width) IM_ASSERT(pad_left + line_width + pad_right == r.w and y < r.h) if (add_and_draw and tex.Format == ImTextureFormat.Alpha8) then local write_ptr, write_ptr_base = tex:GetPixelsAt(r.x, r.y + y) for i = 0, pad_left - 1 do write_ptr[write_ptr_base + i] = 0x00 end for i = 0, line_width - 1 do write_ptr[write_ptr_base + pad_left + i] = 0xFF end for i = 0, pad_right - 1 do write_ptr[write_ptr_base + pad_left + line_width + i] = 0x00 end elseif (add_and_draw and tex.Format == ImTextureFormat.RGBA32) then local write_ptr, write_ptr_base = tex:GetPixelsAt(r.x, r.y + y) for i = 0, pad_left - 1 do write_u32(write_ptr, write_ptr_base + i * 4, IM_COL32(255, 255, 255, 0)) end for i = 0, line_width - 1 do write_u32(write_ptr, write_ptr_base + (pad_left + i) * 4, IM_COL32_WHITE) end for i = 0, pad_right - 1 do write_u32(write_ptr, write_ptr_base + (pad_left + line_width + i) * 4, IM_COL32(255, 255, 255, 0)) end end local uv0 = ImVec2(r.x + pad_left - 1, r.y + y) * atlas.TexUvScale local uv1 = ImVec2(r.x + pad_left + line_width + 1, r.y + y + 1) * atlas.TexUvScale local half_v = (uv0.y + uv1.y) * 0.5 atlas.TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v) end end --- @param atlas ImFontAtlas --- @param x int --- @param y int --- @param w int --- @param h int --- @param in_str string[] --- @param in_marker_char string function ImFontAtlasBuildRenderBitmapFromString(atlas, x, y, w, h, in_str, in_marker_char) local tex = atlas.TexData IM_ASSERT(x >= 0 and x + w <= tex.Width) IM_ASSERT(y >= 0 and y + h <= tex.Height) if tex.Format == ImTextureFormat.Alpha8 then local out_p, out_p_base = tex:GetPixelsAt(x, y) local str_base = 1 for off_y = 0, h - 1 do for off_x = 0, w - 1 do out_p[out_p_base + off_x] = (in_str[str_base + off_x] == in_marker_char) and 0xFF or 0x00 end out_p_base = out_p_base + tex.Width str_base = str_base + w end elseif tex.Format == ImTextureFormat.RGBA32 then local out_p, out_p_base = tex:GetPixelsAt(x, y) local str_base = 1 for off_y = 0, h - 1 do for off_x = 0, w - 1 do write_u32(out_p, out_p_base + off_x * 4, (in_str[str_base + off_x] == in_marker_char) and IM_COL32_WHITE or IM_COL32_BLACK_TRANS) end out_p_base = out_p_base + tex.Width * 4 str_base = str_base + w end end end --- @param atlas ImFontAtlas function ImFontAtlasBuildUpdateTexDataBasic(atlas) local builder = atlas.Builder local pack_size = (bit32.band(atlas.Flags, ImFontAtlasFlags.NoMouseCursors) ~= 0) and ImVec2(2, 2) or ImVec2(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H) local r = ImFontAtlasRect() local add_and_draw = (atlas:GetCustomRect(builder.PackIdMouseCursors, r) == false) if (add_and_draw) then builder.PackIdMouseCursors = atlas:AddCustomRect(pack_size.x, pack_size.y, r) IM_ASSERT(builder.PackIdMouseCursors ~= ImFontAtlasRectId_Invalid) if bit32.band(atlas.Flags, ImFontAtlasFlags.NoMouseCursors) ~= 0 then ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, {"X", "X", "X", "X"}, "X") else local x_for_white = r.x local x_for_black = r.x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1 ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, ".") ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, "X") end end atlas.TexUvWhitePixel = ImVec2((r.x + 0.5) * atlas.TexUvScale.x, (r.y + 0.5) * atlas.TexUvScale.y) end function ImFontAtlasUpdateDrawListsSharedData(atlas) for _, shared_data in atlas.DrawListSharedDatas:iter() do if (shared_data.FontAtlas == atlas) then shared_data.TexUvWhitePixel = atlas.TexUvWhitePixel shared_data.TexUvLines = atlas.TexUvLines end end end function ImFontAtlasBuildInit(atlas) if atlas.FontLoader == nil then -- IMGUI_ENABLE_STB_TRUETYPE atlas:SetFontLoader(ImFontAtlasGetFontLoaderForStbTruetype()) end if atlas.TexData == nil or atlas.TexData.Pixels == nil then ImFontAtlasTextureAdd(atlas, ImUpperPowerOfTwo(atlas.TexMinWidth), ImUpperPowerOfTwo(atlas.TexMinHeight)) end atlas.Builder = ImFontAtlasBuilder() if atlas.FontLoader.LoaderInit then atlas.FontLoader.LoaderInit(atlas) end ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas) ImFontAtlasPackInit(atlas) ImFontAtlasBuildUpdateTexData(atlas) ImFontAtlasBuildUpdatePointers(atlas) ImFontAtlasUpdateDrawListsSharedData(atlas) ImTextInitClassifiers() end --- @param atlas ImFontAtlas function ImFontAtlasBuildDestroy(atlas) for _, font in atlas.Fonts:iter() do ImFontAtlasFontDestroyOutput(atlas, font) end if atlas.Builder and atlas.FontLoader and atlas.FontLoader.LoaderShutdown then atlas.FontLoader.LoaderShutdown(atlas) IM_ASSERT(atlas.FontLoaderData == nil) end atlas.Builder = nil end --- @param atlas ImFontAtlas --- @param old_font ImFont? --- @param new_font ImFont? function ImFontAtlasBuildNotifySetFont(atlas, old_font, new_font) for _, shared_data in atlas.DrawListSharedDatas:iter() do if shared_data.Font == old_font then shared_data.Font = new_font end local ctx = shared_data.Context if ctx then repeat if old_font == nil and ctx.Font == nil and ctx.FontSizeBase == 0.0 then -- While this should work either way, we save ourselves the bother / debugging confusion of running ImGui code so early when it is not needed. -- Also fixes erroneously rewriting style.FontSizeBase during init if adding default fonts. break end if ctx.IO.FontDefault == old_font then ctx.IO.FontDefault = new_font end if ctx.Font == old_font then local curr_ctx = ImGui.GetCurrentContext() local need_bind_ctx = ctx ~= curr_ctx if need_bind_ctx then ImGui.SetCurrentContext(ctx) end ImGui.SetCurrentFont(new_font, ctx.FontSizeBase, ctx.FontSize) if need_bind_ctx then ImGui.SetCurrentContext(curr_ctx) end end for _, font_stack_data in ctx.FontStack:iter() do if font_stack_data.Font == old_font then font_stack_data.Font = new_font end end until true end end end --- @param atlas ImFontAtlas function ImFontAtlasBuildMain(atlas) IM_ASSERT(not atlas.Locked, "Cannot modify a locked ImFontAtlas!") if (atlas.TexData and atlas.TexData.Format ~= atlas.TexDesiredFormat) then ImFontAtlasBuildClear(atlas) end if atlas.Builder == nil then ImFontAtlasBuildInit(atlas) end -- Default font is none are specified if atlas.Sources.Size == 0 then atlas:AddFontDefault() end -- [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs -- ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); -- if atlas.RendererHasTextures == false then -- ImFontAtlasBuildLegacyPreloadAllGlyphRanges(atlas) -- end atlas.TexIsBuilt = true end function MT.ImTextureData:DestroyPixels() self.Pixels = nil self.UseColors = false end function ImTextureDataGetFormatBytesPerPixel(format) if format == ImTextureFormat.Alpha8 then return 1 elseif format == ImTextureFormat.RGBA32 then return 4 end IM_ASSERT(false) return 0 end function MT.ImTextureData:Create(format, w, h) IM_ASSERT(self.Status == ImTextureStatus.Destroyed) self:DestroyPixels() self.Format = format self.Status = ImTextureStatus.WantCreate self.Width = w self.Height = h self.BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format) self.UseColors = false self.Pixels = {} ImStd.memset(self.Pixels, 0, self.Width * self.Height * self.BytesPerPixel) self.UsedRect.x = 0 self.UsedRect.y = 0 self.UsedRect.w = 0 self.UsedRect.h = 0 self.UpdateRect.x = 65535 self.UpdateRect.y = 65535 self.UpdateRect.w = 0 self.UpdateRect.h = 0 end function MT.ImFontBaked:ClearOutputData() self.FallbackAdvanceX = 0.0 self.Glyphs:clear() self.IndexAdvanceX:clear() self.IndexLookup:clear() self.FallbackGlyphIndex = -1 self.Ascent = 0.0 self.Descent = 0.0 self.MetricsTotalSurface = 0 end --- @param c ImWchar --- @return ImFontGlyph? function MT.ImFontBaked:FindGlyph(c) if c < self.IndexLookup.Size then local i = self.IndexLookup.Data[c + 1] if i == IM_FONTGLYPH_INDEX_NOT_FOUND then return self.Glyphs.Data[self.FallbackGlyphIndex] end if i ~= IM_FONTGLYPH_INDEX_UNUSED then return self.Glyphs.Data[i] end end local glyph = ImFontBaked_BuildLoadGlyph(self, c, nil) return (glyph) and glyph or self.Glyphs.Data[self.FallbackGlyphIndex] end function MT.ImFontBaked:IsGlyphLoaded(c) if c >= self.IndexLookup.Size then return false end return self.IndexLookup.Data[c + 1] ~= IM_FONTGLYPH_INDEX_UNUSED end --- @param c ImWchar --- @return ImFontGlyph? function MT.ImFontBaked:FindGlyphNoFallback(c) if c < self.IndexLookup.Size then -- IM_LIKELY local i = self.IndexLookup.Data[c + 1] if i == IM_FONTGLYPH_INDEX_NOT_FOUND then return nil end if i ~= IM_FONTGLYPH_INDEX_UNUSED then return self.Glyphs.Data[i] end end self.LoadNoFallback = true local glyph = ImFontBaked_BuildLoadGlyph(self, c, nil) self.LoadNoFallback = false return glyph end function MT.ImFont:ClearOutputData() local atlas = self.OwnerAtlas if atlas ~= nil then ImFontAtlasFontDiscardBakes(atlas, self, 0) end for i = 1, (IM_UNICODE_CODEPOINT_MAX + 1) / 8192 / 8 do self.Used8kPagesMap[i] = 0 end self.LastBaked = nil end --- @param font_id ImGuiID --- @param baked_size float --- @param rasterizer_density float --- @return ImGuiID function ImFontAtlasBakedGetId(font_id, baked_size, rasterizer_density) local hashed_data = {font_id, baked_size, rasterizer_density} return ImHashData(hashed_data) end --- @param atlas ImFontAtlas --- @param font ImFont --- @param font_size float --- @param font_rasterizer_density float --- @return ImFontBaked? function ImFontAtlasBakedGetOrAdd(atlas, font, font_size, font_rasterizer_density) IM_ASSERT(font_size > 0.0 and font_rasterizer_density > 0.0) local baked_id = ImFontAtlasBakedGetId(font.FontId, font_size, font_rasterizer_density) local builder = atlas.Builder local baked = builder.BakedMap[baked_id] if baked ~= nil then IM_ASSERT(baked.Size == font_size and baked.OwnerFont == font and baked.BakedId == baked_id) return baked end if (bit32.band(font.Flags, ImFontFlags.LockBakedSizes) ~= 0 or atlas.Locked) then baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size, font_rasterizer_density) if baked ~= nil then return baked end if atlas.Locked then IM_ASSERT(not atlas.Locked, "Cannot use dynamic font size with a locked ImFontAtlas!") return nil end end baked = ImFontAtlasBakedAdd(atlas, font, font_size, font_rasterizer_density, baked_id) builder.BakedMap[baked_id] = baked return baked end --- @param atlas ImFontAtlas --- @param baked ImFontBaked --- @param src? ImFontConfig --- @param in_glyph ImFontGlyph --- @return ImFontGlyph function ImFontAtlasBakedAddFontGlyph(atlas, baked, src, in_glyph) local glyph_idx = baked.Glyphs.Size + 1 baked.Glyphs:push_back(in_glyph) local glyph = baked.Glyphs.Data[glyph_idx] IM_ASSERT(baked.Glyphs.Size < 0xFFFE) if (glyph.PackId ~= ImFontAtlasRectId_Invalid) then local r = ImFontAtlasPackGetRect(atlas, glyph.PackId) IM_ASSERT(glyph.U0 == 0.0 and glyph.V0 == 0.0 and glyph.U1 == 0.0 and glyph.V1 == 0.0) glyph.U0 = (r.x) * atlas.TexUvScale.x glyph.V0 = (r.y) * atlas.TexUvScale.y glyph.U1 = (r.x + r.w) * atlas.TexUvScale.x glyph.V1 = (r.y + r.h) * atlas.TexUvScale.y baked.MetricsTotalSurface = baked.MetricsTotalSurface + r.w * r.h end if (src ~= nil) then local ref_size = baked.OwnerFont.Sources[1].SizePixels local offsets_scale = (ref_size ~= 0.0) and (baked.Size / ref_size) or 1.0 local advance_x = ImClamp(glyph.AdvanceX, src.GlyphMinAdvanceX * offsets_scale, src.GlyphMaxAdvanceX * offsets_scale) if (advance_x ~= glyph.AdvanceX) then local char_off_x = src.PixelSnapH and ImTrunc((advance_x - glyph.AdvanceX) * 0.5) or (advance_x - glyph.AdvanceX) * 0.5 glyph.X0 = glyph.X0 + char_off_x glyph.X1 = glyph.X1 + char_off_x end if (src.PixelSnapH) then advance_x = IM_ROUND(advance_x) end glyph.AdvanceX = advance_x + src.GlyphExtraAdvanceX end if (glyph.Colored) then atlas.TexData.UseColors = true atlas.TexPixelsUseColors = true end local codepoint = glyph.Codepoint ImFontBaked_BuildGrowIndex(baked, codepoint + 1) baked.IndexAdvanceX.Data[codepoint + 1] = glyph.AdvanceX baked.IndexLookup.Data[codepoint + 1] = glyph_idx -- (ImU16) local page_n = math.floor(codepoint / 8192) baked.OwnerFont.Used8kPagesMap[bit32.rshift(page_n, 3) + 1] = bit32.bor(baked.OwnerFont.Used8kPagesMap[bit32.rshift(page_n, 3) + 1], bit32.lshift(1, bit32.band(page_n, 7))) return glyph end --- @param atlas ImFontAtlas --- @param baked ImFontBaked --- @param src? ImFontConfig --- @param codepoint ImWchar --- @param advance_x float function ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, advance_x) -- IM_UNUSED(atlas) if (src ~= nil) then local ref_size = baked.OwnerFont.Sources[1].SizePixels local offsets_scale = (ref_size ~= 0.0) and (baked.Size / ref_size) or 1.0 advance_x = ImClamp(advance_x, src.GlyphMinAdvanceX * offsets_scale, src.GlyphMaxAdvanceX * offsets_scale) if (src.PixelSnapH) then advance_x = IM_ROUND(advance_x) end advance_x = advance_x + src.GlyphExtraAdvanceX end ImFontBaked_BuildGrowIndex(baked, codepoint + 1) baked.IndexAdvanceX.Data[codepoint + 1] = advance_x end --- @param size float --- @param density float? --- @return ImFontBaked? function MT.ImFont:GetFontBaked(size, density) if not density then density = -1.0 end --- @type ImFontBaked? local baked = self.LastBaked size = ImGui.GetRoundedFontSize(size) if density < 0.0 then density = self.CurrentRasterizerDensity end if baked and baked.Size == size and baked.RasterizerDensity == density then return baked end local atlas = self.OwnerAtlas local builder = atlas.Builder baked = ImFontAtlasBakedGetOrAdd(atlas, self, size, density) if baked == nil then return nil end baked.LastUsedFrame = builder.FrameCount self.LastBaked = baked return baked end --- @param atlas ImFontAtlas --- @param font ImFont --- @param c ImWchar --- @return ImWchar --- @nodiscard local function ImFontAtlas_FontHookRemapCodepoint(atlas, font, c) -- IM_UNUSED(atlas) if #font.RemapPairs > 0 then local ret = font.RemapPairs[c] return (ret ~= nil) and ret or c end return c end --- @param baked ImFontBaked --- @param codepoint ImWchar --- @param only_load_advance_x? float --- @return ImFontGlyph? --- @return float? # Updated `only_load_advance_x` function ImFontBaked_BuildLoadGlyph(baked, codepoint, only_load_advance_x) local font = baked.OwnerFont local atlas = font.OwnerAtlas if atlas.Locked or bit32.band(font.Flags, ImFontFlags.NoLoadGlyphs) ~= 0 then if baked.FallbackGlyphIndex == -1 and baked.LoadNoFallback == false then ImFontAtlasBuildSetupFontBakedFallback(baked) end return nil, only_load_advance_x end local src_codepoint = codepoint codepoint = ImFontAtlas_FontHookRemapCodepoint(atlas, font, codepoint) if (codepoint == font.EllipsisChar and font.EllipsisAutoBake) then local glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked) if (glyph) then return glyph, only_load_advance_x end end local loader_user_data_p = baked.FontLoaderDatas local src_n = 1 for _, src in font.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader if (not src.GlyphExcludeRanges or ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) then if only_load_advance_x == nil then local glyph_buf = ImFontGlyph() if loader.FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, glyph_buf, nil) then glyph_buf.Codepoint = src_codepoint glyph_buf.SourceIdx = src_n return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph_buf) end else local ret --[[@as bool]] ret, only_load_advance_x = loader.FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, nil, only_load_advance_x) if ret then --- @cast only_load_advance_x float ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, only_load_advance_x) return nil, only_load_advance_x end end end -- loader_user_data_p = loader_user_data_p + loader.FontBakedSrcLoaderDataSize src_n = src_n + 1 end if (baked.LoadNoFallback) then return nil, only_load_advance_x end if (baked.FallbackGlyphIndex == -1) then ImFontAtlasBuildSetupFontBakedFallback(baked) end ImFontBaked_BuildGrowIndex(baked, codepoint + 1); baked.IndexAdvanceX.Data[codepoint + 1] = baked.FallbackAdvanceX baked.IndexLookup.Data[codepoint + 1] = IM_FONTGLYPH_INDEX_NOT_FOUND return nil, only_load_advance_x end --- @param baked ImFontBaked --- @param codepoint ImWchar --- @return float function ImFontBaked_BuildLoadGlyphAdvanceX(baked, codepoint) if (baked.Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE) or baked.LoadNoRenderOnLayout then local only_advance_x local glyph glyph, only_advance_x = ImFontBaked_BuildLoadGlyph(baked, codepoint, only_advance_x) --- @cast only_advance_x float return glyph and glyph.AdvanceX or only_advance_x else local glyph = ImFontBaked_BuildLoadGlyph(baked, codepoint, nil) return glyph and glyph.AdvanceX or baked.FallbackAdvanceX end end --- @param c ImWchar --- @return bool function MT.ImFont:IsGlyphInFont(c) local atlas = self.OwnerAtlas c = ImFontAtlas_FontHookRemapCodepoint(atlas, self, c) for _, src in self.Sources:iter() do local loader = src.FontLoader and src.FontLoader or atlas.FontLoader if loader.FontSrcContainsGlyph ~= nil and loader.FontSrcContainsGlyph(atlas, src, c) then return true end end return false end --- @param c ImWchar --- @return float function MT.ImFontBaked:GetCharAdvance(c) if c < self.IndexAdvanceX.Size then local x = self.IndexAdvanceX.Data[c + 1] if x >= 0.0 then return x end end return ImFontBaked_BuildLoadGlyphAdvanceX(self, c) end function BuildLoadGlyphGetAdvanceOrFallback(baked, codepoint) return ImFontBaked_BuildLoadGlyphAdvanceX(baked, codepoint) end --- @param text ImString --- @param text_begin int --- @param text_end int --- @param flags ImDrawTextFlags --- @return int local function ImTextCalcWordWrapNextLineStart(text, text_begin, text_end, flags) local pos = text_begin if bit32.band(flags, ImDrawTextFlags.WrapKeepBlanks) == 0 then while pos < text_end and ImCharIsBlankA(ImStrByte(text, pos)) do pos = pos + 1 end end if pos < text_end and ImStrByte(text, pos) == 10 then -- '\n' pos = pos + 1 end return pos end --- @param bits ImU32[] --- @param codepoint_min unsigned_int --- @param codepoint_end unsigned_int --- @param char_class ImWcharClass function ImTextClassifierClear(bits, codepoint_min, codepoint_end, char_class) for c = codepoint_min, codepoint_end - 1 do ImTextClassifierSetCharClass(bits, codepoint_min, codepoint_end, char_class, c) end end --- @param bits ImU32[] --- @param codepoint_min unsigned_int --- @param codepoint_end unsigned_int --- @param char_class ImWcharClass --- @param c unsigned_int function ImTextClassifierSetCharClass(bits, codepoint_min, codepoint_end, char_class, c) IM_ASSERT(c >= codepoint_min and c < codepoint_end) -- IM_UNUSED(codepoint_end) c = c - codepoint_min local shift = bit32.lshift(bit32.band(c, 15), 1) bits[bit32.rshift(c, 4) + 1] = bit32.bor(bit32.band(bits[bit32.rshift(c, 4) + 1], bit32.bnot(bit32.lshift(0x03, shift))), bit32.lshift(char_class, shift)) end function ImTextClassifierSetCharClassFromStr(bits, codepoint_min, codepoint_end, char_class, s) local s_end = #s + 1 local pos = 1 while (pos < s_end) do local wanted, c = ImStd.ImTextCharFromUtf8(s, pos, s_end) pos = pos + wanted ImTextClassifierSetCharClass(bits, codepoint_min, codepoint_end, char_class, c) end end function ImTextClassifierGet(_BITS, _CHAR_OFFSET) return bit32.band(bit32.rshift(_BITS[bit32.rshift(_CHAR_OFFSET, 4) + 1], bit32.lshift(bit32.band(_CHAR_OFFSET, 15), 1)), 0x03) end local g_CharClassifierIsSeparator_0000_007f = {} for i = 1, 128 / 16 do g_CharClassifierIsSeparator_0000_007f[i] = 0 end local g_CharClassifierIsSeparator_3000_300f = {} for i = 1, 16 / 16 do g_CharClassifierIsSeparator_3000_300f[i] = 0 end function ImTextInitClassifiers() if (ImTextClassifierGet(g_CharClassifierIsSeparator_0000_007f, 44) ~= 0) then return end ImTextClassifierClear(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass.Other) ImTextClassifierSetCharClassFromStr(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass.Blank, " \t") ImTextClassifierSetCharClassFromStr(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass.Punct, ".,;!?\"") ImTextClassifierClear(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass.Other) ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass.Blank, 0x3000) ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass.Punct, 0x3001) ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass.Punct, 0x3002) end --- @param font ImFont --- @param size float --- @param text ImString --- @param pos int --- @param text_end int --- @param wrap_width float --- @param flags ImDrawTextFlags --- @return int function ImFontCalcWordWrapPositionEx(font, size, text, pos, text_end, wrap_width, flags) local baked = font:GetFontBaked(size) local scale = size / baked.Size local line_width = 0.0 local blank_width = 0.0 wrap_width = wrap_width / scale local s = pos IM_ASSERT(text_end ~= nil) local prev_type = ImWcharClass.Other local keep_blanks = bit32.band(flags, ImDrawTextFlags.WrapKeepBlanks) ~= 0 local span_end = s local span_width = 0.0 local stop = false while s < text_end do repeat --- @type unsigned_int local c = ImStrByte(text, s) local next_s if c < 0x80 then next_s = s + 1 else local wanted, out_char = ImStd.ImTextCharFromUtf8(text, s, text_end) c = out_char next_s = s + wanted end if c < 32 then if c == 10 then -- '\n' return s end if c == 13 then -- '\r' s = next_s break end end local char_width = (c < baked.IndexAdvanceX.Size) and baked.IndexAdvanceX.Data[c + 1] or -1.0 if char_width < 0.0 then char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c) end local curr_type if c < 128 then curr_type = ImTextClassifierGet(g_CharClassifierIsSeparator_0000_007f, c) elseif (c >= 0x3000 and c < 0x3010) then curr_type = ImTextClassifierGet(g_CharClassifierIsSeparator_3000_300f, bit32.band(c, 15)) else curr_type = ImWcharClass.Other end if curr_type == ImWcharClass.Blank then if (prev_type ~= ImWcharClass.Blank and not keep_blanks) then span_end = s line_width = line_width + span_width span_width = 0.0 end blank_width = blank_width + char_width else if (prev_type == ImWcharClass.Punct and curr_type ~= ImWcharClass.Punct and not (c >= 48 and c <= 57)) then span_end = s line_width = line_width + (span_width + blank_width) blank_width = 0.0 span_width = 0.0 elseif (prev_type == ImWcharClass.Blank and keep_blanks) then span_end = s line_width = line_width + (span_width + blank_width) blank_width = 0.0 span_width = 0.0 end span_width = span_width + char_width end if (span_width + blank_width + line_width > wrap_width) then if span_width + blank_width > wrap_width then stop = true; break end return span_end end prev_type = curr_type s = next_s until true if stop then break end end if s == pos and s < text_end then local bytes = ImStd.ImTextCountUtf8BytesFromChar(text, s, text_end) return s + bytes end return s end --- @param font ImFont --- @param size float --- @param max_width float --- @param wrap_width float --- @param text ImString --- @param text_begin int --- @param text_end_display? int --- @param text_end? int --- @param out_offset? ImVec2 --- @param flags ImDrawTextFlags --- @return ImVec2 text_size --- @return int remaining local TEXT_SIZE_CACHE_MAX = 4096 @native function ImFontCalcTextSizeEx(font, size, max_width, wrap_width, text, text_begin, text_end_display, text_end, out_offset, flags) -- [Luau] cache for the common case (whole string, single pass, no wrap/limit): per baked font, text -> unscaled width, line count. -- Advances of a baked font never change once loaded, so entries stay valid. ponytail: whole-cache reset at TEXT_SIZE_CACHE_MAX entries, LRU if dynamic text churns it local cache_key = nil if text_begin == 1 and out_offset == nil and wrap_width <= 0.0 and max_width >= FLT_MAX and type(text) == "string" and (text_end == nil or text_end == #text + 1) and (text_end_display == nil or text_end_display == #text + 1) and (flags == nil or bit32.band(flags, ImDrawTextFlags.StopOnNewLine) == 0) then local baked = font:GetFontBaked(size) local cache = baked._TextSizeCache if cache == nil or baked._TextSizeCacheN >= TEXT_SIZE_CACHE_MAX then cache = {}; baked._TextSizeCache = cache; baked._TextSizeCacheN = 0 end local e = cache[text] if e then return ImVec2(e[1] * (size / baked.Size), e[2] * size), #text + 1 end cache_key = text end if not text_end then text_end = #text + 1 end if not text_end_display then text_end_display = text_end end local baked = font:GetFontBaked(size) local line_height = size local scale = line_height / baked.Size local text_size = ImVec2() local line_width = 0.0 local word_wrap_enabled = (wrap_width > 0.0) local word_wrap_eol local s = text_begin local stop = false while s < text_end_display do repeat if word_wrap_enabled then if not word_wrap_eol then word_wrap_eol = ImFontCalcWordWrapPositionEx(font, size, text, s, text_end, wrap_width - line_width, flags) end if s >= word_wrap_eol then if text_size.x < line_width then text_size.x = line_width end text_size.y = text_size.y + line_height line_width = 0.0 s = ImTextCalcWordWrapNextLineStart(text, s, text_end, flags) if bit32.band(flags, ImDrawTextFlags.StopOnNewLine) ~= 0 then stop = true; break end word_wrap_eol = nil break end end local prev_s = s local c = ImStrByte(text, s) if c < 0x80 then s = s + 1 else local wanted, out_char = ImStd.ImTextCharFromUtf8(text, s, text_end) c = out_char s = s + wanted end if c == 10 then -- '\n' text_size.x = ImMax(text_size.x, line_width) text_size.y = text_size.y + line_height line_width = 0.0 if bit32.band(flags, ImDrawTextFlags.StopOnNewLine) ~= 0 then stop = true; break end break end if c == 13 then -- '\r' break end local char_width = (c < baked.IndexAdvanceX.Size) and baked.IndexAdvanceX.Data[c + 1] or -1.0 if (char_width < 0.0) then char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c) end char_width = char_width * scale if (line_width + char_width >= max_width) then s = prev_s stop = true; break end line_width = line_width + char_width until true if stop then break end end if (text_size.x < line_width) then text_size.x = line_width end if out_offset then out_offset.x = line_width out_offset.y = text_size.y + line_height end if (line_width > 0 or text_size.y == 0.0) then text_size.y = text_size.y + line_height end local out_remaining = s if cache_key then baked._TextSizeCache[cache_key] = { text_size.x / scale, text_size.y / line_height } baked._TextSizeCacheN += 1 end return text_size, out_remaining end --- @param size float --- @param max_width float --- @param wrap_width float --- @param text ImString --- @param text_begin int --- @param text_end? int function MT.ImFont:CalcTextSizeA(size, max_width, wrap_width, text, text_begin, text_end) return ImFontCalcTextSizeEx(self, size, max_width, wrap_width, text, text_begin, text_end, text_end, nil, ImDrawTextFlags.None) end --- Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. --- @param draw_list ImDrawList --- @param size float --- @param pos ImVec2 --- @param col ImU32 --- @param c ImWchar --- @param cpu_fine_clip ImVec4 function MT.ImFont:RenderChar(draw_list, size, pos, col, c, cpu_fine_clip) local baked = self:GetFontBaked(size) local glyph = baked:FindGlyph(c) if not glyph or not glyph.Visible then return end if glyph.Colored then col = bit32.bor(col, bit32.bnot(IM_COL32_A_MASK)) end local scale if size >= 0.0 then scale = size / baked.Size else scale = 1.0 end local x = pos.x local y = pos.y if bit32.band(draw_list.Flags, ImDrawListFlags.TextNoPixelSnap) == 0 then x = IM_TRUNC(x) y = IM_TRUNC(y) end local x1 = x + glyph.X0 * scale local x2 = x + glyph.X1 * scale if cpu_fine_clip and (x1 > cpu_fine_clip.z or x2 < cpu_fine_clip.x) then return end local y1 = y + glyph.Y0 * scale local y2 = y + glyph.Y1 * scale local u1 = glyph.U0 local v1 = glyph.V0 local u2 = glyph.U1 local v2 = glyph.V1 -- Always CPU fine clip. Code extracted from RenderText(). -- CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. if cpu_fine_clip then if x1 < cpu_fine_clip.x then u1 = u1 + (1.0 - (x2 - cpu_fine_clip.x) / (x2 - x1)) * (u2 - u1); x1 = cpu_fine_clip.x end if y1 < cpu_fine_clip.y then v1 = v1 + (1.0 - (y2 - cpu_fine_clip.y) / (y2 - y1)) * (v2 - v1); y1 = cpu_fine_clip.y end if x2 > cpu_fine_clip.z then u2 = u1 + ((cpu_fine_clip.z - x1) / (x2 - x1)) * (u2 - u1); x2 = cpu_fine_clip.z end if y2 > cpu_fine_clip.w then v2 = v1 + ((cpu_fine_clip.w - y1) / (y2 - y1)) * (v2 - v1); y2 = cpu_fine_clip.w end if y1 >= y2 then return end end draw_list:PrimReserve(6, 4) draw_list:PrimRectUV(ImVec2(x1, y1), ImVec2(x2, y2), ImVec2(u1, v1), ImVec2(u2, v2), col) end function MT.ImFontAtlas:AddFont(font_cfg_in) IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") IM_ASSERT((font_cfg_in.FontData ~= nil and font_cfg_in.FontDataSize > 0) or (font_cfg_in.FontLoader ~= nil)) IM_ASSERT(font_cfg_in.SizePixels > 0.0, "Is ImFontConfig struct correctly initialized?") IM_ASSERT(font_cfg_in.RasterizerDensity > 0.0, "Is ImFontConfig struct correctly initialized?") if font_cfg_in.GlyphOffset.x ~= 0.0 or font_cfg_in.GlyphOffset.y ~= 0.0 or font_cfg_in.GlyphMinAdvanceX ~= 0.0 or font_cfg_in.GlyphMaxAdvanceX ~= FLT_MAX then IM_ASSERT(font_cfg_in.SizePixels ~= 0.0, "Specifying glyph offset/advances requires a reference size to base it on.") end if self.Builder == nil then ImFontAtlasBuildInit(self) end local is_first_font = (self.Fonts.Size == 0) local font if not font_cfg_in.MergeMode then font = ImFont() font.FontId = self.FontNextUniqueID self.FontNextUniqueID = self.FontNextUniqueID + 1 font.Flags = font_cfg_in.Flags font.LegacySize = font_cfg_in.SizePixels font.CurrentRasterizerDensity = font_cfg_in.RasterizerDensity self.Fonts:push_back(font) else IM_ASSERT(self.Fonts.Size > 0, "Cannot use MergeMode for the first font!") font = (font_cfg_in.DstFont ~= nil) and font_cfg_in.DstFont or self.Fonts:back() ImFontAtlasFontDiscardBakes(self, font, 0) end self.Sources:push_back(font_cfg_in) local font_cfg = self.Sources:back() if (font_cfg.DstFont == nil) then font_cfg.DstFont = font end font.Sources:push_back(font_cfg) ImFontAtlasBuildUpdatePointers(self) if font_cfg.GlyphExcludeRanges ~= nil then local size = 0 for _, v in ipairs(font_cfg.GlyphExcludeRanges) do if v == 0 then break end size = size + 1 end IM_ASSERT(bit32.band(size, 1) == 0, "GlyphExcludeRanges[] size must be multiple of two!") IM_ASSERT(size <= 64, "GlyphExcludeRanges[] size must be small!") end if font_cfg.FontLoader ~= nil then IM_ASSERT(font_cfg.FontLoader.FontBakedLoadGlyph ~= nil) IM_ASSERT(font_cfg.FontLoader.LoaderInit == nil and font_cfg.FontLoader.LoaderShutdown == nil) end if font_cfg_in.MergeMode and font_cfg_in.SizePixels > 0 then IM_ASSERT(bit32.band(font.Flags, ImFontFlags.ImplicitRefSize) == 0, "Cannot use MergeMode with an explicit reference size when the destination font used an implicit reference size!") end IM_ASSERT(font_cfg.FontLoaderData == nil) if not ImFontAtlasFontSourceInit(self, font_cfg) then ImFontAtlasFontDestroySourceData(self, font_cfg) self.Sources:pop_back() font.Sources:pop_back() if not font_cfg.MergeMode then font = nil self.Fonts:pop_back() end return nil end ImFontAtlasFontSourceAddToFont(self, font, font_cfg) if (is_first_font) then ImFontAtlasBuildNotifySetFont(self, nil, font) end return font end --- @param ctx ImGuiContext --- @return float local function GetExpectedContextFontSize(ctx) return ((ctx.Style.FontSizeBase > 0.0) and ctx.Style.FontSizeBase or 13.0) * ctx.Style.FontScaleMain * ctx.Style.FontScaleDpi end --- @param font_cfg ImFontConfig function MT.ImFontAtlas:AddFontDefault(font_cfg) if self.OwnerContext == nil or GetExpectedContextFontSize(self.OwnerContext) >= 15.0 then return self:AddFontDefaultVector(font_cfg) else return self:AddFontDefaultBitmap(font_cfg) end end function MT.ImFontAtlas:AddFontFromMemoryTTF(font_data, font_data_size, size_pixels, font_cfg_template, glyph_ranges) IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") local font_cfg = font_cfg_template and font_cfg_template or ImFontConfig() IM_ASSERT(font_cfg.FontData == nil) IM_ASSERT(font_data_size > 100, "Incorrect value for font_data_size!") font_cfg.FontData = font_data font_cfg.FontDataSize = font_data_size font_cfg.SizePixels = (size_pixels > 0.0) and size_pixels or font_cfg.SizePixels if glyph_ranges then font_cfg.GlyphRanges = glyph_ranges end return self:AddFont(font_cfg) end -- TODO: GetDefaultCompressedFontDataProggyClean, GetDefaultCompressedFontDataProggyForever function MT.ImFontAtlas:AddFontFromMemoryCompressedTTF() -- TODO: end function MT.ImFontAtlas:AddFontFromFileTTF(filename, size_pixels, font_cfg_template, glyph_ranges) IM_ASSERT(not self.Locked, "Cannot modify a locked ImFontAtlas!") local data, data_size = ImStd.ImFileLoadToMemory(filename, "rb") if not data then if (font_cfg_template == nil or (bit32.band(font_cfg_template.Flags, ImFontFlags.NoLoadError) == 0)) then -- IMGUI_DEBUG_LOG("While loading '%s'\n", filename) IM_ASSERT_USER_ERROR(0, "Could not load font file!") end return nil end local font_cfg = font_cfg_template and font_cfg_template or ImFontConfig() if not font_cfg.Name or font_cfg.Name == "" then for i = #filename, 1, -1 do local c = string.byte(filename, i, i) if (c == 47 or c == 92) then -- '/' or '\\' font_cfg.Name = string.sub(filename, i + 1) break end end end return self:AddFontFromMemoryTTF(data, data_size, size_pixels, font_cfg, glyph_ranges) end function GetDefaultFontDataProggyClean() return ImStd.ImFileLoadToMemory("fonts/ProggyClean.ttf", "rb") end function GetDefaultFontDataProggyForever() return ImStd.ImFileLoadToMemory("fonts/ProggyForever.ttf", "rb") end -- TODO: IMGUI_DISABLE_DEFAULT_FONT, IMGUI_DISABLE_DEFAULT_FONT_BITMAP --- @param font_cfg_template ImFontConfig function MT.ImFontAtlas:AddFontDefaultBitmap(font_cfg_template) local font_cfg = font_cfg_template and font_cfg_template or ImFontConfig() if not font_cfg_template then font_cfg.PixelSnapH = true end if font_cfg.SizePixels <= 0.0 then font_cfg.SizePixels = 13.0 font_cfg.Flags = bit32.bor(font_cfg.Flags, ImFontFlags.ImplicitRefSize) end if not font_cfg.Name or font_cfg.Name == "" then font_cfg.Name = "ProggyClean.ttf" end font_cfg.EllipsisChar = 0x0085 font_cfg.GlyphOffset.y = font_cfg.GlyphOffset.y + 1.0 * (font_cfg.SizePixels / 13.0) local ttf_data, ttf_data_size = GetDefaultFontDataProggyClean() return self:AddFontFromMemoryTTF(ttf_data, ttf_data_size, font_cfg.SizePixels, font_cfg) end --- @param font_cfg_template ImFontConfig function MT.ImFontAtlas:AddFontDefaultVector(font_cfg_template) local font_cfg = font_cfg_template and font_cfg_template or ImFontConfig() if not font_cfg_template then font_cfg.PixelSnapH = true end if font_cfg.SizePixels <= 0.0 then font_cfg.SizePixels = 13.0 font_cfg.Flags = bit32.bor(font_cfg.Flags, ImFontFlags.ImplicitRefSize) end if not font_cfg.Name or font_cfg.Name == "" then font_cfg.Name = "ProggyForever.ttf" end font_cfg.ExtraSizeScale = font_cfg.ExtraSizeScale * 1.015 font_cfg.GlyphOffset.y = font_cfg.GlyphOffset.y + 0.5 * (font_cfg.SizePixels / 16.0) local ttf_data, ttf_data_size = GetDefaultFontDataProggyForever() return self:AddFontFromMemoryTTF(ttf_data, ttf_data_size, font_cfg.SizePixels, font_cfg) end function MT.ImFontAtlas:GetCustomRect(id, out_r) local r = ImFontAtlasPackGetRectSafe(self, id) if r == nil then return false end IM_ASSERT(self.TexData.Width > 0 and self.TexData.Height > 0) if out_r == nil then return true end out_r.x = r.x out_r.y = r.y out_r.w = r.w out_r.h = r.h ImVec2_Copy(out_r.uv0, ImVec2((r.x), (r.y)) * self.TexUvScale) ImVec2_Copy(out_r.uv1, ImVec2((r.x + r.w), (r.y + r.h)) * self.TexUvScale) return true end --- @param atlas ImFontAtlas --- @param cursor_type ImGuiMouseCursor --- @param out_offset ImVec2 --- @param out_size ImVec2 --- @param out_uv_border ImVec2[] --- @param out_uv_fill ImVec2[] function ImFontAtlasGetMouseCursorTexData(atlas, cursor_type, out_offset, out_size, out_uv_border, out_uv_fill) if cursor_type <= ImGuiMouseCursor.None or cursor_type >= ImGuiMouseCursor.COUNT then return false end if bit32.band(atlas.Flags, ImFontAtlasFlags.NoMouseCursors) ~= 0 then return false end local r = ImFontAtlasPackGetRect(atlas, atlas.Builder.PackIdMouseCursors) local pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type + 1][1] + ImVec2(r.x, r.y) local size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type + 1][2] ImVec2_Copy(out_size, size) ImVec2_Copy(out_offset, FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type + 1][3]) ImVec2_Copy(out_uv_border[1], (pos) * atlas.TexUvScale) ImVec2_Copy(out_uv_border[2], (pos + size) * atlas.TexUvScale) pos.x = pos.x + (FONT_ATLAS_DEFAULT_TEX_DATA_W + 1) ImVec2_Copy(out_uv_fill[1], (pos) * atlas.TexUvScale) ImVec2_Copy(out_uv_fill[2], (pos + size) * atlas.TexUvScale) return true end function MT.ImFontAtlas:AddCustomRect(width, height, out_r) IM_ASSERT(width > 0 and width <= 0xFFFF) IM_ASSERT(height > 0 and height <= 0xFFFF) if (self.Builder == nil) then ImFontAtlasBuildInit(self) end local r_id = ImFontAtlasPackAddRect(self, width, height) if (r_id == ImFontAtlasRectId_Invalid) then return ImFontAtlasRectId_Invalid end if (out_r ~= nil) then self:GetCustomRect(r_id, out_r) end if (self.RendererHasTextures) then local r = ImFontAtlasPackGetRect(self, r_id) ImFontAtlasTextureBlockQueueUpload(self, self.TexData, r.x, r.y, r.w, r.h) end return r_id end local function IM_NORMALIZE2F_OVER_ZERO(VX, VY) local d2 = VX * VX + VY * VY if d2 > 0.0 then local inv_len = ImRsqrt(d2) VX = VX * inv_len VY = VY * inv_len end return VX, VY end local function IM_FIXNORMAL2F(VX, VY) local IM_FIXNORMAL2F_MAX_INVLEN2 = 100 local d2 = VX * VX + VY * VY if d2 > 0.000001 then local inv_len2 = 1.0 / d2 if inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2 then inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2 end VX = VX * inv_len2 VY = VY * inv_len2 end return VX, VY end function MT.ImDrawData:Clear() self.Valid = false self.FrameCount = 0; self.TotalIdxCount = 0; self.TotalVtxCount = 0 self.CmdLists:resize(0) self.DisplayPos = ImVec2(0.0, 0.0) self.DisplaySize = ImVec2(0.0, 0.0) self.FramebufferScale = ImVec2(0.0, 0.0) self.OwnerViewport = nil self.Textures = nil end function ImGui.AddDrawListToDrawDataEx(draw_data, out_list, draw_list) if draw_list.CmdBuffer.Size == 0 then return end if draw_list.CmdBuffer.Size == 1 and draw_list.CmdBuffer.Data[1].ElemCount == 0 and draw_list.CmdBuffer.Data[1].UserCallback == nil then return end IM_ASSERT(draw_list.VtxBuffer.Size == 0 or draw_list._VtxWritePtr == draw_list.VtxBuffer.Size + 1) IM_ASSERT(draw_list.IdxBuffer.Size == 0 or draw_list._IdxWritePtr == draw_list.IdxBuffer.Size + 1) if (bit32.band(draw_list.Flags, ImDrawListFlags.AllowVtxOffset) == 0) then IM_ASSERT(draw_list._VtxCurrentIdx == draw_list.VtxBuffer.Size + 1) end out_list:push_back(draw_list) draw_data.TotalVtxCount = draw_data.TotalVtxCount + draw_list.VtxBuffer.Size draw_data.TotalIdxCount = draw_data.TotalIdxCount + draw_list.IdxBuffer.Size end function MT.ImDrawData:AddDrawList(draw_list) draw_list:_PopUnusedDrawCmd() ImGui.AddDrawListToDrawDataEx(self, self.CmdLists, draw_list) end local IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN = 4 local IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX = 512 local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD, _MAXERROR) return ImClamp(IM_ROUNDUP_TO_EVEN(ImCeil(IM_PI / ImAcos(1 - ImMin(_MAXERROR, _RAD) / _RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) end local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N, _MAXERROR) return (_MAXERROR / (1 - ImCos(IM_PI / ImMax(_N, IM_PI)))) end local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N, _RAD) return ((1 - ImCos(IM_PI / ImMax(_N, IM_PI))) / _RAD) end function MT.ImDrawListSharedData:SetCircleTessellationMaxError(max_error) if self.CircleTessellationMaxError == max_error then return end IM_ASSERT(max_error > 0) self.CircleTessellationMaxError = max_error for i = 1, 64 do -- IM_COUNTOF(CircleSegmentCounts) local radius = (i - 1) self.CircleSegmentCounts[i] = (i > 1) and IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, self.CircleTessellationMaxError) or IM_DRAWLIST_ARCFAST_SAMPLE_MAX end self.ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, self.CircleTessellationMaxError) end --- @param data ImDrawListSharedData function MT.ImDrawList:_SetDrawListSharedData(data) if self._Data ~= nil then self._Data.DrawLists:find_erase_unsorted(self) end self._Data = data if self._Data ~= nil then self._Data.DrawLists:push_back(self) end end -- TODO: function MT.ImDrawList:_ResetForNewFrame() self._ContentClipX0 = nil -- set again by Begin() (Roblox backend scroll reuse) if self._Splitter._Count > 1 then self._Splitter:Merge(self) end self._Splitter._Current = 0 -- [Lua] recover from an error thrown mid-split self._Splitter._Count = 1 self.CmdBuffer:resize(0) self.IdxBuffer:resize(0) self.VtxBuffer:resize(0) self.Flags = self._Data.InitialFlags self._CmdHeader = ImDrawCmdHeader() -- memset(&_CmdHeader, 0, sizeof(_CmdHeader)) self._VtxCurrentIdx = 1 self._VtxWritePtr = 1 self._IdxWritePtr = 1 self._ClipRectStack:resize(0) self._TextureStack:resize(0) self._Path:resize(0) self.CmdBuffer:push_back(ImDrawCmd()) self._FringeScale = self._Data.InitialFringeScale end function MT.ImDrawList:_ClearFreeMemory() self.CmdBuffer:clear() self.IdxBuffer:clear() self.VtxBuffer:clear() self.Flags = ImDrawListFlags.None self._VtxCurrentIdx = 1 self._VtxWritePtr = 1 self._IdxWritePtr = 1 self._ClipRectStack:clear() self._TextureStack:clear() -- self._CallbacksDataBuf:clear() self._Path:clear() self._Splitter:ClearFreeMemory() end function MT.ImDrawList:AddDrawCmd() local draw_cmd = ImDrawCmd() ImVec4_Copy(draw_cmd.ClipRect, self._CmdHeader.ClipRect) -- Same as calling ImDrawCmd_HeaderCopy()? draw_cmd.TexRef = self._CmdHeader.TexRef draw_cmd.VtxOffset = self._CmdHeader.VtxOffset draw_cmd.IdxOffset = self.IdxBuffer.Size IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z and draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w) self.CmdBuffer:push_back(draw_cmd) end function MT.ImDrawList:_PopUnusedDrawCmd() while self.CmdBuffer.Size > 0 do local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] if curr_cmd.ElemCount ~= 0 or curr_cmd.UserCallback ~= nil then break end self.CmdBuffer:pop_back() end end --- @param callback ImDrawCallback --- @param userdata any --- @param userdata_size? size_t function MT.ImDrawList:AddCallback(callback, userdata, userdata_size) if userdata_size == nil then userdata_size = 0 end IM_ASSERT(callback ~= nil) IM_ASSERT_PARANOID(self.CmdBuffer.Size > 0) local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] IM_ASSERT(curr_cmd.UserCallback == nil) if curr_cmd.ElemCount ~= 0 then self:AddDrawCmd() curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] end curr_cmd.UserCallback = callback -- TODO: _CallbacksDataBuf? if userdata_size == 0 then curr_cmd.UserCallbackData = userdata else IM_ASSERT(userdata ~= nil) IM_ASSERT(userdata_size < bit32.lshift(1, 31)) end self:AddDrawCmd() end --- Compare ClipRect, TexRef, VtxOffset --- @param CMD_LHS ImDrawCmd|ImDrawCmdHeader --- @param CMD_RHS ImDrawCmd|ImDrawCmdHeader --- @return bool local function ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) if CMD_LHS.ClipRect.x ~= CMD_RHS.ClipRect.x or CMD_LHS.ClipRect.y ~= CMD_RHS.ClipRect.y or CMD_LHS.ClipRect.z ~= CMD_RHS.ClipRect.z or CMD_LHS.ClipRect.w ~= CMD_RHS.ClipRect.w then return false end if CMD_LHS.TexRef._TexData ~= CMD_RHS.TexRef._TexData or CMD_LHS.TexRef._TexID ~= CMD_RHS.TexRef._TexID then return false end if CMD_LHS.VtxOffset ~= CMD_RHS.VtxOffset then return false end return true end --- Copy ClipRect, TexRef, VtxOffset --- @param CMD_DST ImDrawCmd|ImDrawCmdHeader --- @param CMD_SRC ImDrawCmd|ImDrawCmdHeader local function ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) CMD_DST.ClipRect.x = CMD_SRC.ClipRect.x CMD_DST.ClipRect.y = CMD_SRC.ClipRect.y CMD_DST.ClipRect.z = CMD_SRC.ClipRect.z CMD_DST.ClipRect.w = CMD_SRC.ClipRect.w CMD_DST.TexRef._TexData = CMD_SRC.TexRef._TexData CMD_DST.TexRef._TexID = CMD_SRC.TexRef._TexID CMD_DST.VtxOffset = CMD_SRC.VtxOffset end --- @param CMD_0 ImDrawCmd --- @param CMD_1 ImDrawCmd local function ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) return CMD_0.IdxOffset + CMD_0.ElemCount == CMD_1.IdxOffset end function MT.ImDrawList:_TryMergeDrawCmds() IM_ASSERT_PARANOID(self.CmdBuffer.Size > 0) local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] local prev_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size - 1] if ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) and ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) and curr_cmd.UserCallback == nil and prev_cmd.UserCallback == nil then prev_cmd.ElemCount = prev_cmd.ElemCount + curr_cmd.ElemCount self.CmdBuffer:pop_back() end end function MT.ImDrawList:_OnChangedClipRect() IM_ASSERT_PARANOID(self.CmdBuffer.Size > 0) local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] if (curr_cmd.ElemCount ~= 0 and self._CmdHeader.ClipRect ~= curr_cmd.ClipRect) then self:AddDrawCmd() return end IM_ASSERT(curr_cmd.UserCallback == nil) local prev_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size - 1] if (curr_cmd.ElemCount == 0 and self.CmdBuffer.Size > 1 and ImDrawCmd_HeaderCompare(self._CmdHeader, prev_cmd) and ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) and prev_cmd.UserCallback == nil) then self.CmdBuffer:pop_back() return end ImVec4_Copy(curr_cmd.ClipRect, self._CmdHeader.ClipRect) end function MT.ImDrawList:_OnChangedTexture() IM_ASSERT_PARANOID(self.CmdBuffer.Size > 0) local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] if curr_cmd.ElemCount ~= 0 and curr_cmd.TexRef ~= self._CmdHeader.TexRef then self:AddDrawCmd() return end if curr_cmd.UserCallback ~= nil then return end local prev_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size - 1] if curr_cmd.ElemCount == 0 and self.CmdBuffer.Size > 1 and ImDrawCmd_HeaderCompare(self._CmdHeader, prev_cmd) and ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) and prev_cmd.UserCallback == nil then self.CmdBuffer:pop_back() return end curr_cmd.TexRef = self._CmdHeader.TexRef end function MT.ImDrawList:_OnChangedVtxOffset() self._VtxCurrentIdx = 1 IM_ASSERT_PARANOID(self.CmdBuffer.Size > 0) local curr_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] if curr_cmd.ElemCount ~= 0 then self:AddDrawCmd() return end IM_ASSERT(curr_cmd.UserCallback == nil) curr_cmd.VtxOffset = self._CmdHeader.VtxOffset end ---------------------------------------------------------------- -- [SECTION] ImDrawListSplitter ---------------------------------------------------------------- -- Lua: channels swap ImVector objects with the draw list (C++ memcpy of the vector headers). -- Channel 0 holds nothing while it is the current channel (its buffers live in the draw list). -- Copy ClipRect, TexRef, VtxOffset (TexRef is assigned by reference, never mutated) local function ImDrawCmd_HeaderCopyRef(dst, src) ImVec4_Copy(dst.ClipRect, src.ClipRect) dst.TexRef = src.TexRef dst.VtxOffset = src.VtxOffset end function MT.ImDrawListSplitter:Clear() self._Current = 0 self._Count = 1 end function MT.ImDrawListSplitter:ClearFreeMemory() for i = 1, self._Channels.Size do local ch = self._Channels.Data[i] if i - 1 == self._Current then -- Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again self._Channels.Data[i] = ImDrawChannel() else ch._CmdBuffer:clear() ch._IdxBuffer:clear() end end self._Current = 0 self._Count = 1 self._Channels:clear() end --- @param draw_list ImDrawList --- @param channels_count int function MT.ImDrawListSplitter:Split(draw_list, channels_count) IM_ASSERT(self._Current == 0 and self._Count <= 1, "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.") local old_channels_count = self._Channels.Size if old_channels_count < channels_count then self._Channels:reserve(channels_count) self._Channels:resize(channels_count) end self._Count = channels_count -- Channel 0 is the draw list itself (memset to 0 in C++) local channels = self._Channels.Data channels[1] = { _CmdBuffer = nil, _IdxBuffer = nil } for i = 2, channels_count do if i > old_channels_count or channels[i] == nil then channels[i] = ImDrawChannel() else channels[i]._CmdBuffer:resize(0) channels[i]._IdxBuffer:resize(0) end end end --- @param draw_list ImDrawList function MT.ImDrawListSplitter:Merge(draw_list) -- Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. if self._Count <= 1 then return end self:SetCurrentChannel(draw_list, 0) draw_list:_PopUnusedDrawCmd() -- Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. local new_cmd_buffer_count = 0 local new_idx_buffer_count = 0 local last_cmd = (self._Count > 0 and draw_list.CmdBuffer.Size > 0) and draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size] or nil local idx_offset = last_cmd and (last_cmd.IdxOffset + last_cmd.ElemCount) or 0 local channels = self._Channels.Data for i = 2, self._Count do local ch = channels[i] local cmds = ch._CmdBuffer if cmds.Size > 0 and cmds.Data[cmds.Size].ElemCount == 0 and cmds.Data[cmds.Size].UserCallback == nil then -- Equivalent of PopUnusedDrawCmd() cmds:pop_back() end if cmds.Size > 0 and last_cmd ~= nil then -- Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. -- Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. local next_cmd = cmds.Data[1] if ImDrawCmd_HeaderCompare(last_cmd, next_cmd) and last_cmd.UserCallback == nil and next_cmd.UserCallback == nil then -- Merge previous channel last draw command with current channel first draw command if matching. last_cmd.ElemCount = last_cmd.ElemCount + next_cmd.ElemCount idx_offset = idx_offset + next_cmd.ElemCount cmds:erase(1) -- FIXME-OPT: Improve for multiple merges. end end if cmds.Size > 0 then last_cmd = cmds.Data[cmds.Size] end new_cmd_buffer_count = new_cmd_buffer_count + cmds.Size new_idx_buffer_count = new_idx_buffer_count + ch._IdxBuffer.Size for cmd_n = 1, cmds.Size do cmds.Data[cmd_n].IdxOffset = idx_offset idx_offset = idx_offset + cmds.Data[cmd_n].ElemCount end end local cmd_write = draw_list.CmdBuffer.Size + 1 local idx_write = draw_list.IdxBuffer.Size + 1 draw_list.CmdBuffer:resize(draw_list.CmdBuffer.Size + new_cmd_buffer_count) draw_list.IdxBuffer:resize(draw_list.IdxBuffer.Size + new_idx_buffer_count) -- Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) local dst_cmds = draw_list.CmdBuffer.Data local dst_idx = draw_list.IdxBuffer.Data for i = 2, self._Count do local ch = channels[i] local src_cmds = ch._CmdBuffer.Data for n = 1, ch._CmdBuffer.Size do dst_cmds[cmd_write] = src_cmds[n] src_cmds[n] = nil -- ownership moved to the draw list cmd_write = cmd_write + 1 end local src_idx = ch._IdxBuffer.Data for n = 1, ch._IdxBuffer.Size do dst_idx[idx_write] = src_idx[n] idx_write = idx_write + 1 end end draw_list._IdxWritePtr = idx_write -- Ensure there's always a non-callback draw command trailing the command-buffer if draw_list.CmdBuffer.Size == 0 or draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].UserCallback ~= nil then draw_list:AddDrawCmd() end -- If current command is used with different settings we need to add a new command local curr_cmd = draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size] if curr_cmd.ElemCount == 0 then ImDrawCmd_HeaderCopyRef(curr_cmd, draw_list._CmdHeader) -- Copy ClipRect, TexRef, VtxOffset elseif not ImDrawCmd_HeaderCompare(curr_cmd, draw_list._CmdHeader) then draw_list:AddDrawCmd() end self._Count = 1 end --- @param draw_list ImDrawList --- @param idx int # 0-based channel index function MT.ImDrawListSplitter:SetCurrentChannel(draw_list, idx) IM_ASSERT(idx >= 0 and idx < self._Count) if self._Current == idx then return end -- Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() local channels = self._Channels.Data local cur = channels[self._Current + 1] cur._CmdBuffer = draw_list.CmdBuffer cur._IdxBuffer = draw_list.IdxBuffer self._Current = idx local ch = channels[idx + 1] draw_list.CmdBuffer = ch._CmdBuffer draw_list.IdxBuffer = ch._IdxBuffer draw_list._IdxWritePtr = draw_list.IdxBuffer.Size + 1 -- If current command is used with different settings we need to add a new command local curr_cmd = nil if draw_list.CmdBuffer.Size > 0 then curr_cmd = draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size] end if curr_cmd == nil then draw_list:AddDrawCmd() elseif curr_cmd.ElemCount == 0 then ImDrawCmd_HeaderCopyRef(curr_cmd, draw_list._CmdHeader) -- Copy ClipRect, TexRef, VtxOffset elseif not ImDrawCmd_HeaderCompare(curr_cmd, draw_list._CmdHeader) then draw_list:AddDrawCmd() end end --- @param count int function MT.ImDrawList:ChannelsSplit(count) self._Splitter:Split(self, count) end function MT.ImDrawList:ChannelsMerge() self._Splitter:Merge(self) end --- @param n int # 0-based function MT.ImDrawList:ChannelsSetCurrent(n) self._Splitter:SetCurrentChannel(self, n) end --- @param points ImVec2[] --- @param points_count int --- @param col ImU32 @native function MT.ImDrawList:AddConvexPolyFilled(points, points_count, col) if points_count < 3 or bit32.band(col, IM_COL32_A_MASK) == 0 then return end local uv = self._Data.TexUvWhitePixel if bit32.band(self.Flags, ImDrawListFlags.AntiAliasedFill) ~= 0 then local AA_SIZE = self._FringeScale local col_trans = bit32.band(col, bit32.bnot(IM_COL32_A_MASK)) local idx_count = (points_count - 2) * 3 + points_count * 6 local vtx_count = points_count * 2 self:PrimReserve(idx_count, vtx_count) local vtx_inner_idx = self._VtxCurrentIdx local vtx_outer_idx = self._VtxCurrentIdx + 1 local idx_data = self.IdxBuffer.Data for i = 2, points_count - 1 do local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = vtx_inner_idx; idx_data[idx_write_ptr + 1] = vtx_inner_idx + ((i - 1) * 2); idx_data[idx_write_ptr + 2] = vtx_inner_idx + (i * 2) self._IdxWritePtr = idx_write_ptr + 3 end self._Data.TempBuffer:reserve_discard(points_count) local temp_normals = self._Data.TempBuffer.Data local i0 = points_count for i1 = 1, points_count do local p0 = points[i0] local p1 = points[i1] local dx = p1.x - p0.x local dy = p1.y - p0.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) temp_normals[i0].x = dy temp_normals[i0].y = -dx i0 = i1 end local vtx_data = self.VtxBuffer.Buf i0 = points_count for i1 = 1, points_count do local n0 = temp_normals[i0] local n1 = temp_normals[i1] local dm_x = (n0.x + n1.x) * 0.5 local dm_y = (n0.y + n1.y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) dm_x = dm_x * AA_SIZE * 0.5 dm_y = dm_y * AA_SIZE * 0.5 local vtx_write_ptr = self._VtxWritePtr WV(vtx_data, vtx_write_ptr + 0, points[i1].x - dm_x, points[i1].y - dm_y, uv.x, uv.y, col) WV(vtx_data, vtx_write_ptr + 1, points[i1].x + dm_x, points[i1].y + dm_y, uv.x, uv.y, col_trans) self._VtxWritePtr = vtx_write_ptr + 2 local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = vtx_inner_idx + ((i1 - 1) * 2); idx_data[idx_write_ptr + 1] = vtx_inner_idx + ((i0 - 1) * 2); idx_data[idx_write_ptr + 2] = vtx_outer_idx + ((i0 - 1) * 2) idx_data[idx_write_ptr + 3] = vtx_outer_idx + ((i0 - 1) * 2); idx_data[idx_write_ptr + 4] = vtx_outer_idx + ((i1 - 1) * 2); idx_data[idx_write_ptr + 5] = vtx_inner_idx + ((i1 - 1) * 2) self._IdxWritePtr = idx_write_ptr + 6 i0 = i1 end self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count else local idx_count = (points_count - 2) * 3 local vtx_count = points_count self:PrimReserve(idx_count, vtx_count) local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf for i = 1, vtx_count do local vtx_write_ptr = self._VtxWritePtr WVP(vtx_data, vtx_write_ptr + 0, points[i], uv, col) self._VtxWritePtr = vtx_write_ptr + 1 end for i = 3, points_count do local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = self._VtxCurrentIdx; idx_data[idx_write_ptr + 1] = self._VtxCurrentIdx + i - 2; idx_data[idx_write_ptr + 2] = self._VtxCurrentIdx + i - 1 self._IdxWritePtr = idx_write_ptr + 3 end self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count end end function MT.ImDrawList:PushTexture(tex_ref) self._TextureStack:push_back(tex_ref) self._CmdHeader.TexRef = tex_ref if (tex_ref._TexData ~= nil) then IM_ASSERT(tex_ref._TexData.WantDestroyNextFrame == false) end self:_OnChangedTexture() end function MT.ImDrawList:PopTexture() self._TextureStack:pop_back() self._CmdHeader.TexRef = (self._TextureStack.Size == 0) and ImTextureRef() or self._TextureStack.Data[self._TextureStack.Size] self:_OnChangedTexture() end function MT.ImDrawList:_SetTexture(tex_ref) if (self._CmdHeader.TexRef == tex_ref) then return end self._CmdHeader.TexRef = tex_ref self._TextureStack.Data[self._TextureStack.Size] = tex_ref self:_OnChangedTexture() end @native function MT.ImDrawList:PrimReserve(idx_count, vtx_count) IM_ASSERT_PARANOID(idx_count >= 0 and vtx_count >= 0) if (self._VtxCurrentIdx + vtx_count >= bit32.lshift(1, 16)) and (bit32.band(self.Flags, ImDrawListFlags.AllowVtxOffset) ~= 0) then self._CmdHeader.VtxOffset = self.VtxBuffer.Size + 1 self:_OnChangedVtxOffset() end local draw_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] draw_cmd.ElemCount = draw_cmd.ElemCount + idx_count local vtx_buffer_old_size = self.VtxBuffer.Size self.VtxBuffer:resize(vtx_buffer_old_size + vtx_count) self._VtxWritePtr = vtx_buffer_old_size + 1 local idx_buffer_old_size = self.IdxBuffer.Size self.IdxBuffer:resize(idx_buffer_old_size + idx_count) self._IdxWritePtr = idx_buffer_old_size + 1 end function MT.ImDrawList:PrimUnreserve(idx_count, vtx_count) IM_ASSERT_PARANOID(idx_count >= 0 and vtx_count >= 0) local draw_cmd = self.CmdBuffer.Data[self.CmdBuffer.Size] draw_cmd.ElemCount = draw_cmd.ElemCount - idx_count self.VtxBuffer:shrink(self.VtxBuffer.Size - vtx_count) self.IdxBuffer:shrink(self.IdxBuffer.Size - idx_count) self._VtxWritePtr = self.VtxBuffer.Size + 1 self._IdxWritePtr = self.IdxBuffer.Size + 1 end --- @param a ImVec2 --- @param c ImVec2 --- @param col ImU32 @native function MT.ImDrawList:PrimRect(a, c, col) local uv = self._Data.TexUvWhitePixel local idx = self._VtxCurrentIdx local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = idx idx_data[idx_write_ptr + 1] = idx + 1 idx_data[idx_write_ptr + 2] = idx + 2 idx_data[idx_write_ptr + 3] = idx idx_data[idx_write_ptr + 4] = idx + 2 idx_data[idx_write_ptr + 5] = idx + 3 local vtx_write_ptr = self._VtxWritePtr local ax, ay, cx, cy, u, v = a.x, a.y, c.x, c.y, uv.x, uv.y WV(vtx_data, vtx_write_ptr + 0, ax, ay, u, v, col) WV(vtx_data, vtx_write_ptr + 1, cx, ay, u, v, col) WV(vtx_data, vtx_write_ptr + 2, cx, cy, u, v, col) WV(vtx_data, vtx_write_ptr + 3, ax, cy, u, v, col) self._VtxWritePtr = vtx_write_ptr + 4 self._VtxCurrentIdx = idx + 4 self._IdxWritePtr = idx_write_ptr + 6 end --- @param a ImVec2 --- @param c ImVec2 --- @param uv_a ImVec2 --- @param uv_c ImVec2 --- @param col any function MT.ImDrawList:PrimRectUV(a, c, uv_a, uv_c, col) local idx = self._VtxCurrentIdx local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = idx idx_data[idx_write_ptr + 1] = idx + 1 idx_data[idx_write_ptr + 2] = idx + 2 idx_data[idx_write_ptr + 3] = idx idx_data[idx_write_ptr + 4] = idx + 2 idx_data[idx_write_ptr + 5] = idx + 3 local vtx_write_ptr = self._VtxWritePtr WV(vtx_data, vtx_write_ptr + 0, a.x, a.y, uv_a.x, uv_a.y, col) WV(vtx_data, vtx_write_ptr + 1, c.x, a.y, uv_c.x, uv_a.y, col) WV(vtx_data, vtx_write_ptr + 2, c.x, c.y, uv_c.x, uv_c.y, col) WV(vtx_data, vtx_write_ptr + 3, a.x, c.y, uv_a.x, uv_c.y, col) self._VtxWritePtr = vtx_write_ptr + 4 self._VtxCurrentIdx = idx + 4 self._IdxWritePtr = idx_write_ptr + 6 end --- @param points ImVec2[] --- @param points_count int --- @param col ImU32 --- @param thickness float --- @param flags? ImDrawFlags @native function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) if flags == nil then flags = 0 end if points_count < 2 or bit32.band(col, IM_COL32_A_MASK) == 0 then return end local closed = bit32.band(flags, ImDrawFlags.Closed) ~= 0 local opaque_uv = self._Data.TexUvWhitePixel local count = closed and points_count or points_count - 1 -- Number of line segments local thick_line = thickness > self._FringeScale IM_ASSERT_USER_ERROR_RET(bit32.band(flags, ImDrawFlags.InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?") if bit32.band(self.Flags, ImDrawListFlags.AntiAliasedLines) ~= 0 then -- Anti-aliased stroke local AA_SIZE = self._FringeScale local col_trans = bit32.band(col, bit32.bnot(IM_COL32_A_MASK)) -- Thicknesses <1.0 should behave like thickness 1.0 thickness = ImMax(thickness, 1.0) local integer_thickness = ImFloor(thickness) local fractional_thickness = thickness - integer_thickness -- Do we want to draw this line using a texture? local use_texture = bit32.band(self.Flags, ImDrawListFlags.AntiAliasedLinesUseTex) ~= 0 and integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX and fractional_thickness <= 0.00001 and AA_SIZE == 1.0 IM_ASSERT_PARANOID((not use_texture) or bit32.band(self._Data.Font.OwnerAtlas.Flags, ImFontAtlasFlags.NoBakedLines) == 0) local idx_count = use_texture and (count * 6) or (thick_line and count * 18 or count * 12) local vtx_count = use_texture and (points_count * 2) or (thick_line and points_count * 4 or points_count * 3) self:PrimReserve(idx_count, vtx_count) -- Temporary buffer local temp_buffer_size = points_count * ((use_texture or not thick_line) and 3 or 5) self._Data.TempBuffer:reserve_discard(temp_buffer_size) local temp_normals = self._Data.TempBuffer.Data local temp_points = self._Data.TempBuffer.Data; local temp_points_start = points_count + 1 -- Calculate normals for each line segment for i1 = 1, count do local i2 = (i1 == points_count) and 1 or i1 + 1 local p1 = points[i1] local p2 = points[i2] local dx = p2.x - p1.x local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) temp_normals[i1].x = dy temp_normals[i1].y = -dx end if not closed then ImVec2_Copy(temp_normals[points_count], temp_normals[points_count - 1]) end -- If we are drawing a one-pixel-wide line without a texture, or a textured line of any width if use_texture or not thick_line then -- [PATH 1] Texture-based lines (thick or non-thick) -- [PATH 2] Non texture-based lines (non-thick) local half_draw_size = use_texture and (thickness * 0.5 + 1) or AA_SIZE -- If line is not closed, the first and last points need to be generated differently if not closed then ImVec2_CopyV(temp_points[temp_points_start + 0], ImVec2_AddVA(points[1], ImVec2_MulVX(temp_normals[1], half_draw_size))) ImVec2_CopyV(temp_points[temp_points_start + 1], ImVec2_SubVA(points[1], ImVec2_MulVX(temp_normals[1], half_draw_size))) ImVec2_CopyV(temp_points[temp_points_start + (points_count - 1) * 2 + 0], ImVec2_AddVA(points[points_count], ImVec2_MulVX(temp_normals[points_count], half_draw_size))) ImVec2_CopyV(temp_points[temp_points_start + (points_count - 1) * 2 + 1], ImVec2_SubVA(points[points_count], ImVec2_MulVX(temp_normals[points_count], half_draw_size))) end -- Generate indices and vertices local idx1 = self._VtxCurrentIdx local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf for i1 = 1, count do local i2 = (i1 == points_count) and 1 or i1 + 1 local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + (use_texture and 2 or 3)) -- Average normals local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) dm_x = dm_x * half_draw_size dm_y = dm_y * half_draw_size -- Add temporary vertices for the outer edges local out_off = (i2 - 1) * 2 temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_x temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_y temp_points[temp_points_start + out_off + 1].x = points[i2].x - dm_x temp_points[temp_points_start + out_off + 1].y = points[i2].y - dm_y if use_texture then -- Add indices for two triangles local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = idx2 + 0; idx_data[idx_write_ptr + 1] = idx1 + 0; idx_data[idx_write_ptr + 2] = idx1 + 1 idx_data[idx_write_ptr + 3] = idx2 + 1; idx_data[idx_write_ptr + 4] = idx1 + 1; idx_data[idx_write_ptr + 5] = idx2 + 0 self._IdxWritePtr = idx_write_ptr + 6 else -- Add indices for four triangles local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = idx2 + 0; idx_data[idx_write_ptr + 1] = idx1 + 0; idx_data[idx_write_ptr + 2] = idx1 + 2 idx_data[idx_write_ptr + 3] = idx1 + 2; idx_data[idx_write_ptr + 4] = idx2 + 2; idx_data[idx_write_ptr + 5] = idx2 + 0 idx_data[idx_write_ptr + 6] = idx2 + 1; idx_data[idx_write_ptr + 7] = idx1 + 1; idx_data[idx_write_ptr + 8] = idx1 + 0 idx_data[idx_write_ptr + 9] = idx1 + 0; idx_data[idx_write_ptr + 10] = idx2 + 0; idx_data[idx_write_ptr + 11] = idx2 + 1 self._IdxWritePtr = idx_write_ptr + 12 end idx1 = idx2 end -- Add vertices if use_texture then -- Texture-based: need to implement TexUvLines lookup local tex_uvs = self._Data.TexUvLines[integer_thickness] local tex_uv0 = ImVec2(tex_uvs.x, tex_uvs.y) local tex_uv1 = ImVec2(tex_uvs.z, tex_uvs.w) for i = 0, points_count - 1 do local vtx_write_ptr = self._VtxWritePtr WVP(vtx_data, vtx_write_ptr + 0, temp_points[temp_points_start + i * 2 + 0], tex_uv0, col) WVP(vtx_data, vtx_write_ptr + 1, temp_points[temp_points_start + i * 2 + 1], tex_uv1, col) self._VtxWritePtr = vtx_write_ptr + 2 end else -- If we're not using a texture, we need the center vertex as well for i = 0, points_count - 1 do local vtx_write_ptr = self._VtxWritePtr WVP(vtx_data, vtx_write_ptr + 0, points[i + 1], opaque_uv, col) WVP(vtx_data, vtx_write_ptr + 1, temp_points[temp_points_start + i * 2 + 0], opaque_uv, col_trans) WVP(vtx_data, vtx_write_ptr + 2, temp_points[temp_points_start + i * 2 + 1], opaque_uv, col_trans) self._VtxWritePtr = vtx_write_ptr + 3 end end else -- [PATH 3] Non texture-based lines (thick) local half_inner_thickness = (thickness - AA_SIZE) * 0.5 -- If line is not closed, handle first and last points if not closed then local points_last = points_count - 1 ImVec2_CopyV(temp_points[temp_points_start + 0], ImVec2_AddVA(points[1], ImVec2_MulVX(temp_normals[1], (half_inner_thickness + AA_SIZE)))) ImVec2_CopyV(temp_points[temp_points_start + 1], ImVec2_AddVA(points[1], ImVec2_MulVX(temp_normals[1], half_inner_thickness))) ImVec2_CopyV(temp_points[temp_points_start + 2], ImVec2_SubVA(points[1], ImVec2_MulVX(temp_normals[1], half_inner_thickness))) ImVec2_CopyV(temp_points[temp_points_start + 3], ImVec2_SubVA(points[1], ImVec2_MulVX(temp_normals[1], (half_inner_thickness + AA_SIZE)))) ImVec2_CopyV(temp_points[temp_points_start + points_last * 4 + 0], ImVec2_AddVA(points[points_count], ImVec2_MulVX(temp_normals[points_last + 1], (half_inner_thickness + AA_SIZE)))) ImVec2_CopyV(temp_points[temp_points_start + points_last * 4 + 1], ImVec2_AddVA(points[points_count], ImVec2_MulVX(temp_normals[points_last + 1], half_inner_thickness))) ImVec2_CopyV(temp_points[temp_points_start + points_last * 4 + 2], ImVec2_SubVA(points[points_count], ImVec2_MulVX(temp_normals[points_last + 1], half_inner_thickness))) ImVec2_CopyV(temp_points[temp_points_start + points_last * 4 + 3], ImVec2_SubVA(points[points_count], ImVec2_MulVX(temp_normals[points_last + 1], (half_inner_thickness + AA_SIZE)))) end -- Generate indices and vertices local idx1 = self._VtxCurrentIdx local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf for i1 = 1, count do local i2 = (i1 == points_count) and 1 or i1 + 1 local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + 4) -- Average normals local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) local dm_out_x = dm_x * (half_inner_thickness + AA_SIZE) local dm_out_y = dm_y * (half_inner_thickness + AA_SIZE) local dm_in_x = dm_x * half_inner_thickness local dm_in_y = dm_y * half_inner_thickness -- Add temporary vertices local out_off = (i2 - 1) * 4 temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_out_x temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_out_y temp_points[temp_points_start + out_off + 1].x = points[i2].x + dm_in_x temp_points[temp_points_start + out_off + 1].y = points[i2].y + dm_in_y temp_points[temp_points_start + out_off + 2].x = points[i2].x - dm_in_x temp_points[temp_points_start + out_off + 2].y = points[i2].y - dm_in_y temp_points[temp_points_start + out_off + 3].x = points[i2].x - dm_out_x temp_points[temp_points_start + out_off + 3].y = points[i2].y - dm_out_y -- Add indices local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = idx2 + 1; idx_data[idx_write_ptr + 1] = idx1 + 1; idx_data[idx_write_ptr + 2] = idx1 + 2 idx_data[idx_write_ptr + 3] = idx1 + 2; idx_data[idx_write_ptr + 4] = idx2 + 2; idx_data[idx_write_ptr + 5] = idx2 + 1 idx_data[idx_write_ptr + 6] = idx2 + 1; idx_data[idx_write_ptr + 7] = idx1 + 1; idx_data[idx_write_ptr + 8] = idx1 + 0 idx_data[idx_write_ptr + 9] = idx1 + 0; idx_data[idx_write_ptr + 10] = idx2 + 0; idx_data[idx_write_ptr + 11] = idx2 + 1 idx_data[idx_write_ptr + 12] = idx2 + 2; idx_data[idx_write_ptr + 13] = idx1 + 2; idx_data[idx_write_ptr + 14] = idx1 + 3 idx_data[idx_write_ptr + 15] = idx1 + 3; idx_data[idx_write_ptr + 16] = idx2 + 3; idx_data[idx_write_ptr + 17] = idx2 + 2 self._IdxWritePtr = idx_write_ptr + 18 idx1 = idx2 end -- Add vertices for i = 0, points_count - 1 do local vtx_write_ptr = self._VtxWritePtr WVP(vtx_data, vtx_write_ptr + 0, temp_points[temp_points_start + i * 4 + 0], opaque_uv, col_trans) WVP(vtx_data, vtx_write_ptr + 1, temp_points[temp_points_start + i * 4 + 1], opaque_uv, col) WVP(vtx_data, vtx_write_ptr + 2, temp_points[temp_points_start + i * 4 + 2], opaque_uv, col) WVP(vtx_data, vtx_write_ptr + 3, temp_points[temp_points_start + i * 4 + 3], opaque_uv, col_trans) self._VtxWritePtr = vtx_write_ptr + 4 end end self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count else -- [PATH 4] Non texture-based, Non anti-aliased lines local idx_count = count * 6 local vtx_count = count * 4 self:PrimReserve(idx_count, vtx_count) local idx_data = self.IdxBuffer.Data; local vtx_data = self.VtxBuffer.Buf for i1 = 1, count do local i2 = (i1 == points_count) and 1 or i1 + 1 local p1 = points[i1] local p2 = points[i2] local dx = p2.x - p1.x local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) dx = dx * (thickness * 0.5) dy = dy * (thickness * 0.5) local vtx_write_ptr = self._VtxWritePtr WV(vtx_data, vtx_write_ptr + 0, p1.x + dy, p1.y - dx, opaque_uv.x, opaque_uv.y, col) WV(vtx_data, vtx_write_ptr + 1, p2.x + dy, p2.y - dx, opaque_uv.x, opaque_uv.y, col) WV(vtx_data, vtx_write_ptr + 2, p2.x - dy, p2.y + dx, opaque_uv.x, opaque_uv.y, col) WV(vtx_data, vtx_write_ptr + 3, p1.x - dy, p1.y + dx, opaque_uv.x, opaque_uv.y, col) self._VtxWritePtr = vtx_write_ptr + 4 local idx_write_ptr = self._IdxWritePtr idx_data[idx_write_ptr + 0] = self._VtxCurrentIdx + 0; idx_data[idx_write_ptr + 1] = self._VtxCurrentIdx + 1; idx_data[idx_write_ptr + 2] = self._VtxCurrentIdx + 2 idx_data[idx_write_ptr + 3] = self._VtxCurrentIdx + 0; idx_data[idx_write_ptr + 4] = self._VtxCurrentIdx + 2; idx_data[idx_write_ptr + 5] = self._VtxCurrentIdx + 3 self._IdxWritePtr = idx_write_ptr + 6 self._VtxCurrentIdx = self._VtxCurrentIdx + 4 end end end function MT.ImDrawList:PathRect(a, b, rounding, flags) if not rounding then rounding = 0.0 end if not flags then flags = 0 end if rounding >= 0.5 then IM_ASSERT(bit32.band(flags, 0x0F) == 0, "Misuse of legacy hardcoded ImDrawCornerFlags values!") if bit32.band(flags, ImDrawFlags.RoundCornersMask_) == 0 then flags = bit32.bor(flags, ImDrawFlags.RoundCornersAll) end rounding = ImMin(rounding, ImAbs(b.x - a.x) * (((bit32.band(flags, ImDrawFlags.RoundCornersTop) == ImDrawFlags.RoundCornersTop) or (bit32.band(flags, ImDrawFlags.RoundCornersBottom) == ImDrawFlags.RoundCornersBottom)) and 0.5 or 1.0) - 1.0) rounding = ImMin(rounding, ImAbs(b.y - a.y) * (((bit32.band(flags, ImDrawFlags.RoundCornersLeft) == ImDrawFlags.RoundCornersLeft) or (bit32.band(flags, ImDrawFlags.RoundCornersRight) == ImDrawFlags.RoundCornersRight)) and 0.5 or 1.0) - 1.0) end if rounding < 0.5 or (bit32.band(flags, ImDrawFlags.RoundCornersMask_) == ImDrawFlags.RoundCornersNone) then self:PathLineTo(a) self:PathLineTo(ImVec2(b.x, a.y)) self:PathLineTo(b) self:PathLineTo(ImVec2(a.x, b.y)) else local rounding_tl = (bit32.band(flags, ImDrawFlags.RoundCornersTopLeft) ~= 0) and rounding or 0.0 local rounding_tr = (bit32.band(flags, ImDrawFlags.RoundCornersTopRight) ~= 0) and rounding or 0.0 local rounding_br = (bit32.band(flags, ImDrawFlags.RoundCornersBottomRight) ~= 0) and rounding or 0.0 local rounding_bl = (bit32.band(flags, ImDrawFlags.RoundCornersBottomLeft) ~= 0) and rounding or 0.0 self:PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9) self:PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12) self:PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3) self:PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6) end end @native function MT.ImDrawList:AddRectFilled(p_min, p_max, col, rounding, flags) if not rounding then rounding = 0.0 end if not flags then flags = 0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end if rounding < 0.5 or (bit32.band(flags, ImDrawFlags.RoundCornersMask_) == ImDrawFlags.RoundCornersNone) then self:PrimReserve(6, 4) self:PrimRect(p_min, p_max, col) else self:PathRect(p_min, p_max, rounding, flags) self:PathFillConvex(col) end end --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param col_upr_left ImU32 --- @param col_upr_right ImU32 --- @param col_bot_right ImU32 --- @param col_bot_left ImU32 function MT.ImDrawList:AddRectFilledMultiColor(p_min, p_max, col_upr_left, col_upr_right, col_bot_right, col_bot_left) if bit32.band(bit32.bor(col_upr_left, col_upr_right, col_bot_right, col_bot_left), IM_COL32_A_MASK) == 0 then return end local uv = self._Data.TexUvWhitePixel self:PrimReserve(6, 4) self:PrimWriteIdx(self._VtxCurrentIdx); self:PrimWriteIdx(self._VtxCurrentIdx + 1); self:PrimWriteIdx(self._VtxCurrentIdx + 2) self:PrimWriteIdx(self._VtxCurrentIdx); self:PrimWriteIdx(self._VtxCurrentIdx + 2); self:PrimWriteIdx(self._VtxCurrentIdx + 3) self:PrimWriteVtx(p_min, uv, col_upr_left) self:PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right) self:PrimWriteVtx(p_max, uv, col_bot_right) self:PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left) end --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param col ImU32 --- @param rounding float --- @param thickness? float --- @param flags? ImDrawFlags @native function MT.ImDrawList:AddRect(p_min, p_max, col, rounding, thickness, flags) if thickness == nil then thickness = 1.0 end if flags == nil then flags = 0 end IM_ASSERT_USER_ERROR_RET(bit32.band(flags, ImDrawFlags.InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?") if bit32.band(col, IM_COL32_A_MASK) == 0 then return end -- [Luau] square corners + whole-pixel thickness: 4 filled rects instead of a stroked path (same pixels, far cheaper here) if (rounding == nil or rounding < 0.5 or bit32.band(flags, ImDrawFlags.RoundCornersMask_) == ImDrawFlags.RoundCornersNone) and thickness >= 1.0 and thickness % 1 == 0 and p_max.x - p_min.x > 2 * thickness and p_max.y - p_min.y > 2 * thickness then local x0, y0, x1, y1, t = p_min.x, p_min.y, p_max.x, p_max.y, thickness self:PrimReserve(24, 16) self:PrimRect(ImVec2(x0, y0), ImVec2(x1, y0 + t), col) self:PrimRect(ImVec2(x0, y1 - t), ImVec2(x1, y1), col) self:PrimRect(ImVec2(x0, y0 + t), ImVec2(x0 + t, y1 - t), col) self:PrimRect(ImVec2(x1 - t, y0 + t), ImVec2(x1, y1 - t), col) return end if bit32.band(self.Flags, ImDrawListFlags.AntiAliasedLines) ~= 0 then self:PathRect(p_min + ImVec2(0.50, 0.50), p_max - ImVec2(0.50, 0.50), rounding, flags) else self:PathRect(p_min + ImVec2(0.50, 0.50), p_max - ImVec2(0.49, 0.49), rounding, flags) end self:PathStroke(col, thickness, ImDrawFlags.Closed) end function MT.ImDrawList:AddLine(p1, p2, col, thickness) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1 + ImVec2(0.5, 0.5)) self:PathLineTo(p2 + ImVec2(0.5, 0.5)) self:PathStroke(col, thickness) end --- @param min_x float --- @param max_x float --- @param y float --- @param col ImU32 --- @param thickness? float function MT.ImDrawList:AddLineH(min_x, max_x, y, col, thickness) if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(ImVec2(min_x + 0.5, y + 0.5)) self:PathLineTo(ImVec2(max_x + 0.5, y + 0.5)) self:PathStroke(col, thickness) end --- @param x float --- @param min_y float --- @param max_y float --- @param col ImU32 --- @param thickness? float function MT.ImDrawList:AddLineV(x, min_y, max_y, col, thickness) if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(ImVec2(x + 0.5, min_y + 0.5)) self:PathLineTo(ImVec2(x + 0.5, max_y + 0.5)) self:PathStroke(col, thickness) end function MT.ImDrawList:AddTriangle(p1, p2, p3, col, thickness) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathLineTo(p2) self:PathLineTo(p3) self:PathStroke(col, thickness, ImDrawFlags.Closed) end function MT.ImDrawList:AddQuad(p1, p2, p3, p4, col, thickness) if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathLineTo(p2) self:PathLineTo(p3) self:PathLineTo(p4) self:PathStroke(col, thickness, ImDrawFlags.Closed) end function MT.ImDrawList:AddQuadFilled(p1, p2, p3, p4, col) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathLineTo(p2) self:PathLineTo(p3) self:PathLineTo(p4) self:PathFillConvex(col) end function MT.ImDrawList:AddTriangleFilled(p1, p2, p3, col) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathLineTo(p2) self:PathLineTo(p3) self:PathFillConvex(col) end --- @param center ImVec2 --- @param radius float --- @param col ImU32 --- @param num_segments int --- @param thickness float function MT.ImDrawList:AddCircle(center, radius, col, num_segments, thickness) if num_segments == nil then num_segments = 0 end if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 or radius < 0.5 then return end if num_segments <= 0 then -- Use arc with automatic segment count self:_PathArcToFastEx(center, radius - 0.5, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0) self._Path.Size = self._Path.Size - 1 else -- Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) -- Because we are filling a closed shape we remove 1 from the count of segments/points local a_max = (IM_PI * 2.0) * (num_segments - 1) / num_segments self:PathArcTo(center, radius - 0.5, 0.0, a_max, num_segments - 1) end self:PathStroke(col, thickness, ImDrawFlags.Closed) end --- @param center ImVec2 --- @param radius float --- @param col ImU32 --- @param num_segments int function MT.ImDrawList:AddCircleFilled(center, radius, col, num_segments) if num_segments == nil then num_segments = 0 end if bit32.band(col, IM_COL32_A_MASK) == 0 or radius < 0.5 then return end if num_segments <= 0 then -- Use arc with automatic segment count self:_PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0) self._Path.Size = self._Path.Size - 1 else -- Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) -- Because we are filling a closed shape we remove 1 from the count of segments/points local a_max = (IM_PI * 2.0) * (num_segments - 1) / num_segments self:PathArcTo(center, radius, 0.0, a_max, num_segments - 1) end self:PathFillConvex(col) end --- @param font ImFont --- @param font_size float --- @param pos ImVec2 --- @param col ImU32 --- @param text string --- @param text_begin? int # Defaults to 1 --- @param text_end int --- @param wrap_width float --- @param cpu_fine_clip_rect? ImVec4 @native function MT.ImDrawList:AddText(font, font_size, pos, col, text, text_begin, text_end, wrap_width, cpu_fine_clip_rect) -- Overload: AddText(pos, col, text, text_end?) if type(font) == "table" and type(font[1]) == "number" then font, font_size, pos, col, text, text_begin, text_end, wrap_width, cpu_fine_clip_rect = nil, 0.0, font, font_size, pos, 1, col, 0.0, nil if text_end == nil then text_end = #text + 1 end end if text_begin == nil then text_begin = 1 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end if text_begin == text_end then return end if font == nil then font = self._Data.Font end if font_size == 0.0 then font_size = self._Data.FontSize end local clip_rect = ImVec4() -- Don't modify the clip rect! ImVec4_Copy(clip_rect, self._CmdHeader.ClipRect) if (cpu_fine_clip_rect) then clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect.x) clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect.y) clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect.z) clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect.w) end font:RenderText(self, font_size, pos, col, clip_rect, text, text_begin, text_end, wrap_width, (cpu_fine_clip_rect ~= nil) and ImDrawTextFlags.CpuFineClip or ImDrawTextFlags.None) end --- @param tex_ref ImTextureRef --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param uv_min? ImVec2 --- @param uv_max? ImVec2 --- @param col? ImU32 function MT.ImDrawList:AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col) if uv_min == nil then uv_min = ImVec2(0, 0) end if uv_max == nil then uv_max = ImVec2(1, 1) end if col == nil then col = IM_COL32_WHITE end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end local push_texture_id = tex_ref ~= self._CmdHeader.TexRef if push_texture_id then self:PushTexture(tex_ref) end self:PrimReserve(6, 4) self:PrimRectUV(p_min, p_max, uv_min, uv_max, col) if push_texture_id then self:PopTexture() end end --- @param tex_ref ImTextureRef --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param uv_min ImVec2 --- @param uv_max ImVec2 --- @param col ImU32 --- @param rounding float --- @param flags ImDrawFlags function MT.ImDrawList:AddImageRounded(tex_ref, p_min, p_max, uv_min, uv_max, col, rounding, flags) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end IM_ASSERT(bit32.band(flags, 0x0F) == 0, "Misuse of legacy hardcoded ImDrawCornerFlags values!") if bit32.band(flags, ImDrawFlags.RoundCornersMask_) == 0 then flags = bit32.bor(flags, ImDrawFlags.RoundCornersAll) end if rounding < 0.5 or bit32.band(flags, ImDrawFlags.RoundCornersMask_) == ImDrawFlags.RoundCornersNone then self:AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col) return end local push_texture_id = (tex_ref ~= self._CmdHeader.TexRef) if push_texture_id then self:PushTexture(tex_ref) end local vert_start_idx = self.VtxBuffer.Size + 1 self:PathRect(p_min, p_max, rounding, flags) self:PathFillConvex(col) local vert_end_idx = self.VtxBuffer.Size + 1 ImGui.ShadeVertsLinearUV(self, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true) if push_texture_id then self:PopTexture() end end --- @param radius float function MT.ImDrawList:_CalcCircleAutoSegmentCount(radius) local radius_idx = ImFloor(radius + 0.999) + 1 if radius_idx >= 1 and radius_idx <= 64 then -- IM_COUNTOF(_Data->CircleSegmentCounts) return self._Data.CircleSegmentCounts[radius_idx] else return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, self._Data.CircleTessellationMaxError) end end function MT.ImDrawList:PushClipRect(cr_min, cr_max, intersect_with_current_clip_rect) local cr = ImVec4(cr_min.x, cr_min.y, cr_max.x, cr_max.y) if intersect_with_current_clip_rect then local current = self._CmdHeader.ClipRect if cr.x < current.x then cr.x = current.x end if cr.y < current.y then cr.y = current.y end if cr.z > current.z then cr.z = current.z end if cr.w > current.w then cr.w = current.w end end cr.z = ImMax(cr.x, cr.z) cr.w = ImMax(cr.y, cr.w) self._ClipRectStack:push_back(cr) ImVec4_Copy(self._CmdHeader.ClipRect, cr) self:_OnChangedClipRect() end function MT.ImDrawList:PopClipRect() self._ClipRectStack:pop_back() if (self._ClipRectStack.Size == 0) then -- LUA: No "Ternary Operator" ImVec4_Copy(self._CmdHeader.ClipRect, self._Data.ClipRectFullscreen) else ImVec4_Copy(self._CmdHeader.ClipRect, self._ClipRectStack.Data[self._ClipRectStack.Size]) end self:_OnChangedClipRect() end --- @param center ImVec2 --- @param radius float --- @param a_min_sample int --- @param a_max_sample int --- @param a_step int @native function MT.ImDrawList:_PathArcToFastEx(center, radius, a_min_sample, a_max_sample, a_step) if radius < 0.5 then self._Path:push_back(center) return end if a_step <= 0 then a_step = math.floor(IM_DRAWLIST_ARCFAST_SAMPLE_MAX / self:_CalcCircleAutoSegmentCount(radius)) end a_step = ImClamp(a_step, 1, math.floor(IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4)) local sample_range = ImAbs(a_max_sample - a_min_sample) local a_next_step = a_step local samples = sample_range + 1 local extra_max_sample = false if a_step > 1 then samples = math.floor(sample_range / a_step) + 1 local overstep = sample_range % a_step if overstep > 0 then extra_max_sample = true samples = samples + 1 if sample_range > 0 then a_step = a_step - math.floor((a_step - overstep) / 2) end end end self._Path:resize(self._Path.Size + samples) local out_ptr = self._Path.Size - samples + 1 local sample_index = a_min_sample if sample_index < 0 or sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX then sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX if sample_index < 0 then sample_index = sample_index + IM_DRAWLIST_ARCFAST_SAMPLE_MAX end end if a_max_sample >= a_min_sample then local a = a_min_sample while a <= a_max_sample do if sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX then sample_index = sample_index - IM_DRAWLIST_ARCFAST_SAMPLE_MAX end local s = self._Data.ArcFastVtx[sample_index + 1] ImVec2_CopyV(self._Path.Data[out_ptr], center.x + s.x * radius, center.y + s.y * radius) out_ptr = out_ptr + 1 a = a + a_step sample_index = sample_index + a_step a_step = a_next_step end else local a = a_min_sample while a >= a_max_sample do if sample_index < 0 then sample_index = sample_index + IM_DRAWLIST_ARCFAST_SAMPLE_MAX end local s = self._Data.ArcFastVtx[sample_index + 1] ImVec2_CopyV(self._Path.Data[out_ptr], center.x + s.x * radius, center.y + s.y * radius) out_ptr = out_ptr + 1 a = a - a_step sample_index = sample_index - a_step a_step = a_next_step end end if extra_max_sample then local normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX if normalized_max_sample < 0 then normalized_max_sample = normalized_max_sample + IM_DRAWLIST_ARCFAST_SAMPLE_MAX end local s = self._Data.ArcFastVtx[normalized_max_sample + 1] ImVec2_CopyV(self._Path.Data[out_ptr], center.x + s.x * radius, center.y + s.y * radius) out_ptr = out_ptr + 1 end IM_ASSERT_PARANOID(self._Path.Size == out_ptr - 1) end @native function MT.ImDrawList:PathArcToFast(center, radius, a_min_of_12, a_max_of_12) if radius < 0.5 then self._Path:push_back(center) return end self:_PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0) end --- @param center ImVec2 --- @param radius float --- @param a_min float --- @param a_max float --- @param num_segments int function MT.ImDrawList:_PathArcToN(center, radius, a_min, a_max, num_segments) if radius < 0.5 then self._Path:push_back(center) return end -- Note that we are adding a point at both a_min and a_max. -- If you are trying to draw a full closed circle you don't want the overlapping points! self._Path:reserve(self._Path.Size + (num_segments + 1)) for i = 0, num_segments do local a = a_min + (i / num_segments) * (a_max - a_min) self._Path:push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius)) end end --- @param center ImVec2 --- @param radius float --- @param a_min float --- @param a_max float --- @param num_segments? int function MT.ImDrawList:PathArcTo(center, radius, a_min, a_max, num_segments) if num_segments == nil then num_segments = 0 end if radius < 0.5 then self._Path:push_back(center) return end if num_segments > 0 then self:_PathArcToN(center, radius, a_min, a_max, num_segments) return end if radius <= self._Data.ArcFastRadiusCutoff then local a_is_reverse = a_max < a_min local a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0) local a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0) local a_min_sample = a_is_reverse and ImFloor(a_min_sample_f) or ImCeil(a_min_sample_f) local a_max_sample = a_is_reverse and ImCeil(a_max_sample_f) or ImFloor(a_max_sample_f) local a_mid_samples = a_is_reverse and ImMax(a_min_sample - a_max_sample, 0) or ImMax(a_max_sample - a_min_sample, 0) local a_min_segment_angle = a_min_sample * IM_PI * 2.0 / IM_DRAWLIST_ARCFAST_SAMPLE_MAX local a_max_segment_angle = a_max_sample * IM_PI * 2.0 / IM_DRAWLIST_ARCFAST_SAMPLE_MAX local a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5 local a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5 self._Path:reserve(self._Path.Size + (a_mid_samples + 1 + (a_emit_start and 1 or 0) + (a_emit_end and 1 or 0))) if a_emit_start then self._Path:push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)) end if a_mid_samples > 0 then self:_PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0) end if a_emit_end then self._Path:push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)) end else local arc_length = ImAbs(a_max - a_min) local circle_segment_count = self:_CalcCircleAutoSegmentCount(radius) local arc_segment_count = ImMax(ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0)), 1) self:_PathArcToN(center, radius, a_min, a_max, arc_segment_count) end end -- Not recommended to call this directly! --- @param draw_list ImDrawList --- @param size float --- @param pos ImVec2 --- @param col ImU32 --- @param clip_rect ImVec4 --- @param text ImString --- @param text_begin int --- @param text_end int --- @param wrap_width? float --- @param flags? ImDrawTextFlags @native function MT.ImFont:RenderText(draw_list, size, pos, col, clip_rect, text, text_begin, text_end, wrap_width, flags) if wrap_width == nil then wrap_width = .0 end if flags == nil then flags = 0 end local x = pos.x local y = pos.y if y > clip_rect.w then return end if bit32.band(draw_list.Flags, ImDrawListFlags.TextNoPixelSnap) == 0 then x = IM_TRUNC(x) y = IM_TRUNC(y) end -- if not text_end then -- end local line_height = size local baked = self:GetFontBaked(size) local scale = size / baked.Size local origin_x = x local word_wrap_enabled = (wrap_width > 0.0) local s = text_begin if y + line_height < clip_rect.y then while y + line_height < clip_rect.y and s < text_end do local line_end = ImMemchr(text, '\n', s) if word_wrap_enabled then s = ImFontCalcWordWrapPositionEx(self, size, text, s, (line_end ~= nil) and line_end or text_end, wrap_width, flags) s = ImTextCalcWordWrapNextLineStart(text, s, text_end, flags) else s = (line_end ~= nil) and (line_end + 1) or text_end end y = y + line_height end end if text_end - s > 1e4 and not word_wrap_enabled then local s_end = s local y_end = y while (y_end < clip_rect.w and s_end < text_end) do local _end = ImMemchr(text, '\n', s_end) s_end = (_end ~= nil) and (_end + 1) or text_end y_end = y_end + line_height end text_end = s_end end if s == text_end then return end local vtx_count_max = (text_end - s) * 4 local idx_count_max = (text_end - s) * 6 local idx_expected_size = draw_list.IdxBuffer.Size + idx_count_max draw_list:PrimReserve(idx_count_max, vtx_count_max) local vtx_write = draw_list._VtxWritePtr local idx_write = draw_list._IdxWritePtr local vtx_index = draw_list._VtxCurrentIdx local cmd_count = draw_list.CmdBuffer.Size local cpu_fine_clip = bit32.band(flags, ImDrawTextFlags.CpuFineClip) ~= 0 local idx_data = draw_list.IdxBuffer.Data; local vtx_data = draw_list.VtxBuffer.Buf local color_untinted = bit32.bor(col, bit32.bnot(IM_COL32_A_MASK)) local word_wrap_eol local stop = false local text_is_str = type(text) == "string" local lookup, lookup_n, glyphs = baked.IndexLookup.Data, baked.IndexLookup.Size, baked.Glyphs.Data while s < text_end do repeat if word_wrap_enabled then if not word_wrap_eol then word_wrap_eol = ImFontCalcWordWrapPositionEx(self, size, text, s, text_end, wrap_width - (x - origin_x), flags) end if s >= word_wrap_eol then x = origin_x y = y + line_height if y > clip_rect.w then stop = true; break end word_wrap_eol = nil s = ImTextCalcWordWrapNextLineStart(text, s, text_end, flags) break end end local c if text_is_str then c = string.byte(text, s) else c = text[s] end if c < 0x80 then s = s + 1 else local wanted, out_char = ImStd.ImTextCharFromUtf8(text, s, text_end) c = out_char s = s + wanted end if c < 32 then if c == 10 then -- '\n' x = origin_x y = y + line_height if y > clip_rect.w then stop = true; break end break end if c == 13 then -- '\r' break end end local glyph local gi = (c < lookup_n) and lookup[c + 1] or nil if gi ~= nil and gi ~= IM_FONTGLYPH_INDEX_NOT_FOUND and gi ~= IM_FONTGLYPH_INDEX_UNUSED then glyph = glyphs[gi] else glyph = baked:FindGlyph(c) -- may load the glyph and grow the tables lookup, lookup_n, glyphs = baked.IndexLookup.Data, baked.IndexLookup.Size, baked.Glyphs.Data end local char_width = glyph.AdvanceX * scale if glyph.Visible then local x1 = x + glyph.X0 * scale local x2 = x + glyph.X1 * scale local y1 = y + glyph.Y0 * scale local y2 = y + glyph.Y1 * scale if x1 <= clip_rect.z and x2 >= clip_rect.x then local u1 = glyph.U0 local v1 = glyph.V0 local u2 = glyph.U1 local v2 = glyph.V1 if (cpu_fine_clip) then if (x1 < clip_rect.x) then u1 = u1 + (1.0 - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1) x1 = clip_rect.x end if (y1 < clip_rect.y) then v1 = v1 + (1.0 - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1) y1 = clip_rect.y end if (x2 > clip_rect.z) then u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1) x2 = clip_rect.z end if (y2 > clip_rect.w) then v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1) y2 = clip_rect.w end if (y1 >= y2) then x = x + char_width break end end local glyph_col = glyph.Colored and color_untinted or col do local o = (vtx_write - 1) * 36 writef64(vtx_data, o, x1); writef64(vtx_data, o + 8, y1); writef64(vtx_data, o + 16, u1); writef64(vtx_data, o + 24, v1); writeu32(vtx_data, o + 32, glyph_col) writef64(vtx_data, o + 36, x2); writef64(vtx_data, o + 44, y1); writef64(vtx_data, o + 52, u2); writef64(vtx_data, o + 60, v1); writeu32(vtx_data, o + 68, glyph_col) writef64(vtx_data, o + 72, x2); writef64(vtx_data, o + 80, y2); writef64(vtx_data, o + 88, u2); writef64(vtx_data, o + 96, v2); writeu32(vtx_data, o + 104, glyph_col) writef64(vtx_data, o + 108, x1); writef64(vtx_data, o + 116, y2); writef64(vtx_data, o + 124, u1); writef64(vtx_data, o + 132, v2); writeu32(vtx_data, o + 140, glyph_col) idx_data[idx_write + 0] = vtx_index; idx_data[idx_write + 1] = vtx_index + 1; idx_data[idx_write + 2] = vtx_index + 2; idx_data[idx_write + 3] = vtx_index; idx_data[idx_write + 4] = vtx_index + 2; idx_data[idx_write + 5] = vtx_index + 3; vtx_write = vtx_write + 4 vtx_index = vtx_index + 4 idx_write = idx_write + 6 end end end x = x + char_width until true if stop then break end end -- Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui.* calls because CalcTextSize() is always used if cmd_count ~= draw_list.CmdBuffer.Size then IM_ASSERT(draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].ElemCount == 0) draw_list.CmdBuffer:pop_back() draw_list:PrimUnreserve(idx_count_max, vtx_count_max) draw_list:AddDrawCmd() return self:RenderText(draw_list, size, pos, col, clip_rect, text, text_begin, text_end, wrap_width, flags) -- was `goto begin` end draw_list.VtxBuffer.Size = vtx_write - 1 draw_list.IdxBuffer.Size = idx_write - 1 draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].ElemCount = draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].ElemCount - (idx_expected_size - draw_list.IdxBuffer.Size) draw_list._VtxWritePtr = vtx_write draw_list._IdxWritePtr = idx_write draw_list._VtxCurrentIdx = vtx_index end --- @param draw_list ImDrawList --- @param pos ImVec2 --- @param color ImU32 --- @param dir ImGuiDir --- @param scale? float local arrow_a, arrow_b, arrow_c = ImVec2(), ImVec2(), ImVec2() -- scratch: the path is consumed by AddTriangleFilled before returning function ImGui.RenderArrow(draw_list, pos, color, dir, scale) if scale == nil then scale = 1.0 end local h = draw_list._Data.FontSize * 1.00 local r = h * 0.40 * scale local cx, cy = pos.x + h * 0.50, pos.y + h * 0.50 * scale local ax, ay, bx, by, qx, qy if dir == ImGuiDir.Up or dir == ImGuiDir.Down then if dir == ImGuiDir.Up then r = -r end ax, ay = 0.000 * r, 0.750 * r bx, by = -0.866 * r, -0.750 * r qx, qy = 0.866 * r, -0.750 * r elseif dir == ImGuiDir.Left or dir == ImGuiDir.Right then if dir == ImGuiDir.Left then r = -r end ax, ay = 0.750 * r, 0.000 * r bx, by = -0.750 * r, 0.866 * r qx, qy = -0.750 * r, -0.866 * r else IM_ASSERT(false) end arrow_a.x, arrow_a.y = cx + ax, cy + ay arrow_b.x, arrow_b.y = cx + bx, cy + by arrow_c.x, arrow_c.y = cx + qx, cy + qy draw_list:AddTriangleFilled(arrow_a, arrow_b, arrow_c, color) end --- @param draw_list ImDrawList --- @param pos ImVec2 --- @param col ImU32 function ImGui.RenderBullet(draw_list, pos, col) -- FIXME-OPT: This should be baked in font now that it's easier local font_size = draw_list._Data.FontSize draw_list:AddCircleFilled(pos, font_size * 0.20, col, (font_size < 22) and 8 or ((font_size < 40) and 12 or 0)) -- Hardcode optimal/nice tessellation threshold end --- @param draw_list ImDrawList --- @param pos ImVec2 --- @param col ImU32 --- @param sz float function ImGui.RenderCheckMark(draw_list, pos, col, sz) local thickness = ImMax(sz / 5.0, 1.0) sz = sz - thickness * 0.5 pos = pos + ImVec2(thickness * 0.25, thickness * 0.25) local third = sz / 3.0 local bx = pos.x + third local by = pos.y + sz - third * 0.5 draw_list:PathLineTo(ImVec2(bx - third, by - third)) draw_list:PathLineTo(ImVec2(bx, by)) draw_list:PathLineTo(ImVec2(bx + third * 2.0, by - third * 2.0)) draw_list:PathStroke(col, thickness) end -- Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side --- @param draw_list ImDrawList --- @param pos ImVec2 --- @param half_sz ImVec2 --- @param direction ImGuiDir --- @param col ImU32 function ImGui.RenderArrowPointingAt(draw_list, pos, half_sz, direction, col) if direction == ImGuiDir.Left then draw_list:AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col) elseif direction == ImGuiDir.Right then draw_list:AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col) elseif direction == ImGuiDir.Up then draw_list:AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col) elseif direction == ImGuiDir.Down then draw_list:AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col) elseif direction == ImGuiDir.None or direction == ImGuiDir.COUNT then end end local function ImAcos01(x) if x <= 0.0 then return IM_PI * 0.5 end if x >= 1.0 then return 0.0 end return ImAcos(x) end -- FIXME: Cleanup and move code to ImDrawList --- @param draw_list ImDrawList --- @param rect ImRect --- @param col ImU32 --- @param fill_x0 float --- @param fill_x1 float --- @param rounding float function ImGui.RenderRectFilledInRangeH(draw_list, rect, col, fill_x0, fill_x1, rounding) if fill_x0 > fill_x1 then return end local p0 = ImVec2(fill_x0, rect.Min.y) local p1 = ImVec2(fill_x1, rect.Max.y) if rounding == 0.0 then draw_list:AddRectFilled(p0, p1, col, 0.0) return end rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5, (rect.Max.y - rect.Min.y) * 0.5) - 1.0, 0.0, rounding) local inv_rounding = 1.0 / rounding local arc0_b = ImAcos01(1.0 - (p0.x - rect.Min.x) * inv_rounding) local arc0_e = ImAcos01(1.0 - (p1.x - rect.Min.x) * inv_rounding) local half_pi = IM_PI * 0.5 -- We will == compare to this because we know this is the exact value ImAcos01 can return. local x0 = ImMax(p0.x, rect.Min.x + rounding) if arc0_b == arc0_e then draw_list:PathLineTo(ImVec2(x0, p1.y)) draw_list:PathLineTo(ImVec2(x0, p0.y)) elseif arc0_b == 0.0 and arc0_e == half_pi then draw_list:PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6) -- BL draw_list:PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9) -- TR else draw_list:PathArcTo(ImVec2(x0, p1.y - rounding), rounding, math.pi - arc0_e, math.pi - arc0_b) -- BL draw_list:PathArcTo(ImVec2(x0, p0.y + rounding), rounding, math.pi + arc0_b, math.pi + arc0_e) -- TR end if p1.x > rect.Min.x + rounding then local arc1_b = ImAcos01(1.0 - (rect.Max.x - p1.x) * inv_rounding) local arc1_e = ImAcos01(1.0 - (rect.Max.x - p0.x) * inv_rounding) local x1 = ImMin(p1.x, rect.Max.x - rounding) if arc1_b == arc1_e then draw_list:PathLineTo(ImVec2(x1, p0.y)) draw_list:PathLineTo(ImVec2(x1, p1.y)) elseif arc1_b == 0.0 and arc1_e == half_pi then draw_list:PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12) -- TR draw_list:PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3) -- BR else draw_list:PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b) -- TR draw_list:PathArcTo(ImVec2(x1, p1.y - rounding), rounding, arc1_b, arc1_e) -- BR end end draw_list:PathFillConvex(col) end --- @param r_in ImRect --- @param r_outer ImRect --- @param threshold float --- @return ImDrawFlags function ImGui.CalcRoundingFlagsForRectInRect(r_in, r_outer, threshold) local round_l = r_in.Min.x <= r_outer.Min.x + threshold local round_r = r_in.Max.x >= r_outer.Max.x - threshold local round_t = r_in.Min.y <= r_outer.Min.y + threshold local round_b = r_in.Max.y >= r_outer.Max.y - threshold local flags = ImDrawFlags.RoundCornersNone if round_t and round_l then flags = bit32.bor(flags, ImDrawFlags.RoundCornersTopLeft) end if round_t and round_r then flags = bit32.bor(flags, ImDrawFlags.RoundCornersTopRight) end if round_b and round_l then flags = bit32.bor(flags, ImDrawFlags.RoundCornersBottomLeft) end if round_b and round_r then flags = bit32.bor(flags, ImDrawFlags.RoundCornersBottomRight) end return flags end -- Helper for ColorPicker4() -- NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. -- Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. -- FIXME: uses ImGui.GetColorU32 --- @param draw_list ImDrawList --- @param p_min ImVec2 --- @param p_max ImVec2 --- @param col ImU32 --- @param grid_step float --- @param grid_off ImVec2 --- @param rounding? float --- @param flags? ImDrawFlags function ImGui.RenderColorRectWithAlphaCheckerboard(draw_list, p_min, p_max, col, grid_step, grid_off, rounding, flags) if rounding == nil then rounding = 0.0 end if flags == nil then flags = 0 end if bit32.band(flags, ImDrawFlags.RoundCornersMask_) == 0 then flags = ImDrawFlags.RoundCornersDefault_ end if bit32.rshift(bit32.band(col, IM_COL32_A_MASK), IM_COL32_A_SHIFT) < 0xFF then local col_bg1 = ImGui.GetColorU32(ImStd.ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col), nil, true) local col_bg2 = ImGui.GetColorU32(ImStd.ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col), nil, true) draw_list:AddRectFilled(p_min, p_max, col_bg1, rounding, flags) local yi = 0 local y = p_min.y + grid_off.y local x_start local x local cell_flags while y < p_max.y do repeat local y1 = ImClamp(y, p_min.y, p_max.y) local y2 = ImMin(y + grid_step, p_max.y) if y2 <= y1 then break end x_start = p_min.x + grid_off.x + ((yi + 1) % 2) * grid_step x = x_start while x < p_max.x do repeat local x1 = ImClamp(x, p_min.x, p_max.x) local x2 = ImMin(x + grid_step, p_max.x) if x2 <= x1 then break end cell_flags = ImDrawFlags.RoundCornersNone if y1 <= p_min.y then if x1 <= p_min.x then cell_flags = bit32.bor(cell_flags, ImDrawFlags.RoundCornersTopLeft) end if x2 >= p_max.x then cell_flags = bit32.bor(cell_flags, ImDrawFlags.RoundCornersTopRight) end end if y2 >= p_max.y then if x1 <= p_min.x then cell_flags = bit32.bor(cell_flags, ImDrawFlags.RoundCornersBottomLeft) end if x2 >= p_max.x then cell_flags = bit32.bor(cell_flags, ImDrawFlags.RoundCornersBottomRight) end end -- Combine flags if flags == ImDrawFlags.RoundCornersNone or cell_flags == ImDrawFlags.RoundCornersNone then cell_flags = ImDrawFlags.RoundCornersNone else cell_flags = bit32.band(cell_flags, flags) end draw_list:AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags) until true x = x + grid_step * 2.0 end until true y = y + grid_step yi = yi + 1 end else draw_list:AddRectFilled(p_min, p_max, col, rounding, flags) end end function ImGui.RenderRectFilledWithHole(draw_list, outer, inner, col, rounding) local fill_L = inner.Min.x > outer.Min.x local fill_R = inner.Max.x < outer.Max.x local fill_U = inner.Min.y > outer.Min.y local fill_D = inner.Max.y < outer.Max.y local D = ImDrawFlags local bor = bit32.bor local function f(c, v) return c and 0 or v end if fill_L then draw_list:AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, bor(D.RoundCornersNone, f(fill_U, D.RoundCornersTopLeft), f(fill_D, D.RoundCornersBottomLeft))) end if fill_R then draw_list:AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, bor(D.RoundCornersNone, f(fill_U, D.RoundCornersTopRight), f(fill_D, D.RoundCornersBottomRight))) end if fill_U then draw_list:AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, bor(D.RoundCornersNone, f(fill_L, D.RoundCornersTopLeft), f(fill_R, D.RoundCornersTopRight))) end if fill_D then draw_list:AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, bor(D.RoundCornersNone, f(fill_L, D.RoundCornersBottomLeft), f(fill_R, D.RoundCornersBottomRight))) end if fill_L and fill_U then draw_list:AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, D.RoundCornersTopLeft) end if fill_R and fill_U then draw_list:AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, D.RoundCornersTopRight) end if fill_L and fill_D then draw_list:AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, D.RoundCornersBottomLeft) end if fill_R and fill_D then draw_list:AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, D.RoundCornersBottomRight) end end ---------------------------------------------------------------- -- Extra primitives (Ngon, Ellipse, Bezier, concave fill) ---------------------------------------------------------------- -- [port] These follow the 1.92 stroker this port uses (no ImDrawFlags_StrokeXXX placement flags). function MT.ImDrawList:PathEllipticalArcTo(center, radius, rot, a_min, a_max, num_segments) if num_segments == nil or num_segments <= 0 then num_segments = self:_CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)) end local cos_rot, sin_rot = ImCos(rot), ImSin(rot) for i = 0, num_segments do local a = a_min + (i / num_segments) * (a_max - a_min) local px, py = ImCos(a) * radius.x, ImSin(a) * radius.y self._Path:push_back(ImVec2(px * cos_rot - py * sin_rot + center.x, px * sin_rot + py * cos_rot + center.y)) end end function ImBezierCubicCalc(p1, p2, p3, p4, t) local u = 1.0 - t local w1, w2, w3, w4 = u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y) end function ImBezierQuadraticCalc(p1, p2, p3, t) local u = 1.0 - t local w1, w2, w3 = u * u, 2 * u * t, t * t return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y) end local function PathBezierCubicCurveToCasteljau(path, x1, y1, x2, y2, x3, y3, x4, y4, tess_tol, level) local dx, dy = x4 - x1, y4 - y1 local d2 = math.abs((x2 - x4) * dy - (y2 - y4) * dx) local d3 = math.abs((x3 - x4) * dy - (y3 - y4) * dx) if (d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy) then path:push_back(ImVec2(x4, y4)) elseif level < 10 then local x12, y12 = (x1 + x2) * 0.5, (y1 + y2) * 0.5 local x23, y23 = (x2 + x3) * 0.5, (y2 + y3) * 0.5 local x34, y34 = (x3 + x4) * 0.5, (y3 + y4) * 0.5 local x123, y123 = (x12 + x23) * 0.5, (y12 + y23) * 0.5 local x234, y234 = (x23 + x34) * 0.5, (y23 + y34) * 0.5 local x1234, y1234 = (x123 + x234) * 0.5, (y123 + y234) * 0.5 PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1) PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1) end end local function PathBezierQuadraticCurveToCasteljau(path, x1, y1, x2, y2, x3, y3, tess_tol, level) local dx, dy = x3 - x1, y3 - y1 local det = (x2 - x3) * dy - (y2 - y3) * dx if det * det * 4.0 < tess_tol * (dx * dx + dy * dy) then path:push_back(ImVec2(x3, y3)) elseif level < 10 then local x12, y12 = (x1 + x2) * 0.5, (y1 + y2) * 0.5 local x23, y23 = (x2 + x3) * 0.5, (y2 + y3) * 0.5 local x123, y123 = (x12 + x23) * 0.5, (y12 + y23) * 0.5 PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1) PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1) end end function MT.ImDrawList:PathBezierCubicCurveTo(p2, p3, p4, num_segments) local p1 = self._Path:back() if num_segments == nil or num_segments == 0 then PathBezierCubicCurveToCasteljau(self._Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, self._Data.CurveTessellationTol, 0) else local t_step = 1.0 / num_segments for i_step = 1, num_segments do self._Path:push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step)) end end end function MT.ImDrawList:PathBezierQuadraticCurveTo(p2, p3, num_segments) local p1 = self._Path:back() if num_segments == nil or num_segments == 0 then PathBezierQuadraticCurveToCasteljau(self._Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, self._Data.CurveTessellationTol, 0) else local t_step = 1.0 / num_segments for i_step = 1, num_segments do self._Path:push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step)) end end end function MT.ImDrawList:AddNgon(center, radius, col, num_segments, thickness) if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 or num_segments <= 2 then return end local a_max = (IM_PI * 2.0) * (num_segments - 1.0) / num_segments self:PathArcTo(center, radius - 0.5, 0.0, a_max, num_segments - 1) self:PathStroke(col, thickness, ImDrawFlags.Closed) end function MT.ImDrawList:AddNgonFilled(center, radius, col, num_segments) if bit32.band(col, IM_COL32_A_MASK) == 0 or num_segments <= 2 then return end local a_max = (IM_PI * 2.0) * (num_segments - 1.0) / num_segments self:PathArcTo(center, radius, 0.0, a_max, num_segments - 1) self:PathFillConvex(col) end function MT.ImDrawList:AddEllipse(center, radius, col, rot, num_segments, thickness) if rot == nil then rot = 0.0 end if thickness == nil then thickness = 1.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end if num_segments == nil or num_segments <= 0 then num_segments = self:_CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)) end local a_max = IM_PI * 2.0 * (num_segments - 1.0) / num_segments self:PathEllipticalArcTo(center, radius, rot, 0.0, a_max, num_segments - 1) self:PathStroke(col, thickness, ImDrawFlags.Closed) end function MT.ImDrawList:AddEllipseFilled(center, radius, col, rot, num_segments) if rot == nil then rot = 0.0 end if bit32.band(col, IM_COL32_A_MASK) == 0 then return end if num_segments == nil or num_segments <= 0 then num_segments = self:_CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)) end local a_max = IM_PI * 2.0 * (num_segments - 1.0) / num_segments self:PathEllipticalArcTo(center, radius, rot, 0.0, a_max, num_segments - 1) self:PathFillConvex(col) end function MT.ImDrawList:AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathBezierCubicCurveTo(p2, p3, p4, num_segments or 0) self:PathStroke(col, thickness or 1.0) end function MT.ImDrawList:AddBezierQuadratic(p1, p2, p3, col, thickness, num_segments) if bit32.band(col, IM_COL32_A_MASK) == 0 then return end self:PathLineTo(p1) self:PathBezierQuadraticCurveTo(p2, p3, num_segments or 0) self:PathStroke(col, thickness or 1.0) end -- ponytail: ear-clipping, no anti-aliased fringe (upstream's AA triangulator not ported). O(n^2) is fine for UI polygons. --- @param points ImVec2[] # 1-based function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col) if points_count < 3 or bit32.band(col, IM_COL32_A_MASK) == 0 then return end local idx = {} local area = 0.0 for i = 1, points_count do idx[i] = i local a, b = points[i], points[i % points_count + 1] area = area + (a.x * b.y - b.x * a.y) end local sign = (area >= 0) and 1 or -1 local function cross(o, a, b) return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) end local guard = 0 while #idx > 3 and guard < points_count * points_count do guard = guard + 1 local n = #idx local clipped = false for i = 1, n do local ia, ib, ic = idx[(i - 2) % n + 1], idx[i], idx[i % n + 1] local a, b, c = points[ia], points[ib], points[ic] if cross(a, b, c) * sign > 0 then local inside = false for j = 1, n do local p = idx[j] if p ~= ia and p ~= ib and p ~= ic then local q = points[p] if cross(a, b, q) * sign >= 0 and cross(b, c, q) * sign >= 0 and cross(c, a, q) * sign >= 0 then inside = true; break end end end if not inside then self:AddTriangleFilled(a, b, c, col) table.remove(idx, i) clipped = true break end end end if not clipped then break end end if #idx == 3 then self:AddTriangleFilled(points[idx[1]], points[idx[2]], points[idx[3]], col) end end function MT.ImDrawList:PathFillConcave(col) self:AddConcavePolyFilled(self._Path.Data, self._Path.Size, col) self._Path.Size = 0 end return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imgui_h.lua'] = function() --- Dear ImGui WIP -- (Definitions) --- @meta local type = ImGui._GetTypeFunc() local rawget = rawget; local rawset = rawset -- [LuaBitOp](https://bitop.luajit.org/semantics.html) local bitAnd = bit32.band; local bitOr = bit32.bor local bitLShift = bit32.lshift --- @class char : integer --- @class unsigned_char : integer --- @alias ImS8 char --- @alias ImU8 unsigned_char --- @class ImU16 : integer --- @class ImS16 : integer --- @class ImU32 : integer --- @class ImS32 : integer --- @param val number --- @return ImU8 function ImU8(val) return bitAnd(val, 0xFF) end --- @param val number --- @return ImS8 function ImS8(val) return bitAnd(val, 0xFF) - (bitAnd(val, 0x80) ~= 0 and 0x100 or 0) end --- @param val number --- @return ImU16 function ImU16(val) return bitAnd(val, 0xFFFF) end --- @param val number --- @return ImS16 function ImS16(val) return bitAnd(val, 0xFFFF) - (bitAnd(val, 0x8000) ~= 0 and 0x10000 or 0) end --- @param val number --- @return ImU32 function ImU32(val) return bitAnd(val, 0xFFFFFFFF) end --- @param val number --- @return ImS32 function ImS32(val) return bitAnd(val, 0xFFFFFFFF) end --- @alias float number --- @class double : number --- @alias int integer --- @alias unsigned_int integer --- @alias short integer --- @alias unsigned_short integer --- @alias size_t unsigned_int --- @alias ImWchar16 unsigned_short --- @alias ImWchar ImWchar16 --- @alias bool boolean --- @alias ImGuiID unsigned_int --- @alias ImTextureID integer --- @alias ImGuiKeyChord int --- @alias ImDrawIdx unsigned_int IMGUI_VERSION = "1.93.0 WIP" IMGUI_VERSION_NUM = 19298 IM_UNICODE_CODEPOINT_INVALID = 0xFFFD IM_UNICODE_CODEPOINT_MAX = 0xFFFF IM_ALLOC = ImGui.MemAlloc IM_FREE = ImGui.MemFree --- @param owner table --- @param field string|int IM_DELETE = function(owner, field) if owner[field] ~= nil then owner[field] = nil; ImGui.MemFree(owner, field); end end --------------------------------------------------------------------------------------- -- [SECTION] METATABLE MANAGEMENT --------------------------------------------------------------------------------------- --- File-scope metatable storage local MT = {} function ImGui.GetMetatables() return MT end --- @param _EXPR any --- @param _MSG string? function IM_ASSERT(_EXPR, _MSG) assert((_EXPR), _MSG) end IM_ASSERT_PARANOID = IM_ASSERT --- Note that `S64` and `U64` are not supported --- @enum ImGuiDataType ImGuiDataType = { S8 = 0, -- signed char / char U8 = 1, -- unsigned char S16 = 2, -- short U16 = 3, -- unsigned short S32 = 4, -- int U32 = 5, -- unsigned int Float = 6, -- float Double = 7, -- double Bool = 8, -- bool (provided for user convenience, not supported by scalar widgets) String = 9, -- string (provided for user convenience, not supported by scalar widgets) COUNT = 10 } ImGuiDataType.Pointer = 11 -- [internal] ImGuiDataType.ID = 12 -- [internal] ImTextureID_Invalid = -1 --- @enum ImTextureFormat ImTextureFormat = { RGBA32 = 0, Alpha8 = 1, } --- @enum ImTextureStatus ImTextureStatus = { OK = 0, Destroyed = 1, WantCreate = 2, WantUpdates = 3, WantDestroy = 4, } --- @enum ImFontAtlasFlags ImFontAtlasFlags = { None = 0, NoPowerOfTwoHeight = bitLShift(1, 0), NoMouseCursors = bitLShift(1, 1), NoBakedLines = bitLShift(1, 2) } --- @enum ImGuiDir ImGuiDir = { None = -1, Left = 0, Right = 1, Up = 2, Down = 3, COUNT = 4 } --- @enum ImGuiMouseButton ImGuiMouseButton = { Left = 0, Right = 1, Middle = 2, COUNT = 5 } --- @enum ImGuiMouseCursor ImGuiMouseCursor = { None = -1, Arrow = 0, TextInput = 1, ResizeAll = 2, ResizeNS = 3, ResizeEW = 4, ResizeNESW = 5, ResizeNWSE = 6, Hand = 7, Wait = 8, Progress = 9, NotAllowed = 10, COUNT = 11 } --- @class ImTextureRect --- @field x unsigned_short --- @field y unsigned_short --- @field w unsigned_short --- @field h unsigned_short --- @param x? unsigned_short --- @param y? unsigned_short --- @param w? unsigned_short --- @param h? unsigned_short --- @return ImTextureRect function ImTextureRect(x, y, w, h) return { x = x, y = y, w = w, h = h } end -- [Luau] Stored as named fields {x=, y=} so the common `.x`/`.y` access is a plain table read (no metamethod call). -- Numeric keys 1, 2 still work through the metatable, but are slower: prefer .x/.y in hot code. --- @class ImVec2 --- @operator add(ImVec2): ImVec2 --- @operator sub(ImVec2): ImVec2 --- @operator mul(number): ImVec2 --- @operator mul(ImVec2): ImVec2 --- @operator div(number): ImVec2 --- @operator div(ImVec2): ImVec2 --- @field x number --- @field y number local IM_VEC2 = {} local VEC2_KEYS = { "x", "y" } IM_VEC2.__index = function(t, k) local n = VEC2_KEYS[k] if n then return rawget(t, n) end end IM_VEC2.__newindex = function(t, k, v) local n = VEC2_KEYS[k] IM_ASSERT(n ~= nil) rawset(t, n, v) end --- @param x? number --- @param y? number --- @return ImVec2 --- @nodiscard @native function ImVec2(x, y) return setmetatable({ x = x or 0, y = y or 0 }, IM_VEC2) end @native function IM_VEC2.__add(lhs, rhs) return setmetatable({ x = lhs.x + rhs.x, y = lhs.y + rhs.y }, IM_VEC2) end @native function IM_VEC2.__sub(lhs, rhs) return setmetatable({ x = lhs.x - rhs.x, y = lhs.y - rhs.y }, IM_VEC2) end @native function IM_VEC2.__mul(lhs, rhs) if type(rhs) == "number" then return setmetatable({ x = lhs.x * rhs, y = lhs.y * rhs }, IM_VEC2) end return setmetatable({ x = lhs.x * rhs.x, y = lhs.y * rhs.y }, IM_VEC2) end @native function IM_VEC2.__div(lhs, rhs) if type(rhs) == "number" then return setmetatable({ x = lhs.x / rhs, y = lhs.y / rhs }, IM_VEC2) end return setmetatable({ x = lhs.x / rhs.x, y = lhs.y / rhs.y }, IM_VEC2) end function IM_VEC2.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y end function IM_VEC2:__tostring() return string.format("ImVec2(%g, %g)", self.x, self.y) end --- @param dest ImVec2 --- @param src ImVec2 @native function ImVec2_Copy(dest, src) dest.x = src.x; dest.y = src.y end function ImVec2_CopyV(dest, src_x, src_y) dest.x = src_x; dest.y = src_y end function ImVec2_AddVA(v, add_x, add_y) return v.x + add_x, v.y + add_y end function ImVec2_SubVA(v, sub_x, sub_y) return v.x - sub_x, v.y - sub_y end function ImVec2_MulVX(a, scalar) return a.x * scalar, a.y * scalar end --- An inlined version of `ImVec2_Copy` currently for use in certain ImVector `push_back` local function ImVec2_TCopy(t, k, v) local dest = t[k]; dest.x = v.x; dest.y = v.y; end -- [Luau] Same layout as ImVec2: named fields x, y, z, w; numeric keys 1..4 go through the metatable. --- @class ImVec4 --- @operator add(ImVec4): ImVec4 --- @operator sub(ImVec4): ImVec4 --- @operator mul(number): ImVec4 --- @field x number --- @field y number --- @field z number --- @field w number local IM_VEC4 = {} local VEC4_KEYS = { "x", "y", "z", "w" } IM_VEC4.__index = function(t, k) local n = VEC4_KEYS[k] if n then return rawget(t, n) end end IM_VEC4.__newindex = function(t, k, v) local n = VEC4_KEYS[k] IM_ASSERT(n ~= nil) rawset(t, n, v) end --- @return ImVec4 --- @nodiscard @native function ImVec4(x, y, z, w) return setmetatable({ x = x or 0, y = y or 0, z = z or 0, w = w or 0 }, IM_VEC4) end function IM_VEC4.__add(lhs, rhs) return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w) end function IM_VEC4.__sub(lhs, rhs) return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w) end function IM_VEC4.__mul(lhs, rhs) return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs) end function IM_VEC4.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y and lhs.z == rhs.z and lhs.w == rhs.w end function IM_VEC4:__tostring() return string.format("ImVec4(%g, %g, %g, %g)", self.x, self.y, self.z, self.w) end --- @param dest ImVec4 --- @param src ImVec4 @native function ImVec4_Copy(dest, src) dest.x = src.x; dest.y = src.y; dest.z = src.z; dest.w = src.w end --- A compact ImVector clone --- @class ImVector --- @field Data T[] # 1-based table --- @field Size int # >= 0 --- @field _Constructor function --- @field _CopyFunc function local IM_VECTOR = {} -- Support 1-based number key indexing while keep method accessing speed --- @param t ImVector --- @param k string|int --- @return any IM_VECTOR.__index = function(t, k) local m = IM_VECTOR[k] -- methods first (hot path) if m ~= nil then return m end if k == "Data" then return nil end -- Data has already been discarded return t.Data[IM_ASSERT(k >= 1 and k <= t.Size) or k] -- if the mt access turns out nil, the k must be int index into Data end --- @param t ImVector --- @param k int --- @param v any IM_VECTOR.__newindex = function(t, k, v) if k == "Data" then rawset(t, "Data", v); return; end -- set new Data. old Data is already discarded IM_ASSERT(k >= 1 and k <= t.Size) t.Data[k] = v end local _default_constructor = function() return nil end local _default_copyfunc = function(t, k, v) t[k] = v end local function _grow_capacity(v, sz) local new_capacity = (v.Capacity ~= 0) and math.floor(v.Capacity + v.Capacity / 2) or 8; return (new_capacity > sz) and new_capacity or sz; end --- @param T? function --- @param COPY_FUNC? function --- @return ImVector --- @nodiscard function ImVector(T, COPY_FUNC) return setmetatable({Data = nil, Size = 0, Capacity = 0, _Constructor = T or _default_constructor, _CopyFunc = COPY_FUNC or _default_copyfunc}, IM_VECTOR) end function IM_VECTOR:push_back(value) if self.Size == self.Capacity then self:reserve(_grow_capacity(self, self.Size + 1)) end; self._CopyFunc(self.Data, self.Size + 1, value); self.Size = self.Size + 1; return value end function IM_VECTOR:pop_back() IM_ASSERT(self.Size > 0); self.Size = self.Size - 1; end function IM_VECTOR:push_front(value) if self.Size == 0 then self:push_back(value) else self:insert(1, value) end end function IM_VECTOR:clear() if self.Data then self.Size = 0; self.Capacity = 0; IM_FREE(self, "Data"); self.Data = nil end end function IM_VECTOR:clear_delete() for i = 1, self.Size do self.Data[i] = nil end self.Size = 0 end function IM_VECTOR:empty() return self.Size == 0 end function IM_VECTOR:back() IM_ASSERT(self.Size > 0) return self.Data[self.Size] end function IM_VECTOR:erase(i) IM_ASSERT(i >= 1 and i <= self.Size) local removed = (table.remove(self.Data, i)) ~= nil self.Size = self.Size - 1 return removed end local function _iter(v, i) i = i + 1 if i <= v.Size then return i, v.Data[i] end end function IM_VECTOR:iter() return _iter, self, 0 end function IM_VECTOR:find_index(value) for i = 1, self.Size do if self.Data[i] == value then return i end end return nil end function IM_VECTOR:erase_unsorted(index) IM_ASSERT(index >= 1 and index <= self.Size) local last_idx = self.Size if index ~= last_idx then self.Data[index] = self.Data[last_idx] end self.Data[last_idx] = nil self.Size = self.Size - 1 return true end function IM_VECTOR:find_erase(value) local idx = self:find_index(value) if idx then return self:erase(idx) end return false end function IM_VECTOR:find_erase_unsorted(value) local idx = self:find_index(value) if idx then return self:erase_unsorted(idx) end return false end function IM_VECTOR:reserve(new_capacity) if new_capacity <= self.Capacity then return end local new_data = IM_ALLOC(self._Constructor, new_capacity) if self.Data then ImStd.memmove(new_data, 1, self.Data, 1, self.Size) IM_FREE(self, "Data") end self.Data = new_data self.Capacity = new_capacity end function IM_VECTOR:reserve_discard(new_capacity) if new_capacity <= self.Capacity then return end if self.Data then IM_FREE(self, "Data") end self.Data = IM_ALLOC(self._Constructor, new_capacity) self.Capacity = new_capacity end function IM_VECTOR:shrink(new_size) IM_ASSERT(new_size <= self.Size) self.Size = new_size end function IM_VECTOR:resize(new_size, v) if new_size > self.Capacity then self:reserve(_grow_capacity(self, new_size)) end if v ~= nil and new_size > self.Size then local data = self.Data for n = self.Size + 1, new_size do data[n] = v end end self.Size = new_size end function IM_VECTOR:swap(other) self.Size, other.Size = other.Size, self.Size; self.Capacity, other.Capacity = other.Capacity, self.Capacity; self.Data, other.Data = other.Data, self.Data end function IM_VECTOR:contains(v) for i = 1, self.Size do if self.Data[i] == v then return true end end return false end -- NOTE: This currently does not use type-aware copy! function IM_VECTOR:insert(pos, value) IM_ASSERT(pos >= 1 and pos <= self.Size + 1); if self.Size == self.Capacity then self:reserve(_grow_capacity(self, self.Size + 1)) end; for i = self.Size, pos, -1 do self.Data[i + 1] = self.Data[i] end self.Data[pos] = value self.Size = self.Size + 1 return value end -- NOTE: This currently does not copy type related info! --- @nodiscard function IM_VECTOR:copy() local v = ImVector(); v:resize(self.Size) local dest = v.Data; local src = self.Data for i = 1, v.Size do dest[i] = src[i] end return v end -- Not keeping value-key records inside `ImVector`, instead just find it --- @return int # 0-based index function IM_VECTOR:index_from_ptr(p) local data = self.Data; for i = 1, self.Size do if p == data[i] then return i - 1 end end --- @diagnostic disable-next-line IM_ASSERT(false, "index_from_ptr failed!") end --- @class ImDrawCmd --- @field ClipRect ImVec4 --- @field TexRef ImTextureRef --- @field VtxOffset unsigned_int --- @field IdxOffset unsigned_int --- @field ElemCount unsigned_int --- @field UserCallback ImDrawCallback --- @field UserCallbackData any --- @field UserCallbackDataSize int --- @field UserCallbackDataOffset int local IM_DRAWCMD = {} IM_DRAWCMD.__index = IM_DRAWCMD --- @return ImDrawCmd --- @nodiscard function ImDrawCmd() return setmetatable({ ClipRect = ImVec4(), TexRef = nil, VtxOffset = 0, IdxOffset = 0, ElemCount = 0, UserCallback = nil, UserCallbackData = nil, UserCallbackDataSize = 0, UserCallbackDataOffset = 0 }, IM_DRAWCMD) end --- @return ImTextureID function IM_DRAWCMD:GetTexID() local tex_id = (self.TexRef._TexData) and self.TexRef._TexData.TexID or self.TexRef._TexID if self.TexRef._TexData ~= nil then IM_ASSERT(tex_id ~= ImTextureID_Invalid, "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!") end return tex_id end --- @class ImDrawVert --- @field [1] ImVec2 # pos --- @field [2] ImVec2 # uv --- @field [3] ImU32 # col --- @return ImDrawVert --- @nodiscard function ImDrawVert() return { ImVec2(), ImVec2(), nil } end -- [Luau] ImDrawList.VtxBuffer storage: one buffer, VTX_STRIDE bytes per vertex. Vertex i (1-based) is at -- byte (i - 1) * VTX_STRIDE: f64 pos.x, f64 pos.y, f64 uv.x, f64 uv.y, u32 col. (f64 keeps results identical to tables.) -- Same Size/Capacity/resize/reserve/shrink/clear interface as ImVector; elements are read with ImDrawVtx_* below. VTX_STRIDE = 36 local IM_VTXBUF = {} IM_VTXBUF.__index = IM_VTXBUF function ImDrawVtxBuffer() return setmetatable({ Size = 0, Capacity = 0, Buf = buffer.create(0) }, IM_VTXBUF) end function IM_VTXBUF:reserve(n) if n <= self.Capacity then return end local nb = buffer.create(n * VTX_STRIDE) buffer.copy(nb, 0, self.Buf, 0, self.Size * VTX_STRIDE) self.Buf = nb self.Capacity = n end function IM_VTXBUF:resize(n) if n > self.Capacity then self:reserve(math.max(n, math.floor(self.Capacity * 1.5), 64)) end self.Size = n end function IM_VTXBUF:shrink(n) self.Size = n end function IM_VTXBUF:clear() self.Size = 0; self.Capacity = 0; self.Buf = buffer.create(0) end function ImDrawVtx_Pos(b, i) local o = (i - 1) * VTX_STRIDE; return buffer.readf64(b, o), buffer.readf64(b, o + 8) end function ImDrawVtx_Col(b, i) return buffer.readu32(b, (i - 1) * VTX_STRIDE + 32) end --- @class ImDrawCmdHeader --- @field ClipRect ImVec4 --- @field TexRef ImTextureRef --- @field VtxOffset unsigned_int --- @return ImDrawCmdHeader --- @nodiscard function ImDrawCmdHeader() return { ClipRect = ImVec4(), TexRef = nil, VtxOffset = 0 } end --- @class ImDrawChannel --- @field _CmdBuffer ImVector --- @field _IdxBuffer ImVector --- @return ImDrawChannel --- @nodiscard function ImDrawChannel() return { _CmdBuffer = ImVector(), _IdxBuffer = ImVector() } end --- @class ImDrawListSplitter --- @field _Current int --- @field _Count int --- @field _Channels ImVector --- @return ImDrawListSplitter --- @nodiscard MT.ImDrawListSplitter = {} -- methods in imgui_draw.lua MT.ImDrawListSplitter.__index = MT.ImDrawListSplitter function ImDrawListSplitter() return setmetatable({ _Current = 0, _Count = 0, _Channels = ImVector() }, MT.ImDrawListSplitter) end --- @class ImDrawList --- @field CmdBuffer ImVector --- @field IdxBuffer ImVector --- @field VtxBuffer ImVector --- @field Flags ImDrawListFlags --- @field _VtxCurrentIdx unsigned_int # 1-based, generally == (VtxBuffer.Size + 1) --- @field _Data ImDrawListSharedData # Pointes to shared draw data --- @field _VtxWritePtr unsigned_int # 1-based, points to the current writing vertex in VtxBuffer (see ImDrawVtxBuffer) --- @field _IdxWritePtr unsigned_int # 1-based, points to the current writing index in IdxBuffer.Data --- @field _Path ImVector # current path building --- @field _CmdHeader ImDrawCmdHeader # template of active commands. Fields should match those of CmdBuffer:back() --- @field _Splitter ImDrawListSplitter --- @field _ClipRectStack ImVector --- @field _TextureStack ImVector --- @field _CallbacksDataBuf any --- @field _FringeScale float --- @field _OwnerName string MT.ImDrawList = {} MT.ImDrawList.__index = MT.ImDrawList --- @param pos ImVec2 --- @param uv ImVec2 --- @param col ImU32 function MT.ImDrawList:PrimWriteVtx(pos, uv, col) local b, o = self.VtxBuffer.Buf, (self._VtxWritePtr - 1) * VTX_STRIDE buffer.writef64(b, o, pos.x); buffer.writef64(b, o + 8, pos.y) buffer.writef64(b, o + 16, uv.x); buffer.writef64(b, o + 24, uv.y) buffer.writeu32(b, o + 32, col) self._VtxWritePtr = self._VtxWritePtr + 1 self._VtxCurrentIdx = self._VtxCurrentIdx + 1 end --- @param idx ImDrawIdx function MT.ImDrawList:PrimWriteIdx(idx) self.IdxBuffer.Data[self._IdxWritePtr] = idx self._IdxWritePtr = self._IdxWritePtr + 1 end --- @param pos ImVec2 --- @param uv ImVec2 --- @param col ImU32 function MT.ImDrawList:PrimVtx(pos, uv, col) self:PrimWriteIdx(self._VtxCurrentIdx) self:PrimWriteVtx(pos, uv, col) end --- @param data? ImDrawListSharedData --- @return ImDrawList --- @nodiscard function ImDrawList(data) --- @type ImDrawList local this = setmetatable({ CmdBuffer = ImVector(), IdxBuffer = ImVector(), VtxBuffer = ImDrawVtxBuffer(), Flags = 0, _VtxCurrentIdx = 1, _Data = nil, _VtxWritePtr = 1, _IdxWritePtr = 1, _Path = ImVector(ImVec2, ImVec2_TCopy), _CmdHeader = ImDrawCmdHeader(), _Splitter = ImDrawListSplitter(), _ClipRectStack = ImVector(), _TextureStack = ImVector(), _CallbacksDataBuf = nil, _FringeScale = 0, _OwnerName = nil }, MT.ImDrawList) this:_SetDrawListSharedData(data) return this end --- @class ImDrawData --- @field Valid bool --- @field FrameCount int --- @field TotalIdxCount int --- @field TotalVtxCount int --- @field CmdLists ImVector --- @field DisplayPos ImVec2 --- @field DisplaySize ImVec2 --- @field FramebufferScale ImVec2 --- @field OwnerViewport ImGuiViewport --- @field Textures ImVector MT.ImDrawData = {} MT.ImDrawData.__index = MT.ImDrawData --- @return ImDrawData function ImDrawData() --- @type ImDrawData local this = setmetatable({}, MT.ImDrawData) this.CmdLists = ImVector() this:Clear() return this end --- @class ImTextureData --- @field UniqueID int --- @field Status ImTextureStatus --- @field BackendUserData any --- @field QueueUserData any --- @field TexID ImTextureID --- @field Format ImTextureFormat --- @field Width int --- @field Height int --- @field BytesPerPixel int --- @field Pixels unsigned_char[] --- @field UsedRect ImTextureRect --- @field UpdateRect ImTextureRect --- @field Updates ImVector --- @field UnusedFrames int --- @field RefCount unsigned_short --- @field UseColors bool --- @field WantDestroyNextFrame bool MT.ImTextureData = {} MT.ImTextureData.__index = MT.ImTextureData --- @return ImTextureData --- @nodiscard function ImTextureData() --- @type ImTextureData local this = setmetatable({}, MT.ImTextureData) this.UniqueID = 0 this.Status = ImTextureStatus.Destroyed this.BackendUserData = nil this.TexID = ImTextureID_Invalid this.Format = 0 this.Width = 0 this.Height = 0 this.BytesPerPixel = 0 this.Pixels = nil this.UsedRect = ImTextureRect() this.UpdateRect = ImTextureRect() this.Updates = ImVector() this.UnusedFrames = 0 this.RefCount = 0 this.UseColors = false this.WantDestroyNextFrame = false return this end --- @param x int --- @param y int function MT.ImTextureData:GetPixelsAt(x, y) return self.Pixels, (x + y * self.Width) * self.BytesPerPixel + 1 end function MT.ImTextureData:GetPitch() return self.Width * self.BytesPerPixel end function MT.ImTextureData:GetTexID() return self.TexID end --- @param tex_id ImTextureID function MT.ImTextureData:SetTexID(tex_id) self.TexID = tex_id end --- @param status ImTextureStatus function MT.ImTextureData:SetStatus(status) self.Status = status if (status == ImTextureStatus.Destroyed and not self.WantDestroyNextFrame and self.Pixels ~= nil) then self.Status = ImTextureStatus.WantCreate end end --- @class ImTextureRef --- @field _TexData? ImTextureData --- @field _TexID ImTextureID local IM_TEXTURE_REF = {} IM_TEXTURE_REF.__index = IM_TEXTURE_REF --- @return ImTextureRef --- @nodiscard function ImTextureRef(tex_id) return setmetatable({ _TexData = nil, _TexID = tex_id or ImTextureID_Invalid }, IM_TEXTURE_REF) end --- @class ImFontBaked --- @field IndexAdvanceX ImVector # Glyphs->AdvanceX in a directly indexable way. Note that codepoint starts from 0, so IndexAdvanceX.Data[0 + 1] holds the advanceX of glyph at codepoint 0 --- @field FallbackAdvanceX float --- @field Size float --- @field RasterizerDensity float --- @field IndexLookup ImVector # Index glyphs by Unicode codepoint. use IndexLookup.Data[codepoint + 1] for codepoint. Stores 1-based index! --- @field Glyphs ImVector --- @field FallbackGlyphIndex int # Initial value = -1, then becomes 1-based index if fallback char is set --- @field Ascent float --- @field Descent float --- @field MetricsTotalSurface unsigned_int --- @field WantDestroy bool --- @field LoadNoFallback bool --- @field LoadNoRenderOnLayout bool --- @field LastUsedFrame int --- @field BakedId ImGuiID --- @field OwnerFont ImFont --- @field FontLoaderDatas any MT.ImFontBaked = {} MT.ImFontBaked.__index = MT.ImFontBaked --- @return ImFontBaked --- @nodiscard function ImFontBaked() --- @type ImFontBaked local this = setmetatable({}, MT.ImFontBaked) this.IndexAdvanceX = ImVector() this.FallbackAdvanceX = 0 this.Size = 0 this.RasterizerDensity = 0 this.IndexLookup = ImVector() this.Glyphs = ImVector() this.FallbackGlyphIndex = -1 this.Ascent = 0 this.Descent = 0 this.MetricsTotalSurface = 0 this.WantDestroy = false this.LoadNoFallback = false this.LoadNoRenderOnLayout = false this.LastUsedFrame = 0 this.BakedId = 0 this.OwnerFont = nil this.FontLoaderDatas = nil return this end --- @class ImFont --- @field LastBaked ImFontBaked --- @field OwnerAtlas ImFontAtlas --- @field Flags ImFontFlags --- @field CurrentRasterizerDensity float --- @field FontId ImGuiID --- @field LegacySize float --- @field Sources ImVector --- @field EllipsisChar ImWchar --- @field FallbackChar ImWchar --- @field Used8kPagesMap ImU8[] # 1-based table --- @field EllipsisAutoBake bool --- @field RemapPairs table # LUA: No ImGuiStorage --- @field Scale float MT.ImFont = {} MT.ImFont.__index = MT.ImFont function MT.ImFont:IsLoaded() return self.OwnerAtlas ~= nil end function MT.ImFont:GetDebugName() if self.Sources.Size > 0 then return self.Sources[1].Name else return "" end end --- @return ImFont --- @nodiscard function ImFont() --- @type ImFont local this = setmetatable({}, MT.ImFont) this.LastBaked = nil this.OwnerAtlas = nil this.Flags = 0 this.CurrentRasterizerDensity = 0 this.FontId = 0 this.LegacySize = 0 this.Sources = ImVector() this.EllipsisChar = 0 this.FallbackChar = 0 this.Used8kPagesMap = {} this.EllipsisAutoBake = false this.RemapPairs = {} this.Scale = 0 return this end --- @class ImFontConfig --- @field Name string --- @field FontData table --- @field FontDataSize int --- @field FontDataOwnedByAtlas bool --- @field MergeMode bool --- @field PixelSnapH bool --- @field OversampleH ImS8 --- @field OversampleV ImS8 --- @field EllipsisChar ImWchar --- @field SizePixels float --- @field GlyphRanges ImWchar[] --- @field GlyphExcludeRanges ImWchar[] --- @field GlyphOffset ImVec2 --- @field GlyphMinAdvanceX float --- @field GlyphMaxAdvanceX float --- @field GlyphExtraAdvanceX float --- @field FontNo ImU32 --- @field FontLoaderFlags unsigned_int --- @field RasterizerMultiply float --- @field RasterizerDensity float --- @field ExtraSizeScale float --- @field Flags ImFontFlags --- @field DstFont ImFont --- @field FontLoader ImFontLoader --- @field FontLoaderData any local IM_FONT_CONFIG = {} IM_FONT_CONFIG.__index = IM_FONT_CONFIG --- @return ImFontConfig --- @nodiscard function ImFontConfig() --- @type ImFontConfig local this = setmetatable({}, IM_FONT_CONFIG) this.Name = nil this.FontData = nil this.FontDataSize = 0 this.FontDataOwnedByAtlas = true this.MergeMode = false this.PixelSnapH = false this.OversampleH = 0 this.OversampleV = 0 this.EllipsisChar = 0 this.SizePixels = 0 this.GlyphRanges = nil this.GlyphExcludeRanges = nil this.GlyphOffset = ImVec2() this.GlyphMinAdvanceX = 0 this.GlyphMaxAdvanceX = FLT_MAX this.GlyphExtraAdvanceX = 0 this.FontNo = 0 this.FontLoaderFlags = 0 this.RasterizerMultiply = 1.0 this.RasterizerDensity = 1.0 this.ExtraSizeScale = 1.0 this.Flags = 0 this.DstFont = nil this.FontLoader = nil this.FontLoaderData = nil return this end --- @class ImFontAtlas --- @field Flags ImFontAtlasFlags --- @field TexDesiredFormat ImTextureFormat --- @field TexGlyphPadding int --- @field TexMinWidth int --- @field TexMinHeight int --- @field TexMaxWidth int --- @field TexMaxHeight int --- @field TexRef ImTextureRef --- @field TexData ImTextureData --- @field TexList ImVector --- @field Locked bool --- @field RendererHasTextures bool --- @field TexPixelsUseColors bool --- @field TexUvScale ImVec2 --- @field TexUvWhitePixel ImVec2 --- @field Fonts ImVector --- @field Sources ImVector --- @field TexUvLines ImVec4[] # 0-based table --- @field TexNextUniqueID int --- @field FontNextUniqueID int --- @field DrawListSharedDatas ImVector --- @field Builder ImFontAtlasBuilder --- @field FontLoader ImFontLoader --- @field FontLoaderName string --- @field FontLoaderData any --- @field FontLoaderFlags unsigned_int --- @field RefCount int --- @field OwnerContext ImGuiContext MT.ImFontAtlas = {} MT.ImFontAtlas.__index = MT.ImFontAtlas --- @return ImFontAtlas --- @nodiscard function ImFontAtlas() --- @type ImFontAtlas local this = setmetatable({}, MT.ImFontAtlas) this.Flags = 0 this.TexDesiredFormat = ImTextureFormat.RGBA32 this.TexGlyphPadding = 1 this.TexMinWidth = 512 this.TexMinHeight = 128 this.TexMaxWidth = 8192 this.TexMaxHeight = 8192 this.TexRef = ImTextureRef() this.TexData = nil this.TexList = ImVector() this.Locked = false this.RendererHasTextures = false this.TexPixelsUseColors = nil this.TexUvScale = nil this.TexUvWhitePixel = nil this.Fonts = ImVector() this.Sources = ImVector() this.TexUvLines = {} this.TexNextUniqueID = 1 this.FontNextUniqueID = 1 this.DrawListSharedDatas = ImVector() this.Builder = nil this.FontLoader = nil this.FontLoaderName = nil this.FontLoaderData = nil this.FontLoaderFlags = nil this.RefCount = 0 this.OwnerContext = nil return this end --- @class ImFontAtlasRect --- @field x unsigned_short --- @field y unsigned_short --- @field w unsigned_short --- @field h unsigned_short --- @field uv0 ImVec2 --- @field uv1 ImVec2 --- @alias ImFontAtlasRectId int ImFontAtlasRectId_Invalid = -1 --- @return ImFontAtlasRect --- @nodiscard function ImFontAtlasRect() return { x = nil, y = nil, w = nil, h = nil, uv0 = ImVec2(), uv1 = ImVec2() } end --- @class ImFontGlyph --- @field Colored boolean --- @field Visible boolean --- @field SourceIdx unsigned_int --- @field Codepoint unsigned_int --- @field AdvanceX float --- @field X0 float --- @field Y0 float --- @field X1 float --- @field Y1 float --- @field U0 float --- @field V0 float --- @field U1 float --- @field V1 float --- @field PackId int --- @return ImFontGlyph --- @nodiscard function ImFontGlyph() return { Colored = false, Visible = false, SourceIdx = 0, Codepoint = 0, AdvanceX = 0, X0 = 0, Y0 = 0, X1 = 0, Y1 = 0, U0 = 0, V0 = 0, U1 = 0, V1 = 0, PackId = -1 } end --- @class ImGuiKeyData --- @field Down bool --- @field DownDuration float --- @field DownDurationPrev float --- @field AnalogValue float --- @return ImGuiKeyData --- @nodiscard function ImGuiKeyData() return { Down = false, DownDuration = 0.0, DownDurationPrev = 0.0, AnalogValue = 0.0 } end --- @enum ImGuiConfigFlags ImGuiConfigFlags = { None = 0, NavEnableKeyboard = bitLShift(1, 0), NavEnableGamepad = bitLShift(1, 1), NoMouse = bitLShift(1, 4), NoMouseCursorChange = bitLShift(1, 5), NoKeyboard = bitLShift(1, 6), DockingEnable = bitLShift(1, 7), ViewportsEnable = bitLShift(1, 10), IsSRGB = bitLShift(1, 20), IsTouchScreen = bitLShift(1, 21) } --- @class ImGuiIO MT.ImGuiIO = {} MT.ImGuiIO.__index = MT.ImGuiIO --- @return ImGuiIO function ImGuiIO() local this = { Ctx = nil, KeyCtrl = false, KeyShift = false, KeyAlt = false, KeySuper = false, KeyMods = nil, BackendFlags = ImGuiBackendFlags.None, ConfigFlags = ImGuiConfigFlags.None, DisplaySize = ImVec2(-1.0, -1.0), DeltaTime = 1.0 / 60.0, DisplayFramebufferScale = ImVec2(1.0, 1.0), MousePos = ImVec2(), MousePosPrev = ImVec2(), WantSetMousePos = false, MouseDelta = ImVec2(), MouseDown = {[0] = false, [1] = false, [2] = false}, MouseWheel = 0, MouseWheelH = 0, MouseCtrlLeftAsRightClick = false, MouseWheelRequestAxisSwap = false, ConfigColorEditFlags = ImGuiColorEditFlags.DefaultOptions_, ConfigMacOSXBehaviors = false, ConfigNavCursorVisibleAuto = true, ConfigNavCursorVisibleAlways = false, ConfigInputTrickleEventQueue = true, ConfigWindowsResizeFromEdges = true, ConfigDebugIniSettings = false, ConfigWindowsCopyContentsWithCtrlC = false, ConfigWindowsMoveFromTitleBarOnly = false, ConfigErrorRecovery = true, ConfigErrorRecoveryEnableAssert = true, ConfigErrorRecoveryEnableDebugLog = true, ConfigErrorRecoveryEnableTooltip = true, ConfigDebugHighlightIdConflicts = false, ConfigDebugHighlightIdConflictsShowItemPicker = true, IniFilename = "imgui.ini", -- Roblox: no disk access, only used as a flag (nil disables .ini handling) IniSavingRate = 5.0, LogFilename = "imgui_log.txt", WantSaveIniSettings = false, ConfigDockingNoSplit = false, ConfigDockingNoDockingOver = false, ConfigDockingWithShift = false, ConfigDockingAlwaysTabBar = false, ConfigDockingTransparentPayload = false, ConfigViewportsNoAutoMerge = false, ConfigViewportsNoTaskBarIcon = false, ConfigViewportsNoDecoration = true, ConfigViewportsNoDefaultParent = true, ConfigViewportsPlatformFocusSetsImGuiFocus = true, ConfigMemoryCompactTimer = 60.0, MouseDrawCursor = false, MouseClicked = {[0] = false, [1] = false, [2] = false}, MouseReleased = {[0] = false, [1] = false, [2] = false}, MouseClickedCount = {[0] = 0, [1] = 0, [2] = 0}, MouseClickedLastCount = {[0] = 0, [1] = 0, [2] = 0}, MouseDownDuration = {[0] = -1, [1] = -1, [2] = -1}, MouseDownDurationPrev = {[0] = -1, [1] = -1, [2] = -1}, MouseDragMaxDistanceAbs = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2()}, MouseDragMaxDistanceSqr = {[0] = 0, [1] = 0, [2] = 0}, MouseDownOwned = {[0] = nil, [1] = nil, [2] = nil}, MouseDownOwnedUnlessPopupClose = {[0] = nil, [1] = nil, [2] = nil}, MouseClickedTime = {[0] = 0, [1] = 0, [2] = 0}, MouseReleasedTime = {[0] = 0, [1] = 0, [2] = 0}, MouseClickedPos = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2()}, MouseDoubleClicked = {[0] = false, [1] = false, [2] = false}, MouseDoubleClickTime = 0.30, MouseSingleClickDelay = 0.50, MouseDoubleClickMaxDist = 6.0, MouseDragThreshold = 6.0, KeyRepeatDelay = 0.275, KeyRepeatRate = 0.050, KeysData = {}, -- size = ImGuiKey.NamedKey_COUNT WantCaptureMouse = nil, WantCaptureKeyboard = nil, WantTextInput = nil, Framerate = 0, MetricsRenderVertices = 0, MetricsRenderIndices = 0, MetricsRenderWindows = 0, MetricsActiveWindows = 0, NavActive = false, NavVisible = false, MetricsRenderWindows = 0, Fonts = nil, FontDefault = nil, BackendPlatformUserData = nil, BackendRendererUserData = nil, InputQueueCharacters = ImVector(), AppAcceptingEvents = true, InputQueueSurrogate = 0 } for i = 0, ImGuiKey.NamedKey_COUNT - 1 do this.KeysData[i] = ImGuiKeyData() end return setmetatable(this, MT.ImGuiIO) end --- @class ImGuiPlatformImeData --- @field WantVisible bool --- @field WantTextInput bool --- @field InputPos ImVec2 --- @field InputLineHeight float --- @field ViewportId ImGuiID --- @return ImGuiPlatformImeData --- @nodiscard function ImGuiPlatformImeData() return { WantVisible = false, WantTextInput = false, InputPos = ImVec2(), InputLineHeight = 0.0, ViewportId = 0 } end --- @param dest ImGuiPlatformImeData --- @param src ImGuiPlatformImeData function ImGuiPlatformImeData_Copy(dest, src) dest.WantVisible = src.WantVisible dest.WantTextInput = src.WantTextInput ImVec2_Copy(dest.InputPos, src.InputPos) dest.InputLineHeight = src.InputLineHeight dest.ViewportId = src.ViewportId end --- @param data1 ImGuiPlatformImeData --- @param data2 ImGuiPlatformImeData function ImGuiPlatformImeData_Compare(data1, data2) if data1.WantVisible ~= data2.WantVisible or data1.WantTextInput ~= data2.WantTextInput or data1.InputPos ~= data2.InputPos or data1.InputLineHeight ~= data2.InputLineHeight or data1.ViewportId ~= data2.ViewportId then return false end return true end --- @enum ImGuiViewportFlags ImGuiViewportFlags = { None = 0, IsPlatformWindow = bitLShift(1, 0), IsPlatformMonitor = bitLShift(1, 1), OwnedByApp = bitLShift(1, 2), NoDecoration = bitLShift(1, 3), NoTaskBarIcon = bitLShift(1, 4), NoFocusOnAppearing = bitLShift(1, 5), NoFocusOnClick = bitLShift(1, 6), NoInputs = bitLShift(1, 7), NoRendererClear = bitLShift(1, 8), NoAutoMerge = bitLShift(1, 9), TopMost = bitLShift(1, 10), CanHostOtherWindows = bitLShift(1, 11), IsMinimized = bitLShift(1, 12), IsFocused = bitLShift(1, 13) } --- @class ImGuiViewport --- @field ID ImGuiID --- @field Flags ImGuiViewportFlags --- @field Pos ImVec2 --- @field Size ImVec2 --- @field FramebufferScale ImVec2 --- @field WorkPos ImVec2 --- @field WorkSize ImVec2 --- @field DpiScale float --- @field ParentViewportId ImGuiID --- @field ParentViewport ImGuiViewport --- @field DrawData ImDrawData --- @field RendererUserData any --- @field PlatformUserData any --- @field PlatformHandle any --- @field PlatformHandleRaw any --- @field PlatformWindowCreated bool --- @field PlatformRequestMove bool --- @field PlatformRequestResize bool --- @field PlatformRequestClose bool MT.ImGuiViewport = {} MT.ImGuiViewport.__index = MT.ImGuiViewport function MT.ImGuiViewport:GetCenter() return ImVec2(self.Pos.x + self.Size.x * 0.5, self.Pos.y + self.Size.y * 0.5) end function MT.ImGuiViewport:GetWorkCenter() return ImVec2(self.WorkPos.x + self.WorkSize.x * 0.5, self.WorkPos.y + self.WorkSize.y * 0.5) end --- @return ImGuiViewport --- @nodiscard function ImGuiViewport() return setmetatable({ ID = 0, Flags = 0, Pos = ImVec2(), Size = ImVec2(), FramebufferScale = ImVec2(), WorkPos = ImVec2(), WorkSize = ImVec2(), DpiScale = 0, PlatformHandle = nil, PlatformHandleRaw = nil, PlatformWindowCreated = false }, MT.ImGuiViewport) end --- @class ImGuiPlatformIO --- @field Platform_GetClipboardTextFn fun(ctx?: ImGuiContext): string --- @field Platform_CreateWindow fun(vp: ImGuiViewport) --- @field Platform_OnChangedViewport fun(vp: ImGuiViewport) --- @field Monitors ImVector --- @field Textures ImVector --- @field Viewports ImVector MT.ImGuiPlatformIO = {} MT.ImGuiPlatformIO.__index = MT.ImGuiPlatformIO --- @return ImGuiPlatformIO --- @nodiscard function ImGuiPlatformIO() local this = { Platform_GetClipboardTextFn = nil, Platform_SetClipboardTextFn = nil, Platform_OpenInShellFn = nil, Platform_OpenInShellUserData = nil, Renderer_TextureMaxWidth = 0, Renderer_TextureMaxHeight = 0, Renderer_RenderState = nil, Monitors = ImVector(), Textures = ImVector(), Viewports = ImVector(), Platform_LocaleDecimalPoint = 46, -- '.' Platform_OnChangedViewport = nil, } return setmetatable(this, MT.ImGuiPlatformIO) end --- @class ImGuiPlatformMonitor --- @field MainPos ImVec2 --- @field MainSize ImVec2 --- @field WorkPos ImVec2 --- @field WorkSize ImVec2 --- @field DpiScale float --- @field PlatformHandle any --- @return ImGuiPlatformMonitor --- @nodiscard function ImGuiPlatformMonitor() return { MainPos = ImVec2(0, 0), MainSize = ImVec2(0, 0), WorkPos = ImVec2(0, 0), WorkSize = ImVec2(0, 0), DpiScale = 1.0, PlatformHandle = nil } end --- @enum ImGuiWindowFlags ImGuiWindowFlags = { None = 0, NoTitleBar = bitLShift(1, 0), NoResize = bitLShift(1, 1), NoMove = bitLShift(1, 2), NoScrollbar = bitLShift(1, 3), NoScrollWithMouse = bitLShift(1, 4), NoCollapse = bitLShift(1, 5), AlwaysAutoResize = bitLShift(1, 6), NoBackground = bitLShift(1, 7), NoSavedSettings = bitLShift(1, 8), NoMouseInputs = bitLShift(1, 9), MenuBar = bitLShift(1, 10), HorizontalScrollbar = bitLShift(1, 11), NoFocusOnAppearing = bitLShift(1, 12), NoBringToFrontOnFocus = bitLShift(1, 13), AlwaysVerticalScrollbar = bitLShift(1, 14), AlwaysHorizontalScrollbar = bitLShift(1, 15), NoNavInputs = bitLShift(1, 16), NoNavFocus = bitLShift(1, 17), UnsavedDocument = bitLShift(1, 18), NoDocking = bitLShift(1, 19), DockNodeHost = bitLShift(1, 23), ChildWindow = bitLShift(1, 24), Tooltip = bitLShift(1, 25), Popup = bitLShift(1, 26), Modal = bitLShift(1, 27), ChildMenu = bitLShift(1, 28) } -- [Internal] ImGuiWindowFlags.NoNav = bitOr(ImGuiWindowFlags.NoNavInputs, ImGuiWindowFlags.NoNavFocus) ImGuiWindowFlags.NoDecoration = bitOr(ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoScrollbar, ImGuiWindowFlags.NoCollapse) ImGuiWindowFlags.NoInputs = bitOr(ImGuiWindowFlags.NoMouseInputs, ImGuiWindowFlags.NoNavInputs, ImGuiWindowFlags.NoNavFocus) --- @enum ImGuiItemFlags ImGuiItemFlags = { None = 0, NoTabStop = bitLShift(1, 0), NoNav = bitLShift(1, 1), NoNavDefaultFocus = bitLShift(1, 2), ButtonRepeat = bitLShift(1, 3), AutoClosePopups = bitLShift(1, 4), AllowDuplicateId = bitLShift(1, 5), Disabled = bitLShift(1, 6), LiveEditOnInputText = bitLShift(1, 7), LiveEditOnInputScalar = bitLShift(1, 8) } ImGuiItemFlags.LiveEditOnInput = bitOr(ImGuiItemFlags.LiveEditOnInputText, ImGuiItemFlags.LiveEditOnInputScalar) --- @enum ImGuiItemStatusFlags ImGuiItemStatusFlags = { None = 0, HoveredRect = bitLShift(1, 0), HasDisplayRect = bitLShift(1, 1), Edited = bitLShift(1, 2), ToggledSelection = bitLShift(1, 3), ToggledOpen = bitLShift(1, 4), HasDeactivated = bitLShift(1, 5), Deactivated = bitLShift(1, 6), HoveredWindow = bitLShift(1, 7), Visible = bitLShift(1, 8), HasClipRect = bitLShift(1, 9), HasShortcut = bitLShift(1, 10), EditedInternal = bitLShift(1, 11) } --- @enum ImGuiChildFlags ImGuiChildFlags = { None = 0, Borders = bitLShift(1, 0), AlwaysUseWindowPadding = bitLShift(1, 1), ResizeX = bitLShift(1, 2), ResizeY = bitLShift(1, 3), AutoResizeX = bitLShift(1, 4), AutoResizeY = bitLShift(1, 5), AlwaysAutoResize = bitLShift(1, 6), FrameStyle = bitLShift(1, 7), NavFlattened = bitLShift(1, 8) } ImGuiChildFlags.ResizeBoth = bitOr(ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY) ImGuiChildFlags.ResizeXAndY = ImGuiChildFlags.ResizeBoth --- @enum ImGuiNextItemDataFlags ImGuiNextItemDataFlags = { None = 0, HasWidth = bitLShift(1, 0), HasOpen = bitLShift(1, 1), HasShortcut = bitLShift(1, 2), HasRefVal = bitLShift(1, 3), HasStorageID = bitLShift(1, 4), HasColorMarker = bitLShift(1, 5) } --- @enum ImDrawFlags ImDrawFlags = { None = 0, RoundCornersTopLeft = bitLShift(1, 4), RoundCornersTopRight = bitLShift(1, 5), RoundCornersBottomLeft = bitLShift(1, 6), RoundCornersBottomRight = bitLShift(1, 7), RoundCornersNone = bitLShift(1, 8), Closed = bitLShift(1, 9) } ImDrawFlags.RoundCornersTop = bitOr(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersTopRight) ImDrawFlags.RoundCornersBottom = bitOr(ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersBottomRight) ImDrawFlags.RoundCornersLeft = bitOr(ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersTopLeft) ImDrawFlags.RoundCornersRight = bitOr(ImDrawFlags.RoundCornersBottomRight, ImDrawFlags.RoundCornersTopRight) ImDrawFlags.RoundCornersAll = bitOr(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersTopRight, ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersBottomRight) ImDrawFlags.RoundCornersDefault_ = ImDrawFlags.RoundCornersAll ImDrawFlags.RoundCornersMask_ = bitOr(ImDrawFlags.RoundCornersAll, ImDrawFlags.RoundCornersNone) ImDrawFlags.InvalidMask_ = 0x8000000F --- @enum ImDrawListFlags ImDrawListFlags = { None = 0, AntiAliasedLines = bitLShift(1, 0), AntiAliasedLinesUseTex = bitLShift(1, 1), AntiAliasedFill = bitLShift(1, 2), AllowVtxOffset = bitLShift(1, 3), TextNoPixelSnap = bitLShift(1, 4) } --- @enum ImFontFlags ImFontFlags = { None = 0, NoLoadError = bitLShift(1, 1), NoLoadGlyphs = bitLShift(1, 2), LockBakedSizes = bitLShift(1, 3), ImplicitRefSize = bitLShift(1, 4) } --- @enum ImGuiMouseSource ImGuiMouseSource = { Mouse = 0, TouchScreen = 1, Pen = 2, COUNT = 3 } --- @enum ImGuiCond ImGuiCond = { None = 0, Always = bitLShift(1, 0), Once = bitLShift(1, 1), FirstUseEver = bitLShift(1, 2), Appearing = bitLShift(1, 3) } --- @enum ImGuiInputFlags ImGuiInputFlags = { None = 0, Repeat = bitLShift(1, 0), RouteActive = bitLShift(1, 10), RouteFocused = bitLShift(1, 11), RouteGlobal = bitLShift(1, 12), RouteAlways = bitLShift(1, 13), RouteOverFocused = bitLShift(1, 14), RouteOverActive = bitLShift(1, 15), RouteUnlessBgFocused = bitLShift(1, 16), RouteFromRootWindow = bitLShift(1, 17), Tooltip = bitLShift(1, 18) } --- @enum ImGuiButtonFlags ImGuiButtonFlags = { None = 0, MouseButtonLeft = bitLShift(1, 0), MouseButtonRight = bitLShift(1, 1), MouseButtonMiddle = bitLShift(1, 2), EnableNav = bitLShift(1, 3), PressedOnClick = bitLShift(1, 4), PressedOnClickRelease = bitLShift(1, 5), PressedOnClickReleaseAnywhere = bitLShift(1, 6), PressedOnRelease = bitLShift(1, 7), PressedOnDoubleClick = bitLShift(1, 8), PressedOnDragDropHold = bitLShift(1, 9), FlattenChildren = bitLShift(1, 11), AllowOverlap = bitLShift(1, 12), AlignTextBaseLine = bitLShift(1, 15), NoKeyModsAllowed = bitLShift(1, 16), NoHoldingActiveId = bitLShift(1, 17), NoNavFocus = bitLShift(1, 18), NoHoveredOnFocus = bitLShift(1, 19), NoSetKeyOwner = bitLShift(1, 20), NoTestKeyOwner = bitLShift(1, 21), NoFocus = bitLShift(1, 22) } ImGuiButtonFlags.MouseButtonMask_ = bitOr(ImGuiButtonFlags.MouseButtonLeft, ImGuiButtonFlags.MouseButtonRight, ImGuiButtonFlags.MouseButtonMiddle) ImGuiButtonFlags.PressedOnMask_ = bitOr(ImGuiButtonFlags.PressedOnClick, ImGuiButtonFlags.PressedOnClickRelease, ImGuiButtonFlags.PressedOnClickReleaseAnywhere, ImGuiButtonFlags.PressedOnRelease, ImGuiButtonFlags.PressedOnDoubleClick, ImGuiButtonFlags.PressedOnDragDropHold) ImGuiButtonFlags.PressedOnDefault_ = ImGuiButtonFlags.PressedOnClickRelease ImGuiButtonFlags.NoKeyModifiers = ImGuiButtonFlags.NoKeyModsAllowed --- @enum ImGuiStyleVar ImGuiStyleVar = { Alpha = 0, DisabledAlpha = 1, WindowPadding = 2, WindowRounding = 3, WindowBorderSize = 4, WindowMinSize = 5, WindowTitleAlign = 6, ChildRounding = 7, ChildBorderSize = 8, PopupRounding = 9, PopupBorderSize = 10, FramePadding = 11, FrameRounding = 12, FrameBorderSize = 13, ItemSpacing = 14, ItemInnerSpacing = 15, IndentSpacing = 16, CellPadding = 17, ScrollbarSize = 18, ScrollbarRounding = 19, ScrollbarPadding = 20, GrabMinSize = 21, GrabRounding = 22, ImageRounding = 23, ImageBorderSize = 24, TabRounding = 25, TabBorderSize = 26, TabMinWidthBase = 27, TabMinWidthShrink = 28, TabBarBorderSize = 29, TabBarOverlineSize = 30, TableAngledHeadersAngle = 31, TableAngledHeadersTextAlign = 32, TreeLinesSize = 33, TreeLinesRounding = 34, MenuItemRounding = 35, SelectableRounding = 36, DragDropTargetRounding = 37, ButtonTextAlign = 38, SelectableTextAlign = 39, SeparatorTextBorderSize = 40, SeparatorTextAlign = 41, SeparatorTextPadding = 42, COUNT = 43 } --- @enum ImGuiHoveredFlags ImGuiHoveredFlags = { None = 0, ChildWindows = bitLShift(1, 0), RootWindow = bitLShift(1, 1), AnyWindow = bitLShift(1, 2), NoPopupHierarchy = bitLShift(1, 3), DockHierarchy = bitLShift(1, 4), AllowWhenBlockedByPopup = bitLShift(1, 5), AllowWhenBlockedByActiveItem = bitLShift(1, 7), AllowWhenOverlappedByItem = bitLShift(1, 8), AllowWhenOverlappedByWindow = bitLShift(1, 9), AllowWhenDisabled = bitLShift(1, 10), NoNavOverride = bitLShift(1, 11), ForTooltip = bitLShift(1, 12), Stationary = bitLShift(1, 13), DelayNone = bitLShift(1, 14), DelayShort = bitLShift(1, 15), DelayNormal = bitLShift(1, 16), NoSharedDelay = bitLShift(1, 17) } --- @enum ImGuiFocusedFlags ImGuiFocusedFlags = { None = 0, ChildWindows = bitLShift(1, 0), -- Return true if any children of the window is focused RootWindow = bitLShift(1, 1), -- Test from root window (top most parent of the current hierarchy) AnyWindow = bitLShift(1, 2), -- Return true if any window is focused NoPopupHierarchy = bitLShift(1, 3), -- Do not consider popup hierarchy DockHierarchy = bitLShift(1, 4), -- Consider docking hierarchy } ImGuiFocusedFlags.RootAndChildWindows = bitOr(ImGuiFocusedFlags.RootWindow, ImGuiFocusedFlags.ChildWindows) ImGuiHoveredFlags.AllowWhenOverlapped = bitOr(ImGuiHoveredFlags.AllowWhenOverlappedByItem, ImGuiHoveredFlags.AllowWhenOverlappedByWindow) ImGuiHoveredFlags.RectOnly = bitOr(ImGuiHoveredFlags.AllowWhenBlockedByPopup, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem, ImGuiHoveredFlags.AllowWhenOverlapped) ImGuiHoveredFlags.RootAndChildWindows = bitOr(ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.ChildWindows) ImGuiHoveredFlags.DelayMask_ = bitOr(ImGuiHoveredFlags.DelayNone, ImGuiHoveredFlags.DelayShort, ImGuiHoveredFlags.DelayNormal, ImGuiHoveredFlags.NoSharedDelay) ImGuiHoveredFlags.AllowedMaskForIsWindowHovered = bitOr(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.AnyWindow, ImGuiHoveredFlags.NoPopupHierarchy, ImGuiHoveredFlags.DockHierarchy, ImGuiHoveredFlags.AllowWhenBlockedByPopup, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem, ImGuiHoveredFlags.ForTooltip, ImGuiHoveredFlags.Stationary) ImGuiHoveredFlags.AllowedMaskForIsItemHovered = bitOr(ImGuiHoveredFlags.AllowWhenBlockedByPopup, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem, ImGuiHoveredFlags.AllowWhenOverlapped, ImGuiHoveredFlags.AllowWhenDisabled, ImGuiHoveredFlags.NoNavOverride, ImGuiHoveredFlags.ForTooltip, ImGuiHoveredFlags.Stationary, ImGuiHoveredFlags.DelayMask_) --- @enum ImGuiKey ImGuiKey = { None = 0, NamedKey_BEGIN = 512, Tab = 512, LeftArrow = 513, RightArrow = 514, UpArrow = 515, DownArrow = 516, PageUp = 517, PageDown = 518, Home = 519, End = 520, Insert = 521, Delete = 522, Backspace = 523, Space = 524, Enter = 525, Escape = 526, LeftCtrl = 527, LeftShift = 528, LeftAlt = 529, LeftSuper = 530, RightCtrl = 531, RightShift = 532, RightAlt = 533, RightSuper = 534, Menu = 535, -- 1 ~ 9 K0 = 536, K1 = 537, K2 = 538, K3 = 539, K4 = 540, K5 = 541, K6 = 542, K7 = 543, K8 = 544, K9 = 545, A = 546, B = 547, C = 548, D = 549, E = 550, F = 551, G = 552, H = 553, I = 554, J = 555, K = 556, L = 557, M = 558, N = 559, O = 560, P = 561, Q = 562, R = 563, S = 564, T = 565, U = 566, V = 567, W = 568, X = 569, Y = 570, Z = 571, F1 = 572, F2 = 573, F3 = 574, F4 = 575, F5 = 576, F6 = 577, F7 = 578, F8 = 579, F9 = 580, F10 = 581, F11 = 582, F12 = 583, F13 = 584, F14 = 585, F15 = 586, F16 = 587, F17 = 588, F18 = 589, F19 = 590, F20 = 591, F21 = 592, F22 = 593, F23 = 594, F24 = 595, Apostrophe = 596, Comma = 597, Minus = 598, Period = 599, Slash = 600, Semicolon = 601, Equal = 602, LeftBracket = 603, Backslash = 604, RightBracket = 605, GraveAccent = 606, CapsLock = 607, ScrollLock = 608, NumLock = 609, PrintScreen = 610, Pause = 611, Keypad0 = 612, Keypad1 = 613, Keypad2 = 614, Keypad3 = 615, Keypad4 = 616, Keypad5 = 617, Keypad6 = 618, Keypad7 = 619, Keypad8 = 620, Keypad9 = 621, KeypadDecimal = 622, KeypadDivide = 623, KeypadMultiply = 624, KeypadSubtract = 625, KeypadAdd = 626, KeypadEnter = 627, KeypadEqual = 628, AppBack = 629, AppForward = 630, Oem102 = 631, GamepadStart = 632, GamepadBack = 633, GamepadFaceLeft = 634, GamepadFaceRight = 635, GamepadFaceUp = 636, GamepadFaceDown = 637, GamepadDpadLeft = 638, GamepadDpadRight = 639, GamepadDpadUp = 640, GamepadDpadDown = 641, GamepadL1 = 642, GamepadR1 = 643, GamepadL2 = 644, GamepadR2 = 645, GamepadL3 = 646, GamepadR3 = 647, GamepadLStickLeft = 648, GamepadLStickRight = 649, GamepadLStickUp = 650, GamepadLStickDown = 651, GamepadRStickLeft = 652, GamepadRStickRight = 653, GamepadRStickUp = 654, GamepadRStickDown = 655, MouseLeft = 656, MouseRight = 657, MouseMiddle = 658, MouseX1 = 659, MouseX2 = 660, MouseWheelX = 661, MouseWheelY = 662, ReservedForModCtrl = 663, ReservedForModShift = 664, ReservedForModAlt = 665, ReservedForModSuper = 666, NamedKey_END = 667 } ImGuiKey.NamedKey_COUNT = ImGuiKey.NamedKey_END - ImGuiKey.NamedKey_BEGIN ImGuiMod_None = 0 ImGuiMod_Ctrl = bitLShift(1, 12) ImGuiMod_Shift = bitLShift(1, 13) ImGuiMod_Alt = bitLShift(1, 14) ImGuiMod_Super = bitLShift(1, 15) ImGuiMod_Mask_ = 0xF000 --- @enum ImGuiCol ImGuiCol = { Text = 0, TextDisabled = 1, WindowBg = 2, ChildBg = 3, PopupBg = 4, Border = 5, BorderShadow = 6, FrameBg = 7, FrameBgHovered = 8, FrameBgActive = 9, TitleBg = 10, TitleBgActive = 11, TitleBgCollapsed = 12, MenuBarBg = 13, ScrollbarBg = 14, ScrollbarGrab = 15, ScrollbarGrabHovered = 16, ScrollbarGrabActive = 17, CheckMark = 18, CheckboxSelectedBg = 19, SliderGrab = 20, SliderGrabActive = 21, Button = 22, ButtonHovered = 23, ButtonActive = 24, Header = 25, HeaderHovered = 26, HeaderActive = 27, Separator = 28, SeparatorHovered = 29, SeparatorActive = 30, ResizeGrip = 31, ResizeGripHovered = 32, ResizeGripActive = 33, InputTextCursor = 34, TabHovered = 35, Tab = 36, TabSelected = 37, TabSelectedOverline = 38, TabDimmed = 39, TabDimmedSelected = 40, TabDimmedSelectedOverline = 41, DockingPreview = 42, DockingEmptyBg = 43, PlotLines = 44, PlotLinesHovered = 45, PlotHistogram = 46, PlotHistogramHovered = 47, TableHeaderBg = 48, TableBorderStrong = 49, TableBorderLight = 50, TableRowBg = 51, TableRowBgAlt = 52, TextLink = 53, TextSelectedBg = 54, TreeLines = 55, DragDropTarget = 56, DragDropTargetBg = 57, UnsavedMarker = 58, NavCursor = 59, NavWindowingHighlight = 60, NavWindowingDimBg = 61, ModalWindowDimBg = 62, COUNT = 63 } --- @enum ImGuiBackendFlags ImGuiBackendFlags = { None = 0, HasGamepad = bitLShift(1, 0), HasMouseCursors = bitLShift(1, 1), HasSetMousePos = bitLShift(1, 2), RendererHasVtxOffset = bitLShift(1, 3), RendererHasTextures = bitLShift(1, 4), -- [BETA] Multi-Viewports RendererHasViewports = bitLShift(1, 10), PlatformHasViewports = bitLShift(1, 11), HasMouseHoveredViewport = bitLShift(1, 12), HasParentViewport = bitLShift(1, 13) } --- @enum ImGuiDragDropFlags ImGuiDragDropFlags = { None = 0, SourceNoPreviewTooltip = bitLShift(1, 0), SourceNoDisableHover = bitLShift(1, 1), SourceNoHoldToOpenOthers = bitLShift(1, 2), SourceAllowNullID = bitLShift(1, 3), SourceExtern = bitLShift(1, 4), PayloadAutoExpire = bitLShift(1, 5), PayloadNoCrossContext = bitLShift(1, 6), PayloadNoCrossProcess = bitLShift(1, 7), AcceptBeforeDelivery = bitLShift(1, 10), AcceptNoDrawDefaultRect = bitLShift(1, 11), AcceptNoPreviewTooltip = bitLShift(1, 12), AcceptDrawAsHovered = bitLShift(1, 13) } ImGuiDragDropFlags.AcceptPeekOnly = bitOr(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoDrawDefaultRect) IM_COL32_R_SHIFT = 0 IM_COL32_G_SHIFT = 8 IM_COL32_B_SHIFT = 16 IM_COL32_A_SHIFT = 24 IM_COL32_A_MASK = 0xFF000000 --- @param R ImU32 --- @param G ImU32 --- @param B ImU32 --- @param A ImU32 IM_COL32 = function(R, G, B, A) return (bitOr(bitLShift(A, IM_COL32_A_SHIFT), bitLShift(B, IM_COL32_B_SHIFT), bitLShift(G, IM_COL32_G_SHIFT), bitLShift(R, IM_COL32_R_SHIFT))) end IM_COL32_WHITE = IM_COL32(255, 255, 255, 255) IM_COL32_BLACK = IM_COL32(0, 0, 0, 255) IM_COL32_BLACK_TRANS = IM_COL32(0, 0, 0, 0) --- @enum ImGuiPopupFlags ImGuiPopupFlags = { None = 0, MouseButtonLeft = bitLShift(1, 2), MouseButtonRight = bitLShift(2, 2), MouseButtonMiddle = bitLShift(3, 2), NoReopen = bitLShift(1, 5), NoOpenOverExistingPopup = bitLShift(1, 7), NoOpenOverItems = bitLShift(1, 8), AnyPopupId = bitLShift(1, 10), AnyPopupLevel = bitLShift(1, 11) } ImGuiPopupFlags.AnyPopup = bitOr(ImGuiPopupFlags.AnyPopupId, ImGuiPopupFlags.AnyPopupLevel) ImGuiPopupFlags.MouseButtonShift_ = 2 ImGuiPopupFlags.MouseButtonMask_ = 0x0C ImGuiPopupFlags.InvalidMask_ = 0x03 --- @enum ImGuiComboFlags ImGuiComboFlags = { None = 0, PopupAlignLeft = bitLShift(1, 0), HeightSmall = bitLShift(1, 1), HeightRegular = bitLShift(1, 2), HeightLarge = bitLShift(1, 3), HeightLargest = bitLShift(1, 4), NoArrowButton = bitLShift(1, 5), NoPreview = bitLShift(1, 6), WidthFitPreview = bitLShift(1, 7) } ImGuiComboFlags.HeightMask_ = bitOr(ImGuiComboFlags.HeightSmall, ImGuiComboFlags.HeightRegular, ImGuiComboFlags.HeightLarge, ImGuiComboFlags.HeightLargest) ImGuiComboFlags.CustomPreview = bitLShift(1, 20) --- @enum ImGuiSelectableFlags ImGuiSelectableFlags = { None = 0, NoAutoClosePopups = bitLShift(1, 0), SpanAllColumns = bitLShift(1, 1), AllowDoubleClick = bitLShift(1, 2), Disabled = bitLShift(1, 3), AllowOverlap = bitLShift(1, 4), Highlight = bitLShift(1, 5), SelectOnNav = bitLShift(1, 6), NoHoldingActiveID = bitLShift(1, 20), SelectOnClick = bitLShift(1, 22), SelectOnRelease = bitLShift(1, 23), SpanAvailWidth = bitLShift(1, 24), SetNavIdOnHover = bitLShift(1, 25), NoPadWithHalfSpacing = bitLShift(1, 26), NoSetKeyOwner = bitLShift(1, 27), } --- @enum ImGuiColorEditFlags ImGuiColorEditFlags = { None = 0, NoAlpha = bitLShift(1, 1), NoPicker = bitLShift(1, 2), NoOptions = bitLShift(1, 3), NoSmallPreview = bitLShift(1, 4), NoInputs = bitLShift(1, 5), NoTooltip = bitLShift(1, 6), NoLabel = bitLShift(1, 7), NoSidePreview = bitLShift(1, 8), NoDragDrop = bitLShift(1, 9), NoBorder = bitLShift(1, 10), NoColorMarkers = bitLShift(1, 11), -- Alpha preview AlphaOpaque = bitLShift(1, 12), AlphaNoBg = bitLShift(1, 13), AlphaPreviewHalf = bitLShift(1, 14), -- User Options (right-click on widget to change some of them) AlphaBar = bitLShift(1, 18), HDR = bitLShift(1, 19), DisplayRGB = bitLShift(1, 20), DisplayHSV = bitLShift(1, 21), DisplayHex = bitLShift(1, 22), Uint8 = bitLShift(1, 23), Float = bitLShift(1, 24), PickerHueBar = bitLShift(1, 25), PickerHueWheel = bitLShift(1, 26), PickerNoRotate = bitLShift(1, 27), InputRGB = bitLShift(1, 28), InputHSV = bitLShift(1, 29) } ImGuiColorEditFlags.DefaultOptions_ = bitOr(ImGuiColorEditFlags.Uint8, ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.InputRGB, ImGuiColorEditFlags.PickerHueBar) ImGuiColorEditFlags.AlphaMask_ = bitOr( ImGuiColorEditFlags.NoAlpha, ImGuiColorEditFlags.AlphaOpaque, ImGuiColorEditFlags.AlphaNoBg, ImGuiColorEditFlags.AlphaPreviewHalf ) ImGuiColorEditFlags.DisplayMask_ = bitOr( ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.DisplayHSV, ImGuiColorEditFlags.DisplayHex ) ImGuiColorEditFlags.DataTypeMask_ = bitOr( ImGuiColorEditFlags.Uint8, ImGuiColorEditFlags.Float ) ImGuiColorEditFlags.PickerMask_ = bitOr( ImGuiColorEditFlags.PickerHueWheel, ImGuiColorEditFlags.PickerHueBar ) ImGuiColorEditFlags.InputMask_ = bitOr( ImGuiColorEditFlags.InputRGB, ImGuiColorEditFlags.InputHSV ) --- @enum ImGuiSliderFlags ImGuiSliderFlags = { None = 0, Logarithmic = bitLShift(1, 5), NoRoundToFormat = bitLShift(1, 6), NoInput = bitLShift(1, 7), WrapAround = bitLShift(1, 8), ClampOnInput = bitLShift(1, 9), ClampZeroRange = bitLShift(1, 10), NoSpeedTweaks = bitLShift(1, 11), ColorMarkers = bitLShift(1, 12), InvalidMask_ = 0x7000000F, } ImGuiSliderFlags.AlwaysClamp = bitOr(ImGuiSliderFlags.ClampOnInput, ImGuiSliderFlags.ClampZeroRange) ImGuiSliderFlags.Vertical = bitLShift(1, 20) ImGuiSliderFlags.ReadOnly = bitLShift(1, 21) --- @class ImGuiWindowClass --- @field ClassId ImGuiID --- @field ParentViewportId ImGuiID --- @field FocusRouteParentWindowId ImGuiID --- @field ViewportFlagsOverrideSet ImGuiViewportFlags --- @field ViewportFlagsOverrideClear ImGuiViewportFlags --- @return ImGuiWindowClass --- @nodiscard function ImGuiWindowClass() return { ClassId = 0, ParentViewportId = 0xFFFFFFFF, FocusRouteParentWindowId = 0, ViewportFlagsOverrideSet = 0, ViewportFlagsOverrideClear = 0, TabItemFlagsOverrideSet = 0, DockNodeFlagsOverrideSet = 0, DockingAlwaysTabBar = false, DockingAllowUnclassed = true } end --- @enum ImGuiInputTextFlags ImGuiInputTextFlags = { None = 0, -- Basic filters (also see ImGuiInputTextFlags.CallbackCharFilter) CharsDecimal = bitLShift(1, 0), CharsHexadecimal = bitLShift(1, 1), CharsScientific = bitLShift(1, 2), CharsUppercase = bitLShift(1, 3), CharsNoBlank = bitLShift(1, 4), -- Inputs AllowTabInput = bitLShift(1, 5), EnterReturnsTrue = bitLShift(1, 6), EscapeClearsAll = bitLShift(1, 7), CtrlEnterForNewLine = bitLShift(1, 8), -- Other options ReadOnly = bitLShift(1, 9), Password = bitLShift(1, 10), AlwaysOverwrite = bitLShift(1, 11), AutoSelectAll = bitLShift(1, 12), ParseEmptyRefVal = bitLShift(1, 13), DisplayEmptyRefVal = bitLShift(1, 14), NoHorizontalScroll = bitLShift(1, 15), NoUndoRedo = bitLShift(1, 16), -- Elide display / Alignment ElideLeft = bitLShift(1, 17), -- Callback features CallbackCompletion = bitLShift(1, 18), CallbackHistory = bitLShift(1, 19), CallbackAlways = bitLShift(1, 20), CallbackCharFilter = bitLShift(1, 21), CallbackResize = bitLShift(1, 22), CallbackEdit = bitLShift(1, 23), -- Multi-line Word-Wrapping [BETA] WordWrap = bitLShift(1, 24), -- [Internal] Multiline = bitLShift(1, 26), TempInput = bitLShift(1, 27), LocalizeDecimalPoint = bitLShift(1, 28), } --- @class ImGuiInputTextCallbackData --- @return ImGuiInputTextCallbackData -- Buf is a 1-based zero-terminated byte table; positions (CursorPos, pos...) are 0-based byte offsets like upstream. MT.ImGuiInputTextCallbackData = {} MT.ImGuiInputTextCallbackData.__index = MT.ImGuiInputTextCallbackData function ImGuiInputTextCallbackData() return setmetatable({}, MT.ImGuiInputTextCallbackData) end function MT.ImGuiInputTextCallbackData:DeleteChars(pos, bytes_count) IM_ASSERT(pos + bytes_count <= self.BufTextLen) local buf = self.Buf local n = self.BufTextLen - bytes_count - pos + 1 -- includes zero terminator for i = 1, n do buf[pos + i] = buf[pos + bytes_count + i] end if self.CursorPos >= pos + bytes_count then self.CursorPos = self.CursorPos - bytes_count elseif self.CursorPos >= pos then self.CursorPos = pos end self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos self.BufDirty = true self.BufTextLen = self.BufTextLen - bytes_count end --- @param new_text string function MT.ImGuiInputTextCallbackData:InsertChars(pos, new_text) local new_text_len = #new_text if new_text_len == 0 then return end local is_resizable = bit32.band(self.Flags, ImGuiInputTextFlags.CallbackResize) ~= 0 -- We support partial insertion local avail = self.BufSize - 1 - self.BufTextLen if not is_resizable and new_text_len > avail then new_text_len = avail -- ponytail: truncates by bytes, not to the closest UTF-8 codepoint end if new_text_len <= 0 then return end -- ponytail: CallbackResize buffer growth not supported, text is truncated at BufSize instead if self.BufTextLen + new_text_len + 1 > self.BufSize then new_text_len = self.BufSize - 1 - self.BufTextLen if new_text_len <= 0 then return end end local buf = self.Buf for i = self.BufTextLen, pos + 1, -1 do buf[i + new_text_len] = buf[i] end for i = 1, new_text_len do buf[pos + i] = string.byte(new_text, i) end buf[self.BufTextLen + new_text_len + 1] = 0 self.BufDirty = true self.BufTextLen = self.BufTextLen + new_text_len if self.CursorPos >= pos then self.CursorPos = self.CursorPos + new_text_len end self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos end function MT.ImGuiInputTextCallbackData:SelectAll() self.SelectionStart = 0; self.SelectionEnd = self.BufTextLen end function MT.ImGuiInputTextCallbackData:ClearSelection() self.SelectionStart = self.BufTextLen; self.SelectionEnd = self.BufTextLen end function MT.ImGuiInputTextCallbackData:HasSelection() return self.SelectionStart ~= self.SelectionEnd end --- @alias ImGuiInputTextCallback fun(data: ImGuiInputTextCallbackData) --- @alias ImGuiMemAllocFunc fun(T: function, start_idx: int, end_idx: int, userdata: any): table --- @alias ImGuiMemFreeFunc fun(owner: table, field: string, userdata: any) --- @alias ImDrawCallback fun(parent_list: ImDrawList, cmd: ImDrawCmd) --- @enum ImGuiTreeNodeFlags ImGuiTreeNodeFlags = { None = 0, Selected = bitLShift(1, 0), Framed = bitLShift(1, 1), AllowOverlap = bitLShift(1, 2), NoTreePushOnOpen = bitLShift(1, 3), NoAutoOpenOnLog = bitLShift(1, 4), DefaultOpen = bitLShift(1, 5), OpenOnDoubleClick = bitLShift(1, 6), OpenOnArrow = bitLShift(1, 7), Leaf = bitLShift(1, 8), Bullet = bitLShift(1, 9), FramePadding = bitLShift(1, 10), SpanAvailWidth = bitLShift(1, 11), SpanFullWidth = bitLShift(1, 12), SpanLabelWidth = bitLShift(1, 13), SpanAllColumns = bitLShift(1, 14), LabelSpanAllColumns = bitLShift(1, 15), NavLeftJumpsToParent = bitLShift(1, 17), DrawLinesNone = bitLShift(1, 18), DrawLinesFull = bitLShift(1, 19), DrawLinesToNodes = bitLShift(1, 20), NoNavFocus = bitLShift(1, 27), ClipLabelForTrailingButton = bitLShift(1, 28), UpsideDownArrow = bitLShift(1, 29), } ImGuiTreeNodeFlags.CollapsingHeader = bitOr(ImGuiTreeNodeFlags.Framed, ImGuiTreeNodeFlags.NoTreePushOnOpen, ImGuiTreeNodeFlags.NoAutoOpenOnLog) ImGuiTreeNodeFlags.OpenOnMask_ = bitOr(ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.OpenOnArrow) ImGuiTreeNodeFlags.DrawLinesMask_ = bitOr(ImGuiTreeNodeFlags.DrawLinesNone, ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DrawLinesToNodes) --- @enum ImGuiTableFlags ImGuiTableFlags = { None = 0, Resizable = bitLShift(1, 0), Reorderable = bitLShift(1, 1), Hideable = bitLShift(1, 2), Sortable = bitLShift(1, 3), NoSavedSettings = bitLShift(1, 4), ContextMenuInBody = bitLShift(1, 5), RowBg = bitLShift(1, 6), BordersInnerH = bitLShift(1, 7), BordersOuterH = bitLShift(1, 8), BordersInnerV = bitLShift(1, 9), BordersOuterV = bitLShift(1, 10), NoBordersInBody = bitLShift(1, 11), NoBordersInBodyUntilResize = bitLShift(1, 12), SizingFixedFit = bitLShift(1, 13), SizingFixedSame = bitLShift(2, 13), SizingStretchProp = bitLShift(3, 13), SizingStretchSame = bitLShift(4, 13), NoHostExtendX = bitLShift(1, 16), NoHostExtendY = bitLShift(1, 17), NoKeepColumnsVisible = bitLShift(1, 18), PreciseWidths = bitLShift(1, 19), NoClip = bitLShift(1, 20), PadOuterX = bitLShift(1, 21), NoPadOuterX = bitLShift(1, 22), NoPadInnerX = bitLShift(1, 23), ScrollX = bitLShift(1, 24), ScrollY = bitLShift(1, 25), SortMulti = bitLShift(1, 26), SortTristate = bitLShift(1, 27), HighlightHoveredColumn = bitLShift(1, 28), } ImGuiTableFlags.BordersH = bitOr(ImGuiTableFlags.BordersInnerH, ImGuiTableFlags.BordersOuterH) ImGuiTableFlags.BordersV = bitOr(ImGuiTableFlags.BordersInnerV, ImGuiTableFlags.BordersOuterV) ImGuiTableFlags.BordersInner = bitOr(ImGuiTableFlags.BordersInnerV, ImGuiTableFlags.BordersInnerH) ImGuiTableFlags.BordersOuter = bitOr(ImGuiTableFlags.BordersOuterV, ImGuiTableFlags.BordersOuterH) ImGuiTableFlags.Borders = bitOr(ImGuiTableFlags.BordersInner, ImGuiTableFlags.BordersOuter) ImGuiTableFlags.SizingMask_ = bitOr(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.SizingFixedSame, ImGuiTableFlags.SizingStretchProp, ImGuiTableFlags.SizingStretchSame) --- @enum ImGuiTableColumnFlags ImGuiTableColumnFlags = { None = 0, Disabled = bitLShift(1, 0), DefaultHide = bitLShift(1, 1), DefaultSort = bitLShift(1, 2), WidthStretch = bitLShift(1, 3), WidthFixed = bitLShift(1, 4), NoResize = bitLShift(1, 5), NoReorder = bitLShift(1, 6), NoHide = bitLShift(1, 7), NoClip = bitLShift(1, 8), NoSort = bitLShift(1, 9), NoSortAscending = bitLShift(1, 10), NoSortDescending = bitLShift(1, 11), NoHeaderLabel = bitLShift(1, 12), NoHeaderWidth = bitLShift(1, 13), PreferSortAscending = bitLShift(1, 14), PreferSortDescending = bitLShift(1, 15), IndentEnable = bitLShift(1, 16), IndentDisable = bitLShift(1, 17), AngledHeader = bitLShift(1, 18), IsEnabled = bitLShift(1, 24), IsVisible = bitLShift(1, 25), IsSorted = bitLShift(1, 26), IsHovered = bitLShift(1, 27), NoDirectResize_ = bitLShift(1, 30), } ImGuiTableColumnFlags.WidthMask_ = bitOr(ImGuiTableColumnFlags.WidthStretch, ImGuiTableColumnFlags.WidthFixed) ImGuiTableColumnFlags.IndentMask_ = bitOr(ImGuiTableColumnFlags.IndentEnable, ImGuiTableColumnFlags.IndentDisable) ImGuiTableColumnFlags.StatusMask_ = bitOr(ImGuiTableColumnFlags.IsEnabled, ImGuiTableColumnFlags.IsVisible, ImGuiTableColumnFlags.IsSorted, ImGuiTableColumnFlags.IsHovered) --- @enum ImGuiTableRowFlags ImGuiTableRowFlags = { None = 0, Headers = bitLShift(1, 0) } --- @enum ImGuiTableBgTarget ImGuiTableBgTarget = { None = 0, RowBg0 = 1, RowBg1 = 2, CellBg = 3 } --- @enum ImGuiSortDirection ImGuiSortDirection = { None = 0, Ascending = 1, Descending = 2 } --- @class ImGuiPayload --- Drag and drop payload. `Data` is any Lua value (C++ stores raw bytes); `DataSize` kept for API parity. local IM_PAYLOAD = {} IM_PAYLOAD.__index = IM_PAYLOAD function IM_PAYLOAD:Clear() ImGuiPayload_Clear(self) end function IM_PAYLOAD:IsDataType(t) return ImGuiPayload_IsDataType(self, t) end function IM_PAYLOAD:IsPreview() return self.Preview end function IM_PAYLOAD:IsDelivery() return self.Delivery end function ImGuiPayload() return setmetatable({ Data = nil, DataSize = 0, SourceId = 0, SourceParentId = 0, DataFrameCount = -1, DataType = "", Preview = false, Delivery = false }, IM_PAYLOAD) end function ImGuiPayload_Clear(p) p.SourceId = 0; p.SourceParentId = 0; p.Data = nil; p.DataSize = 0; p.DataType = ""; p.DataFrameCount = -1; p.Preview = false; p.Delivery = false end function ImGuiPayload_IsDataType(p, t) return p.DataFrameCount ~= -1 and p.DataType == t end function ImGuiPayload_IsPreview(p) return p.Preview end function ImGuiPayload_IsDelivery(p) return p.Delivery end --- @class ImGuiTextBuffer # string builder: Buf is a list of string chunks local ImGuiTextBufferMT = {} ImGuiTextBufferMT.__index = ImGuiTextBufferMT function ImGuiTextBuffer() return setmetatable({ Buf = {} }, ImGuiTextBufferMT) end function ImGuiTextBufferMT:clear() self.Buf = {} end function ImGuiTextBufferMT:empty() return #self.Buf == 0 end function ImGuiTextBufferMT:append(str) self.Buf[#self.Buf + 1] = str end function ImGuiTextBufferMT:appendf(fmt, ...) self.Buf[#self.Buf + 1] = string.format(fmt, ...) end function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end function ImGuiTextBufferMT:size() return #self:c_str() 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) function ImGuiSettingsHandler() return { TypeName = nil, TypeHash = 0, ClearAllFn = nil, ReadInitFn = nil, ReadOpenFn = nil, ReadLineFn = nil, ApplyAllFn = nil, WriteAllFn = nil, CleanupFn = nil, UserData = nil } end return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imgui_impl_roblox.lua'] = function() --- ImGui Backend for Roblox --- - Renderer: exact software rasterizer (1:1 with imgui's triangles) into 256x256 EditableImage tiles at native --- screen resolution; only tiles whose content changed are redrawn/uploaded (see RenderDrawData). --- - Platform: UserInputService --- - Files: an in-memory file system (VFS), pre-filled with the fonts from imgui_impl_roblox_fonts.lua --- Requires "Allow Mesh / Image APIs" (EditableImage) in game settings. local UserInputService = game:GetService("UserInputService") local Players = game:GetService("Players") local AssetService = game:GetService("AssetService") local floor, ceil, min, max = math.floor, math.ceil, math.min, math.max local readu8, readu32, writeu32, readstring = buffer.readu8, buffer.readu32, buffer.writeu32, buffer.readstring local readf64 = buffer.readf64 local band, rshift = bit32.band, bit32.rshift local ImGui_ImplRoblox_GetBackendData local ImGui_ImplRoblox_UpdateTexture local ImGui_ImplRoblox_RenderDrawData local ImGui_ImplRoblox_Shutdown local KEY_MAP = {} -- Enum.KeyCode -> ImGuiKey do local names = { Return = "Enter", Escape = "Escape", Backspace = "Backspace", Tab = "Tab", Space = "Space", KeypadEnter = "KeypadEnter", Up = "UpArrow", Down = "DownArrow", Left = "LeftArrow", Right = "RightArrow", Home = "Home", End = "End", PageUp = "PageUp", PageDown = "PageDown", Insert = "Insert", Delete = "Delete", LeftControl = "LeftCtrl", RightControl = "RightCtrl", LeftShift = "LeftShift", RightShift = "RightShift", LeftAlt = "LeftAlt", RightAlt = "RightAlt", LeftSuper = "LeftSuper", RightSuper = "RightSuper", Quote = "Apostrophe", Comma = "Comma", Minus = "Minus", Period = "Period", Slash = "Slash", Semicolon = "Semicolon", Equals = "Equal", LeftBracket = "LeftBracket", BackSlash = "Backslash", RightBracket = "RightBracket", Backquote = "GraveAccent", CapsLock = "CapsLock", KeypadPeriod = "KeypadDecimal", KeypadDivide = "KeypadDivide", KeypadMultiply = "KeypadMultiply", KeypadMinus = "KeypadSubtract", KeypadPlus = "KeypadAdd", KeypadEquals = "KeypadEqual", } local digits = { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" } for i = 0, 9 do names[digits[i + 1]] = "K" .. i names["Keypad" .. digits[i + 1]] = "Keypad" .. i end for i = 1, 12 do names["F" .. i] = "F" .. i end for c in ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"):gmatch(".") do names[c] = c end for rbx_name, imgui_name in pairs(names) do KEY_MAP[Enum.KeyCode[rbx_name]] = ImGuiKey[imgui_name] end end -- Roblox has no "text input" event, so characters come from KeyCode.Value (ASCII for printable keys) + a US layout shift table. local SHIFTED = { ["1"] = "!", ["2"] = "@", ["3"] = "#", ["4"] = "$", ["5"] = "%", ["6"] = "^", ["7"] = "&", ["8"] = "*", ["9"] = "(", ["0"] = ")", ["-"] = "_", ["="] = "+", ["["] = "{", ["]"] = "}", ["\\"] = "|", [";"] = ":", ["'"] = "\"", [","] = "<", ["."] = ">", ["/"] = "?", ["`"] = "~", } local MOUSE_BUTTONS = { [Enum.UserInputType.MouseButton1] = 0, -- ImGuiMouseButton.Left [Enum.UserInputType.MouseButton2] = 1, -- ImGuiMouseButton.Right [Enum.UserInputType.MouseButton3] = 2, -- ImGuiMouseButton.Middle } --- @return boolean ctrl, boolean shift, boolean alt local function ImGui_ImplRoblox_UpdateKeyModifiers() local io = ImGui.GetIO() local K = Enum.KeyCode local ctrl = UserInputService:IsKeyDown(K.LeftControl) or UserInputService:IsKeyDown(K.RightControl) local shift = UserInputService:IsKeyDown(K.LeftShift) or UserInputService:IsKeyDown(K.RightShift) local alt = UserInputService:IsKeyDown(K.LeftAlt) or UserInputService:IsKeyDown(K.RightAlt) io:AddKeyEvent(ImGuiMod_Ctrl, ctrl) io:AddKeyEvent(ImGuiMod_Shift, shift) io:AddKeyEvent(ImGuiMod_Alt, alt) io:AddKeyEvent(ImGuiMod_Super, UserInputService:IsKeyDown(K.LeftSuper) or UserInputService:IsKeyDown(K.RightSuper)) return ctrl, shift, alt end --- @return table? function ImGui_ImplRoblox_GetBackendData() return ImGui.GetCurrentContext() and ImGui.GetIO().BackendPlatformUserData or nil end local function ImGui_ImplRoblox_UpdateMonitors(w, h) local platform_io = ImGui.GetPlatformIO() platform_io.Monitors:resize(0) local imgui_monitor = ImGuiPlatformMonitor() ImVec2_Copy(imgui_monitor.MainSize, ImVec2(w, h)) ImVec2_Copy(imgui_monitor.WorkSize, ImVec2(w, h)) platform_io.Monitors:push_back(imgui_monitor) end --------------------------------------------------------- -- PLATFORM DATA & CALLBACKS --------------------------------------------------------- -- Games can't touch the OS clipboard, so copy/paste only works inside ImGui local clipboard = "" local function ImGui_ImplRoblox_PlatformSetClipboardText(ctx, text) clipboard = text end local function ImGui_ImplRoblox_PlatformGetClipboardText(ctx) return clipboard end --------------------------------------------------------- -- FILE SYSTEM (in-memory, Roblox has no file access) --------------------------------------------------------- local VFS = {} -- path -> string of raw bytes --- Registers a file so ImGui can load it, e.g. ImGui_ImplRoblox.AddFile("fonts/MyFont.ttf", bytes) --- then io.Fonts:AddFontFromFileTTF("fonts/MyFont.ttf", 16) local function ImGui_ImplRoblox_AddFile(path, bytes) VFS[path] = bytes end for path, hex in pairs(IM_INCLUDE("imgui_impl_roblox_fonts.lua")) do VFS[path] = hex:gsub("%s", ""):gsub("%x%x", function(h) return string.char(tonumber(h, 16)) end) end function ImStd.ImFileOpen(filename, mode) local data = VFS[filename] return data and { Data = data, Pos = 0 } or nil end function ImStd.ImFileClose(f) end function ImStd.ImFileGetSize(f) return #f.Data end function ImStd.ImFileRead(f, data, count) local s, pos = f.Data, f.Pos count = min(count, #s - pos) for i = 1, count do data[i] = string.byte(s, pos + i) end f.Pos = pos + count return count end function ImStd.ImFileLoadToMemory(filename, mode) local f = ImStd.ImFileOpen(filename, mode) if not f or #f.Data == 0 then return end local file_data = {} local size = ImStd.ImFileRead(f, file_data, #f.Data) return file_data, size end --------------------------------------------------------- -- TEXTURE MANAGEMENT --------------------------------------------------------- -- Copies a region of ImTextureData pixels (1-based byte table) into our RGBA8 buffer local function CopyTexturePixels(tex, dst, x, y, w, h) local bpp, tex_w = tex.BytesPerPixel, tex.Width for row = 0, h - 1 do local src, src_base = tex:GetPixelsAt(x, y + row) local dst_off = ((y + row) * tex_w + x) * 4 if bpp == 4 then for i = 0, w - 1 do local s = src_base + i * 4 writeu32(dst, dst_off + i * 4, src[s] + src[s + 1] * 256 + src[s + 2] * 65536 + src[s + 3] * 16777216) end else -- Alpha8: white with alpha for i = 0, w - 1 do writeu32(dst, dst_off + i * 4, 16777215 + src[src_base + i] * 16777216) end end end end function ImGui_ImplRoblox_UpdateTexture(tex) local bd = ImGui_ImplRoblox_GetBackendData() if tex.Status == ImTextureStatus.WantCreate then local t = { Buffer = buffer.create(tex.Width * tex.Height * 4), Width = tex.Width, Height = tex.Height } CopyTexturePixels(tex, t.Buffer, 0, 0, tex.Width, tex.Height) bd.TextureCount = bd.TextureCount + 1 bd.Textures[bd.TextureCount] = t tex.BackendUserData = bd.TextureCount tex:SetTexID(bd.TextureCount) tex:SetStatus(ImTextureStatus.OK) elseif tex.Status == ImTextureStatus.WantUpdates then local t = bd.Textures[tex.BackendUserData] IM_ASSERT(t ~= nil) for _, r in tex.Updates:iter() do CopyTexturePixels(tex, t.Buffer, r.x, r.y, r.w, r.h) end tex:SetStatus(ImTextureStatus.OK) elseif tex.Status == ImTextureStatus.WantDestroy then if tex.BackendUserData then bd.Textures[tex.BackendUserData] = nil tex.BackendUserData = nil end tex:SetTexID(ImTextureID_Invalid) tex:SetStatus(ImTextureStatus.Destroyed) end end --------------------------------------------------------- -- RENDERING (software rasterizer into tile buffers) --------------------------------------------------------- -- Buffer layout: 4 bytes per pixel, R G B A, row-major, 0-based offsets. ImU32 colours are already R | G<<8 | B<<16 | A<<24. -- Blending is non-premultiplied "over" with a transparent (alpha 0) background, so the game stays visible behind ImGui. local buf, buf_w -- buffer/width of the tile being drawn local TILE_SIZE -- Vector2, set below -- Blends one pixel (r, g, b, a are 0..255). One u32 read/write, one division in the general case. -- FillSpan below inlines the same math with per-span constants - keep the two in sync. @native local function BlendPixel(o, r, g, b, a) if a >= 255 then writeu32(buf, o, floor(r + 0.5) + floor(g + 0.5) * 256 + floor(b + 0.5) * 65536 + 4278190080) return end if a <= 0 then return end local d = readu32(buf, o) local da = rshift(d, 24) if da == 0 then writeu32(buf, o, floor(r + 0.5) + floor(g + 0.5) * 256 + floor(b + 0.5) * 65536 + floor(a + 0.5) * 16777216) return end local sa = a / 255 local dr, dg, db = band(d, 255), band(rshift(d, 8), 255), band(rshift(d, 16), 255) if da == 255 then local ns = 1 - sa writeu32(buf, o, floor(r * sa + dr * ns + 0.5) + floor(g * sa + dg * ns + 0.5) * 256 + floor(b * sa + db * ns + 0.5) * 65536 + 4278190080) else local k = da * ((1 - sa) / 255) local oa = sa + k local inv = 1 / oa writeu32(buf, o, floor((r * sa + dr * k) * inv + 0.5) + floor((g * sa + dg * k) * inv + 0.5) * 256 + floor((b * sa + db * k) * inv + 0.5) * 65536 + floor(oa * 255 + 0.5) * 16777216) end end -- Fills pixels [x0, x1) of row y with one colour @native local function FillSpan(y, x0, x1, r, g, b, a) if a <= 0 then return end local o0 = (y * buf_w + x0) * 4 local o1 = o0 + (x1 - x0 - 1) * 4 if a >= 255 then local packed = floor(r + 0.5) + floor(g + 0.5) * 256 + floor(b + 0.5) * 65536 + 4278190080 for o = o0, o1, 4 do writeu32(buf, o, packed) end return end local packed0 = floor(r + 0.5) + floor(g + 0.5) * 256 + floor(b + 0.5) * 65536 + floor(a + 0.5) * 16777216 local sa = a / 255 local ns = 1 - sa local c1 = ns / 255 local rs, gs, bs = r * sa, g * sa, b * sa local last_d, last_v = -1, 0 -- UI backgrounds are mostly flat: reuse the previous result for the same destination for o = o0, o1, 4 do local d = readu32(buf, o) local da = rshift(d, 24) if d == last_d then writeu32(buf, o, last_v) elseif da == 0 then writeu32(buf, o, packed0) else last_d = d local dr, dg, db = band(d, 255), band(rshift(d, 8), 255), band(rshift(d, 16), 255) if da == 255 then last_v = floor(rs + dr * ns + 0.5) + floor(gs + dg * ns + 0.5) * 256 + floor(bs + db * ns + 0.5) * 65536 + 4278190080 else local k = da * c1 local oa = sa + k local inv = 1 / oa last_v = floor((rs + dr * k) * inv + 0.5) + floor((gs + dg * k) * inv + 0.5) * 256 + floor((bs + db * k) * inv + 0.5) * 65536 + floor(oa * 255 + 0.5) * 16777216 end writeu32(buf, o, last_v) end end end @native local function UnpackColor(col) return col % 256, floor(col / 256) % 256, floor(col / 65536) % 256, floor(col / 16777216) % 256 end -- Nearest texel at (u, v) as r, g, b, a (0..255) @native local function SampleTexture(t, u, v) local tw, th = t.Width, t.Height local tx, ty = floor(u * tw), floor(v * th) if tx < 0 then tx = 0 elseif tx >= tw then tx = tw - 1 end if ty < 0 then ty = 0 elseif ty >= th then ty = th - 1 end local o = (ty * tw + tx) * 4 local tb = t.Buffer return readu8(tb, o), readu8(tb, o + 1), readu8(tb, o + 2), readu8(tb, o + 3) end -- Axis aligned, single colour quad (rects, glyphs, images). Pixel centers inside [x0, x1) x [y0, y1) are drawn. @native local function DrawRect(x0, y0, x1, y1, u0, v0, u1, v1, col, t, cx0, cy0, cx1, cy1) local r, g, b, a = UnpackColor(col) if a == 0 then return end local px0, py0 = max(ceil(x0 - 0.5), cx0), max(ceil(y0 - 0.5), cy0) local px1, py1 = min(ceil(x1 - 0.5), cx1), min(ceil(y1 - 0.5), cy1) if px0 >= px1 or py0 >= py1 then return end if not t or (u0 == u1 and v0 == v1) then if t then local tr, tg, tb, ta = SampleTexture(t, u0, v0) r, g, b, a = r * tr / 255, g * tg / 255, b * tb / 255, a * ta / 255 end if a <= 0 then return end -- Rows of a flat rect usually blend over identical rows: when this row's destination equals the previous -- row's (exact string compare), the result is identical too, so memcpy the previous row's result. local len = (px1 - px0) * 4 local prev_dst, prev_o = nil, 0 for y = py0, py1 - 1 do local o = (y * buf_w + px0) * 4 if a >= 255 then if prev_dst then buffer.copy(buf, o, buf, prev_o, len) else FillSpan(y, px0, px1, r, g, b, a); prev_dst = true end else local dst = readstring(buf, o, len) if dst == prev_dst then buffer.copy(buf, o, buf, prev_o, len) else FillSpan(y, px0, px1, r, g, b, a) prev_dst = dst end end prev_o = o end return end local du, dv = (u1 - u0) / (x1 - x0), (v1 - v0) / (y1 - y0) local tw, th, tbuf = t.Width, t.Height, t.Buffer local r255, g255, b255, a255 = r / 255, g / 255, b / 255, a / 255 for y = py0, py1 - 1 do local ty = floor((v0 + (y + 0.5 - y0) * dv) * th) if ty < 0 then ty = 0 elseif ty >= th then ty = th - 1 end local trow = ty * tw local o = (y * buf_w + px0) * 4 for x = px0, px1 - 1 do local tx = floor((u0 + (x + 0.5 - x0) * du) * tw) if tx < 0 then tx = 0 elseif tx >= tw then tx = tw - 1 end local to = (trow + tx) * 4 local ta = readu8(tbuf, to + 3) if ta > 0 then BlendPixel(o, readu8(tbuf, to) * r255, readu8(tbuf, to + 1) * g255, readu8(tbuf, to + 2) * b255, ta * a255) end o = o + 4 end end end -- Generic triangle: per-vertex colour + uv, top-left fill rule, clipped to [cx0, cx1) x [cy0, cy1) @native local function DrawTriangle(vbuf, va, vb, vc, t, cx0, cy0, cx1, cy1, ox, oy) local x0, y0 = readf64(vbuf, va) - ox, readf64(vbuf, va + 8) - oy local x1, y1 = readf64(vbuf, vb) - ox, readf64(vbuf, vb + 8) - oy local x2, y2 = readf64(vbuf, vc) - ox, readf64(vbuf, vc + 8) - oy local area = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0) if area == 0 then return end if area < 0 then -- make the winding consistent so "inside" means all edge functions >= 0 vb, vc = vc, vb x1, y1, x2, y2 = x2, y2, x1, y1 area = -area end local minx, maxx = max(floor(min(x0, x1, x2)), cx0), min(ceil(max(x0, x1, x2)), cx1 - 1) local miny, maxy = max(floor(min(y0, y1, y2)), cy0), min(ceil(max(y0, y1, y2)), cy1 - 1) if minx > maxx or miny > maxy then return end -- Edge functions E(p) = A*px + B*py + C, w0 is opposite va, w1 opposite vb, w2 opposite vc local A0, B0 = y1 - y2, x2 - x1; local C0 = -(A0 * x1 + B0 * y1) local A1, B1 = y2 - y0, x0 - x2; local C1 = -(A1 * x2 + B1 * y2) local A2, B2 = y0 - y1, x1 - x0; local C2 = -(A2 * x0 + B2 * y0) local tl0 = A0 > 0 or (A0 == 0 and B0 > 0) local tl1 = A1 > 0 or (A1 == 0 and B1 > 0) local tl2 = A2 > 0 or (A2 == 0 and B2 > 0) local inv = 1 / area local ra, ga, ba, aa = UnpackColor(readu32(vbuf, va + 32)) local rb, gb, bb, ab = UnpackColor(readu32(vbuf, vb + 32)) local rc, gc, bc, ac = UnpackColor(readu32(vbuf, vc + 32)) local ua, vva, ub, vvb, uc, vvc = readf64(vbuf, va + 16), readf64(vbuf, va + 24), readf64(vbuf, vb + 16), readf64(vbuf, vb + 24), readf64(vbuf, vc + 16), readf64(vbuf, vc + 24) local textured = t and not (ua == ub and ua == uc and vva == vvb and vva == vvc) if t and not textured then -- constant uv (e.g. the atlas white pixel): fold the texel into the vertex colours local tr, tg, tb, ta = SampleTexture(t, ua, vva) ra, ga, ba, aa = ra * tr / 255, ga * tg / 255, ba * tb / 255, aa * ta / 255 rb, gb, bb, ab = rb * tr / 255, gb * tg / 255, bb * tb / 255, ab * ta / 255 rc, gc, bc, ac = rc * tr / 255, gc * tg / 255, bc * tb / 255, ac * ta / 255 end local flat = not textured and ra == rb and ra == rc and ga == gb and ga == gc and ba == bb and ba == bc and aa == ab and aa == ac if flat and aa <= 0 then return end for y = miny, maxy do local py = y + 0.5 -- Narrow the x range of this row using the edges (expanded by one pixel, exact test below) local xl, xr = minx, maxx local e0, e1, e2 = B0 * py + C0, B1 * py + C1, B2 * py + C2 if A0 ~= 0 then local xe = -e0 / A0 - 0.5; if A0 > 0 then xl = max(xl, floor(xe)) else xr = min(xr, ceil(xe)) end end if A1 ~= 0 then local xe = -e1 / A1 - 0.5; if A1 > 0 then xl = max(xl, floor(xe)) else xr = min(xr, ceil(xe)) end end if A2 ~= 0 then local xe = -e2 / A2 - 0.5; if A2 > 0 then xl = max(xl, floor(xe)) else xr = min(xr, ceil(xe)) end end local row = y * buf_w for x = xl, xr do local px = x + 0.5 local w0, w1, w2 = A0 * px + e0, A1 * px + e1, A2 * px + e2 if (w0 > 0 or (w0 == 0 and tl0)) and (w1 > 0 or (w1 == 0 and tl1)) and (w2 > 0 or (w2 == 0 and tl2)) then local o = (row + x) * 4 if flat then BlendPixel(o, ra, ga, ba, aa) else w0, w1, w2 = w0 * inv, w1 * inv, w2 * inv local r = w0 * ra + w1 * rb + w2 * rc local g = w0 * ga + w1 * gb + w2 * gc local b = w0 * ba + w1 * bb + w2 * bc local a = w0 * aa + w1 * ab + w2 * ac if textured then local tr, tg, tb, ta = SampleTexture(t, w0 * ua + w1 * ub + w2 * uc, w0 * vva + w1 * vvb + w2 * vvc) r, g, b, a = r * tr / 255, g * tg / 255, b * tb / 255, a * ta / 255 end BlendPixel(o, r, g, b, a) end end end end end -- Layers: every ImDrawList (one per top level window, popup, tooltip, plus the viewport bg/fg lists) gets its own -- Frame, stacked by draw order. A layer is covered by TILE x TILE EditableImages (one ImageLabel each) placed -- relative to the layer's origin (top-left of its content). Primitives are hashed into tiles in layer-relative -- coordinates, so moving a window only moves its Frame: no tile changes, nothing re-rasterized or uploaded. -- Only tiles whose hash changed are redrawn; the hash covers everything that affects a tile's pixels. local TILE = 128 TILE_SIZE = Vector2.new(TILE, TILE) local P1, P2 = 2147483647, 2147483629 -- two independent 31 bit hashes per tile (collision odds ~2^-62) local KEY_W = 64 -- tile key = ty * KEY_W + tx (layers up to 16384 px wide) local CLIP_PAD = 2048 -- content up to this far off screen is kept, so dragging a window past the edge doesn't redraw it local LAYER_KEEP_FRAMES = 120 -- unused layers are destroyed after this many rendered frames -- Primitive arrays (reused between frames, no per-frame allocation) local pr_a, pr_b, pr_c, pr_d, pr_t, pr_g = {}, {}, {}, {}, {}, {} -- vertices (pr_d == false -> triangle), texture, gradient kind local pr_cx0, pr_cy0, pr_cx1, pr_cy1 = {}, {}, {}, {} -- clip (screen pixels) local pr_bx0, pr_by0, pr_bx1, pr_by1 = {}, {}, {}, {} -- clipped bounds (screen pixels) local pr_tex = {} -- texture id local pr_vb = {} -- vertex buffer (draw list VtxBuffer.Buf) local pr_k = {} -- layer kind (1..3) local plist1, plist2, plist3 = {}, {}, {} -- primitive indices per layer kind @native local function HashVertex(h1, h2, vbuf, v, ox, oy) local x, y = readf64(vbuf, v) - ox, readf64(vbuf, v + 8) - oy local uv = readf64(vbuf, v + 16) * 8192 + readf64(vbuf, v + 24) local c = readu32(vbuf, v + 32) h1 = (h1 * 48271 + x * 4096 + y) % P1 h1 = (h1 * 48271 + uv * 4096) % P1 h1 = (h1 * 48271 + c) % P1 h2 = (h2 * 16807 + y * 4093 + x) % P2 h2 = (h2 * 16807 + uv * 65521) % P2 h2 = (h2 * 16807 + c) % P2 return h1, h2 end -- Axis aligned quad with a linear colour gradient and constant uv (ColorPicker hue/SV/alpha bars, AddRectFilledMultiColor). -- kind 1: colour varies along y (ca top, cb bottom), kind 2: along x (ca left, cb right). Same pixels as the two triangles. @native local function DrawRectGradient(x0, y0, x1, y1, ca, cb, kind, t, u, v, cx0, cy0, cx1, cy1) local px0, py0 = max(ceil(x0 - 0.5), cx0), max(ceil(y0 - 0.5), cy0) local px1, py1 = min(ceil(x1 - 0.5), cx1), min(ceil(y1 - 0.5), cy1) if px0 >= px1 or py0 >= py1 then return end local ra, ga, ba, aa = UnpackColor(ca) local rb, gb, bb, ab = UnpackColor(cb) if t then local tr, tg, tb, ta = SampleTexture(t, u, v) ra, ga, ba, aa = ra * tr / 255, ga * tg / 255, ba * tb / 255, aa * ta / 255 rb, gb, bb, ab = rb * tr / 255, gb * tg / 255, bb * tb / 255, ab * ta / 255 end if kind == 1 then local inv = 1 / (y1 - y0) for y = py0, py1 - 1 do local f = (y + 0.5 - y0) * inv local nf = 1 - f FillSpan(y, px0, px1, ra * nf + rb * f, ga * nf + gb * f, ba * nf + bb * f, aa * nf + ab * f) end else -- Every row gets the same colours: when a row's destination equals the previous row's, copy its result local inv = 1 / (x1 - x0) local len = (px1 - px0) * 4 local opaque = aa >= 255 and ab >= 255 local prev_dst, prev_o = nil, 0 for y = py0, py1 - 1 do local o = (y * buf_w + px0) * 4 local dst = (not opaque) and readstring(buf, o, len) or true if prev_dst ~= nil and dst == prev_dst then buffer.copy(buf, o, buf, prev_o, len) else local oo = o for x = px0, px1 - 1 do local f = (x + 0.5 - x0) * inv local nf = 1 - f BlendPixel(oo, ra * nf + rb * f, ga * nf + gb * f, ba * nf + bb * f, aa * nf + ab * f) oo = oo + 4 end prev_dst = dst end prev_o = o end end end -- Layer kinds per draw list: 1 = drawn before the window content (background, title bar, borders, scrollbar), -- 2 = window content (positioned at the scroll origin inside a ClipsDescendants frame, so scrolling just moves it), -- 3 = anything not clipped to the content drawn after content started (menu bar, overlays). Stacked 1 < 2 < 3. local function NewFrame(parent, clips) local frame = Instance.new("Frame") frame.Name = "Layer" frame.BackgroundTransparency = 1 frame.BorderSizePixel = 0 frame.Size = UDim2.fromOffset(0, 0) frame.ClipsDescendants = clips frame.Visible = false frame.Parent = parent return frame end local function GetLayer(bd, draw_list, kind) local set = bd.Layers[draw_list] if not set then set = { LastUsed = 0 }; bd.Layers[draw_list] = set end local layer = set[kind] if layer then return layer end local root, frame if kind == 2 then root = NewFrame(bd.Gui, true) frame = NewFrame(root, false); frame.Visible = true else frame = NewFrame(bd.Gui, false); root = frame end layer = { Root = root, Frame = frame, Tiles = {}, TH1 = {}, TH2 = {}, TN = {}, TL = {}, TX = {}, TY = {}, Touched = {}, NTouched = 0, Visible = false, X = false, Y = false, Z = -1, CX0 = false, CY0 = false, CX1 = false, CY1 = false } set[kind] = layer return layer end local function HideLayer(layer) if layer.Visible then layer.Visible = false; layer.Root.Visible = false end end local function GetTile(bd, layer, key, tx, ty) local tile = layer.Tiles[key] if tile then return tile end local img = AssetService:CreateEditableImage({ Size = Vector2.new(TILE, TILE) }) assert(img, "imgui_impl_roblox: EditableImage memory budget exceeded") local label = Instance.new("ImageLabel") label.Name = "Tile" .. key label.BackgroundTransparency = 1 label.BorderSizePixel = 0 local scale = bd.Scale label.Size = UDim2.fromOffset(TILE / scale, TILE / scale) label.Position = UDim2.fromOffset(tx * TILE / scale, ty * TILE / scale) label.ResampleMode = Enum.ResamplerMode.Pixelated label.ImageContent = Content.fromObject(img) label.Visible = false label.Active = bd.TilesActive label.Parent = layer.Frame tile = { Image = img, Label = label, Buffer = buffer.create(TILE * TILE * 4), H1 = -1, H2 = -1, Visible = false, BX0 = TILE, BY0 = TILE, BX1 = 0, BY1 = 0 } layer.Tiles[key] = tile return tile end local function DestroyLayerSet(set) for kind = 1, 3 do local layer = set[kind] if layer then for _, tile in pairs(layer.Tiles) do tile.Image:Destroy() end layer.Root:Destroy() end end end local function DestroyTiles(bd) for _, set in pairs(bd.Layers) do DestroyLayerSet(set) end bd.Layers = {} end -- Exact signature of everything in a draw list that affects its layers (nil = can't skip: user callbacks) local sig_buf = buffer.create(4096) @native local function DrawListSignature(draw_list, ox, oy) local idx, ni = draw_list.IdxBuffer.Data, draw_list.IdxBuffer.Size local ncmd = draw_list.CmdBuffer.Size local need = ni * 4 + ncmd * 64 + 64 if buffer.len(sig_buf) < need then sig_buf = buffer.create(need * 2) end local b, o = sig_buf, 0 for i = 1, ni do writeu32(b, o, idx[i]); o += 4 end for _, pcmd in draw_list.CmdBuffer:iter() do if pcmd.UserCallback ~= nil then return nil end local c = pcmd.ClipRect buffer.writef64(b, o, c.x); buffer.writef64(b, o + 8, c.y); buffer.writef64(b, o + 16, c.z); buffer.writef64(b, o + 24, c.w) writeu32(b, o + 32, pcmd.ElemCount); writeu32(b, o + 36, pcmd.IdxOffset); writeu32(b, o + 40, pcmd.VtxOffset) buffer.writef64(b, o + 44, pcmd:GetTexID()) o += 52 end buffer.writef64(b, o, ox); buffer.writef64(b, o + 8, oy) buffer.writef64(b, o + 16, draw_list._ContentClipX0 or -1); buffer.writef64(b, o + 24, draw_list._ContentClipY0 or -1) buffer.writef64(b, o + 32, draw_list._ContentClipX1 or -1); buffer.writef64(b, o + 40, draw_list._ContentClipY1 or -1) buffer.writef64(b, o + 48, draw_list._ContentClipX0 and draw_list._ScrollOriginX or -1) buffer.writef64(b, o + 56, draw_list._ContentClipX0 and draw_list._ScrollOriginY or -1) o += 64 return readstring(draw_list.VtxBuffer.Buf, 0, draw_list.VtxBuffer.Size * VTX_STRIDE) .. readstring(b, 0, o) end -- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true) local profilebegin, profileend = debug.profilebegin, debug.profileend local profiling = false local function PB(name) if profiling then profilebegin(name) end end local function PE() if profiling then profileend() end end @native local function DrawLayer(bd, layer, plist, np, lx0, ly0, ox, oy, force, z, clip_x0, clip_y0, clip_x1, clip_y1) local scale = bd.Scale -- Pass 2: hash primitives into layer-relative tiles PB("ImGui tile hash") local th1, th2, tn, tl, touched = layer.TH1, layer.TH2, layer.TN, layer.TL, layer.Touched for k = 1, layer.NTouched do tn[touched[k]] = 0 end local nt = 0 for pi = 1, np do local p = plist[pi] local tex_id = pr_tex[p] -- The clip rect only affects pixels inside the primitive's bounds, so hash the clipped bounds (relative) -- instead of the clip itself: a window clipped by the (fixed) viewport rect stays hash-stable when moved. local cx0, cy0, cx1, cy1 = pr_bx0[p] - lx0, pr_by0[p] - ly0, pr_bx1[p] - lx0, pr_by1[p] - ly0 local h1 = ((cx0 * 8191 + cy0) * 8191 + cx1) % P1 local h2 = ((cy1 * 8191 + cx1) * 8191 + cy0 + tex_id) % P2 local vax, vay = lx0 + ox, ly0 + oy local vbuf = pr_vb[p] h1, h2 = HashVertex(h1, h2, vbuf, pr_a[p], vax, vay) h1, h2 = HashVertex(h1, h2, vbuf, pr_b[p], vax, vay) h1, h2 = HashVertex(h1, h2, vbuf, pr_c[p], vax, vay) local vd = pr_d[p] if vd then h1, h2 = HashVertex(h1, h2, vbuf, vd, vax, vay) end for ty = floor((pr_by0[p] - ly0) / TILE), floor((pr_by1[p] - 1 - ly0) / TILE) do for tx = floor((pr_bx0[p] - lx0) / TILE), floor((pr_bx1[p] - 1 - lx0) / TILE) do local key = ty * KEY_W + tx local k = tn[key] if not k or k == 0 then k = 0 th1[key], th2[key] = 0, 0 if not tl[key] then tl[key] = {} end nt = nt + 1 touched[nt] = key layer.TX[key], layer.TY[key] = tx, ty end k = k + 1 tn[key] = k tl[key][k] = p th1[key] = (th1[key] * 48271 + h1) % P1 th2[key] = (th2[key] * 16807 + h2 + k) % P2 end end end layer.NTouched = nt PE() -- Place the layer (this is all a window move costs) local root = layer.Root if root ~= layer.Frame then -- content: clip frame at the content clip rect, tiles frame at the scroll origin relative to it if layer.CX0 ~= clip_x0 or layer.CY0 ~= clip_y0 or layer.CX1 ~= clip_x1 or layer.CY1 ~= clip_y1 then layer.CX0, layer.CY0, layer.CX1, layer.CY1 = clip_x0, clip_y0, clip_x1, clip_y1 root.Position = UDim2.fromOffset(clip_x0 / scale, clip_y0 / scale) root.Size = UDim2.fromOffset((clip_x1 - clip_x0) / scale, (clip_y1 - clip_y0) / scale) layer.X = false end if layer.X ~= lx0 or layer.Y ~= ly0 then layer.X, layer.Y = lx0, ly0 layer.Frame.Position = UDim2.fromOffset((lx0 - clip_x0) / scale, (ly0 - clip_y0) / scale) end elseif layer.X ~= lx0 or layer.Y ~= ly0 then layer.X, layer.Y = lx0, ly0 root.Position = UDim2.fromOffset(lx0 / scale, ly0 / scale) end if layer.Z ~= z then layer.Z = z; root.ZIndex = z end if not layer.Visible then layer.Visible = true; root.Visible = true end -- Pass 3: redraw + upload changed tiles, hide unused ones PB("ImGui raster+upload") for key, tile in pairs(layer.Tiles) do if not tn[key] or tn[key] == 0 then if tile.Visible then tile.Visible = false; tile.Label.Visible = false; tile.H1 = -1 end end end for kk = 1, nt do local key = touched[kk] local count = tn[key] local tx, ty = layer.TX[key], layer.TY[key] local tile = GetTile(bd, layer, key, tx, ty) if force or tile.H1 ~= th1[key] or tile.H2 ~= th2[key] then tile.H1, tile.H2 = th1[key], th2[key] local x0, y0 = lx0 + tx * TILE, ly0 + ty * TILE local x1, y1 = x0 + TILE, y0 + TILE buf, buf_w = tile.Buffer, TILE local list = tl[key] -- Dirty region = old content bounds + new content bounds. Outside it the tile is already -- transparent, so only this region is cleared and uploaded (edge tiles are often mostly empty). local nx0, ny0, nx1, ny1 = TILE, TILE, 0, 0 for k = 1, count do local p = list[k] local a, b = pr_bx0[p] - x0, pr_by0[p] - y0 local c, d = pr_bx1[p] - x0, pr_by1[p] - y0 if a < nx0 then nx0 = a end if b < ny0 then ny0 = b end if c > nx1 then nx1 = c end if d > ny1 then ny1 = d end end nx0, ny0, nx1, ny1 = max(nx0, 0), max(ny0, 0), min(nx1, TILE), min(ny1, TILE) local rx0, ry0, rx1, ry1 = min(nx0, tile.BX0), min(ny0, tile.BY0), max(nx1, tile.BX1), max(ny1, tile.BY1) tile.BX0, tile.BY0, tile.BX1, tile.BY1 = nx0, ny0, nx1, ny1 local rw = rx1 - rx0 if rw == TILE then buffer.fill(buf, ry0 * TILE * 4, 0, (ry1 - ry0) * TILE * 4) else for y = ry0, ry1 - 1 do buffer.fill(buf, (y * TILE + rx0) * 4, 0, rw * 4) end end local tox, toy = ox + x0, oy + y0 for k = 1, count do local p = list[k] local cx0, cy0 = max(pr_cx0[p], x0) - x0, max(pr_cy0[p], y0) - y0 local cx1, cy1 = min(pr_cx1[p], x1) - x0, min(pr_cy1[p], y1) - y0 local va, vc, vd, vbuf = pr_a[p], pr_c[p], pr_d[p], pr_vb[p] if vd then local ax, ay, cx, cy = readf64(vbuf, va) - tox, readf64(vbuf, va + 8) - toy, readf64(vbuf, vc) - tox, readf64(vbuf, vc + 8) - toy local gk = pr_g[p] if gk then DrawRectGradient(ax, ay, cx, cy, readu32(vbuf, va + 32), readu32(vbuf, vc + 32), gk, pr_t[p], readf64(vbuf, va + 16), readf64(vbuf, va + 24), cx0, cy0, cx1, cy1) else DrawRect(ax, ay, cx, cy, readf64(vbuf, va + 16), readf64(vbuf, va + 24), readf64(vbuf, vc + 16), readf64(vbuf, vc + 24), readu32(vbuf, va + 32), pr_t[p], cx0, cy0, cx1, cy1) end else DrawTriangle(vbuf, va, pr_b[p], vc, pr_t[p], cx0, cy0, cx1, cy1, tox, toy) end end PB("ImGui upload") if rw == TILE and ry0 == 0 and ry1 == TILE then tile.Image:WritePixelsBuffer(Vector2.zero, TILE_SIZE, buf) elseif rw > 0 and ry1 > ry0 then local rh = ry1 - ry0 local sub = buffer.create(rw * rh * 4) for y = 0, rh - 1 do buffer.copy(sub, y * rw * 4, buf, ((ry0 + y) * TILE + rx0) * 4, rw * 4) end tile.Image:WritePixelsBuffer(Vector2.new(rx0, ry0), Vector2.new(rw, rh), sub) end PE() end if not tile.Visible then tile.Visible = true tile.Label.Visible = true end end PE() end @native function ImGui_ImplRoblox_RenderDrawData(draw_data) local bd = ImGui_ImplRoblox_GetBackendData() PB("ImGui RenderDrawData") PB("ImGui textures") if draw_data.Textures ~= nil then for _, tex in draw_data.Textures:iter() do if tex.Status ~= ImTextureStatus.OK then ImGui_ImplRoblox_UpdateTexture(tex) bd.ForceRedraw = true -- texture contents changed: tiles sampling it must be redrawn end end end PE() -- Render rate cap: textures are always updated (imgui expects it), tiles only at bd.RenderRate Hz -- Optional lower cap while scrolling / resizing / moving a window (SetBusyRenderRate, off by default) local rate = bd.RenderRate if bd.BusyRenderRate > 0 then local g = ImGui.GetCurrentContext() local busy = g.WheelingWindow ~= nil or g.MovingWindow ~= nil -- (io.MouseWheel is already cleared by EndFrame) if not busy and g.ActiveId ~= 0 then local w = g.ActiveIdWindow local cur = g.MouseCursor -- ResizeAll..ResizeNWSE while a resize grip/border is held busy = (cur >= ImGuiMouseCursor.ResizeAll and cur <= ImGuiMouseCursor.ResizeNWSE) or (w ~= nil and (g.ActiveId == ImGui.GetWindowScrollbarID(w, ImGuiAxis.X) or g.ActiveId == ImGui.GetWindowScrollbarID(w, ImGuiAxis.Y))) end if busy and (rate <= 0 or bd.BusyRenderRate < rate) then rate = bd.BusyRenderRate end end if rate > 0 then local now = os.clock() if now + 0.002 < bd.NextRender then PE(); return end bd.NextRender = math.max(bd.NextRender + 1 / rate, now) end local sw, sh = floor(draw_data.DisplaySize.x), floor(draw_data.DisplaySize.y) if sw <= 0 or sh <= 0 then PE(); return end local ox, oy = draw_data.DisplayPos.x, draw_data.DisplayPos.y local lim_x0, lim_y0, lim_x1, lim_y1 = -CLIP_PAD, -CLIP_PAD, sw + CLIP_PAD, sh + CLIP_PAD bd.FrameNo += 1 local frame_no = bd.FrameNo local force = bd.ForceRedraw bd.ForceRedraw = false local n = 0 local z = 0 for _, draw_list in draw_data.CmdLists:iter() do -- Unchanged draw list (same vertex bytes, indices, commands, origin and scroll): its layers are already -- correct, only restack them. Static windows then cost one byte compare instead of collect + hash. PB("ImGui unchanged check") local sig = DrawListSignature(draw_list, ox, oy) local set = bd.Layers[draw_list] if sig and set and not force and set.Sig == sig then for kind = 1, 3 do local layer = set[kind] if layer and layer.Visible then z += 1 if layer.Z ~= z then layer.Z = z; layer.Root.ZIndex = z end end end set.LastUsed = frame_no PE() continue end PE() -- Pass 1: collect this list's primitives and their bounds PB("ImGui collect") local first = n + 1 local vbuf, idx = draw_list.VtxBuffer.Buf, draw_list.IdxBuffer.Data local ccx0, ccy0, ccx1, ccy1 = draw_list._ContentClipX0, draw_list._ContentClipY0, draw_list._ContentClipX1, draw_list._ContentClipY1 local content_x0, content_y0, content_x1, content_y1 if ccx0 then content_x0, content_y0 = max(floor(ccx0 - ox), lim_x0), max(floor(ccy0 - oy), lim_y0) content_x1, content_y1 = min(floor(ccx1 - ox), lim_x1), min(floor(ccy1 - oy), lim_y1) end local seen_content = false for _, pcmd in draw_list.CmdBuffer:iter() do if pcmd.UserCallback ~= nil then pcmd.UserCallback(draw_list, pcmd) elseif pcmd.ElemCount > 0 then local clip = pcmd.ClipRect local cx0, cy0 = max(floor(clip.x - ox), lim_x0), max(floor(clip.y - oy), lim_y0) local cx1, cy1 = min(floor(clip.z - ox), lim_x1), min(floor(clip.w - oy), lim_y1) local kind = 1 if ccx0 and clip.x >= ccx0 and clip.y >= ccy0 and clip.z <= ccx1 and clip.w <= ccy1 then kind = 2; seen_content = true if clip.x == ccx0 and clip.y == ccy0 and clip.z == ccx1 and clip.w == ccy1 then -- clipped by the layer's clip frame instead: partly visible rows stay hash-stable while scrolling cx0, cy0, cx1, cy1 = lim_x0, lim_y0, lim_x1, lim_y1 end elseif seen_content then kind = 3 end if cx1 > cx0 and cy1 > cy0 then local tex_id = pcmd:GetTexID() local t = bd.Textures[tex_id] local vo = pcmd.VtxOffset local i, last = pcmd.IdxOffset + 1, pcmd.IdxOffset + pcmd.ElemCount while i <= last do local ia, ic = idx[i], idx[i + 2] -- byte offsets of the vertices (index is 1-based) local va, vb, vc = (vo + ia - 1) * VTX_STRIDE, (vo + idx[i + 1] - 1) * VTX_STRIDE, (vo + ic - 1) * VTX_STRIDE local vd = false local gk = false local pax, pay = readf64(vbuf, va), readf64(vbuf, va + 8) local pbx, pby = readf64(vbuf, vb), readf64(vbuf, vb + 8) local pcx, pcy = readf64(vbuf, vc), readf64(vbuf, vc + 8) local bx0, by0, bx1, by1 if i + 5 <= last and idx[i + 3] == ia and idx[i + 4] == ic then local d = (vo + idx[i + 5] - 1) * VTX_STRIDE local pdx, pdy = readf64(vbuf, d), readf64(vbuf, d + 8) -- axis aligned quad (TL, TR, BR, BL) if pay == pby and pbx == pcx and pcy == pdy and pdx == pax and pax < pbx and pay < pdy then local col, colb, colc, cold = readu32(vbuf, va + 32), readu32(vbuf, vb + 32), readu32(vbuf, vc + 32), readu32(vbuf, d + 32) local tax, tay = readf64(vbuf, va + 16), readf64(vbuf, va + 24) local tbx, tby = readf64(vbuf, vb + 16), readf64(vbuf, vb + 24) local tcx, tcy = readf64(vbuf, vc + 16), readf64(vbuf, vc + 24) local tdx, tdy = readf64(vbuf, d + 16), readf64(vbuf, d + 24) if colb == col and colc == col and cold == col then if tbx == tcx and tby == tay and tdx == tax and tdy == tcy then vd = d end elseif tax == tbx and tax == tcx and tax == tdx and tay == tby and tay == tcy and tay == tdy then -- constant uv, linear gradient: vertical (top/bottom pairs equal) or horizontal (left/right pairs equal) if colb == col and cold == colc then vd = d; gk = 1 elseif cold == col and colb == colc then vd = d; gk = 2 end end if vd then bx0, by0 = ceil(pax - ox - 0.5), ceil(pay - oy - 0.5) bx1, by1 = ceil(pcx - ox - 0.5), ceil(pcy - oy - 0.5) end end end if vd then i = i + 6 else bx0, by0 = floor(min(pax, pbx, pcx) - ox), floor(min(pay, pby, pcy) - oy) bx1, by1 = ceil(max(pax, pbx, pcx) - ox) + 1, ceil(max(pay, pby, pcy) - oy) + 1 i = i + 3 end if bx0 < cx0 then bx0 = cx0 end if by0 < cy0 then by0 = cy0 end if bx1 > cx1 then bx1 = cx1 end if by1 > cy1 then by1 = cy1 end if bx0 < bx1 and by0 < by1 then n = n + 1 pr_a[n], pr_b[n], pr_c[n], pr_d[n], pr_t[n], pr_g[n], pr_tex[n], pr_vb[n] = va, vb, vc, vd, t, gk, tex_id, vbuf pr_cx0[n], pr_cy0[n], pr_cx1[n], pr_cy1[n] = cx0, cy0, cx1, cy1 pr_bx0[n], pr_by0[n], pr_bx1[n], pr_by1[n] = bx0, by0, bx1, by1 pr_k[n] = kind end end end end end PE() -- Split into layer kinds and place each one set = bd.Layers[draw_list] local nk1, nk2, nk3 = 0, 0, 0 local o1x, o1y, o3x, o3y = math.huge, math.huge, math.huge, math.huge for p = first, n do local k = pr_k[p] if k == 1 then nk1 += 1; plist1[nk1] = p if pr_bx0[p] < o1x then o1x = pr_bx0[p] end if pr_by0[p] < o1y then o1y = pr_by0[p] end elseif k == 2 then nk2 += 1; plist2[nk2] = p else nk3 += 1; plist3[nk3] = p if pr_bx0[p] < o3x then o3x = pr_bx0[p] end if pr_by0[p] < o3y then o3y = pr_by0[p] end end end if nk1 > 0 then z += 1 DrawLayer(bd, GetLayer(bd, draw_list, 1), plist1, nk1, o1x, o1y, ox, oy, force, z) elseif set and set[1] then HideLayer(set[1]) end if nk2 > 0 then z += 1 DrawLayer(bd, GetLayer(bd, draw_list, 2), plist2, nk2, floor(draw_list._ScrollOriginX - ox), floor(draw_list._ScrollOriginY - oy), ox, oy, force, z, content_x0, content_y0, content_x1, content_y1) elseif set and set[2] then HideLayer(set[2]) end if nk3 > 0 then z += 1 DrawLayer(bd, GetLayer(bd, draw_list, 3), plist3, nk3, o3x, o3y, ox, oy, force, z) elseif set and set[3] then HideLayer(set[3]) end set = bd.Layers[draw_list] if set then set.LastUsed = frame_no; set.Sig = sig end end -- Hide layers not drawn this frame; free long unused ones (closed windows, old tooltips) for draw_list, set in pairs(bd.Layers) do if set.LastUsed ~= frame_no then set.Sig = nil -- hidden now: must go through the full path when shown again for kind = 1, 3 do if set[kind] then HideLayer(set[kind]) end end if frame_no - set.LastUsed > LAYER_KEEP_FRAMES then DestroyLayerSet(set) bd.Layers[draw_list] = nil end end end -- drop references so old vertex tables can be collected for k = n + 1, bd.LastPrimCount do pr_t[k], pr_vb[k] = nil, nil end bd.LastPrimCount = n PE() end --------------------------------------------------------- -- CORE LIFECYCLE --------------------------------------------------------- --- @param parent Instance? # where the ScreenGui goes, defaults to the local player's PlayerGui --- @param render_scale number? # imgui pixels per Roblox UI point (defaults to 1). Roblox UI points are scaled by the --- # OS display scale, so on a 150% display pass 1.5 to render at physical resolution --- # (imgui then looks the same size as a desktop imgui app). Change later with SetRenderScale(). function ImGui_ImplRoblox_Init(parent, render_scale) local io = ImGui.GetIO() local gui = Instance.new("ScreenGui") gui.Name = "ImGui" gui.IgnoreGuiInset = true -- so GetMouseLocation() and the tiles share the same origin gui.ResetOnSpawn = false gui.DisplayOrder = 1000 gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling -- layers (one Frame per draw list) stack by ZIndex gui.Parent = parent or Players.LocalPlayer:WaitForChild("PlayerGui") local bd = { Time = os.clock(), Gui = gui, Connections = {}, Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1, Layers = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true, } io.BackendPlatformUserData = bd io.BackendFlags = bit32.bor(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset) local platform_io = ImGui.GetPlatformIO() platform_io.Platform_SetClipboardTextFn = ImGui_ImplRoblox_PlatformSetClipboardText platform_io.Platform_GetClipboardTextFn = ImGui_ImplRoblox_PlatformGetClipboardText local screen = gui.AbsoluteSize ImGui_ImplRoblox_UpdateMonitors(screen.X, screen.Y) local function connect(signal, fn) table.insert(bd.Connections, signal:Connect(fn)) end connect(UserInputService.InputBegan, function(input, game_processed) local io = ImGui.GetIO() local button = MOUSE_BUTTONS[input.UserInputType] if button then io:AddMouseSourceEvent(ImGuiMouseSource.Mouse) io:AddMouseButtonEvent(button, true) elseif input.UserInputType == Enum.UserInputType.Keyboard and not game_processed then local ctrl, shift, alt = ImGui_ImplRoblox_UpdateKeyModifiers() local key = KEY_MAP[input.KeyCode] if key then io:AddKeyEvent(key, true) end -- Text: printable ASCII keys, skipped while Ctrl/Alt are held (shortcuts) local v = input.KeyCode.Value if v >= 32 and v < 127 and not (ctrl or alt) then local c = string.char(v) if shift then c = SHIFTED[c] or c:upper() end io:AddInputCharacter(string.byte(c)) end end end) connect(UserInputService.InputEnded, function(input, game_processed) local io = ImGui.GetIO() local button = MOUSE_BUTTONS[input.UserInputType] if button then io:AddMouseButtonEvent(button, false) elseif input.UserInputType == Enum.UserInputType.Keyboard then ImGui_ImplRoblox_UpdateKeyModifiers() local key = KEY_MAP[input.KeyCode] if key then io:AddKeyEvent(key, false) end end end) connect(UserInputService.InputChanged, function(input, game_processed) if input.UserInputType == Enum.UserInputType.MouseWheel then ImGui.GetIO():AddMouseWheelEvent(0, input.Position.Z) end end) connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end) connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end) end function ImGui_ImplRoblox_Shutdown() local io = ImGui.GetIO() local bd = ImGui_ImplRoblox_GetBackendData() for _, c in ipairs(bd.Connections) do c:Disconnect() end DestroyTiles(bd) bd.Gui:Destroy() io.BackendPlatformUserData = nil io.BackendFlags = bit32.band(io.BackendFlags, bit32.bnot(bit32.bor( ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset ))) end function ImGui_ImplRoblox_NewFrame() PB("ImGui NewFrame (backend)") local io = ImGui.GetIO() local bd = ImGui_ImplRoblox_GetBackendData() local screen = bd.Gui.AbsoluteSize local w, h = floor(screen.X * bd.Scale), floor(screen.Y * bd.Scale) if w ~= bd.ScreenW or h ~= bd.ScreenH then bd.ScreenW, bd.ScreenH = w, h ImGui_ImplRoblox_UpdateMonitors(w, h) end ImVec2_CopyV(io.DisplaySize, w, h) local current_time = os.clock() io.DeltaTime = (current_time > bd.Time) and (current_time - bd.Time) or (1.0 / 60.0) bd.Time = current_time local m = UserInputService:GetMouseLocation() if m.X ~= bd.MouseX or m.Y ~= bd.MouseY then bd.MouseX, bd.MouseY = m.X, m.Y io:AddMouseSourceEvent(ImGuiMouseSource.Mouse) io:AddMousePosEvent(m.X * bd.Scale, m.Y * bd.Scale) end -- While the mouse is over imgui, make the tiles Active so Roblox stops passing clicks/wheel to the game (camera zoom etc.) local want = io.WantCaptureMouse if want ~= bd.TilesActive then bd.TilesActive = want for _, set in pairs(bd.Layers) do for kind = 1, 3 do local layer = set[kind]; if layer then for _, tile in pairs(layer.Tiles) do tile.Label.Active = want end end end end end PE() end --- Max tile redraws per second (default 60); 0 = every frame. imgui logic still runs every frame. function ImGui_ImplRoblox_SetRenderRate(hz) ImGui_ImplRoblox_GetBackendData().RenderRate = hz or 0 end --- Optional: max tile redraws per second while scrolling, resizing or moving a window (0 = off, the default) function ImGui_ImplRoblox_SetBusyRenderRate(hz) ImGui_ImplRoblox_GetBackendData().BusyRenderRate = hz or 0 end --- Toggle MicroProfiler labels (debug.profilebegin) for the backend function ImGui_ImplRoblox_SetProfiling(enabled) profiling = enabled and true or false end local function ImGui_ImplRoblox_IsProfiling() return profiling end function ImGui_ImplRoblox_SetRenderScale(scale) local bd = ImGui_ImplRoblox_GetBackendData() if scale == bd.Scale then return end bd.Scale = scale DestroyTiles(bd) bd.ForceRedraw = true end ImGui_ImplRoblox = { Init = ImGui_ImplRoblox_Init, Shutdown = ImGui_ImplRoblox_Shutdown, NewFrame = ImGui_ImplRoblox_NewFrame, RenderDrawData = ImGui_ImplRoblox_RenderDrawData, AddFile = ImGui_ImplRoblox_AddFile, SetRenderScale = ImGui_ImplRoblox_SetRenderScale, SetRenderRate = ImGui_ImplRoblox_SetRenderRate, SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate, SetProfiling = ImGui_ImplRoblox_SetProfiling, IsProfiling = ImGui_ImplRoblox_IsProfiling, } return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imgui_impl_roblox_fonts.lua'] = function() -- [Roblox] Embedded copies of fonts/*.ttf (Roblox can't read files). Generated: hex encoded bytes. -- Add your own fonts the same way, or at runtime with ImGui_ImplRoblox.AddFile(path, bytes). return { ["fonts/ProggyClean.ttf"] = [[ 00010000000c0080000300404f532f3288eb7490000001480000004e636d617002122375000003a0000001526376742000000000000004fc00000002676c796612af8956000007040000928068656164 d79166d3000000cc0000003668686561084201c30000010400000024686d74788a007e8000000198000002066c6f63618c73b0d800000500000002046d61787001ae00da00000128000000206e616d65 2559bb96000099840000019e706f7374a6ac83ef00009b24000005d27072657069020112000004f40000000800010000000100003c55e9d55f0f3cf50003080000000000b767778400000000bd92a6d7 0000fe80038005000000000300020000000000000001000004c0fe40000003800000000003800001000000000000000000000000000000020001000001010090002400000000000200080040000a0000 00760008000000000000038001900005000002bc028a0000008f02bc028a000001c50032020000000000040900000000000000000000000000000000000000000000416c74730040000020ac08000000 0000050001800000038000000380038003800380038003800380038003800380038003800380038003800380038003800380038003800380038003800380038003800380038003800380038003800380 0180010000000080000000800180010001000080008000800080010000800080008000800080008000800080008000800080018000800000008000800080000000800080008000800080008000800080 0100008000800080000000800080008000800080008000000080000000000080000000800100008001000080000001000080008000800080008000800080008001000080008001000000008000800080 0080008000800100008000800000008000800080008001800080000003800080038001000080010000800080008000800080008000800000038000800380038001800100010000800080008000000080 0000008000800000038000800000038001800080008000000000018000800100000000800080008003800000000000800080008000800180000000800100018000800080008000800080000000800080 0080008000800080008000000080008000800080008001000100010001000000008000800080008000800080008000800080008000800080000000800000008000800080008000800080000000800080 00800080008001000100010001000080008000800080008000800080008000800080008000800080008000800080000000000003000000000000001c000100000000004c000300010000001c00040030 00000008000800020000007f00ff20acffff00000000008120acffff00010001dfd500010000000000000000000001060000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000810000000000000000000000000000000000000000000000000000000000000000000000000000b100018db801ff8500000000 000000c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600c600f4011c019e02140288 02fc03140358039c03de041404320450046204a20516056605bc0612067406d60738077e07ec084e086c089608d00910094a09880a160a800b040b560bc80c2e0c820cea0d5e0da40dea0e500e960f28 0fb01012107410e0115211b61204126e12c4134c13ac13f6145814ae14ea1540158015a615b81612167e16c61734178e17e0185618ba18ee1936199619d41a481a9c1af01b5c1bc81c041c4c1c961cea 1d2a1d921dd21e401e8e1ee01f241f761fa61fa620102010202e208a20b220c821142174219821ee22622286230c230c238023802380239823b023d82400244a2468249024ae25062560258225f825f8 265826aa26aa26d82740279a280a286828a8290e292029b829f82a362a602a602b022b2a2b5e2bac2be62c202c342c9a2d282d5c2d782daa2de82e262ea62f262fb62ff4305e30c8313e31b4321e329e 331e338233ee345c34ce353a358635d43626367236e6377637d8383a38a63912397439ae3a2e3a9a3b063b7c3be83c3a3c963d223d863dec3e563ec63f2a3f9a4012406a40d0413641a242084240427a 42b842f0436243cc442a448a44ee455845b645e2465446b44714477a47da485448c6494000240000fe800380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f00530057005b005f00630067006b006f00730077007b007f00830087008b008f000011353315313533153135331531353315313533153135331531353315053533152135331505353315 2135331505353315213533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315 31353315313533153135331531353315313533153135331580808080808080fc8080028080fc8080028080fc8080028080fc8080028080fc8080028080fc8080028080fc8080028080fc8080028080fc 8080028080fc8080028080fc8080028080fc8080808080808080048080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080 80808080808080808080808080808080808080808080808080808080808080800007018000000200040000030007000b000f00130017001b000001353315073533150735331507353315073533150735 33150335331501808080808080808080808080808003808080808080808080808080808080808080ff0080800006010003000280048000030007000b000f001300170000013533153335331505353315 3335331505353315333533150100808080fe80808080fe8080808004008080808080808080808080808080000018000000000380040000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00430047004b004f00530057005b005f00000135331533353315053533153335331505353315313533153135331531353315313533153135331505353315333533150535331533353315 053533153135331531353315313533153135331531353315053533153335331505353315333533150180808080fe80808080fd80808080808080fd80808080fe80808080fd80808080808080fd808080 80fe808080800380808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000150080ff800300040000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530000013533150535331531353315313533153135331505353315333533150535331533353315053533153135 331531353315053533153335331505353315333533150535331531353315313533153135331505353315018080ff0080808080fd80808080fe80808080ff00808080ff00808080fe80808080fd808080 8080ff0080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000014000000000380040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b004f0000133533152135331505353315333533153335331505353315333533153335331505353315333533150735331533353315 05353315333533153335331505353315333533153335331505353315213533158080018080fd008080808080fd808080808080fe0080808080808080fe008080808080fd808080808080fd0080018080 038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000014008000000380040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047004b004f00000135331531353315053533152135331505353315213533150535331531353315213533150535331521353315333533150535331521353315 05353315213533150535331531353315313533153335331501008080fe8080010080fe0080010080fe808080010080fd00800100808080fd0080018080fd8080018080fe008080808080038080808080 80808080808080808080808080808080808080808080808080808080808080808080808080808080808080000003018003000200048000030007000b0000013533150735331507353315018080808080 800400808080808080808000000b0100ff000280048000030007000b000f00130017001b001f00230027002b0000013533150535331507353315053533150735331507353315073533150735331d0135 33150735331d01353315020080ff00808080ff00808080808080808080808080800400808080808080808080808080808080808080808080808080808080808080808000000b0100ff00028004800003 0007000b000f00130017001b001f00230027002b00000135331d013533150735331d01353315073533150735331507353315073533150535331507353315053533150100808080808080808080808080 80ff00808080ff00800400808080808080808080808080808080808080808080808080808080808080808000000b008000800300030000030007000b000f00130017001b001f00230027002b00000135 331505353315333533153335331505353315313533153135331505353315333533153335331505353315018080fe808080808080fe00808080fe008080808080fe808002808080808080808080808080 808080808080808080808080808080000009008000800300030000030007000b000f00130017001b001f0023000001353315073533150535331531353315313533153135331531353315053533150735 33150180808080fe808080808080fe808080800280808080808080808080808080808080808080808080800000040080ff000180010000030007000b000f000025353315073533150735331505353315 01008080808080ff008080808080808080808080808000000005008001800300020000030007000b000f0013000013353315313533153135331531353315313533158080808080800180808080808080 80808080000201000000018001000003000700002535331507353315010080808080808080808000000a0080ff800300048000030007000b000f00130017001b001f0023002700000135331507353315 05353315073533150535331507353315053533150735331505353315073533150280808080ff00808080ff00808080ff00808080ff008080800400808080808080808080808080808080808080808080 80808080808080800014008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00000135331531353315313533150535331521353315 0535331521353315053533153335331533353315053533153335331533353315053533152135331505353315213533150535331531353315313533150100808080fe0080018080fd8080018080fd8080 80808080fd808080808080fd8080018080fd8080018080fe0080808003808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000000 000e008000000300040000030007000b000f00130017001b001f00230027002b002f00330037000001353315053533153135331505353315333533150735331507353315073533150735331505353315 31353315313533153135331531353315018080ff008080fe808080808080808080808080fe80808080808003808080808080808080808080808080808080808080808080808080808080808080808080 000f008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b00000135331531353315313533150535331521353315073533150535331505353315053533150535 331507353315313533153135331531353315313533150100808080fe00800180808080ff0080ff0080ff0080ff0080808080808080038080808080808080808080808080808080808080808080808080 808080808080808080808080000f008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b00000135331531353315313533150535331521353315073533150535 33153135331d013533150735331505353315213533150535331531353315313533150100808080fe00800180808080fe808080808080fd8080018080fe00808080038080808080808080808080808080 8080808080808080808080808080808080808080808080800011008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043000001353315053533153135 33150535331533353315053533152135331505353315213533150535331531353315313533153135331531353315313533150535331507353315028080ff008080fe80808080fe0080010080fd808001 8080fd80808080808080ff008080800380808080808080808080808080808080808080808080808080808080808080808080808080808080808000000012008000000300040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f004300470000133533153135331531353315313533153135331505353315073533150735331531353315313533153135331d0135331507353315 0535331521353315053533153135331531353315808080808080fd808080808080808080808080fd8080018080fe00808080038080808080808080808080808080808080808080808080808080808080 808080808080808080808080808080000011008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000013533153135331505353315053533150735 331531353315313533153135331505353315213533150535331521353315053533152135331505353315313533153135331501808080fe8080ff00808080808080fe0080018080fd8080018080fd8080 018080fe008080800380808080808080808080808080808080808080808080808080808080808080808080808080808080808000000c008000000300040000030007000b000f00130017001b001f0023 0027002b002f00001335331531353315313533153135331531353315073533150535331507353315053533150735331505353315073533158080808080808080ff00808080ff00808080ff0080808003 80808080808080808080808080808080808080808080808080808080808080800013008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b 0000013533153135331531353315053533152135331505353315213533150535331531353315313533150535331521353315053533152135331505353315213533150535331531353315313533150100 808080fe0080018080fd8080018080fe00808080fe0080018080fd8080018080fd8080018080fe0080808003808080808080808080808080808080808080808080808080808080808080808080808080 8080808080808080808000000011008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043000001353315313533153135331505353315213533150535 331521353315053533152135331505353315313533153135331531353315073533150535331505353315313533150100808080fe0080018080fd8080018080fd8080018080fe00808080808080ff0080 fe80808003808080808080808080808080808080808080808080808080808080808080808080808080808080808080000004018000000200030000030007000b000f0000013533150735331503353315 0735331501808080808080808002808080808080fe8080808080800000060080ff000180030000030007000b000f00130017000001353315073533150335331507353315073533150535331501008080 80808080808080ff008002808080808080fe8080808080808080808080800000000a000000800300030000030007000b000f00130017001b001f00230027000001353315313533150535331531353315 053533153135331d013533153135331d013533153135331502008080fe008080fe0080808080808002808080808080808080808080808080808080808080808080800000000c00800100038002800003 0007000b000f00130017001b001f00230027002b002f000013353315313533153135331531353315313533153135331501353315313533153135331531353315313533153135331580808080808080fd 008080808080800200808080808080808080808080ff0080808080808080808080808000000a008000800380030000030007000b000f00130017001b001f002300270000133533153135331d01353315 3135331d01353315313533150535331531353315053533153135331580808080808080fe008080fe0080800280808080808080808080808080808080808080808080808080000000000a008000000300 040000030007000b000f00130017001b001f002300270000013533153135331531353315053533152135331507353315053533150535331507353315033533150100808080fe00800180808080ff0080 ff00808080808003808080808080808080808080808080808080808080808080ff008080001a000000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f00530057005b005f006300670000013533153135331531353315053533152135331505353315213533153135331533353315053533153335331533353315333533150535331533353315 3335331533353315053533152135331531353315313533150535331d013533153135331531353315313533150100808080fe0080018080fd0080010080808080fc8080808080808080fc808080808080 8080fc80800100808080fd808080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000 0012008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331531353315053533153135331505353315213533150535331521353315 0535331531353315313533153135331505353315213533150535331521353315053533152135331501808080ff008080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd00 800200800380808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000018008000000380040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047004b004f00530057005b005f0000133533153135331531353315313533150535331521353315053533152135331505353315313533153135331531353315 3135331505353315213533150535331521353315053533152135331505353315313533153135331531353315313533158080808080fe0080018080fd8080018080fd808080808080fd8080020080fd00 80020080fd0080020080fd0080808080800380808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000e0080 00000380040000030007000b000f00130017001b001f00230027002b002f00330037000001353315313533153135331505353315213533150535331507353315073533150735331d0135331521353315 0535331531353315313533150180808080fe0080018080fd008080808080808080018080fe00808080038080808080808080808080808080808080808080808080808080808080808080808080800000 0014008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f000013353315313533153135331531353315053533152135331505353315 213533150535331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533158080808080fe0080018080fd8080020080fd0080020080fd00800200 80fd0080020080fd0080018080fd808080808003808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080001300800000030004000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000133533153135331531353315313533153135331505353315073533150735331531353315313533153135 33150535331507353315073533150735331531353315313533153135331531353315808080808080fd808080808080808080fe0080808080808080808080800380808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080800000000f008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b0000133533153135 331531353315313533153135331505353315073533150735331531353315313533153135331505353315073533150735331507353315808080808080fd808080808080808080fe008080808080808003 808080808080808080808080808080808080808080808080808080808080808080808080808000000012008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b 003f004300470000013533153135331531353315053533152135331505353315073533150735331521353315313533153135331505353315213533150535331521353315053533153135331531353315 0180808080fe0080018080fd0080808080800100808080fd0080020080fd8080018080fe0080808003808080808080808080808080808080808080808080808080808080808080808080808080808080 80808080800000000014008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00001335331521353315053533152135331505353315 2135331505353315313533153135331531353315313533153135331505353315213533150535331521353315053533152135331505353315213533158080020080fd0080020080fd0080020080fd0080 8080808080fd0080020080fd0080020080fd0080020080fd0080020080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000 000c010000000280040000030007000b000f00130017001b001f00230027002b002f00000135331531353315313533150535331507353315073533150735331507353315073533150535331531353315 313533150100808080ff008080808080808080808080ff00808080038080808080808080808080808080808080808080808080808080808080808080000c008000000280040000030007000b000f0013 0017001b001f00230027002b002f000001353315313533153135331507353315073533150735331507353315073533150735331505353315313533153135331501008080808080808080808080808080 80fe00808080038080808080808080808080808080808080808080808080808080808080808080000011008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b 003f0043000013353315213533150535331521353315053533152135331505353315333533150535331531353315313533150535331521353315053533152135331505353315213533158080020080fd 0080018080fd8080010080fe00808080fe80808080fe8080010080fe0080018080fd80800200800380808080808080808080808080808080808080808080808080808080808080808080808080808080 80800000000c008000000300040000030007000b000f00130017001b001f00230027002b002f000013353315073533150735331507353315073533150735331507353315073533153135331531353315 31353315313533158080808080808080808080808080808080808080038080808080808080808080808080808080808080808080808080808080808080000000001a000000000380040000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f0063006700001135331531353315213533153135331505353315313533152135331531353315 053533153335331533353315333533150535331533353315333533153335331505353315213533152135331505353315213533152135331505353315213533150535331521353315808001808080fc80 808001808080fc8080808080808080fc8080808080808080fc8080010080010080fc8080010080010080fc8080028080fc80800280800380808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080808080000018008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f00530057005b005f000013353315313533152135331505353315313533152135331505353315333533152135331505353315333533152135331505353315213533153335331505353315 2135331533353315053533152135331531353315053533152135331531353315808080018080fd008080018080fd00808080010080fd00808080010080fd00800100808080fd00800100808080fd0080 01808080fd008001808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080001000800000038004000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f0000013533153135331505353315213533150535331521353315053533152135331505353315213533150535331521353315 0535331521353315053533153135331501808080fe8080010080fd8080020080fd0080020080fd0080020080fd0080020080fd8080010080fe8080800380808080808080808080808080808080808080 8080808080808080808080808080808080808080800000000011008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043000013353315313533153135 331531353315053533152135331505353315213533150535331521353315053533153135331531353315313533150535331507353315073533158080808080fe0080018080fd8080018080fd80800180 80fd8080808080fe0080808080800380808080808080808080808080808080808080808080808080808080808080808080808080808080808000000000120080ff800380040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047000001353315313533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315 213533150535331531353315333533150735331501808080fe8080010080fd8080020080fd0080020080fd0080020080fd0080020080fd8080010080fe80808080808080038080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080808000000014008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f0000133533153135331531353315313533150535331521353315053533152135331505353315213533150535331531353315313533153135331505353315213533150535331521353315 05353315213533158080808080fe0080018080fd8080018080fd8080018080fd8080808080fe0080010080fe0080018080fd808002008003808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080800012008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331531353315 313533153135331505353315213533150535331d013533153135331d013533153135331d01353315053533152135331505353315313533153135331531353315010080808080fd8080020080fd008080 80808080fd0080020080fd8080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000000000e000000000380040000030007000b 000f00130017001b001f00230027002b002f0033003700001135331531353315313533153135331531353315313533153135331505353315073533150735331507353315073533150735331507353315 80808080808080fe008080808080808080808080808003808080808080808080808080808080808080808080808080808080808080808080808080000012008000000380040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047000013353315213533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315 21353315053533153135331531353315313533158080020080fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd808080808003808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080000e000000000380040000030007000b000f00130017001b001f00230027002b002f0033003700001135331521353315 05353315213533150535331521353315053533152135331505353315333533150535331533353315053533150735331580028080fc8080028080fd0080018080fd8080018080fe00808080fe80808080 ff008080800380808080808080808080808080808080808080808080808080808080808080808080808000000018000000000380040000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00430047004b004f00530057005b005f00001135331521353315053533152135331521353315053533152135331521353315053533153335331533353315333533150535331533353315 3335331533353315053533153135331533353315313533150535331521353315053533152135331580028080fc8080010080010080fc8080010080010080fc8080808080808080fc8080808080808080 fd008080808080fd8080018080fd808001808003808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000100080 00000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f000013353315213533150535331521353315053533152135331505353315313533150535331531353315 0535331521353315053533152135331505353315213533158080020080fd0080020080fd8080010080fe808080ff008080fe8080010080fd8080020080fd008002008003808080808080808080808080 80808080808080808080808080808080808080808080808080808080000c000000000380040000030007000b000f00130017001b001f00230027002b002f000011353315213533150535331521353315 053533152135331505353315333533150535331507353315073533150735331580028080fc8080028080fd0080018080fe00808080ff0080808080808080038080808080808080808080808080808080 808080808080808080808080808080000012008000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047000013353315313533153135331531353315 3135331531353315073533150535331505353315053533150535331505353315073533153135331531353315313533153135331531353315808080808080808080ff0080ff0080ff0080ff0080ff0080 80808080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000f0100ff000280048000030007000b000f00130017001b001f0023 0027002b002f00330037003b00000135331531353315313533150535331507353315073533150735331507353315073533150735331507353315073533150735331531353315313533150100808080fe 80808080808080808080808080808080808080808080040080808080808080808080808080808080808080808080808080808080808080808080808080808080000a0080ff800300048000030007000b 000f00130017001b001f002300270000133533150735331d013533150735331d013533150735331d013533150735331d0135331507353315808080808080808080808080808080800400808080808080 808080808080808080808080808080808080808080808000000f0100ff000280048000030007000b000f00130017001b001f00230027002b002f00330037003b00000135331531353315313533150735 331507353315073533150735331507353315073533150735331507353315073533150535331531353315313533150100808080808080808080808080808080808080808080fe80808080040080808080 808080808080808080808080808080808080808080808080808080808080808080808080000a008001800300048000030007000b000f00130017001b001f002300270000013533150735331505353315 333533150535331533353315053533152135331505353315213533150180808080ff00808080fe80808080fe0080018080fd808001808004008080808080808080808080808080808080808080808080 8080000000070000ff800380000000030007000b000f00130017001b00001535331531353315313533153135331531353315313533153135331580808080808080808080808080808080808080808080 000201000380020004800003000700000135331d013533150100808004008080808080000010008000000300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f0000 01353315313533153135331d01353315053533153135331531353315313533150535331521353315053533152135331505353315313533153135331531353315010080808080fe0080808080fd808001 8080fd8080018080fe00808080800280808080808080808080808080808080808080808080808080808080808080808080808080800000000013008000000300048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f00430047004b0000133533150735331507353315073533153135331531353315313533150535331521353315053533152135331505353315213533150535 331521353315053533153135331531353315313533158080808080808080808080fe0080018080fd8080018080fd8080018080fd8080018080fd80808080800400808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808000000c008000000300030000030007000b000f00130017001b001f00230027002b002f0000013533153135331531353315 0535331521353315053533150735331507353315213533150535331531353315313533150100808080fe0080018080fd808080808080018080fe00808080028080808080808080808080808080808080 808080808080808080808080800000000013008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b00000135331507353315073533150535 331531353315313533153135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331502808080808080fe0080808080fd80800180 80fd8080018080fd8080018080fd8080018080fe008080808004008080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000000100080 00000300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f000001353315313533153135331505353315213533150535331531353315313533153135331531353315 0535331507353315213533150535331531353315313533150100808080fe0080018080fd808080808080fd80808080018080fe0080808002808080808080808080808080808080808080808080808080 80808080808080808080808080800000000e008000000300048000030007000b000f00130017001b001f00230027002b002f003300370000013533153135331531353315053533150735331505353315 31353315313533153135331505353315073533150735331507353315073533150180808080fe00808080ff0080808080fe80808080808080808080040080808080808080808080808080808080808080 808080808080808080808080808080808000000000150080fe800300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530000013533153135 3315313533153135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331507353315073533150535331531353315313533150100 80808080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808080808080fe0080808002808080808080808080808080808080808080808080808080808080808080808080808080 808080808080808080808080808080000011008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000133533150735331507353315073533153135 33153135331531353315053533152135331505353315213533150535331521353315053533152135331505353315213533158080808080808080808080fe0080018080fd8080018080fd8080018080fd 8080018080fd80800180800400808080808080808080808080808080808080808080808080808080808080808080808080808080808080000008010000000200048000030007000b000f00130017001b 001f00000135331501353315313533150735331507353315073533150735331507353315018080ff0080808080808080808080808004008080fe80808080808080808080808080808080808080800000 000c0080ff000280048000030007000b000f00130017001b001f00230027002b002f00000135331501353315313533150735331507353315073533150735331507353315073533150535331531353315 31353315020080ff008080808080808080808080808080fe0080808004008080fe808080808080808080808080808080808080808080808080808080808080000010008000000300048000030007000b 000f00130017001b001f00230027002b002f00330037003b003f000013353315073533150735331507353315213533150535331521353315053533153335331505353315313533153135331505353315 2135331505353315213533158080808080808080018080fd8080010080fe00808080fe80808080fe8080010080fe00800180800400808080808080808080808080808080808080808080808080808080 80808080808080808080808080000000000a010000000200048000030007000b000f00130017001b001f0023002700000135331531353315073533150735331507353315073533150735331507353315 0735331507353315010080808080808080808080808080808080808004008080808080808080808080808080808080808080808080808080808000000014000000000380030000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b004f0000113533153135331531353315333533153135331505353315213533152135331505353315213533152135331505353315 2135331521353315053533152135331521353315053533152135331521353315808080808080fd0080010080010080fc8080010080010080fc8080010080010080fc8080010080010080fc8080010080 01008002808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000e008000000300030000030007000b000f00130017001b001f0023 0027002b002f00330037000013353315313533153135331531353315053533152135331505353315213533150535331521353315053533152135331505353315213533158080808080fe0080018080fd 8080018080fd8080018080fd8080018080fd808001808002808080808080808080808080808080808080808080808080808080808080808080800000000e008000000300030000030007000b000f0013 0017001b001f00230027002b002f003300370000013533153135331531353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331501008080 80fe0080018080fd8080018080fd8080018080fd8080018080fe00808080028080808080808080808080808080808080808080808080808080808080808080808000000000130080fe80030003000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000133533153135331531353315313533150535331521353315053533152135331505353315213533150535 331521353315053533153135331531353315313533150535331507353315073533158080808080fe0080018080fd8080018080fd8080018080fd8080018080fd8080808080fe00808080808002808080 808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000130080fe800300030000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00430047004b0000013533153135331531353315313533150535331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533150735 33150735331507353315010080808080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808080808080808002808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080000a008000000300030000030007000b000f00130017001b001f00230027000013353315333533153135331505353315313533152135331505353315 0735331507353315073533158080808080fe008080010080fd8080808080808080028080808080808080808080808080808080808080808080808080000d008000000300030000030007000b000f0013 0017001b001f00230027002b002f00330000013533153135331531353315313533150535331d013533153135331d0135331d0135331505353315313533153135331531353315010080808080fd808080 808080fd80808080800280808080808080808080808080808080808080808080808080808080808080800000000d010000000300040000030007000b000f00130017001b001f00230027002b002f0033 00000135331507353315073533153135331531353315313533150535331507353315073533150735331d01353315313533153135331501008080808080808080fe008080808080808080808003808080 8080808080808080808080808080808080808080808080808080808080808000000e008000000300030000030007000b000f00130017001b001f00230027002b002f0033003700001335331521353315 0535331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533158080018080fd8080018080fd8080018080fd8080018080fd8080018080fe0080 80808002808080808080808080808080808080808080808080808080808080808080808080800000000a008000000300030000030007000b000f00130017001b001f0023002700001335331521353315 05353315213533150535331533353315053533153335331505353315073533158080018080fd8080018080fe00808080fe80808080ff0080808002808080808080808080808080808080808080808080 80808080800000000012000000000380030000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000113533152135331505353315213533152135331505353315 21353315213533150535331533353315333533153335331505353315313533153335331531353315053533152135331580028080fc8080010080010080fc8080010080010080fc8080808080808080fd 008080808080fd80800180800280808080808080808080808080808080808080808080808080808080808080808080808080808080808000000a008000000300030000030007000b000f00130017001b 001f002300270000133533152135331505353315333533150535331507353315053533153335331505353315213533158080018080fe00808080ff00808080ff00808080fe0080018080028080808080 80808080808080808080808080808080808080808000000000130080fe800300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000133533152135 331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331507353315073533150535331531353315313533158080018080fd80800180 80fd8080018080fd8080018080fd8080018080fe008080808080808080fe0080808002808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080 80800000000e008000000300030000030007000b000f00130017001b001f00230027002b002f003300370000133533153135331531353315313533153135331507353315053533150535331505353315 05353315313533153135331531353315313533158080808080808080ff0080ff0080ff0080ff008080808080028080808080808080808080808080808080808080808080808080808080808080808000 000e0080ff000300048000030007000b000f00130017001b001f00230027002b002f003300370000013533153135331505353315073533150735331507353315053533153135331d0135331507353315 073533150735331d013533153135331502008080fe8080808080808080fe8080808080808080808080800400808080808080808080808080808080808080808080808080808080808080808080808080 80800000000b0180ff000200048000030007000b000f00130017001b001f00230027002b0000013533150735331507353315073533150735331507353315073533150735331507353315073533150735 331501808080808080808080808080808080808080808080800400808080808080808080808080808080808080808080808080808080808080808000000e0080ff000300048000030007000b000f0013 0017001b001f00230027002b002f003300370000133533153135331d0135331507353315073533150735331d013533153135331505353315073533150735331507353315053533153135331580808080 8080808080808080fe8080808080808080fe808080040080808080808080808080808080808080808080808080808080808080808080808080808080800000000008000001800380028000030007000b 000f00130017001b001f0000133533153135331531353315213533150535331521353315313533153135331580808080010080fc80800100808080020080808080808080808080808080808080800000 0013008000000380038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000013533153135331531353315053533152135331505353315313533153135 331531353315053533150535331531353315313533153135331505353315213533150535331531353315313533150180808080fe0080018080fd0080808080fe8080ff0080808080fe8080018080fe00 8080800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000000040100ff000200010000030007000b000f00002535331507353315 073533150535331501808080808080ff0080808080808080808080808080000000100080ff000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f000001353315 31353315053533150735331505353315313533153135331531353315053533150735331507353315073533150735331507353315053533153135331502008080fe80808080ff0080808080fe80808080 8080808080808080fe808080040080808080808080808080808080808080808080808080808080808080808080808080808080808080808000060100ff800280010000030007000b000f001300170000 2535331533353315053533153335331505353315333533150100808080fe80808080fe8080808080808080808080808080808080808000000003008000000300008000030007000b0000333533153335 3315333533158080808080808080808080800000000d008000000300048000030007000b000f00130017001b001f00230027002b002f0033000001353315073533150535331531353315313533153135 3315313533150535331507353315073533150735331507353315073533150180808080fe808080808080fe80808080808080808080808004008080808080808080808080808080808080808080808080 8080808080808080808080000011008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043000001353315073533150535331531353315313533153135 331531353315053533150535331531353315313533153135331531353315053533150735331507353315073533150180808080fe808080808080fe8080fe808080808080fe8080808080808080040080 80808080808080808080808080808080808080808080808080808080808080808080808080808080800000000005008003000300048000030007000b000f001300000135331505353315333533150535 331521353315018080ff00808080fe008001808004008080808080808080808080800000000e008000000380040000030007000b000f00130017001b001f00230027002b002f00330037000001353315 05353315213533150535331533353315073533150535331507353315333533153335331505353315213533153335331505353315020080fe0080010080fe008080808080ff0080808080808080fd0080 0100808080fd0080038080808080808080808080808080808080808080808080808080808080808080808080800000000015008000000380050000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00430047004b004f005300000135331533353315053533150535331531353315313533153135331505353315213533150535331d013533153135331d013533153135331d0135 33150535331521353315053533153135331531353315313533150100808080ff0080ff0080808080fd8080020080fd00808080808080fd0080020080fd80808080800480808080808080808080808080 808080808080808080808080808080808080808080808080808080808080808080808080808080000005008000800200030000030007000b000f0013000001353315053533150535331d0135331d0135 3315018080ff0080ff00808080028080808080808080808080808080800000000018000000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b 004f00530057005b005f00001335331531353315333533153135331531353315053533152135331505353315213533150535331521353315313533153135331505353315213533150535331521353315 0535331521353315053533153135331533353315313533153135331580808080808080fc8080010080fe0080010080fe00800100808080fd0080010080fe0080010080fe0080010080fe808080808080 8003808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000015008000000380050000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b004f0053000001353315333533150535331505353315313533153135331531353315313533153135331507353315053533150535 33150535331505353315053533150735331531353315313533153135331531353315313533150100808080ff0080fe808080808080808080ff0080ff0080ff0080ff0080ff0080808080808080800480 808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000003018003000280048000030007000b0000013533150735331d0135 33150180808080800400808080808080808000000003010003000200048000030007000b00000135331507353315053533150180808080ff008004008080808080808080000601000300030004800003 0007000b000f0013001700000135331533353315053533153335331505353315333533150100808080fe80808080ff008080800400808080808080808080808080808000000600800300028004800003 0007000b000f0013001700000135331533353315053533153335331505353315333533150100808080fe80808080fe008080800400808080808080808080808080808000000d00800080030003000003 0007000b000f00130017001b001f00230027002b002f00330000013533150535331531353315313533150535331531353315313533153135331531353315053533153135331531353315053533150180 80ff00808080fe008080808080fe00808080ff008002808080808080808080808080808080808080808080808080808080808080800000000005008001800300020000030007000b000f001300001335 3315313533153135331531353315313533158080808080800180808080808080808080800007000001800380020000030007000b000f00130017001b0000113533153135331531353315313533153135 3315313533153135331580808080808080018080808080808080808080808080800000000004008003000280040000030007000b000f0000013533153335331505353315333533150100808080fe0080 808003808080808080808080800000000010000002000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001135331531353315313533153335331531353315 313533150535331521353315313533153135331505353315213533153335331505353315213533153335331580808080808080fd00800100808080fd00800100808080fd008001008080800380808080 80808080808080808080808080808080808080808080808080808080808080800010008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f000001353315 3335331505353315013533153135331531353315313533150535331d013533153135331d0135331d01353315053533153135331531353315313533150100808080ff0080ff0080808080fd8080808080 80fd8080808080040080808080808080ff00808080808080808080808080808080808080808080808080808080808080800000000005008000800200030000030007000b000f001300001335331d0135 331d01353315053533150535331580808080ff0080ff0080028080808080808080808080808080800015000000000380030000030007000b000f00130017001b001f00230027002b002f00330037003b 003f00430047004b004f00530000133533153135331533353315313533150535331521353315213533150535331521353315313533153135331531353315053533152135331505353315213533152135 331505353315313533153335331531353315808080808080fd0080010080010080fc8080010080808080fc8080010080fe0080010080010080fd00808080808002808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080800000000011008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 000001353315333533150535331501353315313533153135331531353315313533150735331505353315053533150535331505353315313533153135331531353315313533150100808080ff0080fe80 80808080808080ff0080ff0080ff0080ff008080808080040080808080808080ff0080808080808080808080808080808080808080808080808080808080808080808000000d00000000038004800003 0007000b000f00130017001b001f00230027002b002f00330000013533153335331501353315213533150535331521353315053533152135331505353315333533150535331507353315073533150100 808080fd8080028080fc8080028080fd0080018080fe00808080ff008080808080040080808080ff00808080808080808080808080808080808080808080808080808080800000000007018000000200 040000030007000b000f00130017001b00000135331503353315073533150735331507353315073533150735331501808080808080808080808080808003808080ff0080808080808080808080808080 8080808000120080ff800300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047000001353315053533153135331531353315053533153335331533353315 0535331533353315053533153335331505353315333533153335331505353315313533153135331505353315018080ff00808080fe008080808080fd80808080fe80808080fe808080808080fe008080 80ff00800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000010008000000300040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f000001353315313533150535331507353315053533153135331531353315313533150535331507353315053533150735331531353315313533153135331531353315 01808080fe80808080ff0080808080fe80808080ff0080808080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808000000014000000000380 038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0000113533152135331505353315313533153135331531353315313533150535331521353315 053533152135331505353315213533150535331531353315313533153135331531353315053533152135331580028080fd008080808080fd8080018080fd8080018080fd8080018080fd808080808080 fd008002808003008080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000010000000000380040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000113533152135331505353315213533150535331521353315053533153335331505353315053533153135331531353315313533153135331505353315 0735331580028080fc8080028080fd0080018080fe00808080ff0080fe808080808080fe8080808003808080808080808080808080808080808080808080808080808080808080808080808080808080 80000000000a0180ff000200048000030007000b000f00130017001b001f0023002700000135331507353315073533150735331507353315033533150735331507353315073533150735331501808080 808080808080808080808080808080808004008080808080808080808080808080ff0080808080808080808080808080800000000012008000000300048000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047000001353315313533153135331505353315213533150535331d01353315313533150535331533353315053533153135331d013533150535331521353315 0535331531353315313533150100808080fe0080018080fd80808080ff00808080ff00808080fd8080018080fe0080808004008080808080808080808080808080808080808080808080808080808080 80808080808080808080808080808000000201000400028004800003000700000135331533353315010080808004008080808000001c000000000380040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047004b004f00530057005b005f00630067006b006f000013353315313533153135331531353315313533150535331521353315053533152135331531353315 333533150535331533353315213533150535331533353315213533150535331521353315313533153335331505353315213533150535331531353315313533153135331531353315808080808080fd00 80028080fc8080010080808080fc80808080018080fc80808080018080fc8080010080808080fc8080028080fd0080808080800380808080808080808080808080808080808080808080808080808080 808080808080808080808080808080808080808080808080808080808080808080808080000b008001800280040000030007000b000f00130017001b001f00230027002b0000013533153135331d0135 331505353315313533153135331505353315213533150535331531353315313533150100808080fe80808080fe0080010080fe8080808003808080808080808080808080808080808080808080808080 80808000000a008000800300030000030007000b000f00130017001b001f0023002700000135331533353315053533153335331505353315333533150535331533353315053533153335331501808080 80fe00808080fe00808080ff00808080ff008080800280808080808080808080808080808080808080808080808080000007008000000280020000030007000b000f00130017001b0000133533153135 33153135331531353315073533150735331507353315808080808080808080808001808080808080808080808080808080808080001e000000000380040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047004b004f00530057005b005f00630067006b006f007300770000133533153135331531353315313533153135331505353315213533150535331533353315 3135331521353315053533153335331533353315333533150535331533353315313533152135331505353315333533153335331533353315053533152135331505353315313533153135331531353315 31353315808080808080fd0080028080fc8080808080010080fc8080808080808080fc8080808080010080fc8080808080808080fc8080028080fd008080808080038080808080808080808080808080 80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000007000004800380050000030007000b000f00130017001b 00001135331531353315313533153135331531353315313533153135331580808080808080048080808080808080808080808080800000000008008002800280048000030007000b000f00130017001b 001f0000013533153135331505353315213533150535331521353315053533153135331501008080fe8080010080fe0080010080fe808080040080808080808080808080808080808080808080000000 000e008000000300038000030007000b000f00130017001b001f00230027002b002f00330037000001353315073533150535331531353315313533153135331531353315053533150735331501353315 313533153135331531353315313533150180808080fe808080808080fe80808080fe808080808080030080808080808080808080808080808080808080808080ff0080808080808080808080000a0080 02000280048000030007000b000f00130017001b001f00230027000013353315313533153135331d013533150535331505353315053533153135331531353315313533158080808080ff0080ff0080ff 0080808080040080808080808080808080808080808080808080808080808000000a008002000280048000030007000b000f00130017001b001f00230027000013353315313533153135331d01353315 053533153135331d013533150535331531353315313533158080808080fe80808080fe008080800400808080808080808080808080808080808080808080808080000000000201800380028004800003 000700000135331505353315020080ff00800400808080808000000000110000ff000380030000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000133533152135 33150535331521353315053533152135331505353315213533150535331531353315213533150535331533353315313533153335331505353315053533158080018080fd8080018080fd8080018080fd 8080018080fd808080010080fd80808080808080fd0080ff008002808080808080808080808080808080808080808080808080808080808080808080808080808080808080000000001a0080ff800380 040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f006300670000013533153135331531353315313533153135331505353315 3135331531353315333533150535331531353315313533153335331505353315313533153335331505353315333533150535331533353315053533153335331505353315333533150535331533353315 01008080808080fd008080808080fd808080808080fe0080808080fe80808080fe80808080fe80808080fe80808080fe8080808003808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080808000000009010001000280028000030007000b000f00130017001b001f002300000135331531353315313533150535 331531353315313533150535331531353315313533150100808080fe80808080fe80808080020080808080808080808080808080808080808080800000040180fe800280000000030007000b000f0000 05353315313533150735331505353315018080808080ff008080808080808080808080800008008002000200048000030007000b000f00130017001b001f000001353315053533153135331507353315 07353315053533153135331531353315010080ff00808080808080ff00808080040080808080808080808080808080808080808080800000000a008002000280048000030007000b000f00130017001b 001f0023002700000135331531353315053533152135331505353315213533150535331521353315053533153135331501008080fe8080010080fe0080010080fe0080010080fe808080040080808080 8080808080808080808080808080808080808080000a008000800300030000030007000b000f00130017001b001f00230027000013353315333533150535331533353315053533153335331505353315 33353315053533153335331580808080ff00808080ff00808080fe00808080fe00808080028080808080808080808080808080808080808080808080808000000016008000000380050000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057000001353315053533152135331505353315213533150535331521353315053533153335331507353315 053533152135331505353315333533153135331505353315333533153135331531353315313533150535331521353315028080fd8080018080fd8080010080fe0080010080fe008080808080ff008001 0080fe0080808080fd80808080808080fd008001808004808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000000 0016008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f005300570000013533150535331521353315053533152135331505353315 21353315053533153335331507353315313533153135331505353315213533150535331521353315053533152135331505353315213533153135331531353315028080fd8080018080fd8080010080fe 0080010080fe0080808080808080fe0080018080fd8080010080fd8080010080fe0080010080808004808080808080808080808080808080808080808080808080808080808080808080808080808080 80808080808080808080808080808000001a000000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f006300670000 0135331505353315313533152135331505353315333533150535331531353315333533150535331531353315053533153135331533353315053533152135331505353315333533153135331505353315 333533153135331531353315313533150535331521353315028080fd008080018080fe00808080fe0080808080fe808080fe0080808080ff0080010080fe0080808080fd80808080808080fd00800180 80048080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000a008000000300040000030007000b 000f00130017001b001f0023002700000135331503353315073533150535331505353315073533152135331505353315313533153135331501808080808080ff0080ff00808080018080fe0080808003 808080ff0080808080808080808080808080808080808080808080800012008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331d 013533150135331531353315053533152135331505353315213533150535331531353315313533153135331505353315213533150535331521353315053533152135331501808080ff008080fe808001 0080fe0080010080fe0080808080fd8080020080fd0080020080fd008002008004808080808080ff00808080808080808080808080808080808080808080808080808080808080808080808080808000 0012008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331505353315033533153135331505353315213533150535331521353315 05353315313533153135331531353315053533152135331505353315213533150535331521353315020080ff0080808080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd 008002008004808080808080ff0080808080808080808080808080808080808080808080808080808080808080808080808080800014008000000380050000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00430047004b004f00000135331531353315053533152135331501353315313533150535331521353315053533152135331505353315313533153135331531353315 05353315213533150535331521353315053533152135331501808080fe8080010080fe808080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd0080020080048080808080 8080808080ff0080808080808080808080808080808080808080808080808080808080808080808080808080800000000014008000000380050000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00430047004b004f0000013533153335331505353315333533150135331531353315053533152135331505353315213533150535331531353315313533153135331505353315 21353315053533152135331505353315213533150180808080fe00808080ff008080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd008002008004808080808080808080 80ff0080808080808080808080808080808080808080808080808080808080808080808080808080800000000012008000000380048000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f0043004700000135331521353315013533153135331505353315213533150535331521353315053533153135331531353315313533150535331521353315053533152135331505353315 21353315010080010080fe808080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd0080020080040080808080ff0080808080808080808080808080808080808080808080 808080808080808080808080808080800016008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0053005700000135331531353315 0535331521353315053533152135331505353315313533150535331521353315053533152135331505353315313533153135331531353315053533152135331505353315213533150535331521353315 01808080fe8080010080fe0080010080fe808080fe8080010080fe0080010080fe0080808080fd8080020080fd0080020080fd0080020080048080808080808080808080808080808080808080808080 80808080808080808080808080808080808080808080808080808080808080000017000000000380040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b 004f00530057005b000001353315313533153135331531353315053533153335331505353315333533150535331521353315313533150535331531353315313533153135331505353315213533150535 33152135331505353315213533153135331531353315018080808080fd80808080fe80808080fe008001008080fd8080808080fd8080018080fd8080018080fd80800180808080038080808080808080 80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000000110080fe800380040000030007000b000f00130017001b001f00230027002b 002f00330037003b003f0043000001353315313533153135331505353315213533150535331507353315073533150735331d013533152135331505353315313533153135331505353315073533150535 33150180808080fe0080018080fd008080808080808080018080fe00808080ff00808080ff00800380808080808080808080808080808080808080808080808080808080808080808080808080808080 80808080800000000014008000000300050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00000135331d01353315013533153135331531353315 31353315313533150535331507353315073533153135331531353315313533150535331507353315073533153135331531353315313533153135331501008080fe808080808080fd8080808080808080 80fe0080808080808080808004808080808080ff00808080808080808080808080808080808080808080808080808080808080808080808080808080808080000014008000000300050000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00000135331505353315013533153135331531353315313533153135331505353315073533150735331531353315 313533153135331505353315073533150735331531353315313533153135331531353315020080ff0080fe808080808080fd808080808080808080fe0080808080808080808004808080808080ff0080 80808080808080808080808080808080808080808080808080808080808080808080808080808080800000000015008000000300050000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00430047004b004f005300000135331505353315333533150135331531353315313533153135331531353315053533150735331507353315313533153135331531353315053533150735 33150735331531353315313533153135331531353315018080ff00808080fe008080808080fd808080808080808080fe00808080808080808080048080808080808080ff008080808080808080808080 80808080808080808080808080808080808080808080808080808080808080000014008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b 004f000001353315333533150135331531353315313533153135331531353315053533150735331507353315313533153135331531353315053533150735331507353315313533153135331531353315 313533150100808080fe008080808080fd808080808080808080fe00808080808080808080040080808080ff008080808080808080808080808080808080808080808080808080808080808080808080 8080808080808000000d010000000280050000030007000b000f00130017001b001f00230027002b002f003300000135331d013533150135331531353315313533150535331507353315073533150735 33150735331505353315313533153135331501808080fe80808080ff00808080808080808080ff0080808004808080808080ff0080808080808080808080808080808080808080808080808080808080 000d010000000280050000030007000b000f00130017001b001f00230027002b002f00330000013533150535331501353315313533153135331505353315073533150735331507353315073533150535 33153135331531353315020080ff0080ff00808080ff00808080808080808080ff0080808004808080808080ff00808080808080808080808080808080808080808080808080808080800000000e0100 00000280050000030007000b000f00130017001b001f00230027002b002f0033003700000135331505353315333533150135331531353315313533150535331507353315073533150735331507353315 053533153135331531353315018080ff00808080fe80808080ff00808080808080808080ff00808080048080808080808080ff0080808080808080808080808080808080808080808080808080808080 000d010000000280048000030007000b000f00130017001b001f00230027002b002f00330000013533153335331501353315313533153135331505353315073533150735331507353315073533150535 331531353315313533150100808080fe80808080ff00808080808080808080ff00808080040080808080ff00808080808080808080808080808080808080808080808080808080800015000000000380 038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0053000013353315313533153135331531353315053533152135331505353315213533150535 33153135331531353315313533152135331505353315213533150535331521353315053533153135331531353315313533158080808080fe0080018080fd8080020080fc8080808080010080fd008002 0080fd0080018080fd808080808003008080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800019008000000380050000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f0063000001353315333533150535331533353315013533153135331521353315053533153335 3315213533150535331533353315213533150535331521353315333533150535331521353315333533150535331521353315313533150535331521353315313533150180808080fe00808080fe008080 018080fd00808080010080fd00808080010080fd00800100808080fd00800100808080fd008001808080fd0080018080800480808080808080808080ff00808080808080808080808080808080808080 80808080808080808080808080808080808080808080808080808080808000000010008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331d 01353315013533153135331505353315213533150535331521353315053533152135331505353315213533150535331521353315053533153135331501808080ff008080fe8080010080fd8080020080 fd0080020080fd0080020080fd8080010080fe80808004808080808080ff0080808080808080808080808080808080808080808080808080808080808080808080000000001000800000038005000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f0000013533150535331503353315313533150535331521353315053533152135331505353315213533150535331521353315 05353315213533150535331531353315020080ff0080808080fe8080010080fd8080020080fd0080020080fd0080020080fd8080010080fe80808004808080808080ff00808080808080808080808080 8080808080808080808080808080808080808080808000000012008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331531353315 0535331521353315013533153135331505353315213533150535331521353315053533152135331505353315213533150535331521353315053533153135331501808080fe8080010080fe808080fe80 80010080fd8080020080fd0080020080fd0080020080fd8080010080fe8080800480808080808080808080ff008080808080808080808080808080808080808080808080808080808080808080808000 0012008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331533353315053533153335331501353315313533150535331521353315 053533152135331505353315213533150535331521353315053533152135331505353315313533150180808080fe00808080ff008080fe8080010080fd8080020080fd0080020080fd0080020080fd80 80010080fe8080800480808080808080808080ff0080808080808080808080808080808080808080808080808080808080808080808080000010008000000380048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000013533152135331501353315313533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315 31353315010080010080fe808080fe8080010080fd8080020080fd0080020080fd0080020080fd8080010080fe808080040080808080ff00808080808080808080808080808080808080808080808080 8080808080808080808000000009008000800300030000030007000b000f00130017001b001f002300001335331521353315053533153335331505353315053533153335331505353315213533158080 018080fe00808080ff0080ff00808080fe008001808002808080808080808080808080808080808080808080808000000016008000000380040000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00430047004b004f0053005700000135331531353315333533150535331521353315053533152135331533353315053533152135331533353315053533153335331521353315 0535331533353315213533150535331521353315053533153335331531353315018080808080fd8080010080fd80800100808080fd00800100808080fd00808080010080fd00808080010080fd808001 0080fd808080808003808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000012008000000380050000030007000b 000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331d0135331501353315213533150535331521353315053533152135331505353315213533150535331521353315 05353315213533150535331531353315313533153135331501808080fe0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd808080808004808080808080ff0080 808080808080808080808080808080808080808080808080808080808080808080808080800000000012008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b 003f004300470000013533150535331501353315213533150535331521353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315 020080ff0080fe8080020080fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd808080808004808080808080ff008080808080808080808080808080808080808080808080 808080808080808080808080808080000014008000000380050000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0000013533153135331505353315 213533150135331521353315053533152135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331501808080fe8080010080fd80 80020080fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd80808080800480808080808080808080ff00808080808080808080808080808080808080808080808080808080 8080808080808080808080000012008000000380048000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331521353315013533152135331505353315 21353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315010080010080fd8080020080fd0080020080fd0080020080fd008002 0080fd0080020080fd0080020080fd8080808080040080808080ff0080808080808080808080808080808080808080808080808080808080808080808080808080800000000d00000000038005000003 0007000b000f00130017001b001f00230027002b002f00330000013533150535331501353315213533150535331521353315053533152135331505353315333533150535331507353315073533150200 80ff0080fe0080028080fc8080028080fd0080018080fe00808080ff00808080808004808080808080ff0080808080808080808080808080808080808080808080808080808080000010008000000300 040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001335331507353315073533153135331531353315313533150535331521353315053533152135331505353315 3135331531353315313533150535331507353315808080808080808080fe0080018080fd8080018080fd8080808080fe0080808003808080808080808080808080808080808080808080808080808080 8080808080808080808080808000000000190000ff800380048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f006300000135 3315313533153135331505353315213533150535331521353315053533153135331531353315313533150535331521353315053533152135331505353315213533150535331521353315053533153135 3315313533153135331531353315053533150100808080fe0080018080fd8080018080fd8080808080fe0080018080fd8080020080fd0080020080fd0080020080fd008080808080fd00800400808080 80808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800012008000000300048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043004700000135331d0135331501353315313533153135331d013533150535331531353315313533153135331505353315213533150535331521353315 0535331531353315313533153135331501808080fe8080808080fe0080808080fd8080018080fd8080018080fe008080808004008080808080ff00808080808080808080808080808080808080808080 808080808080808080808080808080800012008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047000001353315053533150135331531353315 3135331d01353315053533153135331531353315313533150535331521353315053533152135331505353315313533153135331531353315020080ff0080ff0080808080fe0080808080fd8080018080 fd8080018080fe008080808004008080808080ff008080808080808080808080808080808080808080808080808080808080808080808080808000000013008000000300048000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b000001353315053533153335331501353315313533153135331d0135331505353315313533153135331531353315053533152135 3315053533152135331505353315313533153135331531353315018080ff00808080fe8080808080fe0080808080fd8080018080fd8080018080fe0080808080040080808080808080ff008080808080 80808080808080808080808080808080808080808080808080808080808080800014008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b 004f00000135331533353315053533153335331501353315313533153135331d013533150535331531353315313533153135331505353315213533150535331521353315053533153135331531353315 313533150180808080fe00808080fe8080808080fe0080808080fd8080018080fd8080018080fe00808080800400808080808080808080ff008080808080808080808080808080808080808080808080 808080808080808080808080808000000012008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047000001353315333533150135331531353315 3135331d013533150535331531353315313533153135331505353315213533150535331521353315053533153135331531353315313533150100808080fe8080808080fe0080808080fd8080018080fd 8080018080fe0080808080038080808080ff00808080808080808080808080808080808080808080808080808080808080808080808080800014008000000300050000030007000b000f00130017001b 001f00230027002b002f00330037003b003f00430047004b004f00000135331505353315333533150535331501353315313533153135331d013533150535331531353315313533153135331505353315 21353315053533152135331505353315313533153135331531353315018080ff00808080ff0080ff0080808080fe0080808080fd8080018080fd8080018080fe00808080800480808080808080808080 80ff00808080808080808080808080808080808080808080808080808080808080808080808080800016000000000380030000030007000b000f00130017001b001f00230027002b002f00330037003b 003f00430047004b004f00530057000013353315313533153335331531353315053533152135331505353315313533153135331531353315313533153135331505353315213533150535331521353315 213533150535331531353315313533153135331531353315808080808080fe8080010080fd00808080808080fc8080010080fe0080010080010080fd0080808080800280808080808080808080808080 80808080808080808080808080808080808080808080808080808080808080808080808080000000000f0080fe800300030000030007000b000f00130017001b001f00230027002b002f00330037003b 00000135331531353315313533150535331521353315053533150735331507353315213533150535331531353315313533150535331507353315053533150100808080fe0080018080fd808080808080 018080fe00808080ff00808080ff0080028080808080808080808080808080808080808080808080808080808080808080808080808080800012008000000300048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043004700000135331d01353315013533153135331531353315053533152135331505353315313533153135331531353315313533150535331507353315 2135331505353315313533153135331501008080ff00808080fe0080018080fd808080808080fd80808080018080fe0080808004008080808080ff008080808080808080808080808080808080808080 80808080808080808080808080808080800000000012008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000013533150535331503353315 313533153135331505353315213533150535331531353315313533153135331531353315053533150735331521353315053533153135331531353315018080ff008080808080fe0080018080fd808080 808080fd80808080018080fe0080808004008080808080ff008080808080808080808080808080808080808080808080808080808080808080808080808000000013008000000300048000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b000001353315053533153335331501353315313533153135331505353315213533150535331531353315313533153135 331531353315053533150735331521353315053533153135331531353315018080ff00808080fe80808080fe0080018080fd808080808080fd80808080018080fe00808080040080808080808080ff00 808080808080808080808080808080808080808080808080808080808080808080808080800000000012008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b 003f004300470000013533153335331501353315313533153135331505353315213533150535331531353315313533153135331531353315053533150735331521353315053533153135331531353315 0100808080fe80808080fe0080018080fd808080808080fd80808080018080fe00808080038080808080ff00808080808080808080808080808080808080808080808080808080808080808080808080 800000000009010000000200048000030007000b000f00130017001b001f002300000135331d013533150135331531353315073533150735331507353315073533150735331501008080ff0080808080 808080808080808004008080808080ff00808080808080808080808080808080808080800009010000000200048000030007000b000f00130017001b001f002300000135331505353315033533153135 33150735331507353315073533150735331507353315018080ff00808080808080808080808080808004008080808080ff0080808080808080808080808080808080808080000000000a010000000280 048000030007000b000f00130017001b001f00230027000001353315053533153335331501353315313533150735331507353315073533150735331507353315018080ff00808080fe80808080808080 808080808080040080808080808080ff00808080808080808080808080808080808080800009010000000280048000030007000b000f00130017001b001f002300000135331533353315013533153135 331507353315073533150735331507353315073533150100808080fe80808080808080808080808080040080808080fe8080808080808080808080808080808080808080001400800000030004800003 0007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f000001353315313533153335331505353315053533153335331507353315053533153135331531353315 31353315053533152135331505353315213533150535331521353315053533153135331531353315010080808080ff0080ff008080808080fe0080808080fd8080018080fd8080018080fd8080018080 fe008080800400808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000012008000000300048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043004700000135331533353315053533153335331501353315313533153135331531353315053533152135331505353315213533150535331521353315 053533152135331505353315213533150100808080fe00808080fe8080808080fe0080018080fd8080018080fd8080018080fd8080018080fd80800180800400808080808080808080ff008080808080 808080808080808080808080808080808080808080808080808080800010008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331d01353315 013533153135331531353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331501008080ff00808080fe0080018080fd8080018080fd8080 018080fd8080018080fe0080808004008080808080ff008080808080808080808080808080808080808080808080808080808080808080800010008000000300048000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000013533150535331501353315313533153135331505353315213533150535331521353315053533152135331505353315213533150535331531353315 31353315020080ff0080ff00808080fe0080018080fd8080018080fd8080018080fd8080018080fe0080808004008080808080ff00808080808080808080808080808080808080808080808080808080 80808080808000000011008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300000135331505353315333533150135331531353315313533150535 331521353315053533152135331505353315213533150535331521353315053533153135331531353315018080ff00808080fe80808080fe0080018080fd8080018080fd8080018080fd8080018080fe 00808080040080808080808080ff008080808080808080808080808080808080808080808080808080808080808080800012008000000300048000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00430047000001353315333533150535331533353315013533153135331531353315053533152135331505353315213533150535331521353315053533152135331505353315 31353315313533150180808080fe00808080fe80808080fe0080018080fd8080018080fd8080018080fd8080018080fe008080800400808080808080808080ff00808080808080808080808080808080 80808080808080808080808080808080808000000010008000000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f000001353315333533150135331531353315 3135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533150100808080fe80808080fe0080018080fd8080018080fd8080018080fd808001 8080fe00808080038080808080ff008080808080808080808080808080808080808080808080808080808080808080800007008000800300030000030007000b000f00130017001b0000013533150135 33153135331531353315313533153135331501353315018080fe808080808080fe808002808080ff0080808080808080808080ff0080800000140080ff800300038000030007000b000f00130017001b 001f00230027002b002f00330037003b003f00430047004b004f000001353315053533153135331531353315053533152135331531353315053533153335331533353315053533153335331533353315 05353315313533152135331505353315313533153135331505353315028080fe00808080fe008001008080fd808080808080fd808080808080fd808080010080fe00808080fe00800300808080808080 80808080808080808080808080808080808080808080808080808080808080808080808080808080800000000010008000000300048000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00000135331d01353315013533152135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331501008080fe808001 8080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808004008080808080ff00808080808080808080808080808080808080808080808080808080808080808080000000100080 00000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f000001353315053533150135331521353315053533152135331505353315213533150535331521353315 053533152135331505353315313533153135331531353315018080ff0080ff0080018080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808004008080808080ff008080808080 808080808080808080808080808080808080808080808080808080800011008000000300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000013533150535 3315333533150135331521353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315018080ff00808080fe0080018080fd808001 8080fd8080018080fd8080018080fd8080018080fe0080808080040080808080808080ff0080808080808080808080808080808080808080808080808080808080808080808000000010008000000300 040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331533353315013533152135331505353315213533150535331521353315053533152135331505353315 21353315053533153135331531353315313533150100808080fe0080018080fd8080018080fd8080018080fd8080018080fd8080018080fe0080808080038080808080ff008080808080808080808080 80808080808080808080808080808080808080808080000000150080fe800300048000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f005300000135 3315053533150135331521353315053533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315073533150735331505353315313533153135 3315020080ff0080fe8080018080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808080808080fe0080808004008080808080ff00808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808000140080ff000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0000 1335331507353315073533153135331531353315313533150535331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533150535331507353315 808080808080808080fe0080018080fd8080018080fd8080018080fd8080018080fd8080808080fe00808080038080808080808080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080800000150080fe800300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0053000001353315333533150135 33152135331505353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331507353315073533150535331531353315313533150100808080fe 0080018080fd8080018080fd8080018080fd8080018080fd8080018080fe008080808080808080fe00808080038080808080ff0080808080808080808080808080808080808080808080808080808080 80808080808080808080808080808080808000000000001501020000000000000000002400480000000000000001001a00820000000000000002000e006c0000000000000003001a0082000000000000 0004001a00820000000000000005001400000000000000000006001a00820001000000000000001200140001000000000001000d003100010000000000020007002600010000000000030011002d0001 000000000004000d00310001000000000005000a003e0001000000000006000d00310003000104090000002400480003000104090001001a00820003000104090002000e006c00030001040900030022 007a0003000104090004001a00820003000104090005001400000003000104090006001a00820032003000300034002f00300034002f003100356279205472697374616e204772696d6d657252656775 6c61725454582050726f676779436c65616e5454323030342f30342f3135006200790020005400720069007300740061006e0020004700720069006d006d006500720052006500670075006c00610072 005400540058002000500072006f0067006700790043006c00650061006e0054005400000002000000000000000000140000000100000000000000000000000000000000010100000001010201030104 01050106010701080109010a010b010c010d010e010f0110011101120113011401150116011701180119011a011b011c011d011e011f01200003000400050006000700080009000a000b000c000d000e 000f0010001100120013001400150016001700180019001a001b001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f0030003100320033003400350036 003700380039003a003b003c003d003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d005e 005f00600061012101220123012401250126012701280129012a012b012c012d012e012f0130013101320133013401350136013701380139013a013b013c013d013e013f0140014100ac00a300840085 00bd009600e80086008e008b009d00a900a400ef008a00da0083009300f200f3008d0097008800c300de00f1009e00aa00f500f400f600a200ad00c900c700ae006200630090006400cb006500c800ca 00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d5006800eb00ed0089006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079 007b007d007c00b800a1007f007e0080008100ec00ee00ba0e756e69636f6465233078303030310e756e69636f6465233078303030320e756e69636f6465233078303030330e756e69636f6465233078 303030340e756e69636f6465233078303030350e756e69636f6465233078303030360e756e69636f6465233078303030370e756e69636f6465233078303030380e756e69636f6465233078303030390e 756e69636f6465233078303030610e756e69636f6465233078303030620e756e69636f6465233078303030630e756e69636f6465233078303030640e756e69636f6465233078303030650e756e69636f 6465233078303030660e756e69636f6465233078303031300e756e69636f6465233078303031310e756e69636f6465233078303031320e756e69636f6465233078303031330e756e69636f6465233078 303031340e756e69636f6465233078303031350e756e69636f6465233078303031360e756e69636f6465233078303031370e756e69636f6465233078303031380e756e69636f6465233078303031390e 756e69636f6465233078303031610e756e69636f6465233078303031620e756e69636f6465233078303031630e756e69636f6465233078303031640e756e69636f6465233078303031650e756e69636f 6465233078303031660664656c657465044575726f0e756e69636f6465233078303038310e756e69636f6465233078303038320e756e69636f6465233078303038330e756e69636f6465233078303038 340e756e69636f6465233078303038350e756e69636f6465233078303038360e756e69636f6465233078303038370e756e69636f6465233078303038380e756e69636f6465233078303038390e756e69 636f6465233078303038610e756e69636f6465233078303038620e756e69636f6465233078303038630e756e69636f6465233078303038640e756e69636f6465233078303038650e756e69636f646523 3078303038660e756e69636f6465233078303039300e756e69636f6465233078303039310e756e69636f6465233078303039320e756e69636f6465233078303039330e756e69636f6465233078303039 340e756e69636f6465233078303039350e756e69636f6465233078303039360e756e69636f6465233078303039370e756e69636f6465233078303039380e756e69636f6465233078303039390e756e69 636f6465233078303039610e756e69636f6465233078303039620e756e69636f6465233078303039630e756e69636f6465233078303039640e756e69636f6465233078303039650e756e69636f646523 3078303039660000 ]], ["fonts/ProggyForever.ttf"] = [[ 00010000000d0080000300504646544db071471100004e180000001c474445460027001800004df8000000204f532f326861dc280000015800000060636d61709393e3be000003440000018a67617370 ffff000300004df000000008676c7966789d738700000658000041a8686561642c3ad262000000dc0000003668686561043e00e60000011400000024686d747817821441000001b80000018c6c6f6361 99df8a52000004d0000001866d617870010900e400000138000000206e616d65b5c86e22000048000000041a706f7374a844032500004c1c000001d10001000000010000e47302ad5f0f3cf5000b03e8 00000000e5afbb4200000000e5b3d43bffe1ff4401d702bc000000080002000000000000000100000283ff47000001b8ffe1ffe201d70001000000000000000000000000000000040001000000c200e1 000500000000000200000001000100000040000000000000000401b8019000050000028a02bb0000008c028a02bb000001df003101020000000000000000000000008000000710000002000000000000 00005858585800400020e9120283ff47000002af00bb00000003000000000185020600000020000101b800060000000001b8000001b8000000a60074fff900310005000400b900870087001b0016009a 003500a600270029004f0032002d001600310029002e0027002900a6008f001800180018002fffe100050026002f00270034003a0023002a0042004100130031001300290023002c000d0026002a0009 0025000dfffa0000000500210068002700680025fff2007c00300032003b0032002500280032003e008b0064002900850014003e002a003200320045004500570036001dfff90014002f0040003f00bc 003f0016009f003f00280037000500bc0040006dfff9005c0032fff9006d006500180073006d008300250030009f008f00720053003200130013001200490005000500050005000500050002002f0034 00340034003400420042004200420011002a0023002300230023002e0001002e002e002e002f0005002a002a0026002600260026002600260005003b00250025002500250033004400440044002a003e 002b002b002b002b002b0018000c003d003d003d003d001a0032001a00260015001e001800000003000000030000001c0001000000000084000300010000001c0004006800000016001000030006007e 00ab00d200d300ff01010178202620ace912ffff0000002000a100ae00d300d401010178202620ace912ffffffe3ffc1ffbfff5fffbeffbdfec4e099e01417af00010000000000000000000000000000 00000000000000000000010600000100000000000000010200000002000000000000000000000000000000010000030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324 25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061008384868890949a9f9ea0a2a1a3a5a7a6a8a9 abaaacadafb1b0b2b4b3b8b7b9ba006f63646800759d6d6a00736900859600700000667400000000006b7900a4b67e6200000000006c7abf007f82930000000000000000b500bd3c00c0000000000076 0000008189808a878c8d8e8b329200919899970000006e0000007700000000000000002800280028002800440056008600d4010e016a0176019601b601d601ea02080216022802380266027c02ae02ea 030603400378038a03d80410042c0456046a047e049204d4052e0548058405ac05c805e005f40628063c0654066e0686069606b006c606f00750078207aa07f60808082e0840085c0874088808a008b2 08c208d408e608f409020950098009a209d209fa0a1a0a540a720a900ab60ace0ade0b0e0b2e0b4c0b7c0bac0bce0c0a0c260c480c5c0c780c900d0c0d260d5e0d6a0da20dd60df20e220e4a0e800ea6 0eba0f260f480f800fd20fee10321040105e107a10a210dc10ea1120113e1150116a117e11a411c011ee122c127e12b812d812f8131c1350138413ba13de141814361456147814aa14c814e61508153a 156e15a015d016041648168c16a616e6170a172e1756178e17aa17cc1812186818be1918198819f21a581b161b4e1b7c1bac1bde1c221c401c601c821cb41cfc1d3c1d621d881db21df01e2a1e5e1e96 1ec21eee1f1c1f5c1f881fae1fee2044208420c420d4000000050006000001b202bc000300060009000c000f0000132111211b020b01111303210313110601acfe541cbabac6b4c0b80172aeb602bcfd 4402a8fecb0135feb6012cfda70118fecc0149fed1025d00000200a6fffe011202230005000d00003723033733150232161406222634fb3b0e0153402c20202c20c401045b5bfea11f2c20202c000000 000200740146014402070003000700001323353317233533b541418e40400146c0c0c0000002fff8000301bf0203001b001f000001230733152307233723072337233533372335333733073337330733 0737230701bf681f5c6a263b265c263a26606e1f6270263b265c263a265ac11e5c1e013c73368f8f8f8f36733690909090a9737300030031fff1018702160028002d00340000131e031514071523352e 012f01351e0217352e03353436373533151e011f0115262715322735061514173e0135342627fe16282e1c8d3c24430f0f061545251f2c2b164b413c19370f0f2b43023e4884202924250121040f1c32 21720f2c2b010e06063f040b1603a2060f1a2a1d3543092d2a020b05053e1d04960c870c3d2cee07251f1e200a00000000050005000b01b201fa0007000f0017001f0023000012140622263436320614 1632363426221632161406222634163236342622061413330123d13c543b3b545c1e291d1d29cb543c3c543b51291e1e291d2f47fede4701c14f38384f384c271b1b271bfd384f38384f561b271b1b27 01a1fe1500030004fff601b3021500220035003f000025163123262706232226353436372e0235343633321615140e0207161736353714011c021e05173e013534262322061332372e01270615141601 7043480d153c594868342c16130f3f3c3d330f201918593a243dfec301020306080c0725251f171823603425196e1841504f4f0f18316042324a21191928182945373114242214116b454148016c010d 01070307050a090d1009192818151920fe6c241c831c363b303e0000000100b9014600ff02080003000013233533fe44440147c100010087ffc10131023e00110000010e01141617232e04343e023f01 01312b37372b3c040f261d181720210b0b023d3cb1a1b13c061544466761664b3d10100000010087ffc10131023e00110000131e04140e020f01233e01342627c3040f261d181720210b0b3c2b37372b 023d061644476761654b3c10103cb1a1b13c00000001001b0045019d01c700110000010717072715233507273727371735331537019d83832180408120838320814080014d474732468e8e4632474732 468e8e4600010016004a01a201b9000b0000133315231523352335333533fba6a63ea6a63e011f3b9a9a3b9a0001009aff81011e006b0010000036321615140e020f012736372e013534d12d1f151f1e 0b0b1a370a11196b2016203d28200707253029011f1516000001003500e30183012000030000252135210183feb2014ee43c0000000100a6ffff01120069000700003632161406222634c62c20202c20 691f2c1f1f2c000000010027ffde0190022700030000090123010190fedd4501220227fdb802480000030029fff7018f020e00050010001b000013321023221017220e03151417372603323e03353427 0716dcb2b2b2b2111c1f140e04bd1a39111c1e150e04be1b020efdea02163a081a2c4e352721e534fe5f071a2c4e352822e634000001004f000001680207000a0000132737331133152137331151016a 4469fee901690167514efe373d3d017a000100320000018602110020000013273e0233321e0215140607063121152135343736373e01353426232206073701081d5125304824112c3b930101fead0d01 a525283a2d1a4b18019f4105101b1e302e15284e3a923d2e0e0c01a5265021212f1b0d000001002dfff6018b02100029000001161514062322262f01351e023332363534262b01353332363534262322 060f013536333216151406011a706b55224e1617071950293941413140402e38372d214814144a444e623301161e6d41540d070645040c1333312e343a2d26252b0e070740174a3b3237000000020016 000001a20207000a000d00002533152315233523351333031103014a585843f1d0643ab3b53a7b7b490142feaf0112feee00000000010031fff601870207002800001311211523153633321e0315140e 022322262f01351e0233323e0235342e0223220607480121dd18291930332618233d43262b460e0e07184c261527271717282c191c380e010201043b7f0b0a19263f28314826120b060547040b130b19 30212130190c0d0700020029fff8018f0208001b0025000013321e0215140623222635343e023332161f011526232206153613323534232206151416ea1f38311d5b525762243f4f30182e0b0a1f3b45 59244e6565293b3b01571428442b5a597288496e3f1f08040342195f6248fed9777939403f3800000001002e0000018a020700060000133521150323132e015bc54ebe01cb3b1dfe1701ca0000030027 fff6019102110014002400340000011e0115140623222635343726353436333216151426220e02141e02323e02342e0102323e02342e02220e02141e01012c3034684c4d6863545f47466093251d1d10 111d1c241c1e10101d442a2020121221202820211212200115104834454e4d466b211e5b3e45463d5aa606112535251006061025352511fe5907142a3f2a130707132a3f2a140000000200290000018f 0210001b0025000037222e0235343633321615140e022322262f013516333236350603221514333236353426cd1e39301d5b52566324404f2f182e0b0b203b4459234f64642a3b3cb11427442c595a72 88496e3f1f08030441185f62480127787838404038000000000200a60051011201ab0007000f000036321614062226343622263436321614c62c20202c204c2c20202c20bb1f2c1f1f2ca51f2c1f1f2c 0002008fffd1011201ab00100018000036321615140e020f012736372e0135343622263436321614c62c20161e1f0b0a1b370a11194d2d1f1f2d1fbb2016213c291f0707253029011f1516a61f2c1f1f 2c00000000010018005401a001b0000600001325150d011525180187fec80138fe79011e913e6f703e910000000200180098019f01720003000700000121352115213521019ffe790187fe7901870137 3bd93b0000010018005401a001b00006000013051505352d01180187fe790138fec801b09139913e6f7000000002002f00000187021f0007002e0000363216140622263413321615140e031d01233534 3e0435342623220e020f012e03173e04c22d1f1f2d1f3f53521d2a2a1d461521262116342b192d1d160405030c170f01020a22263d6a1f2c1f1f2c01d444341c2f211e2111292916271c1d171f101e21 10171708080207100a01040e231a16000002ffe1ffe901d702200039004100002535170e0423222e0335343633321615140e02071523350623222634363332161f013235342623220615141e0233323e 0237263236342622061401b026020b262b47253f67432e148d6969800f18150a37242b374f50371c310a0b2d54465176273d4b272340281e07d33c2b2b3c2b67012e040b1b151121374a4f2a78a34e43 1823110701c6131f5d835e1a0d0d1c22397c683557371e0d14140747384f39394f00000000020005000001b202070007000a000001132327230723130333030109a94d29c1284da9229e4f0206fdfa88 880206feba010900000300260000019202070015001e00270000011e0415140e022b011133321e021514062715163736353426231332363534262b011501210c172219121e32391fc2b12b3e200f31d2 472754312a0841343e2d7901160307141b301f2639200e0205192b2e182a37b29c0102044c2a21fe6d2f342f2bbd00000001002ffff801890212001a000025150623222e02353436333217152623220e 0215141e0133320188314f3856321870684d33334d2639200f1a42324d5d491c2a4a5f3a759720472d213b4a2e3e5b3b000200270000019002070007000e00001332111023063111133235342b0111c7 c9c8a09f7d7d540206fefdfefe010206fe34cac9fe6d000000010034000001830207000b000013211521173315231521152135014dfefd01e3e40104feb202063b993bbc3b0000000001003a0000017e 020700090000132115231f01152315233a0143f901b5b64a02063b9e013bf10000010023fff801940212002400002527233533150e0423222e02353436333217152623220e0215141e0133323637014e 0163aa02071b20361e3855331870684e32334d2639200e1942321b2907438d3adf0207120d0b2a4a5f3a759720472d213b4a2e3e5b3b0a050001002a0000018d0207000b000033113315333533112335 23152b4bcc4b4bcc0206d4d4fdfaf7f600010042000001750207000b00001335211523113315053537114301327474fece7301cb3b3bfe703a0139010191000000010041fff901760207000e00001333 111406230631353332363511239ed8424ea49330258c0206fe9e505a0139303a012f000000010013000001a50207000b0000331133153733071323030715134be955d4dd5ab4390206e6e6d4fece0104 39ca00000001003100000187020700050000371133112115314b010a010205fe353a000000010013000001a40207000c0000331133173733110711032303111464636564416b396a0206fefefdfb0101 c5feef0113fe3a00000100290000018e020700090000330333131133112303112d0362ba485fba0206fe5a01a6fdfa01a6fe5a0000020023fffa0195021200050019000013321023221012323e03342e 03220e03141e02dcb8b8b8a7221b1e140d0d141e1b221b1e140e0e141f0211fdea0216fe25081a2b4e6a4e2c1a08081a2c4e6a4e2b1a00000002002cffff018b02070010008100001332161514062b01 1c011e011c0131231117323e0235342e022b0115390a3339023339013331333133313331333133313b02313b41db555b55546c01014ba1202e160a0a152a1e5d01010101010101010101010101010101 0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010102065046475905153730321d0206fc131f1f11 111f1f12c30000000002000dffb801ab020f000c002000001332111407171523270623221012323e03342e03220e03141e02c6b828543052283ab8a7221a1f140d0d141e1b221b1e140e0e141e020efe f57b43612c5b1b0216fe25081a2b4e6a4e2c1a08081a2c4e6a4e2b1a00020026000001910207000d00170000370723113332161514060717232737231516373e01353426720348b34f53392c7a4f6f02 634427223335dbda020559452d4510e5d9f3b80102022e2d2b2f00000001002afff6018d02110036000001152e0223220615141e07171e031514062322262f01351e02333236353426272e0335343633 321e0217016d061543233e3d060e0b190c1f092101172a301d65592b4e1212071b562d2d423d4522302f1867571228201b0801f547040d1529300b120f0b0a05070305010411213a274e4a1009084905 101b2e2d2e250e06111f3222485205080902000000010009000001af02070007000013352115231107110a01a4ac4b01cb3b3bfe360101cb00010025fff6019302070018000037113311141e02333236 35113311140e03222e03254c06132b2043304b061626445f46261607a60160fe991a2322123643015ffead21303521161520322c0001000d000001ab0207000600003303331b013303aea149868648a1 0206fe3a01c6fdfa0001fff9000001be0207000c00003303331b01331b013303230b014b513f3a3f53403940514948490206fe63019dfe62019efdfa01b8fe480001ffff000001b90207000b00001327 33173733071323270723b8a050797b51a5b1508d8d500113f3c3c3f3feeddada00010005000001b2020700080000370333173733031523b6b04f878650b14bea011ce4e4fee3e9000001002100000197 02070009000013352115012115053501290166fee00128fe8a011801cb3b35fe6a3a01380193000000010068ffbd01500249000700000127113315231133014fa2a2e7e7021201fde238028c00010027 ffde0190022700030000130123016d012346fede0227fdb80248000000010068ffbd0150024900070000133311233533110768e7e7a3a30249fd7438021e010000010025013f01930207000600001317 2327072337fc9652646552960206c68d8dc600000001fff1ffbe01c7fff7000300000521352101c6fe2c01d4423800000001007c01a0013c02390003000013172327cf6c526d02399999000000020030 fff60188018f0026003800001315321e02150631233627062322263534373e011f01303c012e0623063135323613323e03352223260e04151416d6263a341d013d02022663404f6817551e1f02030709 0f121a107a123a182030170d020a15182d2720160d33018f010c21412ff1191b3d3f3e5d1d060501010e07110a100a0c0705023602fe9d1a21311b110102030a121c14252300000000020032fff70186 02310014001e00001332161514062322262f0107231133153e0402323635342622061514e84757583b203e100f073d44010512172b247032336e34018e6665626a1d0f0f31022fdd030814100cfe9f52 44435353434400000001003bfff7017d018f00140000012206151416333237150623222634363332171526010d414848413e312f4e556e6e554e2f3101594a4c4c4a2b41206ac46a20412b0000020032 fff7018602310016001e000001331123270e0423222635343633321e021f0102323534262206150142443e0603081a1b29143b585746192a18110304c8c83068300230fdd1310307150f0d6a6265660c 11110607feda96435353430000020025fff70193018f0014001a00003714163332363715062322263534363332161514312722061533346c3e432a3e2e4652596d694f5b5aaf2f45e0b4384f1215401d 6d5f5d6e614930a54430740000010028000301900224001300000122061d013315231123112335333534363b01150128231f7d7d447a7a41406c01ed19254b39fed9012739344e3e3700000000020032 ff460186018f001d0027000001331114062b013533323e023d010e04232226353436333216170332353423220615141601483d5a5182881c2a170a010512182a19475b5b3c30341c6b63633533330185 fe6e56563a162425123b0206100c0a65646265141dfed78e965244414d0000000001003e0001017a0231001200001332161511233534262322061d012311331536fd35484428252f3844442501924e43 ff00fa2d303d3bdf022fda3c0002008b0001012d021e0005001100001335331123113723223d01343b01321d01148ba1443b380a0a3809014b3bfe7b014a7f0a400909400a00000000020064ff460154 021e000b001800000123223d01343b01321d011407353311142b01353332363511014a380a0a3809aeae7f70691d2501ca0a400909400a7e3afe62a13b34320164000000000100290002018e021e000b 0000371723270715231133113733d2bc519a334646b550f5f3c92d9c021bfec9a1000000000100850001013302080005000013331123112385ad45680207fdfa01ca000000010014fffe01a4018f001e 000001321615112311342322060711231134232206071123113315363332173e0101442b343d341a1a033d341a1a033e3e1f2a341a0d30018f4535feea0105542225feee0105542124feec0185121d31 161b00000001003e0001017a0193001200001332161511233534262322061d012311331736fd35484428252f384440042501924e43ff00fa2d303d3bdf0185303c0000000002002afff7018d01900007 0011000012321615142035341632363534262206151489a65efe9e835c3a3b5a3b01906666cdcd66fe4850504646505000020032ff4e018601880016001e000013321615140623222e022f0115231133 173e040232363534221514eb42595747192918120303443d070106141929236730c70188696365670c12110606dd023031020814100dfe9e524394944300000000020032ff4e018601880016001e0000 01331123350e0423222635343633321e021f01023236353422151401483e44010512182a194657594217291a130404a26830c8017efdd0dd0208150f0d676563690c12110606fed95243949443000000 0001004500000173018e001300000132161f01152e022322061d01231133073e01010c1d340b0b0410381f38474444021145018e0f070841050c143c23f50185351b230000010045fffe017301970029 0000371e011514062322262f01351e02333e013534272e0135343e023332161f01152e022322151416e8464558491f461414081c491d2e315b53390e20412c213e0e0f06133f215a24ea0b2e3739420c 060641040c1501241a310f0f352c162624140b06063e040b1139191d00010057000601610204001200003732311523222e03351133153315231514d8887d192129181044a2a2413a030f1a3222017c76 3acc460000010036fff601820185001600003735331514333236353631331323350e042322263644562c3e03440140010311172d1b4f4991f4f1663527fbfe7c2a0207130d0c4a000001001d0000019b 0185000600000133032303331301544694569347780185fe7b0185feba0000000001fff8ffff01c00185000c000001330323270723033313373317017c43613f444141614444354c3c0185fe7bd7d701 85fed0c0c000000000010014ffff01a30185000b00002517232707233727331737330101a24e7a784ea2954c6e6d4ccbcb9b9bccb98d8d000001002fff440189018600ae0000011215140e022b013533 323e04353435390323390223390123312331233123312331233123312b01312b02312b6d222635123133151416331631030186030c182f20c3b010170d08030101010101010101010101010101010101 0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 0101010101010101010101010101010101010101010101010101010a474801441d2989010185fe8730112f34243b0c181622110e04024e310106e5313201014900010040ffff01770186000e00003733 1721353e0327223135211589ed01feca0f32694501e5012d34343b113a7a5201323c00000001003fffb201780254002a000001151407161d0114163b01152223222e033d0134262b01353332363d0134 3e0333323115232206010b4848262a1d1f0d26361b0e03262b33332b26030e1b36262c1d2a2601d7645f11116063221d3e141a2c1e17562b2042202a57171e2c1a133e1d000100bcffc800fc023f0003 000017231133fc40403702750001003fffb201780254002a0000133534262b01353233321e031d0114163b01152322061d01140e03232231353332363d01343726ac252a1d1e0e25361b0f02262c3333 2c26020f1b36252c1d2a254848017364211d3e131a2c1e17572a2042202b56181d2c1a143e1d2164601110000001001600b101a1015d0021000001170e0423222e03070e010f01273e0433321e03373e 013701673a050511152819192b1e1c1f10141903033a050511152819192b1e1c1f1014190301420d15152d18141a23241502032d15150d15162c18151a24231603032d140002009fffeb011902090005 000d00001333170723351222263436321614c42e1d01654c3223233223014bc49b9b010a23312323310000000002003fff93017901f20016001c0000011136371506071523352e013534363735331516 17152603110e011514011939272d33264e666450263d23285e323a0158fed702193b15036465066b5c5f6804616205143c19fede012606494386000000010028ffff01900210001b0000373315213533 352335333534363332161f0115262322061d01331523cac5fe99574949524f2134090a302a323288883b3b3ba1325258580a0505401e353f5832000000020037003f0180017d0017001f000000140717 072706222707273726343727371736321737170706323634262206140159163c223e1f491f3e223c16163c223e1f491f3e223c88412e2e412e0103491e39233c13133c23391e491e39233c13133c2339 8d2c3d2b2b3d000000010005000001b20207001800000107331523071533152315233523353335272335332733173701b2785b732194944b949421735b774f87860206c227350b27b6b6270b3527c2e4 e4000000000200bcffce00fc02390003000700001323113311231133fc4040404001320107fd95010800000000020040ffbc01770210003b004b0000251e011514062322262f01351633323635342627 26272e04353436372e013534363332161f0115262322061514161716171e04151406273e013534262726270e011514161716013019154548193910103a33242a252f08031c1927110e26211915444a18 360e0e33332528242f08031d1827110e2647151c302e1916161b302d19751222172c420a0505391a2019141e1a0402100e1c1722131c32101222182b3b0a0505391b1a19141e1a04020f0f1c1721141c 32090c230f1a2c190e0d0c240f1a2c190e0000000002006d01d4014b021b000b001700001323223d01343b01321d01143323223d01343b01321d0114b03a09093a088a3a09093a0901d5093409093409 09340909340900000003fff8002801c001da0014001c0024000036343633321715262322061514163332371506232202321614062226341232363426220614544e3e391e2b222f34342f2e1f24333d25 bc8585bc86969c6f6f9c6fc37e420f26153031312f122411015b7fb37f7fb3fef4699369699300000003005c00a2015b021200280037003b00003722263534373e011f013c012e022322060f01353e06 333216151431232e031506372223220e0415141633323617233533c72f3b4d113d1615080f20161a320b0c021207110c11120939492d01020302282805081918251314082416312935f7f7f22c2b4314 05030101080a160e0b0b06062c0106020602030139409f0208110c012d8e0103060b120d18183db62b000000000200320031018601700006000d00001307171527353733150717152735df6f6fadada7 7070ae012d5d5d42911c92435d5d42911c0000000004fff8002801c001da0007000f0023002d0000123216140622263412323634262206143716171631232627262322311523353332151406273e0135 34262b0115167ebc8585bc86969c6f6f9c6fe6111a2a341e1115181b2f5c67223d131b1d15311f01da7fb37f7fb3fef469936969933e0726412c1a2167f24a15201201141313144f010000000001006d 01b7014b01eb0003000001233533014adcdc01b733000000000200650132015202100007000f000012321614062226341632363426220614ab6245456245583b2a2a3b29020f415b41415b7027372727 3700000000020018ffff019f01970003000f000005213521273315231523352335333533019ffe790187a4a4a43ea5a53e013bea3b73733b72000000000100730185014502ad00190000133315233536 37363534262322060f0135363332161514060706ad98d24d202a251c112a0c0d2733393a1b245601ac2726481d282412190b06062914331c162d224d0001006d0182014b02b000270000011406232226 2f0135163332363534262b01353332363534262322060f0135363332161514060716014b443715310f0e322a1a302b1f1f1f1d241e1b152c0c0c2f2c313f211e4701d6252f0704042a121a19191b2616 1512160804042a0d2a211c1d070d00000001008301b5013502390003000013330723eb49783802398300000000010025ff6b01920184002500002532363f0115062322262f010e042322262715231133 151416333236353631331015140178070c04031b1d131a0403010410162a1b1a2f0b3c402d252b3b034131040202340f1a0d0d0207120e0b1c1ac00218f130353526fbfee2181d0000010030ffb90188 020700100000133311231123101506222f011122263436d8af3446011a0d0d4563630206fdb60220fde5050201010127557955000001009f00c60119013f000700001232161406222634c33223233223 013f2332232332000001008fff7701290001000e0000211615142322262f013516333227300100285b0e1f0808181b5b4929253b0402022e0b5e0000000100720184014602a7000a0000133315233533 3507353733fa4bcc4c53553301ab2626d40e280d0003005300a2016502100007001100150000242035343632161526220615141632363534132335330164feef497f4966452e2d472d2af9f9f38f4747 4747652f363631313636feeb2b000000000200320031018601700006000d00001317150735372717150735372735d8aeae707007ad6f6f0170921c91425d5d4f1c91425d5d43000000040013ffa201a5 0240000a00150018001c000013073537331533152335331715331523152335233537073335371705277b5257304bcb4bf72b2b3290865d665c09fe7809021a0e270dfc272780bc2541412ab7bb909625 5b25000000030013ffa201a50240000a0024002800001307353733153315233533130631331523353637363534262322060f012736333216151406371705277c5257304bcb4be05698d24d202a251c11 290d0c012733393b1c1b09fe7809021a0e270dfc2727fed24d2727471e272413190c06062a13331b172df7255b25000000040012ffa201a50246002600310034003800000114062322262f0135163332 3634262b01353332363534262322060f0135363332161514060716171533152315233523353707332737170527010c483715300d0d292e242a2622211e1f252119182d0a0a2e2c323e211e48692b2b31 91865c66015909fe7809016c242f07040429121d2f1c25171514140804042a0c29201d1d080ee9bc2541412ab7bb9096255b250000020049fff7016f021b00070026000000222634363216140332363f 01150e0223222635343e043d013315140e0315141601092c20202c203e1d42121307184522524e131d221d13471a25261a2f01b11f2c1f1f2cfe60180b0c41050c154136182b1e1e181f11453d1e3022 1f27151f2400000000030005000001b302830007000a000e00000113232723072313033303372327330109a94d29c1284da9229e4f2d3854440206fdfa87870206feb9010a5d5c0000030005000001b3 02830007000a000e00000113232723072313033303370723370109a94d28c1294da9229e4f5f5438480206fdfa87870206feb9010ab95c5c00030005ffff01b302830007000a00110000011323272307 2313033303350723373317230109a94d28c1294da9229e4f3d334e454e330205fdfa87870206feb9010a9d3e5c5c000000030005fffe01b3027b0007000a001f00000113232723072313033303272206 1523343633321633323635373314062322260109a94d28c1294da9229e4f330c0c2f24221a3e0f0b0d012e22241c3a0205fdfa87870206feb9010a891310212b221109081933230000040005ffff01b3 0283000b0017001f002200001323223d01343b01321d01143323223d01343b01321d01140713232723072313033303b03a09093a09893a09093a0942a94d28c1294da9229e4f023d0934090934090934 0909340938fdfa87870206feb9010a0000030005fffe01b30295000f001c001f0000011323272307231326353436321615142733141617333e01353426220603330301139f4d28c1294d9f2f3c543c9f 0112102c1013212f22169e4f01e6fe19878701e71c33283737283334111a06061a11151f1ffe73010a00000000020002ffff01b60207000f001300002515331523352307231325072317370f01112303 013580ca7f2544960117017a016f01b9254bf6bc3b86850205023d99013c38010dfef4000001002fff77018902100028000001220e0215141e0133323715060716151406232227351633323534272e03 353436333217152601082639200e1942324d332538212d262d19181f2e1a3651301770684d333301d5203c4a2e3e5b3b2e49150524201f1e092d0b1f1620032a4a5d38759720472d0002003400030184 02870003000f00000123273303211521112115231f011523010d395444450104feb20147fd01f1f2022a5dfdb83b02063b99013b000200340004018402870003000f0000010723370321152111211523 1f011523012c543848690104feb20147fd01f1f202875d5dfdb93b02063b99013b000000000200340004018402880006001200001307233733172303211521112115231f011523d53d344e464e349301 04feb20147fd01f1f202693e5d5dfe153b02063b99013b0000030034000001840285000b0017002300003721152111211523173315231323223d01343b01321d01143323223d01343b01321d01147f01 04feb20147fd01f1f2313a09093a09893a09093a093b3b02063b993b0148083409093408083409093408000000020042fffe017602830003000f000001232733172311171521353311233521010b3854 44b27373fece7474013202265cb8fe6f01393b01903b0000000200420003017602870003000f0000010723371723113315213533112735210139543848807474fece7373013202875d5db8fe703b3901 91013b000002004200030176028800060012000013072337331723172311331521353311273521e13d344e464e34577474fece7373013202693e5d5d5cfe703b390191013b00000000030042fffe0176 0283000b0017002300000123113315213537112335212723223d01343b01321d01143323223d01343b01321d011401757474fece73730132c53a09093a09893a09093a0901cafe703b390101913b3809 34090934090934090934090000020011000401a7020b00120024000013321e03140e03232231352335333513323e03342e032b011533152315c91f383d2d1d1d2d3d381e8b2e2e8913242a1e14141e2a 24133e6363020b0c23375f7d6036230bf535dcfe33091b2a4b624b2a1b08a235bc0000000002002a0000018e02820009001e000001331123031123033313032206152334363332163332363537331406 2322260146485fba470462ba9d0c0c2f24221a3e0f0b0d012e22241c3a0206fdfa01a6fe5a0206fe5a01f81310212b22110908193323000000030023fffa0195028700030009001d0000012327331732 1023221012323e03342e03220e03141e02011239544413b8b8b8a8211b1e140d0d141d1c221b1e140d0d141f022a5d76fdea0216fe25081a2b4e6a4e2c1a08081a2c4e6a4e2b1a0000030023fffa0195 02880006000c002000001307233733172307321023221012323e03342e03220e03141e02dc3d344e464e343db8b8b8a8211b1e140d0d141d1c221b1e140d0d141f02693e5d5d1afdea0216fe25081a2b 4e6a4e2c1a08081a2c4e6a4e2b1a000000030023fffb0195028100050019002e000013321023221012323e03342e03220e03141e02032206152334363332163332363735331406232226dcb8b8b8a821 1b1e140d0d141d1c221b1e140d0d141f080b0d2f2423193e0f0b0d012e22231d3a0211fdea0216fe25081a2c4e694e2c1b07071b2c4e694e2c1a02191310212b221109081933230000040023fffa0195 0288000b0017001d003100001323223d01343b01321d01143323223d01343b01321d011407321023221012323e03342e03220e03141e02b03a09093a09893a09093a096fb8b8b8a8211b1e140d0d141d 1c221b1e140d0d141f024209340909340909340909340931fdea0216fe25081a2b4e6a4e2c1a08081a2c4e6a4e2b1a000001002e004101890189000b0000010717072707273727371737018981812d80 812d81812d8180015e79792a79792a79792a797900030001ffea01b702220011001c00270000010716151023222707273726351033321737011417372623220e0313323e03353427071601b7411eb853 2e3624411eb8532e36fede07b91a3b111b1e140d6b111b1e140d07b81a0208584169fef5384819584169010b3848fee5382af93a081a2c4efefb081a2b4e35382af83a000002002efff6018a02830003 001500000123273317331114232235113311141633323e02350113395445734baab04b273d1e28130702265c7cfea0b0bd0153fea0433412212419000002002efff6018a028300030015000001072337 17331114232235113311141633323e02350132543948514baab04b273d1e28130702825c5c7cfea0b0bd0153fea04334122124190002002efff6018a0283000600180000130723373317231733111423 2235113311141633323e0235dc3d344e464e34254baab04b273d1e28130702653e5c5c21fea0b0bd0153fea043341122241900000003002ffff6018a0283000b0017002900001323223d01343b01321d 01143323223d01343b01321d011407331114232235113311141633323e0235b13a09093a09893a09093a090e4cabb04b283d1e271307023d09340909340909340909340937fea0b0bd0153fea0433411 2224190000020005ffff01b302820003000c00000107233717330315233703331701365439497050b14b01b14f8702825c5c7cfee3e9ea011ce500000002002affff018e0206000b0014000013321615 142b0115231133151732363534262b0115dc535fb2674b4b5d313d3f2f5d01aa4b4a967f02065cf02b302f2ab40000000001002afff2018e021c0030000013141e0315140e012627351633323635342e 0335343e023f0126362e022322061511231134363332152206ea22303021334e58263133292d212f2f211823220c0c01030a0e261b2e294449529b2f48013214211b2035232b391405103815241d1825 191b2d1e1c2c180f0202010f1716103032fe7b01854d4a982c00000000030026fff501920245002b003a003e0000251514161f012326270e012322263534363332313c022e052322060f01353e063332 03323e0227302a01230e0115141613232733017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0da8c124341a0a01242f0b3c34336f397648e27419370f0f16252025 403c3e46010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c2624019783000000030026fff501920245002b003a003e0000251514161f012326270e012322263534363332313c02 2e052322060f01353e06333203323e02272a02230e0115141613072337017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0da8c225341a0a0101232f0b3c3433b776 3967e27419370f0f16252025403c3e46010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c2624021a83830000030026fff501920245002b003a00410000251514161f012326270e 012322263534363332313c022e052322060f01353e06333203323e0227302a01230e0115141613072337331723017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0d a8c124341a0a01242f0b3c34333f42345a385a34e27419370f0f16252025403c3f45010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c262401ef588383000000030026fff50192 0233002b003a00540000251514161f012326270e012322263534363332313c022e052322060f01353e06333203323e0227302a01230e011514161333221523343633321e013332363d0133140e022322 2e02017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0da8c124341a0a01242f0b3c343309011a2d242515221e0d0c0d2e050d1e15151f1116e27419370f0f162520 25403c3e46010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c262401dc362b371b1a1a0d0e0f1d211511141100000000040026fff50192021d002b003a00460052000025151416 1f012326270e012322263534363332313c022e052322060f01353e06333203323e02272a02230e011514161323223d01343b01321d01143323223d01343b01321d0114017e0a0505440907154c264150 5b5b5c0206080f141e122647101103190b1811181a0da8c225341a0a0101232f0b3c3433103a09093a09893a09093a09e27419370f0f16252025403c3e46010f09120d100b0a05120a093f0109030803 0402fe9b1d2f321a02202c262401ab0934090934090934090934090000040026fff501920272002b003a0042004a0000251514161f012326270e012322263534363332313c022e052322060f01353e06 333203323e02272a02230e0115141612222634363216142622061416323634017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0da8c225341a0a0101232f0b3c3433 66543c3c543c4f2e21212e21e27419370f0f16252025403c3e46010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c2624018638503838505d1f2c1f1f2c000000030005fff501b3 018f00ca00d600e000002515303901233901233123312b7b1c021e053316363f01150e0223222e022f010e042322263534363b013534262322060f01353633321e021f013e04333216171e0115073631 2322061514163332363714313336272e01232201b20101010101010101010101010101010101010101010101010101010101010102010101010101010101020101010102010101020101010201010201 01020101020102010102010201020102010201020102010201020102010202010201020201020201020201020201020202010202020102020201020202020102020202090204060a0e150c2234090a05 0f3019192a16100203010410152416393c4644322a1e132e0d0e2c41131e120c020201030e1324163a30080201f4011c352c2517231b41790102031b1f39b301011c0a1c0d170b0e060111090a3c030a 100b111006050207130f0c3c3839411c32270e08073a18090d0d040502060f0b0a3b4c122a0c42362026231f24b01b17162326000001003bff77017d018e00250000012206151416333237150e010f01 16151406232227351633323534272e013534363332171526010d414848413e310e2b0f0f212d262d19181f2e1a526a6e554e2f3101584a4c4c4a2b410b0f020224201f1e082e0c20161f036960626a20 412b000000030025fff7019302450014001a001e0000371416333236371506232226353436333216151631272206153334272327336c3e432a3e2e4652596d694f5c5901b02e46e03c397648b4384f12 15401d6d5f5d6e614930a5443074698300030025fff7019302450014001a001e0000371416333236371506232226353436333216151631272206153334370723376c3e432a3e2e4652596d694f5c5901 b02e46e00e773866b4384f1215401d6d5f5d6e614930a5443074ec838300000000030025fff7019302450014001a00210000371416333236371506232226353436333216151631272206153334270723 373317236c3e432a3e2e4652596d694f5c5901b02e46e06e43345a395a34b4384f1215401d6d5f5d6e614930a5443074c158838300040025fff70193021d0014001a0026003200003714163332363715 062322263534363332161516312722061533342723223d01343b01321d01143323223d01343b01321d01146c3e432a3e2e4652596d694f5c5901b02e46e09c3a09093a09893909093909b4384f121540 1d6d5f5d6e614930a54430747d09340909340909340909340900000000020033fffc0175023b0003001200001323273313153315222322263d012335331514e3397749a950184736415a9e01b883fdf9 01364e3fc932fb5600020044fffc0174023b0003001200000107233713153315222322263d012335331514014c773967224f174835425a9e023b8383fdf901364e3fc932fb56000000020044fffc0174 0245000e0015000025153315222322263d0123353315140307233733172301254f174835425a9e2842345a385a333401364e3fc932fb5601e658838300030044fffc0174021a000d0019002500002533 15222322263d0123353315140323223d01343b01321d01143323223d01343b01321d011401254f174835425a9e48390909390989390909390933364e3fc932fb5701a109340909340909340909340900 0002002afff4018e021b0020002f000001141e06151406232226353436172e012f01072737273317371707160332363534262f01262322061514160140140613080d0605595858596b64051b0a0b670c 5843512f6a0d5d24492d3c140a0a12322b3b3c0183011b0a1d13211d2613566b6b5e5d6608081f0c0b1f221b453120221c22fe81464726430f0e0945494945000002003e0000017a02200019002d0000 1333221523343633321e013332363d0133140e0223222e02172332161511233534262322061d012311331736a9011a2d242514231e0d0c0d2e050e1d15151f1116490135484427262f384440042501f4 362c361b1a1a0e0d0f1d2115111411634e43ff00fa2d303d3bdf01842f3c00000003002bfff4018d024500070011001500001232161514203534163236353426220615141323273389a65efe9e835c3a 3b5a3b9b387749018d6666cccc66fd475050464650500151830000000003002bfff4018d024500070011001500001232161514203534163236353426220615141307233789a65efe9e835c3a3b5a3be2 763967018d6666cccc66fd4750504646505001d4838300000003002bfff4018d024500070011001800001232161514203534163236353426220615141307233733172389a65efe9e835c3a3b5a3b6842 345a385a34018d6666cccc66fd4750504646505001a95883830000000003002bfff4018d022000070011002a000012321615142035341632363534262206151413221523343633321e013332363d0133 140e0223222e0289a65efe9e835c3a3b5a3b35192e242614231d0e0c0d2e050e1e1514201016018d6666cccc66fd475050464650500183362c361b1a1a0e0d0f1d211511141100000004002bfff4018d 021a00070011001d002900001232161514203534163236353426220615141323223d01343b01321d01143323223d01343b01321d011489a65efe9e835c3a3b5a3b3c3a09093a09893a09093a09018d66 66cccc66fd4750504646505001630934090934090934090934090000000300180031019f0188000f001f00230000372322263d0134363b0132161d011406032322263d0134363b0132161d0114061721 3521fe460407070446050606054604070704460506069cfe7901873206053f040707043f0506010106053f050606053f0506733b0003000cffde01ac01a60012001a0022000001071615142322270727 3726353436333217370514173726232206173236353427071601ac3d21b24b2c39223e1d5e53472e37feec09a81b2e2d3b682f390aa91b018b443451cc283f1a4632516666273fe32a1fbd2146e74850 2a20bd250002003dfff6017b023b0017001b000001331123270e042322263d01331514163332363536272327330136443f060205141726154d3d43262b2c3503293977490185fe7c39020a17120e4852 f4f034343b32eb33830000000002003dfff6017b023b0017001b000001331123270e042322263d01331514163332363536370723370136443f060205141726154d3d43262b2c35031d7738660185fe7c 39020a17120e4852f4f034343b32ebb6838300000002003dfff6017b02450017001e0000011123270e042322263d013315141633323635363127072337331723017a3f060205141726154d3d43262a2d 35025942345a385a340185fe7c39020a17120e4852f4f034343b32eb955883830003003dfff6017b021b00170023002f000001331123270e042322263d013315141633323635362723223d01343b0132 1d01143323223d01343b01321d01140136443f060205141726154d3d43262a2d3503893a09093a09893a08083a090185fe7c39020a17120e4852f4f034343b32eb500934090934090934090934090000 0002001aff6b019e023b0003001a000001072337173302070e032b01353033323e02373631033313014677386659488c270e20241912362e0f17120a060ca0487b023b8383b6feaf62232c1205360c18 13101d017ffed00000020032ff6b01860220000d00170000133216151423222715231133153612323635342622061514da505bab432044441f185937395638018d6666cc41ca02b4d03dfe9d47505046 465050000003001aff6b019e0211000b0017002e00001323223d01343b01321d01143323223d01343b01321d0114173302070e032b01353033323e02373631033313af3a09093a098939090939090c48 8c270e20241912362e0f17120a060ca0487b01cb09340909340909340909340946feaf62232c1205360c1813101d017ffed0000000030026fff501920208002b003a003e0000251514161f012326270e 012322263534363332313c022e052322060f01353e06333203323e02272a02230e0115141613233533017e0a0505440907154c2641505b5b5c0206080f141e122647101103190b1811181a0da8c22534 1a0a0101232f0b3c3433aadddde27419370f0f16252025403c3e46010f09120d100b0a05120a093f01090308030402fe9b1d2f321a02202c262401a93400000000030015000001a3006a000f001f002f 00002532161d0114062b0122263d013436332332161d0114062b0122263d013436332332161d0114062b0122263d01343633019605070705460507070551050707054605070705510507070547040808 04690705510507070551050707055105070705510507070551050707055105070001001efff901990214002b0000012207330723061514153307231e0333323637150623222627233733263437233733 3e01333217152e01012c6e14b212a30184116f061b262517143d1b2f3d58670e41122c02023e122f0e675341301c3d01dc90241e04110f252c3c1d0a1318471c685f251d091c245f691d481815000000 00010018008101a0012c00050000011523352135019f3efeb7012cab703b000000000016010e0001000000000000004700900001000000000001000d00f4000100000000000200070112000100000000 0003001a01500001000000000004000d01870001000000000005002301dd00010000000000060014022b000100000000000900210284000100000000000d000b02be0001000000000010000d02e60001 000000000011000703040003000104090000008e00000003000104090001001a00d80003000104090002000e010200030001040900030034011a0003000104090004001a016b00030001040900050046 0195000300010409000600280201000300010409000900420240000300010409000d001602a60003000104090010001a02ca0003000104090011000e02f40043006f0070007900720069006700680074 00200028006300290020003200300032003600200044006900730063006f002000480065006c006c006f002c00200043006f007000790072006900670068007400200028006300290020003200300031 0039002c00320030003200330020005400720069007300740061006e0020004700720069006d006d006500720000436f7079726967687420286329203230323620446973636f2048656c6c6f2c20436f 707972696768742028632920323031392c32303233205472697374616e204772696d6d65720000500072006f0067006700790046006f00720065007600650072000050726f676779466f726576657200 0052006500670075006c006100720000526567756c6172000031002e003000310032003b00500072006f0067006700790046006f007200650076006500720052006500670075006c006100720000312e 3031323b50726f676779466f7265766572526567756c61720000500072006f0067006700790046006f00720065007600650072000050726f676779466f72657665720000560065007200730069006f00 6e00200031002e003000310032003b0046006f006e007400730065006c00660020004d0061006b0065007200200033002e0035002e00310037000056657273696f6e20312e3031323b466f6e7473656c 66204d616b657220332e352e31370000500072006f0067006700790046006f007200650076006500720052006500670075006c00610072000050726f676779466f7265766572526567756c6172000054 00720069007300740061006e0020004700720069006d006d00650072002c00200054006800690065006200610075006c007400200043006f00750072006f007400005472697374616e204772696d6d65 722c20546869656261756c7420436f75726f7400004d004900540020004c006900630065006e0073006500004d4954204c6963656e73650000500072006f0067006700790046006f0072006500760065 0072000050726f676779466f7265766572000052006500670075006c006100720000526567756c6172000000000200000000000000000000000000010000000000000000000000000000000000c20000 000100020003000400050006000700080009000a000b000c000d000e000f0010001100120013001400150016001700180019001a001b001c001d001e001f002000210022002300240025002600270028 0029002a002b002c002d002e002f0030003100320033003400350036003700380039003a003b003c003d003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050 005100520053005400550056005700580059005a005b005c005d005e01020060006100a30084008500bd009600e80086008e008b009d00a9008a01030083009300f200f3008d0097008800c300de00f1 009e00aa00f500f400f600a200ad00c900c700ae006200630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d100af006700f0009100d600d400d5006800eb00ed0089006a0069006b 006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d007c00b800a1007f007e0080008100ec00ee00ba010400ab010501060b766572746963616c626172096f 76657273636f726507616d6163726f6e044575726f07756e696539313200000000000001ffff000200010000000c00000010001800020000000400000002000000010000000100000000000100000000 e50db79300000000e5afbb4200000000e5b3d43b ]], ["fonts/Cousine-Regular.ttf"] = [[ 00010000001101000004001044534947000000010000ab44000000084646544d4ee467c80000ab6c0000001c47444546010500040000ab4c000000204f532f32f9269e4f0000019800000060636d6170 5d08ad9f000003b00000027a637674204d165eb5000011a00000023c6670676d73d323b00000062c0000070567617370001800090000ab3400000010676c796639545d7f000015900000894468656164 f6dda5880000011c00000036686865610b7802620000015400000024686d74784f0a46ca000001f8000001b86c6f63616c1a4dd2000013dc000001b26d617870047c026700000178000000206e616d65 11e538f900009ed400000a32706f7374ec7cffc70000a9080000022a70726570d998f79400000d340000046a0001000000010000bd3316a55f0f3cf5001f080000000000c96f2dd500000000c96f2dd5 fff6fe3904d606a80000000800020000000000000001000006a9fd99000004cdfff6fff704d60001000000000000000000000000000000040001000000d800790005006a000400020010002f005a0000 032d015200030001000304cd019000050008059a05330000011d059a05330000036100660212080502070409020205020404a00002af400078fb00000000000000003141534300400020221904e7fe7e 022606a902676000009fdfd70000043a054500000020000104cd00440000000004cd000004cd000002030115003600420000002b01f60156015000f800740103014e01f00072007c0094009000800067 00800097009e0085008d01f00160007400740074005e002c000000a2007100a200a200c2007100a200ca00b000a200ed008100a2006600a2006600a2004f004c008e000a0000002400240049019a0073 010e0085fffb0192008000b30082008a0085008a008f00b9008f007500ec0086006300b3008200b3008a00f200a700be00b900450015005e0042009300e3021300a7006c020300850038009e00340213 009f014f001f00ce007f0074001ffffb014700740138013201920090007f01f00077011d00e2006b001b0011000b00990000000000000000000000000001007100a200a200a200a200ca00ca00ca00ca 001b00a200660066006600660066009d0038008e008e008e008e002400a2008e008000800080008000800080001400820085008500850085008f008f008f008f007d00b3008200820082008200820074 006e00b900b900b900b9004200b90042008f0014001c011b017400ff00aafff6018d018f015d00b100b200b20150015a016e00cc005b01f0012500fa00ea00c500000003000000030000001c00010000 00000174000300010000001c0004015800000022002000040002007e00ff0131015302c602da02dc2014201a201e2022203a204420ac22152219ffff0000002000a00131015202c602da02dc20132018 201c20222039204420ac22152219ffffffe30000ff8fff6ffdfdfdeafde9e0b3e0b0e0afe0ace096e08de026debcdeba0001000000200000000000000000000000000000000000000000000000000000 00000000000300620063006400650066006700680069006a006b006c006d0010006e006f0070007100720073007400750076007700780079007a007b007c007d007e007f008000810082008300840085 0086008700880089008a008b008c008d008e008f0090009100920093009400950096009700980099009a009b009c009d009e009f00a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad 00ae00af00b000b100b200b300b400b500b600b700b800b900ba00bb00bc00bd00be00bf0000010600000100000000000000010200000002000000000000000000000000000000010000030405060708 090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758 595a5b5c5d5e5f6061008485878991969ca1a0a2a4a3a5a7a9a8aaabadacaeafb1b3b2b4b6b5bab9bbbc0070636468ce769f6e6a00746900869800710000667500000000006b7a00a6b87f626d000000 006c7b0003808395c1c2c6c7cbccc8c9b700bf00d1d2cfd000000077cacd00828a818b888d8e8f8c939400929a9b99c0c3c56f0000c4780000000000404559585554535251504f4e4d4c4b4a49484746 4544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c4523466020b02660b004262348482d2c452346236120b02661b00426 2348482d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0406120b06660b004262348482d2c4523462361b0406020b02661b040 61b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0042651582320b00d44235921212d2c20204518684420b001602045b0 4676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23 442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b00361592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c 234445b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b005251023208af500b0016123edec2d2c01b0062510f500edec2d2c4623 46608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a2d2c2045b0032546524bb013515b58b0022546206861b00325b003253f 2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c21210c6423648bb84000622d2c21b08051580c6423648bb82000621bb200 402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b53588ab004254964234569b0408b61b08062b020616ab00e23442310b00e f61b21238a121120392f592d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef68a10b00e2344b00ef6b00e2344b00eed1b8ab0042611122039232039 2f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b21 21592d2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034 005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923442310b029e01b2121212121592d2cb0024354584b53234b515a58381b2121591b2121 2121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b0042510b005252046b0042523423cb00425b0072508b0072510b0062520 46b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b00825082058021b0359b00525b003254348b00425b0072508b00625b00325b0016043 481b2159212121212121212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b0042508b0022543482121212d2c452320451820b00050205823652359236820b04050 5821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a58381b2121592d2cb000214b5458381b2121592d2cb002435458b046 2b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b0 00535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb102 0042b123018851b1400188535a58b910000020885458b202010243604259b12401885158b920000040885458b2020202436042b12401885458b2022002436042004b014b5258b2020802436042591bb9 40000080885458b202040243604259b94000008063b80100885458b202080243604259b94000010063b80200885458b202100243604259b94000020063b80400885458b202400243604259595959592d 2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a236542b00b234201b001233f00b002233fb10102060cb006236542b0 072342b00116012d2c7a8a104523f5182d0000004064090304fd01f550281ff246281ff1462a1ff046351f8bee9beeabee036bef8bef02bbef01a4ef011bef5bef6bef0304ec44ec020aeb46ff1fe7e4 261fe6e43d1fe5e41e1fe3e2461f0be20140e246161fe1e0461fbbe0cbe0dbe00340e0333646e046181fbc0114003e011200550113400c3d0355df3ddd55de3ddc55bb41090116000100540116006401 160002ffc00116b30c164620b80116b2010200bc01160010011600020115b2dc3d1fb80111406303ff1f10dd20dd40dd50dd80ddb0dd0620dc50dc80dcb0dc040fdc01d015331f5fc86fc87fc8035fc3 6fc37fc303bfc201c150261f70be0120be30bec0be0370be80be020fbc1fbc022fbc3fbc6fbcafbcdfbc05b9ad261f20b830b850b870b880b805b8ffc0401cb813294610b70120b750b780b7b0b70480 b5b0b5020fb33fb3efb303b8010d402baa481f80b090b002b0b0c0b0d0b0032faf3faf02a0adb0ad02c0add0ad022fac3fac029fab01c0aad0aa02410f010f0032010e00550000010e0010010e002001 0e0070010e0004000f0110401501509c609c709c039996261f9846261f3097409702b8ffc0b396161c46b8ffc0402a960e1146951bff1f0f94af94bf940340941d31464094161b4640940c0f460f932f 933f937f93ef93050fba010c006f010c402002928d261f9153ff1fdf90013090011f902f90026f907f9002008f108f208f03b8ffc040208f181c46208e308e024f8d5f8d6f8d03308c010f8c1f8c2f8c 03408c10134610bf010b0020010b0030010b0003ffc0010bb2172046b9ffc0010b40501014468b82261f894a3c1f88873d1f87843c1f864aff1f9f8501108420843084033083017f82014082090c4673 50261f6f46351f6e46351f1a01185519331855073303550603ff1f6050261f5f50261fb9ffe00107b21f2646b9ffe00107401f131c465e5a481f5c46311f5b5a481f5a46311f13321255050103550432 0355b80108b51b3c1f0f0301b901190118b2351f40b80118b2172846b8010a402550261f52501b1fef51ff510240513538464051252846cf5001df4c014c461d1f4b46481f50b8011b405a014a46261f 4946351f4846351f4746351faf4601df46ef46028046011632155511010f5510320f55020100550100011f1f0f3f0f5f0f7f0f040f0f2f0f4f0f6f0f8f0fdf0fff0f073f0f7f0fef0f036f00014f0001 a016010501b80190b154532b2b4bb807ff524bb009505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0 101db11600425973747374752b2b2b2b2b017374752b2b2b2b73002b2b74742b2b732b2b2b2b732b2b2b2b012b2b2b002b2b2b2b2b2b2b2b2b012b2b002b012b737474732b2b2b2b2b2b2b73002b7374 74742b75737474742b2b73732b2b2b732b012b2b732b2b007374732b017373740073747473742b7301730073742b732b737401737475002b73017400742b7373732b2b735f732b74742b2b2b2b012b2b 742b2b5e732b002b2b2b012b5e73007373737473012b2b2b002b73185f5e000005cc05cc007d054500150060054500150000000000000000000000000000043a001400770000ffec00000000ffec0000 0000ffec0000fe57000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000008000000000000b400bd00aa00a000c800b400850000000000000088007e00a500c000000000000000000000000000bf00c900ab008c00bc009b008d0000000000000000000000000000 00000000000000000000000000b900b4007c000000000094005f000000000000000000000000000000000000000000000000000001a8006f007800a400c80083008d00bb005e018a0103006000740081 00b800c0005004b104c3fe4c00eb01b200c30109007b012b029600c9009600000000000000000000000000000000000000000000009200a8006b009200b7006b009b0000000002f20092023e006e02a5 0345008900a00060024c000000c30000014e00a4015b005e00800069006f0000005e00680000000000000000000000000026034a0087007b0000007500680000000000000000000005820233000bfff4 00830089008f009600690071005b005200000000000000b202030000008d031f00bb00ae00b500000000008b000000000000000006a9037002bc0208fd9900910091004d004d006400640181009f00a8 fe68fe9c009b014501450090fef60017007a0545024d000cffee0598028b006e004c0062004600e8004405110000002c002c002c002c0054007e01300230030604080424045c0492050c054a05760592 05ac05da065c06a8072207e8083208bc0964099e0a6a0b0e0b340b4c0b9c0bd60c260c9c0ddc0e3e0ec20f540fae0ff2102c10b010f4113a118411ec120e12a41306137813d0145e14da158a15c2161a 167e177417f8185a18ac18d8190819301978198c19aa1a581ad61b5c1bde1c681cc81d761dc61e061e5a1ece1efe1f941fea204e20d6215c21b02242229a22f4235e244e24ca255625982618263226b2 2714273e27c4285e292829ac29d42adc2b082c0a2c9c2cec2d0e2de42dee2e4e2ea22efe2f862fa430123054305c30b030f0314c319a31c031de3200327a329232aa32c232da32f4330c337c339033a8 33c033d833f2340a3422343a345434d034e83500351835303548356235cc367a369236aa36c236dc36f43752380a3822383838523870388c38a43984399839b039c639dc39f43a103a263a443a683b1a 3b303b483b5e3b743b8a3ba23bee3cac3cc43cda3cf23d0c3d223da63dbe3dee3e683f203f483fc8402040344048406e409840c6410a415641a441e0420e423c425e43004322436443bc444a44a20000 0002004400000264055500030007002eb101002f3cb207041ced32b10605dc3cb203021ced3200b103002f3cb205041ced32b207061dfc3cb201021ced323311211125211121440220fe240198fe6805 55faab4404cd000000020203000002c90544000300070029401503079802000410040204040809010102059d040203003f2fed11392f111201392f5d33ed323130012303330335331502b19418c4c6c2 018d03b7fabcc9c900020115034d03b605cc0003000700274014039602020907962f060100060106050000060200003f33332f32012f5d5ded12392fed31300123033301230333038c8e28e0fe158d29 e0034d027ffd81027f000000000200360000048b0545001b001f00f0b90004fff040990d1148061d161d261d0306011601260103120f0e0b040a13081d1c1504140904010019041805161f1e07040617 13ac1405ac0617ac181a2f033f0302031a0318300640065006031018201802e018f01802140618180614030a2111110c0c09ac000a010a08040caf0d1d010d1c0010af111915114f11014f115f11ef11 0311401f22487f0d8f0d9f0d034f0d5f0d020d110d11051713030a05002f333f331239392f2f5d712b5d7111333310ed323211333310ed3232012f5ded332f332f111217392f2f2f5d71711133332f5d 2f10ed10ed10ed1112173911121739111217391112173931305d5d2b010321152103231321032313233533132335211333032113330333152103211303a2430104fee5586e56fe95546e54c9e143f101 07596e58016b586e58d3fd4045016a430341fec36cfe680198fe6801986c013d6c0198fe680198fe686cfec3013d000000030042ff73047e05c400390044004f011940c7443d543d02654e016e470165 3c016a2f01752a852a0276298629027622862202650e01790a890a02790989090279038903027a1f8a1f022c6f2d2d454b3327063f241107071f7500850002006f004510452045604570450510452045 304570459045a045b045074545510c6f0b401220488e0b010b0b3a6f001f401f02001f101ff01f031f324073244a1273333f3f242d2d272425402027482540121748252524064b117308000c100c400c 500c600c05400c500ca00cb00cf00c050c0c089007010707050818003f33332f5d11332f5d7110ed323f332f2b2b1133332f11392f33ed3210ed32012f5d71ed332f5d2bed11332f5d71ed5d12392f33 3333cd32323211332fed5d3130005d5d5d5d5d5d5d5d5d5d5d015d01140e02071523352e0127371e0317112627262726232e0535343e02373533151e0317072e0327111e0501141e0217110e0301342e 0227113e03047e3872af7780d7f322aa0b2d4d704d0807040603023162584c381f40729d5d806691664014ae0a273f583b3a7267584124fcb028455d3647623c1b02a430506a3a416b4d2b017c4b805f 3905a1a107b9a725365b44290401e902020102010c1d273749613f52774f28038282042c50754c21304f392104fe560e1f2b3a516c023636472f1e0e019d03213545fd5e3f5134210ffe29041e385200 00050000fff404ce055100030017002b003f005300c1b9003effd8400e090e483828090c483428090c482eb8ffd8b3090e4816b8ffd8400e090e481028090c480c28090c4806b8ffd84016090e487902 8902020203560076008600030001031001bafff00003ffc0403a0a0e481f012f013f01030301030113314ab43bb531b470408040024040135518b409b522b41345b62cb74fb6361927b60eb71db60407 02060018003f3f3fedf4ed3fedf4ed012fedf4ed1112392f5dfdf4ed111239392f2f5d2b383811335d11335d3130002b2b2b2b2b2b2b2b3323013325321e0215140e0223222e0235343e0213342e0223 220e0215141e0233323e0201321e0215140e0223222e0235343e0213342e0223220e0215141e0233323e02dd9103a493fca03a674d2d2d4e683c3c694e2c2d4e6ac61223332123362412132435222033 241302083a674d2d2d4e683c3c694e2c2d4e6ac6122333212336241213243522203324130549081f4d816360825023234f836063814d1ffeb0425835151635574240573617173657fed81f4d81636082 5023234f836063814d1ffeb0425835151635574240573617173657000003002bffec04a1054d003d004f005f00f44018734e834e0279518951026558755885580369530139250120b8ffe8b3090e481c b8ffe8b3090c482eb8fff0403d090c48251201061216120248491923493e303e01303b013b3b3149306b50010c141c146c1403284b5314043e2d5034050419703e803e903e033e3e3019b8ffc0403f10 13483f3001193019306156480f400b17480f602d702d802d036550012950010550342d040a30454b554b654b034b14302853055b43511e03375b51000a16003f33ed323fed1217395d2f1217395d5d5d 012f2bed1239392f2f5d2b12392f5d1117391217395d5d10ed322f5d5d10ed10ed3130005d5d2b2b2b5d015d005d015d005d05222e02270e0323222e0235343e02372e0335343e0233321e0215140e02 071e03173e0137170e01071e0133323637150e0101342e0223220e02151416173e03032e01270e0115141e0233323e020430294c433a161c4756673b6d9e66312d4e6b3e0f1b150c2b57845945765630 4472934e1f3e444a2a2a3f14911a57312b61281a30151838febb182d40272c49351e2617407155314a59a142555e2040614127473c310c15232f1a193226183a668a504d7e6751201c44494c253e6d51 2e23446440476c5646213664605d2e57c6792b8be55e36330709870b0b044922382716192e432a41742b1b323a47fccb64e1742e9565345c4427131e26000000000101f6034d02d605cc0003001c400d 03960002010202040500000200003f332f111201392f5ded31300123033302ac8d29e0034d027f0000010156fe57037b05cc0015002840161006f0110f051f050205051700f0000b010b1000061b003f 3f012f5ded12392f5d33ed32313001141e0217232e0335343e0237330e03021129588960be5c87592b2b59875cbe6089582902128af4e6e17671dbe6fb9090f9e5d97176e1e6f40000010150fe570375 05cc00150024401300f00b0b171105f0100006100602061000051b003f3f012f5d33ed3212392fed313001140e0207233e0335342e0227331e0303752a58875cc0608a582a2a588a60c05c87582a0214 90fbe6db7176e1e6f48a89f4e6e17671d9e5f900000100f802fc03d405cb000e00af40175b066b0602000350036003030f095f096f09030b030708b8ffc0404c0b114808080a0d0504400b1148040402 0e0e0a0d0e700a800a020a060e000d100d020d0d0f10020a0a010b000c750c850c02030904087f0b8f0b020b0806090c0b050d057007800790070307b8ffc0b6090c4807070d00003f332f2b5d331217 392f5d113311335d11331133331133111201392f5dcd39c45d2b0118104de4392f2b331112392f2b3331305f5e5d5d005d0125170517070b0127372537050333029f01082dfee6b977969c77bdfee82d 010b0c8804a4678449fa480102ff0048f849866b012900000001007400b40457049e000b004940250b0e0104020e040901aa40060002010a0302020c0d020e0407050e300701070004ad0905b3003f33 ed32c65d2b0018104de6111201392f5f5e5d331aed32c62b0118104de6313001112311213521113311211502af93fe5801a89301a80260fe5401ac9201acfe549200000000010103fe9502b5012b0003 00394027090019000200100e1148090219020202100e114801990297039a2f006f007f000300009c019b040010f6ed012f5dedfded31302b5d2b5d011321010103a90109fec9fe950296fd6a0001014e 01d0037e02700003001d400f03030500001000020000ba2f010101002f5ded012f5d12392f313001352115014e023001d0a0a000000101f0000002db012b0003001a400c039600000100000405019b00 002fed111201392f5ded31302111331101f0eb012bfed50000010072ffec045905cc0003003d401c8a010139016901790103010210020205850301360366037603030300b8fff0b70000010003190100 003f3f012f5d38325d5d12392f38335d5d313017013301720335b2fccf1405e0fa2000000003007cffec044f055a00130027002b007940523620014611561102460d560d024907590702490359030210 2a202a02402a502a020029012a292a291e006e401450140200140114142d1e6f000a100a020a4f28014f285f28022829292319730f0723730519003fed3fed12392fcd5d71012f5ded12392f5d71ed12 39392f2f5d5d713130005d5d5d5d5d0114020e0123222e01023534123e0133321e011207342e0223220e0215141e0233323e0225353315044f4d85b46667b2834b4b84b46a65b1844cb7284e71484c74 4f28294f724947724f2bfe58eb02a3c3fef7a44747a3010ac3cc010c9f40409ffef4cc9fd47e34357ed39f9ad280383880d222f9f9000000000100940000046a05450012005940390011011111106f02 08081f01010f013f014f015f018f019f01af010701010e100201100270028002030202131408730909030e061001730018003fed323f33332fed111201392f5d7133332f5d71332f10ed322f5d313033 3521110e032335323e0237331121159d01b713607d8e424a8f7c601aa601619103fd2847341f94223d5432fb4c910000000100900000043c055a00260087405c7506850602392001741b841b02761a86 1a0277158715027716871602690a016b1001591001051a0126261d6e1f083f08026f08bf080208080028126e131300602470248024032424cf000100001000020012120d7318070124730018003fed32 3fed332f012f5d5d332f5d11332fed1112392f5d71ed322f3130005d5d5d5d5d5d5d5d5d5d33353e0535342e0223220e0207273e0333321e0215140e04072115902c90a3a585542747613b365d462c07 b809406fa26a69a7753e5687a49c802002d37561a4918481854a3c57391b1e3c593b114c86653a305d8a595ea19082808146920000010080ffec044b055a003b00e64063753985390263390140395039 0278348834026c34014b345b3402742f842f02062e762e862e0377298729026c25015a2501631201640d01550d017908890802790789070279038903027b028b0202361a316e3f205f20022020006e13 40130100130113b8ffc0403c1518481a131a130a3d266e27270b6ecf0adf0aef0a03000a100a020a3619731a1a102c262623732c07107305400b900b02400b900bf00b030b0b0519003f332f5d7110ed 3fed332f1112392fed39012f5d5ded332fed111239392f2f2b5d7110ed332f71ed11393130005d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d01140e0223222e0227371e0333323635342e022b01353332 3e0235342623220607273e0333321e0215140e0207151e03044b3f79b27482b4743a09ba082b4a6d49889b456779336662336e5b3b858377930cb50b507b9e5977a96c3325496f4a527d542b01725b91 6436416b894911385c42247e79445a35169c1937593f6a777a6f0e5d8a5b2d38608149376756400f04093c576a00000000020067000004650545000a000d00554035690679068906037f090109090801 6f0d069002a0020202020f0c6f1004010400047308050f0c1f0c2f0c6f0c040c0c010b06060118003f3f3312392f5d3333ed32012f5ded12392f5d3333ed32322f5d31305d0111231121350133113315 09012103a9b4fd72027bc7bcfe90fe0c01f4013ffec1013f8c037afc888e0343fd4b000000010080ffec044b0545002c008e405e69087908890803690779078907034a175a1702451355130222400d11 482222006e152524211f6f20200a4015010015c015d0150315152e0b6ef00a01cf0adf0a02000a100a020a257320201a736f2801282810247321061073050b0b0519003f332f10ed3fed12392f5ded33 2fed012f5d5d5ded12392f5d7112392fed33323210ed322f2b3130005d5d5d5d01140e0223222e0227371e0333323e0235342e0223220e02072313211521033e0133321e02044b407ebb7b6fa572430e b60b284565484672512c2a4e71482d4c413517b02f0321fd851d30906369a8764001bc64ab7b46345b7a4615284b3b232b5075493c674c2b101c251402d891fe57253540719c000000020097ffec0448 055a0024003800ab407d7a038a03027a028a0202680378038803036723772387230367227722872203453755370243315331024a2d5a2d024b275b27021c1b2c1b3c1b03156e1414006eaf2501402501 0025c025d0250325253a1d2f6e900aa00a02000a100ae00af00a040a2a736f2001102020200220203418730f8f150115150f0734730519003fed3f332f5d10ed12392f5d5ded012f5d71ed3212392f5d 7171ed322fed3130005d5d5d5d5d5d5d5d5d5d01140e0223222e023534123e0133321e0217072e0123220e02153e0133321e0207342e0223220e0215141e0233323e0204483b73aa6f7bb87a3d4582bb 76487e674e17ac1c7b514a78542d31b273609d6f3cb724486a4631645133284b6a424167482601be64ab7d465dacf598b10110b85f1e436e501f5b514586c5815b5f3e72a06b4370502d214162414881 62392d52740000000001009e0000042d0545000e00354010056e06060c006f0b0b10000c100c020cb8ffc0400b1418480c000c730d060518003f3fed32012f2b5d12392fed12392fed313001060a0215 23341a0237213521042d60ab824cbc5086b061fd1f038f04ba8afedafecffec69f9e013b013201248591000000030085ffec0446055a0029003d005100b6407e7528852802760c860c02780288020278 08880802771d871d02792289220278128812026a46016a4001655001654a01653c0165360124101f346e151f6e2a152a152a0a006e403e01003ec03ed03e033e3e53486ee00af00a02cf0adf0a02000a 100a020a241010437339394d761a861a022f731a0779058905024d730519003fed5d3fed5d12392fed391133012f5d5d5ded12392f5d71ed1239392f2f10ed10ed1239393130005d5d5d5d5d5d5d5d5d 5d5d5d5d01140e0223222e0235343e0237352e0335343e0233321e0215140e0207151e0303342e0223220e0215141e0233323e0213342e0223220e0215141e0233323e0204463975b57d7cb577392f4f 65363b5d3f213970a66d73a96f36213f5d3d3d684d2bde1b3e644946633f1c163a665056663711231c4473564f6f452020467251536f441d017a54916c3d3d6b91534773543409040e3e546435447d60 393a607e443464543d0c040a35547102332f523c23233c522f2552452d2e4552fdbb2d59472c2c485a2f3b654a2a294b670000000002008dffec043f055a0024003800a540777a088a08027a078a0702 67207720872003681a781a881a03453755370245315531024a2d5a2d024b275b27021311231133110313006e3f258f259f25af2504c025d0250225251d3a0b6e0a0a2f6ee01df01d02cf1d01001d101d 021d347313184013164818180e2a7322070e7305700b800b020b0b0519003f332f5d10ed3fed12392f2b33ed012f5d5d5ded332fed1112392f5d71ed333130005d5d5d5d5d5d5d5d5d0114020e012322 2e0227371e0133323e02370e0323222e0235343e0233321207342e0223220e0215141e0233323e02043f4684bd775182664816ac1c775b4a7855310115495d6b38609b6c3b3f78af6fecf1c425496b46 41684827234668453267533502bfb1fef2b75d2146704f1b5b554484c4812f4a331b447aa96568a97842feb4b04983633b2d53734642735732224365000201f0000002db043a00030007002440120605 039600000100000908049b050f019b00002fed3fed111201392f5ded33323130211133110311331101f0ebebeb012bfed5030f012bfed50000020160fe950312043a0003000700000111331101132101 01f0ebfe85a90109fec9030f012bfed5fb860296fd6a000000010074009a045704aa00060077b5000152050405b8010d401006001406000506010201520304010403b8010d4028020114020103020608 040000100002000100040402053f066f067f0603064012154806030f020102002f5d332f2b5d3312393d2f333301182f5d3310ded4c187042b1001c187042b10c41001c18704182b872bc43130133501 150901157403e3fca6035a023bcd01a29afe92fe91990000000200740158045703ec00030007004c40370702090400011001020105ad1f047f049f04af04bf040504401216480400ad30015001600170 0104500170018001b001d001050f010101002f5d5d71ed2f2b71ed012f5d3310ce32313013352115013521157403e3fc1d03e303589494fe0094940000010074009a045704aa00060077b50601520102 01b8010d401000061400060100050401520302050203b8010d4028040514040503040206080400001000020006050202030f040104013f006f007f0003004012154800002f2b5d322f5d33393d2f3333 01182f5dc410ce3210c187042b1001c187042b10c41001c18704182b872bc431303735090135011574035afca603e39a99016f016e9afe5ecd0000000002005e00000431055a0027002b006d40496906 7906890603690479048904034a1b5a1b02072517250266007600860003092b980a28281e009800130113132d1d981e0a400f14480a0a23299d28662376238623031d1d189e2304003fed332f5d2fed11 392f2b012fed12392f5ded12392f33ed325d3130005d5d5d5d01140e0607233e0735342e0223220e0207273e0333321e02013533150431253e4f524f3f2701af02273e4e504d3c25294d6d44446f5232 07b80c4a7eb0706cb17e44fd8fc303ea456852423b3b445337436651413b3b4453353754391e2647653e0c5a976c3d305d89fbbcc9c900000002002cfee504a505cc005f0078013b4091014411440235 3f553f753f03013e113e026c347c348c340317180b0e486c087c088c08036c667c66024a665a6602265d016a5301654975498549037f3f8f3f023f400b0e487e3901036f2a7f2a8f2a03024f2a5f2a02 17180b0e486a377a378a37036951014b0f4c1f4c024c4c5600d337292fd30a60280a6ad21a37401418481037012f1a3f1a02370a1a1a0a37037a41b8ffe8b50d114841d356b8ffc0402617204856326f d6150f051563d621282819260126210f151f152f159f15af15059021a0210221b8ffc04017090c484b152121154b03463c100d11483cd55b0046d551b8010f003fed3fed2b1217392f2f2f2b5d5d1133 5d332f10ed11333310ed32012f2bed2b1217392f2f2f5d5d2b10ed11333310ed3210ed11392f5d33005d015d3130002b5d5f5d5f5d2b5d5d5d5d5d5d015d2b5d5d5d5d01140e0223222e02353c013e01 35230e0323222e0235343e0433321e0217333733030e0315141633323e0235342e0223220e010215141e0233323e0237170e0323222e010235341a013633321e011205342623220e0415141e0233323e 02373e0304a5294e72481e3427160101060f2e3b492a3f563517172c415162382a3e2b1c0905207463080f0b061d1428412f193565946078bb7f423b6fa2663b66595126472b616f7e497fcc8e4d54a1 e99683c3803ffe62463b254034281b0e0b1b2c2027473a2e0d0308070402f390efac6010253c2c020b0c0a032747361f416b8b4a4c96887555301b2f3f2497fe052a51493d1534245091c97981e0a660 86e7fec8b198fab362192a3a21572544351f71d00126b6d1016301049276c8fef8766a6d2c4b647177393c674b2b37648f5713343631000000020000000004cc05450007001400724042130203050152 030d035e04051404050304140100060152000d005e07061407060d041007010707167f048f0402040701025f1413135a0d014b0d010d060503040012003f323f33335d5d392f33ed322f012f5d11332f 5d1239872b872bc410c0c01000c18705182b872bc410c0c031302103210323013309012e03270e03070321040a8afdcd89c401fed901f5fdf10d1c171104041017190d9701cf017efe820545fabb03ba 264e46350c0c36464e25fe59000300a200000480054500160021002e0077404f652d016a24016620017b028b0202740b840b940b03070b016f12014b125b120212290d5a17400d1448171706005a0022 012222301c295a00061006a006b006040612285f1c1c291b5f0703295f0612003fed3fed12392fed39012f5ded3212392f5ded12392f2bed11395d5d3130005d5d5d5d5d5d01140e0223211121321e02 15140e02071e030134262b011133323e0213342e022b011121323e020480548ebc68fe28019c75b88043214364445583582efeee9797dfe15172482151335d8250fc010a497d5b33017c67905b2a0545 264f7c563865513b0e0938577102286b5bfe601f3950fdd93f58391afe2217385e00000000010071ffec0476055a002900a4402d392701461d561d661d03661c01360301201f301f02601f701f02a01f 011f1f20401d244820200a0b0bb00a010ab8ffc04045090c480a0a2b7600860002005b30154015501503001510150215461a561a02255f1a20201a04100a200a300a600a700a05300a800ad00ae00a04 0a0a4910591002055f1013003fed5d332f5d713f332f10ed5d012f5d71ed5d12392f2b5d332f11332f2b332f5d71723130005d5d5d5d01141e0233323e0237170e0323222e01023534123e0133321e02 17072e0323220e02013a2854835c3f654f3a159f1c52749b668dcd87414084ca8a65986f4d19a80f3449613c597f522602a983cb8c48304e6636414685694065b801029ea60101af5b375d7942412e58 442a4487c7000000000200a2000004650545000c00170061404575028502027a108a10027017801702141724176417037f0f8f0f021b0f2b0f6b0f03340b01340a013b0301005a000da00d020d0d1914 5a000610060206135f0703145f0612003fed3fed012f5ded12392f5ded3130005d5d5d5d5d5d5d5d5d0114020e0123211121321e0207342e022b011133321204655098dd8cfe8e01379ef3a655c03872 ac7579a2d4ce02b0a8feffae5905454da2faac87c07939fbf3010a00000100a2000004620545000b005a403b07400a14480707000a0303000a010a0a0d05095a000010000200085f0f053f057f058f05 046f058f059f05bf05df0505050509045f0103095f0012003fed3fed12392f7172ed012f5ded3212392f5d332f1112392f2b3130331121152111211521112115a20397fd28029cfd64030105459cfe5a 9afe339c000100c20000043d054500090047402d02020608080b01055a000610060206045f3f017f018f01033f016f019f01030140152948010105005f07030512003f3fed12392f2b5d72ed012f5ded 3212392f12392f313001112115211123112115018102a4fd5cbf037b04a9fe129efde305459c000000010071ffec044f055a00290088404a080201151e251e751e851e0455120127270a25af15011515 1414005ac025d025027f258f250200250125252b361d761d861db61d041d5b300a400a500a03000a100a020a275f2828200fb8fff0400e0d1148185f0f15150f04205f0513003fed3f332f10ed2b1239 2fed012f5d71ed5d12392f5d5d5ded322f332f5d1112392f3130005d5d5d250e0323222e01023534123e0133321e0217072e0123220e0215101233323e023711213521044d245f74894e86c682403e82 c88964976f4b18ab268b6f5a7e4f23a9ac305343310dfedb01df8518362d1e69ba010199a70101af5a34597945386e794587c782fef4feea111719090150a000000100a20000042a0545000b0057403c 0b5a081f002f003f006f007f00056f007f008f00bf000400000d07035a70040100041004a004b0040404025f500701a007b007020707090503040012003f323f33392f5d71ed012f5d71ed3212392f5d 7133ed3130211121112311331121113311036bfdf6bfbf020abf026ffd910545fdca0236fabb0000000100ca000004010545000b005940380606010e0407070000090e70000100045a0f093f098f099f 09044f095f097f098f09cf09df090610090109090c0d04085f0712030b5f0003003fed323fed32111201392f5d5d71edc45d2b110133182f104de4322f3130132115211121152135211121ca0337fec4 013cfcc9013cfec405459cfbf39c9c040d000000000100b0ffec03da05450015004bb7651075108510030bb8ffe840220d1148131308005a111108178009010909000810080208135f14030e5f050909 0513003f332f10ed3fed012f5d332f5d1112392fed12392f3130002b5d01140e0223222627371e03333236351121352103da33659662abcc23bb0a2a3a49296869fec901f501a464a3733eb2c01f405d 3c1d8f8a03099c00000100a2000004cb0545000b00974034740a840a02460a560a660a03640774078407038d00016b007b00024900590002390a01140a0101200b11480a010b720982090209b8ffe040 2d0b0f480809100909000b10000b100b020b0b0d07035a00041004020402070a0176078607020701080503040012003f323f3339395d11331133012f5ded3211332f5d3833332f38332b5d113939002b 31305d5d015d5d5d005d015d5d21010711231133110133090103ebfe19a3bfbf023ce1fe080245027ea9fe2b0545fd5f02a1fdc4fcf70000000100ed0000044c0545000500264016040407035a2f003f 00020000100002000103035f0012003fed3f012f5d5ded12392f3130331133112115edbf02a00545fb579c00000100810000044b0545002c0099b9001effe840130d1148261e361e022a180d1148292a 392a020cb8fff040190b11480d100b11480d0c24241c2c5c2a0040191c4800002e1eb8fff0400d0a11004c1e1b5c001c101c021cb8ffc0b3282d481cb8ffc04009181e481c0615151d24b8ffc0400c0e 1148240d0d2a1d031c0012003f323f33392f332b11331133012f2b2b5ded322b12392f2b33ed11391133332b2b31305d2b5d2b2111343637363706070e01070323032e0327262716171e011511231133 131e0117161736373e013713331103a90102020111110e210ea489a6060e0f1008121301010101a0edb909170b0c0d0e0c0b1809b9e10364336a2c333137352d6426fe4a01b60f292f3118373c30342d 6933fc9c0545fe17174d262c312f2b254e1901eafabb0000000100a20000042a0545001300784024125c00180911480080119011d011e011043f1101c011d011026f117f118f11031111150ab8ffe840 2d0b11480a075c70080100081008a008b00804088c01017a010169010111010903830b01750b01660b010b000812003f33335d5d5d3f33335d5d5d012f5d71ed322b12392f5d5d7171332bed31302101 16171e0115112311330126272e01351133110344fdf804040305aade021005040405ac046a2b2d265927fc940545fb8e282e2762330360fabb00000000020066ffec0466055a0011001d00794056761d 861d02341d01761986190234190179178917023b170179138913023b1301561001451001460d560d0249075907024903590302005b5f12011240191c4800120112121f185b500a01100a010a155f0f04 1b5f0513003fed3fed012f5d71ed12392f5d2b71ed3130005d5d5d5d5d5d5d5d5d5d5d5d5d0114020e0123222e01023534123e0133320003100223220211101233321204664684bf787fc080404482bf 7cf70108c99e989c9c9e99a39402a9adfefab1595eb30105a7ad0102ac56fea5feaa010e0107fef9fef2fef2feec0118000200a20000045f0545000e0019005b403e6617017600860002490f590f690f 03005a7f0f8f0f020f40191c48000f010f0f1b14075a00081008a008b0080408065f1440091148141407135f09030712003f3fed12392f2bed012f5ded3212392f5d2b5ded5d5d3130005d01140e0223 2111231121321e020734262b011133323e02045f3b79b67bfee7bf01cc7dba7c3ec0a4a4f6fe52794f2603b1549b7848fdfe05453a6a955e7d81fded2b4a660000020066fe7d0471055a0020002c008b 4062352c752c852c03352875288528033a267a268a26033a227a228a2203691179118911034a045a0402461f561f02461c561c02055a140b0b005b215f21012140191c48002101142114212e275b5019 0110190119245f1e04052a5f141308605f0f010f002f5ded3fed333fed012f5d71ed1239392f2f5d2b7110ed322f10ed3130005d5d5d5d5d5d5d5d01140e02071e0133323637150e0123222e02272e03 3534123e01333200031002232202111012333212046633628d5a2986651c4017265b31558161461b70a871384482bf7cf70108c99e989c9c9e99a39402a993ebac6d167e72080586090d335f8a570b67 b2f99cad0102ac56fea5feaa010e0107fef9fef2fef2feec01180000000200a20000049905450011001b0097b9001afff0b30f004d10b8ffe040230f11004c8901010b000100200e1148001110111101 041001101003760b860b020b5a12b8ffc040361518487f128f120200120112121d16035a00041004a004b004040410025f1f167f16023f166f169f16ef1604161600155f0503040012003f323fed1239 2f5d71ed32012f5ded3212392f5d5d2bed5d11392f5d33322f38332b5d5d31302b002b21012311231121321e0215140e020701033429011121323e0203bdfe92eebf01e278b3773b2754825b0190f8fe d0fef001185371451f023ffdc1054533618a573e7b674c0ffdab03cddffe2a28435a00000001004fffec0468055a003f00b04079343d016d2d014b1d5b1d026b1001600c01743e843e02743d01403d50 3d02863c01443c543c027637863702742784270204217421842103540b018907017a07018b02017902012a5a2929005a00130113131f41095a7f088f080208345a001f101f021f3413052f60242a2a24 040e5f05400950090209090513003f332f5d10ed3f332f10ed123939012f5dedd65ded1112392f5ded322fed3130005d5d5d5d5d5d5d5d5d5d5d5d5d015d5d5d5d5d01140e0223222427371e0333323e 0235342e02272e0535343e0233321e0217072e0323220e0215141e02171e0504683e7fc386eafefb24b90c30547a5548775530416a854432665e513d22487eac6474a3714414bc0b2b476444506c421d 355b79453770675942260172558f683ab8ae25375a41241b3a5a3f46583823110d1d27354b65436089572829527950213350361c21394e2d3c4b3120120e1f2a39526e000001004c0000048005450007 004a4031070e0104020e04015a0f023f028f029f02bf02cf02064f025f027f028f02cf02df02061002010202080900045f05030112003f3fed32111201392f5d5d71edc62b0118104de6313001112311 2135211502c5befe45043404a9fb5704a99c9c000001008effec043d05450019005e404465157515851503650f750f850f03005a80179017d017e017f017053f1701c017d017027f178f170217171b0d 5a8f0a9f0aaf0a03cf0a01000a100a020a180b03125f0513003fed3f33012f5d5d71ed12392f5d5d7171ed3130005d5d01140e0223222e0235113311141e0233323e02351133043d3a77b57a74ae733a bf193d6950536f441dbe01ea89c27b383575bb87036dfcad618a582828599067034600000001000a000004c205450010008240550f200e1148290f390f022b0f01760386030254036403023603460302 2403010001520f090f5e1000141010000101520309035e0201140201030209021010011010127f028f0202020f020355090144090109000112003f33335d5d3f33012f5d11332f5d12391000c187052b 872bc48718102b872bc43130015d5d5d5d5d5d2b21230133011e0117161736373e0137013302c9c6fe07c90140101d0c0e0d0c0e0c1e10013ec90545fc7a2d612a302f2d3029622f0386000000010000 000004cc05450032014c401121080c004d021810004d02180b0c004c10b8ffe8b40b0c004c1ab8fff040101011004c311811004d31180b0c004c14b8fff0b40b0c004c23b8ffe0401c0b0f004c22180b 0f004c22100a004d01200b11004c00201011004c00b8ffe0b40d0e004c00b8ffe0b4090a004c12b8fff040111011004c12280d0e004c1228090a004c11b8ffe040130b11004c22093209020204090101 0152232b23b80107400c090114090123110152221a22b801074048091114090911000152312b315e320014323200120152141a145e131214131214132b091a031310320132323413092f224f225f2203 22221a3113032b1a0001241a011a1101031212003f17335d113311333f3312392f5d33012f11332f5d1217391000c187052b872bc48718102b872bc48718102b872bc400c18705182b872bc4005d5f5d 012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b31302b2b2b2b2123032e0327262706070e030703230333131e0117161736373e03371333131e03171617323e0237133303fad068050e0f0f0711111211070f0f 0e056ad0d3bd6d080b0505041010070e0f0e066daf6d060e0f0e07101001060a0c0668bd018313343b3f1e464c4d461e3f3b3313fe7d0545fcbd417c31393345431d3d3c3717018ffe7116383b3d1d43 4644667a3603430000010024000004a90545000b00c8405c0909010b060109035903022901010401010302070001080b040b0602070901080a050a06030207020900010702015201080708015e020714 020207050a01520b0405040b5e0a05140a050b0a100a200a02020a020a03060009040804b8ffc040180a1c4804040d08400b1b48080009030604010804120a0103003f333f33121739012f2b11332f2b 12173939392f2f711000c187052b1000c187052b10c48718102b1000c187052b10c410c0c01087c0c0108708c008c0108708c008c03130015d5d005d5d5d0901330901230901230901330266014dcdfe 4d01dccdfe8afe8bcd01dcfe4dcd03440201fd7cfd3f023dfdc302c10284000000010024000004a80545000800964068340644065406035c07013b074b07020907190729070353050134054405020300 0510052005030c0507080e0104020e052f04010406015a0f023f028f029f02bf02cf02064f025f027f028f020410020102020a090603400050006000033f00010000010704030112003f3f3312392f5d 5d3333111201392f5d5d71ed39c65d322b0118104de63231305f5e5d5f5d5d5d5d5d005d01112311013309013302c4bcfe1ccd01760174cd0248fdb8024802fdfd9d0263000100490000048305450009 0075402689080169080157087708022908390849080304081408020801520302035e0708140708030704b8ffc0b30f144800b8ffc0401d090e48040700000704030b2f013f014f01030107045f050302 085f0112003fed323fed32012f5d1217392f2f2f2b2b1000c187052b872bc43130015d5d5d5d5d290135012135211501210483fbc60332fd1703c2fcce03618f041a9c8bfbe200000001019afe5703bd 05cc0007002f401c0207070905f27f008f00023f006f00020000010004f5010005f5001b003fed3fed012f5d5d5ded12392f3331300111211521112115019a0223fe91016ffe5707758bf9a18b000000 00010073ffec045a05cc0003003f401d8b00017a00013900690002000310030305850201360266027602030201b8fff0b70001010102000019003f3f012f5d38335d5d12392f38335d5d5d3130050133 0103a4fccfb203351405e0fa200000000001010efe57033105cc00070029401707f26002010202090400003000020004f5050001f5001b003fed3fed012f5d3312392f5ded3130013521112135211101 0e016ffe910223fe578b065f8bf88b000001008501ba0446054500060063402f85050179048904020504018c0001290069007900030001030610000610067006800604060608660276028602030203b8 fff0400f000301030001100102020000010403003f33332f325d012f5d38335d12392f5d381239335d5d1133335d5d313009022301330103acfeb7feba98017acb017c01ba0323fcdd038bfc75000000 0001fffbff2404d1ff840003000eb4030000bb01002fed012f2f3130073521150504d6dc606000000001019204b1033a05b40005001a400e74038403028004010401038c0093003fed012fcd5d31305d 01253533171502befed4c5e304b1e61def14000000020080ffec0488044e0032004100a5403f8a24017a1e8a1e02693d793d893d0325363536021320090c4806171617021d092d093d0903052d152d02 000301030330461b0c4f385f380238381543264727b8fff8402dc0270127273f470015011539511b1b332c0f261f26022f268f26ff2603262621502c10335012005107070c1216003f33332fed10ed3f ed332f5d711112392fed012f5ded332f5d38ed1112392f5d3333ed322f5d3130005d5d5d2b5d5d5d5d25323637150e0123222e0227230e0323222635343e023f0135342e0223220e0207273e03333216 1511141625323e023d01070e03151416044d0f1e0e22432633492e1803061c4458724a9ea04f80a354ec1b37543832513a2506bc0a3764976bc8c92afdda537a5128be376f5938596f04037008081b37 513634543b20ac966b894e1f01043b435e3a1b0f27433311406b4e2bbbb1fe2e5051063f6074355904010f305b4c5264000200b3ffec044205cc00200034006140427a028a0202443354336433034b23 5b236b23033a0501351c01051f151f751f851f0400476021012121362b06144600138013021326501a1e1013000d153050060316003f33ed3f3f3f33ed012f5ded323212392f5ded3130005d5d5d5d5d 5d0110022322262723140e0207233e03351133111406070607333e0133321203342e0223220e0215141e0233323e020442cbbd74aa300202030301ae01020201b4010101010430a975c3c4ba1e3f5f42 426a4928284969413f6040210222fee4fee656621a372e2104092b3c482704edfe591d39161a17695ffeebfee170a167312d67a97c779e5f272e66a300010082ffec0438044e0025009d405264160164 1001791e891e02641a0144155415024b115b110275088508020b470a0a1c473f1b4f1b8f1b9f1baf1b05cf1bdf1bff1b03601b011b1b27134700000100701b01001b101b601b701b801bc01b061bb8ff c0401c1b1e481b1b185021160e50051f0b7f0b8f0b030b401b1e480b0b0510003f332f2b5d10ed3fed332f2b5d71012f5ded12392f5d5d71ed322fed3130005d5d5d5d5d015d5d13343e0233321e0217 072e0123220e0215141e0233323637170e0323222e0282568db45f629a6f460dc01080765675471f1f4775556c8e11be0944729e6489bf7736021ea3d88035325776440e5b6937699b64649f6e3a6a6d 0c437c5e395697cd0002008affe6041905cc001f0033006b404b442254226422034b325b326b32033a016a0102350a010507150775078507040a041a047a048a040413462a005012019012a012021212 352047000601061a1512002f500b08102550000316003f33ed3f33ed3f3f012f5ded12392f5d713333ed3130005d5d5d5d5d5d250e01232202111021321617333426342635113311141e0217232e0335 01141e0233323e0235342e0223220e02035e31a279cabe018879a331020101b401020201ac01040302fde11d3d6043456b492525486a4540603f20ae695f0116011802365662052a322d0901a3fb1327 483c2b090424323a1a016c70a068313069a878749d602a2e66a3000000020085ffec0446044e0020002b00904065642401640301492959296929034924592402751d851d02771c871c02780e880e027a 0d8a0d024402540264020327471f1f0b49cf0adf0aff0a03000a100a600a030a0a2d2600470015e0150215005026260521501a10055010df0aef0a02800a010a0a1016003f332f5d5d10ed3fed12392f ed012f5ded3212392f5d5ded322fed3130005d5d5d5d5d5d5d015d5d01141e0233323e0237170e0323222e0235343e0233321e021d0101220e0207212e030142264c714a375d4a320c9e10406a986873 b67e434f86af6083b57233fe252e65563b03024808344d6201f7558f6739192c3d242d2d5b492f488ed58d9cd482385497d4801801d21d4a7f625e7e4c2000000001008a0000044b05cc001f005eb900 0afff04036090c481d0146023f0501050506021e1e112f023f026f027f028f0205024014254800020102110211202117500c000004501d050f0115003f3f33ed323fed11120139392f2f5d2b5d11332f 1133332f5d10ed323130002b0111231121352135343e0233321e0217152e0323220e021d0121150244b4fefa01062d649f721d5050471512484f48134262401f01eb03acfc5403ac8e19658f5b2a0306 0804910306050314365e4b0a8e0000000002008ffe58041e044b00310045009c403e7a308a3002663f01450c550c650c034b3a5b3a6b3a03352101051d151d751d851d040a171a177a178a17042f4632 22500e01900ea00e020e0e1a47064605bafff00005ffc040280f154805053c47b01a01001ad01a021a280f3750221f1041500f151509500020063006020606001b003f322f5d10ed3f33ed3f33ed3f01 2f5d71ed332f2b38ed1112392f5d713333ed3130005d5d5d5d5d5d5d01222e0227371e0133323e023d01230e0323222e0235343e023332161733343e0237330e031511140613342e0223220e0215141e 0233323e0202675a89633d0db811715c395b412302133b536e4866905c2b2b5f986e71a72d0303030501ab01020201d421304f65354362401e1e3f614235665031fe582647623c194b51224b7856c228 4c3a234286ca8783cc8d4a6961193e372803092b3c4927fcc6e3e503cf719e632c2d639d71759c5e272b609b000100b90000041905cc001f003f4027700e800e02040d140d740d840d04114612122105 021e46001f801f021f1f11151850050b100000003f3f33ed3f33012f5ded323212392fed3130005d5d133311140607333e0333321e0215112311342e0223220e02151123b9b506030318405269405382 5a2fb5213b50303b674d2cb405ccfe7a32652e2f4c351d2c5c9065fd2f02b750673d182d557d51fd8d0000000002008f0000046505cc0009000d004840280707050404050b4a0c0c01010046a0050105 050e0f0b300a600a02800a010a0750080f0004500315003fed323fed2f5d712f111201392f71ed322f322fed11332f12392f3130252115213521112135212735331502e9017cfc2a01a6fec101f3c8c8 8e8e8e031e8ed2c0c000000000020075fe57034405cc0019001d004b402c75138513020a031a030218180a151a4a1d1d004600150115151e1f0a301a01801a011a1b1750180f1050051b003fed3fed2f 2f5d71012f1112392f5ded322fed1112392f3130005d5d05140e0223222e0227351e0333323e02351121352127353315034447769c5629524c4118163c484f2838614829fe69024bc8c81c6d975f2a07 0c0f098c050c0a071c3d5f4303c58ed2c0c00000000100ec0000046505cc000b00af402c66077607860703640974098409037b018b01024901590169010349085908026b007b008b000349005900020a b8ffe840280b1148010a08091044095409020909009f0baf0bbf0b03000b100b020b100b0b0d07034600040104b8ffc0b31f254804b8ffc0b3161b4804b8ffc040110d11480402070a010701080f0500 040015003f323f3f393911331133012f2b2b2b5ded3211332f385d5d33332f5d3833393931302b5d5d5d005d5d015d005d2101071123113311013309010392fe9284b4b401dbd3fe4901ce01f362fe6f 05ccfc61020dfe2ffd970000000100860000045c05cc00090033401a08080504040501010046a0050105050a0b075008000004500315003fed323fed111201392f71ed322f11332f12392f3130252115 2135211121352102e0017cfc2a01a6fedf01d58e8e8e04b08e0000000001006300000464044e0039008eb9002affd0b3090f4820b8ffd04059090d4822394800000d2e48bf2fcf2fff2f03602f702f02 1f2f2f2f3f2f034f2f5f2f7f2f8f2f04102f202f302f032f2f3b190c48000d100d02f00d010f0d3f0d02cf0ddf0d02100d010d350650192228031f10130f2f0d0015003f32323f3f1733ed32012f5d5d 717172ed3212392f5d5d717171ed12392fed393130002b2b2111342e0223220e0215112311342e0227331e0315333e0333321617333e0333321e0215112311342e02232206151102130c1b2b20213426 14a9010202019501020201020d2433462e58571302122b38482f3d543417a80c1b2b20424d02ae4f6a411b335d8351fda10353224b43300705293538142747361f60642f49321a2c5c9065fd2f02ae4f 6a411ba8a8fd8d00000100b300000419044e0025003d402670228022020421142174218421042546000027190c46000d800d020d1906501f10130f0d0015003f323f3fed33012f5ded3212392fed3130 005d5d2111342e0223220e0215112311342e0227331e0315333e0333321e0215110364213b50303b674d2cb401020201aa01020302031841556a425380572d02b750673d182d557d51fd8d0353224b43 3007052c393b142f4c351d2c5c9065fd2f00000000020082ffec0449044e000f00230059403d6422014622562202641c01461c561c026b180149185918026b120149125912020047af10010010101060 10031010251a47000a010a15500d101f500516003fed3fed012f5ded12392f5d71ed3130005d5d5d5d5d5d5d5d01140e0223222e0235101233321203342e0223220e0215141e0233323e020449437eb5 726db17d44fde8f4eebd2b4d6a40416e4f2d2f4f6939416f502d021e8ed38c45448cd38f01170119feeafee67ea462272963a47b7ea562282762a600000200b3fe57044204500028003c00654044643b 01463b563b026b2b01492b592b020626162676268626043421013b08017903890302004760290129293e331e11460012801202122e501e2410180f111b38500a0516003f33ed3f3f3f33ed012f5ded32 3212392f5ded3130005d5d5d5d5d5d5d5d01140e0223222e0227231e0315112311342e0227331e0315333e0333321e0207342e0223220e0215141e0233323e020442285c966e37645643170501010101 b501020201af0103030304193f50643e6e965c28ba183b61493b684d2d25486a4449623b1902227bd09655142c4632021f2e3a1dfe590503284a3b2a090325343c1a344c31175093ce7d649c6b382561 ac87739d612a396ea20000000002008afe57041a044a00240038006640474b2d5b2d6b2d03443154316431033a1c013503010524152475248524040a201a207a208a2004124625055013019013a01302 13133a2f47002201223450191f16121b2a50050010003f32ed3f3f33ed012f5ded12392f5d713333ed3130005d5d5d5d5d5d01321e021733343e0237330e03151123113436373637230e032322021110 1201342e0223220e0215141e0233323e02021142664f3d180203030501af01020201b50101010102193f516541cabec30212284a694144613d1d1c3c60453b684e2d044a162e452f1939312303092844 6243fb3601b71a3a1a1e1c334e351a011901150119011dfde0779e5e283369a16e6a9f6a362763ab000100f200000415044e001f0046402b7806880602041a141a0204191419021f1f211609460a1010 1f0a6f0a7f0a8f0a040a1603521c10100f0915003f3f3fed33012f5d337c2f1810ed3212392f3130005d5d5d012e0123220e0215112311342e0227331e0317333e033332161704152f673e54865c31b4 0c101206ab070f0e0a02051c3e557452386c2a0396080b44759c58fe0402bd3874675218183e43441d3e6446260a0700000100a7ffec0424044b0038008540586c180179178917026c17016a36017331 83310247315731022437012a1d010a031a0302052015200228492727004815151f3a0b490a0a2f48001f601f701f801f041f2f15052d50222028902802282822101050050b0b0516003f332f10ed3f33 2f5d10ed123939012f5ded332fed1112392fed322fed3130005d5d5d5d5d5d5d5d5d5d01140e0223222e0227371e0333323e0235342e02272e0335343633321e0217072e03232215141e02171e030424 3b70a3695e97724d129f0c354b62393a63482933587947407e633dd4c94f8a6c490ea2072e43542ef52b4e6c414189714901354c7a552e1b3e674c1f3741220b11294130323d2a1e13112841644d93a6 1d3f6345142d38210c972e39261b11102a466d00000100befff003f90554001b005840366a187a188a18031828090e48060612121d0509461a9001010101021a401225481a400b0e48001a011a0c5017 1608005001030305010f003f33332f10ed323fed012f5d2b2b33332f5d10ed3212392f332f3130002b5d13353313331121152111141633323e0237150e032322263511beaa3a7801b0fe50556128554f 45181646576636a2a203ac8e011afee68efd744f4c070a0c058906100e0a8994029f0000000100b9ffec041f043a00250045402c7f228f22027b218b21020a211a212a2103391c01190e460b0b270146 0024802402241906501f1614150c000f003f323f3fed33012f5ded12392fed333130005d5d5d5d0111141e0233323e0235113311141e0217232e0335230e0323222e023511016d1735553f40674927b5 01020201aa01020302031a3e526a465a825427043afd524f6a411b2d557d510273fcad224b433007052c393b142f4c351d2c5c916402d1000001004500000487043a001000944042560401490e590e02 1b0f5b0f02090f012503550302060316030228016801020001520f090f4b1000141010000101520309034b020114020103020902701080100210b8ffc0401e0a0e4810101202400b0e48020f020f5509 014409012a093a090209000115003f33335d5d5d3f33012f2b11332f2b5d12391000c187052b872bc48718102b872bc43130015d5d5d5d5d5d5d21230133011e03173e0337013302cbd5fe4fca010c08 1214110606131415080114c9043afd40163f443f15153f423f1602c200010015000004b8043a002a01524010741e841e02461e561e02241e341e021db8ffe0404a131848901d01651d751d851d03241d 341d02061d161d021c201318489f1c016b1c7b1c8b1c031d1c2d1c3d1c030b1c017b1b8b1b021b200b0e480e200d11481a0e2a0e3a0e030b0e010db8ffe0401f131848900d01250d350d750d850d0401 201318489f01012a013a017a010300b8ffe040700d114815002500350003030600010e01521016104b0f0e140f0f0e0d01521c161c4c070d14070d0101521d231d4c07011407011d070001522923294b 2a00142a00230716030f142a742a842a032a2a2c0f2a66070132070102071c1c16292a10030f0f23167516851602160d01000e15003f333333335d11333f173312392f335f5d5d2f012f11332f5d1217 39872b872bc41000c18705182b872bc487182b872bc48718102b872bc43130015d5f5d2b5d5d2b5d5d2b5d5d2b2b5d5d5d5d5d2b5d5d5d5d2b5d5d5d2123032e0127262706070e010703230333131e03 1536373e01371333131e01171617343e0237133303facc8f0814090b09090b09140a94cbb7b25d030b0b080b0b09140787c1820613090b0a080c0c0365b001d71b4520252525241f471ffe2d043afda1 1855605c1d2d2923491401a8fe57144723292e1e5a5f5619025f00000001005e0000046d043a000b00b9407047040176078607023901790189010376080119085908020a0209070308060b0601020904 03080500050a010209020704030209015208030203084b090214090902000152060b064b050014050006050a01070404030b0909100b700b800b030b0b0d050503070a04010408050f030015003f323f 331739012f332f11332f5d332f111217391000c187052b872bc48718102b1000c187052b10c410c0c01087c0c0108708c008c0108708c008c03130015d5d005d5d015d21090123090133090133090103 a4febffebdc2019ffe73c7012c012ac9fe7301a401bcfe44022c020efe5b01a5fdf4fdd200010042fe570489043a001f00af40521e180f124865127512851203491d591d0203200d11482d033d03022b 023b020200480c49750085000226006600026a107a108a10034910591002001018691879188918031810090c48181f0808111e1f101fb8ffc0b70a11481f1f211211b8fff0400a11400b0f4811821801 18b8ffe0400d0d10481810101e110f0c50051b003fed3f33392f332b5d012f2b383311332f2b383312392f12392b5d1133335d5d5d5d3130002b5d5d2b015d5d2b210e0323222627351e013332363f01 0133011e03173e0337133302c1255062784e223a201330114f8b3012fe2ac001080b201e170203171e1f0cfcbe629d6f3b0407870303768131042ffd7e1b4f4d3e090b3d4b4f1d028100000000010093 0000042c043a0009005840370607160726075607040701520201024b06071406070206600601030608080603030b9f01af01bf010300010101060350040f0107500015003fed323fed32012f5d5d1217 392f2f2f5d1000c187052b872bc43130015d333501213521150121159302a9fd7f034cfd5602cf8903268b89fcda8b00000100e3fe57042505cc003100754012760f860f02690879088908030218090c 4814b8ffe04037090c4818803101313133202cf10525053f0c010c0c117f050100050105250bf50f0c4f0c6f0c038f0caf0c020c0c3019f5180030f5001b003fed3fed12392f5d71ed39012f5d5d3333 2f5d123910ed3212392f5d333130002b2b5d5d01222e023511342e0227353e033511343e0233211523220e021511140e0207151e03151114163b0115031c416c4e2b2f4e633333634e2f2b4e6c410109 d52d412a13294253292b534128505bd5fe572c506f44015f3f57361a0289021a37563e016046704f2a8b152e4a36fea6395c452c0a020a2d445d3afea56a598b00010213fe5702b905cc00030017400a 03ab000004050100001b003f3f111201392fed3130011133110213a6fe570775f88b0000000100a7fe5703e905cc00310073400d7622862202692979298929031cb8ffe0403d090d482f18090d480b30 25012525202cf111050533194f007f008f0003000001000b26f50f252f254f256f25048f25af250225250118f5190001f5001b003fed3fed12392f5d71ed39012f5d5d3312392f33ed32322f5d393130 002b2b5d5d13353332363511343e0237352e033511342e022b013521321e021511141e0217150e031511140e0223a7d55b512841522b29524229142a412dd50109416c4e2b2f4e633333634e2f2b4e6c 41fe578b596a015b3a5d442d0a020a2c455c39015a364a2e158b2a4f7046fea03e56371a0289021a36573ffea1446f502c0000000001006c0229046003270020005d401a16042604360466049604a604 0610300914004c11300914004c1eb8ffc040250914004c1f300914004c0d22101d011d18ad0d0040171c480040090c48001d0aad0f130113002f5ded33dd2b2b32ed012f5d10ce31302b002b2b2b5d01 321e02171e0333323637150e03232226272623220e0207353e010173294f4d4b251532333317457b341f3c3d4428459149815826413c381d328403270d141a0d07100e08322a95161f13082c1a2d0c17 20158f262e00000000020203fef602c9043a00030007002c401502049803000710070207070809000003069d070f03b8010e003f3fed11392f111201392f5d33ed3231300133132313152335021b9418 c4c6c202adfc490544c9c90000010085ffc304460563002900934060681088100244285428024a265a26021b0c49180d0d1306204721210646000510050205052b274600131013e013f0130413245018 1f217f218f210321211b180b0e20050100051005600570058005c00506050500500e180e180e0c0f1901190c002f2f5d1239392f2f10ed332f5d7111331133332f5d10ed012f5ded12392f5ded332fed 1112392f33ed323130005d5d5d01323e0237170e03071523352e0335343e02373533151e0317072e01232206151416027b385d482f09b6093a638c5a806ea46d363a70a368805685613d0db911837a9c a1a8010d1c3651360c3e745c3e08c3c3085389b86e76bf8a5309b8b80737566f3f0e5b6cc9bdc6c90001003800000493055a0036009c406203180c0f480614011b6f22292d6f104f225f22027f0c8f0c 020f2a010c2a22222a0c0306006f003601363638326e060f0f06401724480006100602062c0e73291f0f013f0f6f0f9f0fcf0fdf0fef0f060f0f32257316222216070732730636360618003f332f10ed 323f332f10ed12392f5d7133ed32017c2f5d2b33182f10ed12397d2f5d18ed1217392f2f2f5d5d5d33ed3210ed3130005d2b250e032321353e033d0123353335343e0233321e0217320e020706072e01 2322061d0121152115140e0207213236370493092036513afc8f2b48331dbaba33689f6c4a7e654812010e181f11273216754e7a780198fe680f243c2c02583b390bf02b56442b9a163046664b8d8edc 5c9366371d3a563906080a050c103f40737dd88e8b3b604d3c1735350002009e00e1042f04730023003700ea409d49225922022d223d2202491d591d022d1d3d1d0249195919022d193d190246145614 02221432140246105610022210321002460b560b02220b320b024607560702220732070249025902022d023d02020321061e0c180f1515181e2104000e161612aa6f2e01102e012e2e003904202024aa 00001000800003000c060f031521181e1e21030604091b171f1f29b0401b601b023f1b011b0d050533b009002fed332f332f5d5ded332f33111217391133113311331133012f5ded332f331112392f5d 5ded322f33111739113311331133113331305d5d005d5d5d5d015d5d5d5d005d5d5d5d015d5d133436372737173e01333216173717071e01151406071707270e01232226270727372e0137141e023332 3e0235342e0223220e02b62925646863367f49477e36616860252b2c26646665367e4748803469666625299a2d4c663a39664d2c2c4d66393a664c2d02ac477f36646765272b2a26616960367f474780 3564696525292a26696966367f493a664c2c2c4c663a3a664d2c2c4d6600000000010034000004980545001600b3406f5d15014b15011915291539150352130103401301141324133413030000400050 00030f114f115f11030c040106061608100b0b120915160e0812090e132f120112140400085c110d4f095f097f098f090410090109091718070b600c040c030f60101400100c100c1008151203081200 3f3f331239392f2f11333310ed32113310ed32111201392f5d5d3333ed323239c45d322b0118104de4321112392f331112392f3331305f5e5d5d5d5d5f5d5d5d5d012115211521152111231121352137 213521013309013302fc0141fe81017ffe81b2fe83017d02fe810140fe65c70169016dc702a78e8990ff00010090898e029efd970269000000020213fe3902b905ae00030007002540110307ab000404 08090500050001041b0100003f3f1239392f2f111201392f33ed32313001113311031133110213a6a6a602a4030afcf6fb95030bfcf500000002009fff54042c05cc004d006101054073731083100269 56017560856002435f535f02435b535b02435a535a735a835a04433e533e026a157a158a15032a144a145a14032a514a515a516a51042a500150180d11482a48016c397c398c39032a3901051f151f02 0a241a2402054d154d025d1d2258494146534e0e494b0649053749224bb8ffc04040121948414b052222054b41042c1849004e104e024e4e632d49002c012c5313465d3c1d76468646026a4601461d00 325127202d802d022d2d270b510006060000003f322f10ed2f332f5d10ed1239395d5d113333113333012f5ded12392f5ded1117392f2f2f2f2b10ed10ed10ed12393910ed1139393130005d5d5d5d5d 5d2b5d5d5d5d5d5d5d5d5d5d5d01321e0217072e0323220615141e02171e0315140e02071e0315140e0223222e0227371e0333323e0235342e02272e0335343e02372e0335343601342e02270e031514 1e02173e0302784f8a6c490fa1082e43552e7d8132536d3b448b70461c375236314f371e3a70a46b5d9a754f13a10c374e63393a664d2c395f7b4141836841203b54352a4b3921d301e13558713d3a59 3c1f31526c3c365d442705cc1e3f6245142d3d251159472d402e200e102e496a4c2d5749370d15334051334975532c1b40684d1f37472910152d442f36493323100f2e496a492d5347350f0e2e405030 8b9bfccb304533230e03213445272e4230220f01182f46000002014f04c3037c057b000300070031401f03850000078510040104050190040f003f005f00af00bf00050040161e4800002f2b5d32ed32 012f5ded332fed3130013533152135331502d9a3fdd3a504c3b8b8b8b80000000003001f002604ad05cc0029003d0051011c40777b508b5002744a844a02764f864f02764b864b0274468446027b408b 4002794589450279418941020350135002034a134a020c121c122c1203031813182318036600760086000300c4150a20c61f0b1f701f801f020f1f1f1f022f153f15021540101448151f151f343e100d 11483ec3102a012a2a5348b8fff040570d114848c334300a400ab00ac00ad00a05300ab00ac00a030a0a05c91025c91a20201a7f108f10ef10ff1004501ab01ac01a03001a101a701a801a04101a101a 4d6943794389430343c83900664d764d864d034dc82fd0003fed5d3fed5d1239392f2f5d715d11332f10ed10ed332f5d71012fed2b11332f5ded2b1139392f2f2b5d5d5d113310ed3210ed5d3130005d 5d5d5d5d5d015d5d005d5d015d5d01141e0233323e0237170e0323222e0235343e0233321e0217072e0323220e020514020e0123222e01023534123e0133321e011207342e0223220e0215141e023332 3e02018e1c385438293f2f210c7313344a63435a85572b2b5682574363483110720a202e3c273a533519031f5b9ed57978d49f5c5c9ed47979d59e5b5c4d86b26665b2844d4d84b26566b2864d02fb48 7856301b2d381c232b513f2640729e5e629c6f3b243b4b27211a3226172e53764abbfeefb25555b20111bbbb0111b15656b1feefbba7ee98474798eea7a8ef98464698ef000200ce028b03fd0598002a 003b007ab90003ffe8b3090c4814b8ffd84037090d48222809114829180d11482928090c481e1e17e224060035013535003d0de30e0e2be30000100002001a30e42836e4050513242128b80116b40d0d 0ae413b80115003fed332f3f333312392fed10ed32012f5ded332fed1112392f5d3333ed322f3130002b2b2b2b2b13343e023f0135342623220607273e033332161511141633323637150e0123222627 230e0123222637141e0233323e023d01070e03ce3a638247bf5e56545c0b95083054794f99a61f2b0c1c09173817524b03042b9266798993122639273b5c41229a325a44280366455c381801042b5d59 444d0a2f523e238685fedd3a3c05035e0607554b4d59727d1c3226162d4451253304010d1e3500000002007f008d046003ac000800110050402b00eb0803eb04ec06eb0101130a09eb110ceb0dec0feb 000a010a0b020a010c090001020f03060603ef00ee003fe4393d2f17331133321133113301182f5dedfdedd4ed1112392fedfdedd4ed313025013501331509011521013501331509011503acfeae0152 b2feae0154fd6ffeb00150b1feb101518d016d3f01731ffe8cfe911d016d3f01731ffe8cfe911d000001007400b4045702f200050021401200aa05070002100202023f00010002ad03b3003ffdc65d01 2f5d10deed313025112135211103c6fcae03e3b401ac92fdc20000000004001f002604ad05cc001300270035003e00ec40297b268b2602742084200276258625027621862102741c841c027b168b1602 791b891b0279178917022fb8ffd840150b11483328090c4803261326020320132002342929b8fff0402629313b2bc42c283510353531c43670368036022c362c360a14100d114814c31000010000401e b8fff040320d11481ec30a282c342ac83b3ac82d002d102d022c3b2d2d3b2c03236919791989190319c80f006623762386230323c805d0003fed5d3fed5d1217392f2f2f5d10ed10ed321133012fed2b 11332f5ded2b1139392f2f5d10ed322f383310ed3211393811333130005d5d2b2b5d5d015d5d005d5d015d5d0114020e0123222e01023534123e0133321e011207342e0223220e0215141e0233323e02 05032311231121321615140607130334262b011133323604ad5b9ed57978d49f5c5c9ed47979d59e5b5c4d86b26665b2844d4d84b26566b2864dfedec7a17f01338e976855dd9f5f51aab6505402f9bb feefb25555b20111bbbb0111b15656b1feefbba7ee98474798eea7a8ef98464698effa0150feb0033f7e6f667b13fea202504548fed35500fffffffb05f204d1065212070042000006ce000000020147 03200385055a00130027004ab90011ffe8b3090c480db8ffe84026090c480718090c480318090c4814ac00001eac000a100a800a030a23af000501050519af0f04003fed332f5ded012f5ded332fed31 30002b2b2b2b01140e0223222e0235343e0233321e0207342e0223220e0215141e0233323e0203852d4e693b3b684e2e2e4e683b3b694e2d6d1b3041262541301c1c3041252641301b043d3b684d2d2d 4d683b3c684d2c2c4d683c2641311c1c3141262541311d1d31410000000200740000045704c3000b000f006a40370f0c040b0e0104020e040901aa060002010a03020210110dad400c020e0407050e2f 073f078f07038f079f07df07ef0704070004ad0905b8ffc0b313164805002f2b33ed32c65d712b0018104de62f1aed111201392f5f5e5d33ed32c62b0118104de6113332313001112311213521113311 21150135211502af93fe5801a89301a8fc1d03e302a8fe75018b91018afe7691fd5891910001013802330394058d00200053b55a026a020215b8ffd84028090e481f1f17e16f088f0802080800220ee0 0f0f001e1e0000100002000e0e0be414de011ee400dd003fed323fed332f012f5d332f11332fed1112392f5ded322f3130002b015d01273e0535342623220607273e0333321615140e04072117013a02 1b5864675234474a44580885062e4c6c43839136556763531601cb020233673d5f50474952323e4b494408335740257f703d625249494e2f6b0000000001013202270399058d0035007bb9002affe840 20090f480228090c48302d1622e12323082de11c4f165f1602161c161c0800e10fb8ffc04022090c480f0f3709e10008100802083015e416160c2822221fe428de0ce403090903df003f332f10ed3fed 332f1112392fed39012f5ded12392f2bed1239392f2f5d10ed11332fed1112393130002b2b01140623222e0227371e0133323635342e022b013533323e0235342623220607273e0333321e0215140607 151e0303999b8e5774492406880958554d532538431d3d391d3d32204a474454068707324f673a45684623565a344b3016031b74802740512b0d4345484c2d361d096d0d1f35283c4546410c3a56391c 213b4f2e4b6e1402052536440001019204b1033a05b40005001a400e7b028b02028003010300028c0593003fed012fcd5d31305d0135373315050192e3c5fed404b114ef1de6000000010090fe77043c 043a0027006840180b100f1248390701224605101f201f02601fc01fd01f031fb8ffc0402a2453481f1f29150d1146124027534812401c234812401215480012011220130f121b1a500c050916001500 3f3f3333ed3f3f33012f5d2b2b2bed323212392f2b5d7133ed3130005d2b212e0335230e0123222627231e01151123113311141e0233323e0235113311141e02170394010303030435a7725280200403 01b6b61b3f65494370522eb50102020106313e3f136d6e403a203f1bfe8b05c3fd7c4574552f345b7e4b0269fcaf224c433107000001007ffebc04380545001300414018059a00060106060c02131301 9a020215000c100c020c0413b80110b71207070112030601002f333f12392f10ed32012f5d12392fed322f1112392f5ded31300111231123112311222e0235343e0233211503b784c58550856035325f 8a57024704cbf9f1060ff9f103be2d58865854855d327a00ffff01f001a402db02cf120600d3000000010077fe4401e30000001b0052b9001affe8402f0f1348441a541a0203180d1348181919171640 090c481616081087000000080108139219400d10481919170b8d0595003fed2f392f2bed012f5d332fed11392f2b333311333130002b5d2b01140e0223222627351633323e02353426232a0107373307 1e0101e31e41684b142d1932242939220f3d480e1d0e416b275e5efefe2a45311a010362060d162013282a02b66403530001011d0233039b05820012003f40223f1101111110e002080801010e000210 02020202131408e40909030edc1001e400dd003fed323f33332fed111201392f5d33332f332f10ed322f5d3130013521110e032335323e023733113315012301090d374a562b305749381179ec02336b 02621a2a1e116d12233221fd1c6b0000000200e2028b03ea059800130021005240307a198a19027a158a15027521852102751c851c0200e39014a014c014031414231ae36f0a01000a100a500a030a17 e40fb80115b21fe405b80116003fed3fed012f5d71ed12392f5ded3130005d5d5d5d01140e0223222e0235343e0233321e0207342623220615141e0233323603ea316292625d9061333061926267935d 2c957872747d223d5533757f0412578f683939688f57548f683b3a688f55978688954c6d452085000002006b008d044c03ac000800110050402a03eb08ec0106eb0500eb0101130a0ceb10ec0a0feb0e 09eb0a110810070f090007080c03030306ef00ee003fe4393d2f17331133321133113301182fedd4ed10fded1112392fedd4ed10fded313025233509013533011501233509013533011502fab20152fe b0b00152fcd3b40152feb0b2014f8d1d016f01741ffe8d3ffe931d016f01741ffe8d3f00ffff001b000004cd0545102700d4fef60000102600d10000110700d70198fdb6002840170302181803025019 014019011901601401140020000100115d35115d35115d5d3535003f35350000ffff0011000004b00545102700d4feec0000102600d1f000110700d501acfdb40018400d021718016014011400200001 00115d35115d35003f350000ffff000b000004cd0551102700d6ff210000102600d11900110700d70198fdb600204012030235180302503a01403a013a0040000100115d35115d5d3535003f35350000 00020099fedf046c04390027002b007740366606760686060366047604860403451b551b02690079008900030a0928982b2b001e98001d701d801d031d1d2d139800001000020009b8ffc040150f1348 0909232a9d2b692379238923031d1d189e23b8010e003fed332f5d2fed11392f2b012f5ded12392f5ded12392fed33325d3130005d5d5d37343e0637330e0715141e0233323e0237170e0323222e0201 15233599253e4f524f3f2701af02273e4e504d3c25294d6d44446f523207b80c4a7eaf716cb17e440271c34f456852423b3b445337436651413b3b4453353754391e2647653e0c5a976c3d305d890444 c9c90000ffff0000000004cc06a712260024000011070043ffa300f30015b40215052602b8ffa3b41619040725012b35002b3500ffff0000000004cc06a812260024000011070074005d00f40013400b 02150526025d1518040725012b35002b35000000ffff0000000004cc06a8122600240000110700c3000000f40013400b0216052602001b15040725012b35002b35000000ffff0000000004cc069d1226 00240000110700c5000000f40013400b0215052602002030040725012b35002b35000000ffff0000000004cc065d12260024000011070069000000e20017400d03021505260302001917040725012b35 35002b3535000000ffff0000000004cc0660122600240000110600c403550016400c030238030302031f15040725012b3535003f3535000000020001000004ab0545000f0018008540510b042b049b04 031701020401520211025e03041403040203090509050d080c5c180f0f030d0d1a03015f170b5f080f083f087f088f08046f088f089f08bf08df0805170817080c11075f04030c5f030f12003f33ed3f ed321239392f2f717210ed10ed012f12392f12392f33ed321239392f2f1000c187052b872bc410c0c03130015d0121032301211521112115211121152111230e030703210286feb18ea801e6029bfeaf 0147feb9017afddb4904141515068b011c019cfe64054598fe5296fe2f9804b21042484412fe6f00ffff0071fe440476055a1226002600001107007801620000000bb6011b322a150b25012b35000000 ffff00a20000046206a812260028000011070043ffb900f40015b4010c052601b8ff9db40d10000a25012b35002b3500ffff00a20000046206a812260028000011070074005b00f40013400b010c0526 013f0c0f000a25012b35002b35000000ffff00a20000046206a8122600280000110700c3000000f40015b4010d052601b8ffe4b4120c000a25012b35002b3500ffff00a200000462065d122600280000 11070069001400e20019b602010c05260201b8fff8b4100e000a25012b3535002b353500ffff00ca0000040106a81226002c000011070043ffaf00f40015b4010c052601b8ffb0b40d10000125012b35 002b3500ffff00ca0000040106a81226002c000011070074006700f40013400b010c052601670c0f000125012b35002b35000000ffff00ca0000040106a81226002c0000110700c3000000f40013400b 010d05260100120c000125012b35002b35000000ffff00ca00000401065d1226002c000011070069000000e20017400d02010c0526020100100e000125012b3535002b35350000000002001b00000465 05450010001f008e406272168216020230166016021416241602791a891a027f198f19021b192b193b196b1904111106005a0017011717211e135a060a06080800061006020612085f1e1f094f09023f 096f099f09cf09df09ef090609401f28480909131d5f0b03135f0612003fed3fed12392f2b5d7133ed32012f5d332f113310ed3212392f5ded12392f3130005d5d5d5d5d5f5d0114020e012321112335 331121321e0201211133321211342e022b01112104655098dd8cfe8e878701379ef3a655fe1dfedfa2d4ce3872ac7579012102b0a8feffae59025595025b4da2fafef9fe47010a010a87c07939fe4100 ffff00a20000042a069e122600310000110700c5000000f50013400b0114052601001f2f081225012b35002b35000000ffff0066ffec046606a812260032000011070043ffaa00f40015b4021e052602 b8ffaab41f220a0025012b35002b3500ffff0066ffec046606a812260032000011070074006200f40013400b021e052602621e210a0025012b35002b35000000ffff0066ffec046606a8122600320000 110700c3000000f40013400b021f05260200241e0a0025012b35002b35000000ffff0066ffec0466069d122600320000110700c5000000f40013400b021e0526020029390a0025012b35002b35000000 ffff0066ffec0466065d12260032000011070069000300e20017400d03021e052603020222200a0025012b3535002b35350000000001009d00e1042e0473000b008e401db902c902d90203b900c900d9 0003b608c608d60803b606c606d6060307b8fff0400e12164801101216480a1012164804b8fff0b312164805b8fff0b612164819050103b8fff0402612164819030109101216481609010b1012164816 0b0104800a014f0a01000a100a020a0701b200193f33012f5d5d5d333130005d2b5d2b5d2b5d2b2b2b012b2b5d5d5d5d1309013709011709010709019d0162fea068015e015e69fea2016066fe9ffe9c 014a0162016067fe9f015f69fea4fea0690161fe9d00000000030038ffda04920570001a0022002b00c5408c8b1d01651975198519036a0c7a0c8a0c03770b0167258725024614561402461156110249 07590702490359030234227422842203761f861f027b1e8b1e02361e017426013926013b2b7b2b8b2b031d261e2504231b1815080b040e17005b5f1b011b40191c48001b011b1b2d235b0a500e01100e 010e1e251d260420295f080b18150405161304205f090513003f33ed3f33121739ed111739012f5d7133ed12392f5d2b71ed32111739111217393130005d5d5d5d5d5d5d5d5d5d5d5d5d015d5d005d01 14020e01232226270727372e013534123e013332173717071e010734270116333212011417012e0123220204664684bf786fac3f755e8d302f4482bf7cd980745e8c3030c91efe004f98a394fd921e02 0027744b9c9c02a9adfefab15946449c41bd58e891ad0102ac56869c41bb55e492a472fd528a0118010aa67402ac4241fef90000ffff008effec043d06a812260038000011070043ff9f00f40015b401 1a052601b8ffa0b41b1e0a0025012b35002b3500ffff008effec043d06a812260038000011070074005600f40013400b011a052601561a1d0a0025012b35002b35000000ffff008effec043d06a81226 00380000110700c3000000f40013400b011b05260100201a0a0025012b35002b35000000ffff008effec043d065d12260038000011070069000000e20017400d02011a05260201001e1c0a0025012b35 35002b3535000000ffff0024000004a806a81226003c000011070074006500f40013400b010905260165090c040825012b35002b35000000000200a20000045f05450010001b00634042760f860f0265 1a751a851a036a127a128a1203005a7f118f11021140191c4800110111111d160b075a00081008a008b008040816600615600b060b060b0709030712003f3f1239392f2f10ed10ed012f5ded32321239 2f5d2b5ded3130005d5d5d01140e022321152311331521321e020734262b011133323e02045f3b79b67bfee7bfbf010d7dba7c3ec0a4a4f6fe52794f2602b4589f7847fe0545eb3c6f9c638695fdc02c 4f6b00000001008effe3048f05cc004300bd40297c3a8c3a027538853802654201664101443f543f743f843f04652f01652e752e852e030328090c4833b8ffe84025090c48391f0136481f263d363d02 3d4818401850189018a018041f091818091f032a004811b8ffc0b312174811b8ffc04029090e481111452a462b40121548002b012b113d1f0305245031002b156009700980090309090e500516003fed 332f5d3f3fed121739012f5d2bed12392f2b2bed1217392f2f2f5d10ed5d10ed5d3130002b2b5d5d5d5d5d015d005d01140e022322262f011e0333323635342e0435343e0435342e0223220e02151123 11343e0233321e0215140e0415141e04048f2957875f509437021a424a4e255c6236515f513621313a3121213f5a39446b4927b43f78ae6e669b693521333a332137525f52370127427658341918a40f 1a120a5f4f3b523f39475e4633493a30343f2b253e2d1a234d7a58fc03040377ac70362e506d3e3b574334313220283d3a40546fffff0080ffec048805b4122600440000110600438e000015b4024211 2602b8ff70b44346150325012b35002b35000000ffff0080ffec048805b4122600440000110600744d000013400b02421126022f4245150325012b35002b3500ffff0080ffec048805b4122600440000 110600c3ee000019b70243112602204801b8ffd0b44842150325012b5d35002b35000000ffff0080ffec048805a9122600440000110600c5f8000022400e0242112602304d01204d01104d01b8ffdab4 4d5d150325012b5d5d5d35002b350000ffff0080ffec0488057b12260044000011060069f000001e400a03024211260302204601b8ffd2b44644150325012b5d3535002b35350000ffff0080ffec0488 060b122600440000110600c4f8000017400d03024711260302124c42272f25012b3535002b35350000030014ffec04b8044e00410050005900c640817c588c58027c548c54026a137a138a13036c117c 118c1103053d153d02053715370203211321021b28090e4814385600494b244b09490a0a404857cf4bdf4b021057014b574b571e5b2f48303042484f1e5f1e9f1eaf1e041e512a50350050564b512456 2456243b38352f2f8f2f022f2f351006455019140f1980090109091916003f332f5d11333310ed323f332f5d11333339392f2f10ed10ed10ed32012f5ded332fed111239392f2f5d5d10ed322fed1133 10ed3239393130002b5d5d5d5d5d5d5d01151e0333323637170e0323222e02270e0323222e0235343e023f0135342e0223220e0207273e03333216173e0133321e021d0105141633323e023d01070e03 01220e0207212e0102a701152c46314b59108a0c2b496d4d395c4835121536495c3a44613f1e395d763ea70f2134242033261704a808284a71505b79232d7d4c60814e20fc053939385134197a254a3a 25029e1c3e3323020169095801f711528862375e482d2d5b492f1837594031553e242c54774b6b894e1f01043b435e3a1b0f27433311406b4e2b46454a41589bd27a18cc52643f6074355904010f305b 02521d4a7f62ab9dffff0082fe440438044e1226004600001107007801510000000bb601212e26001c25012b35000000ffff0085ffec044605b412260048000011060043b1000015b4022c112602b8ff b2b42d30151f25012b35002b35000000ffff0085ffec044605b4122600480000110600746f000013400b022c1126026f2c2f151f25012b35002b3500ffff0085ffec044605b4122600480000110600c3 07000013400b022d11260207322c151f25012b35002b3500ffff0085ffec0446057b1226004800001106006908000017400d03022c1126030208302e151f25012b3535002b353500ffff008f00000465 05b4122600c0000011060043bd00001e400b010a112601600b01500b01b8ffa9b40b0e030125012b5d5d35002b350000ffff008f0000046505b4122600c000001106007468000013400b010a11260154 0a0d030125012b35002b3500ffff008f0000046505b4122600c00000110600c30a000022400e010b112601601001501001301001b8fff6b4100a030125012b5d5d5d35002b350000ffff008f00000465 057b122600c00000110600692900002f401f02010a11260201900e01800e01700e01600e01500e01400e01000e0c060925012b5d5d5d5d5d5d3535002b3535000002007dffec044e05d80025003700bb 408145365536653603453155316531034a2e5a2e6a2e034a285a286a28032b043b046b0403052415240213100609041208080c120c1221174703702601a02601002610266026032626393047ff2101ff 210100210121651075108510036a067a068a0603100913060407112b500003000000100002070007000c33501c161211110c00003f332f333fed1139392f2f5d113310ed111217395d5d012f5d5d71ed 12392f5d717233ed1139392f2f332f1217393130005d5d5d5d5d5d013216172e01270527372e0127331e011725170716121d01140e0223222e0235343e0201342e0223220e0215141633323e02026447 752b27694cfefc37da387842d12d532a010837d3a4a73978bc847db576383474ba01b22147715051734921909151764b2403d3201b599f45736e5e2d4e2314331f726c5c95fe7df40679c48a4b4984b9 6f6bb6864bfe0e5e895a2c2d5c885cbeb22c5a8bffff00b30000041905a9122600510000110600c50a000013400b0126112601093141132425012b35002b3500ffff0082ffec044905b4122600520000 11060043ba000015b40224112602b8ffbbb425280a0025012b35002b35000000ffff0082ffec044905b41226005200001106007465000013400b02241126026524270a0025012b35002b3500ffff0082 ffec044905b4122600520000110600c300000013400b0225112602002a240a0025012b35002b3500ffff0082ffec044905a9122600520000110600c500000013400b0224112602002f3f0a0025012b35 002b3500ffff0082ffec0449057b1226005200001106006900000017400d030224112603020028260a0025012b3535002b3535000003007400df0457047500030007000b0063403c060e0b05080e7005 0105030bab003f084f08020008010a0308080d0c09ae40080e0401050e00ae2f013f014f01034f018f019f01ef01040104ad05b3003fedd65d71ed2b0018104df61aed111201392f5f5e5d5d33ed32c4 5d2b0118104de431300135331501352115013533150211a8fdbb03e3fdbaa803beb7b7fea29292fe7fb7b7000003006effec045d044e00190025003100db4024452455246524036b30014a305a30020c 200b1148790789070207400b0f48741984190219b8ffc040090b0f48741484140214b8ffc040670b0f481d2a1e2904261a1815080b040e17170047201a301a401a701a801a901a06001a501aa01ab01a c01a05001a101a601a701a801ae01a061a1a3326470e0a0a0e40282e480e40181b480e2a1d291e04212d080b181504130516162d50131021500509090516003f332f10ed3fed332f1112173911121739 012f2b2b332f10ed12392f5d7172ed322f111739111217393130002b5d012b5d002b5d012b005d5d5d01140e02232226270727372e0135343e023332173717071607342627011e0133323e0225141617 012e0123220e02045d4683bc7765a6404d4c5430334381bc79d57a484e5061bd1110fe032b724045765630fd8b111101fd2a714545755530021e8ed38c45353657445f45bc7a8cd18d466452445a89f7 4c782efdc0352a2762a67e4b752e024032272963a4000000ffff00b9ffec041f05b412260058000011060043a2000015b40126112601b8ff9cb4272a241325012b35002b35000000ffff00b9ffec041f 05b4122600580000110600745a000013400b0126112601542629241325012b35002b3500ffff00b9ffec041f05b4122600580000110600c300000015b40127112601b8fffab42c26241325012b35002b 35000000ffff00b9ffec041f057b1226005800001106006900000019b602012611260201b8fffab42a28241325012b3535002b3535000000ffff0042fe57048905b41226005c0000110600746b000013 400b01201126016b2023111f25012b35002b3500000200b9fe57044205cc0013003800654044792189210264120146125612026b020149025902023516013a2601061b161b761b861b041e4760000100 003a320a2f4600308030023031002f1b280f5023161405501910003fed333fed333f3f012f5ded323212392f5ded3130005d5d5d5d5d5d5d5d01342e0223220e0215141e0233323e02013e0333321e02 15140e0223222e0227231e0315112311331114060706070388183b61493b684d2d25486a4449623b19fde8193f50643e6e965c28285c966e37645643170501010101b5b4010101010222649c6b382561 ac87739d612a396ea201ce344c31175093ce7d7bd09655142c4632021f2e3a1dfe590775fe591d39161a1700ffff0042fe570489057b1226005c00001106006905000017400d02012011260201052422 111f25012b3535002b3535000001008f00000465043a00090033401a07070504040501010046a0050105050b0a0750080f0004500315003fed323fed111201392f71ed322f11332f12392f3130252115 2135211121352102e9017cfc2a01a6fec101f38e8e8e031e8e00000000020014fffb04c5054b0017002800744049762686260246095609024904590402120e120e1611155c1b1b0616162a245c06145f 0f113f117f118f11046f118f119f11bf11df110511110e18165f17030317121f0f5f0e0b0b0e03003f332f10ed323f332f10ed3211392f7172ed012fed12392f12392fed321239392f2f3130005d5d5d 210e012322021134123e013332172115211121152111211525323637112e0123220e0215141e02026117311affec3d7bb97c3a33022efe72016ffe9101b7fd3b163b13133b154e754e27284f74020301 52015cb40100a24c0698fe4896fe39988c0204042103033a7fc88f8ecc843f000003001cffec04b4044e0026003a004300aa40737b428b42027a3e8a3e027638863802792a892a026603760386030364 3374338433036b2f7b2f8b2f030522152202051a151a020a151a1502101d4000482727182508490909254810410141414531484f185f189f18af18041800504040363b2c50201d1b1005365013100e13 80080108081316003f332f5d11333310ed323f3333ed3212392fed012f5ded12392f5ded322fed1112392fed3239393130005d5d5d5d5d5d5d5d5d5d01141e0233323637170e032322270e0123222e02 3510123332173e0133321e021d0125342e0223220e0215141e0233323e0201220e0207212e0102c81329402c414e0e8a0b28446648b6512a855b4b78552daaa2bb4f2d85515b7b4a1ffd6b182c3f2727 412f191b2e3e2328412e19014c19372f20020144085001f7558f67395e482d2d5b492fb75d5a448cd38f01170119b15e53589bd27a18277ea462272963a47b7ea562282762a602291d4a7f62ab9d0000 0001011b04b103b105b4000900254017200150016001800104010603200b0f48038e098c050293003f33fded2b012fc45d31300115232723072335373303b169db02e868fea404c5148a8a14ef000000 00020174047c0358060b00130027008bb90011ffe8b3090f480db8ffe84061090f480718090f480318090f48148400001000200003300070008000b000c000d000066000010f001f0002001e84000a01 0a198e7f0f8f0f020f40090c480f238e2f054f056f05df05040f052f053f054f056f057f059f05bf0508054016194805002f2b5d71edd42b5ded012f5dedd45d5d7172ed3130002b2b2b2b01140e0223 222e0235343e0233321e0207342e0223220e0215141e0233323e0203581e3c5b3d3d5b3c1e1e3c5b3d3d5b3c1e790d1d2e21212e1e0d0d1e2e21212e1d0d054427483821213848272748372121374827 0f1d180f0f181d0f0f1e180f0f181e00000100ff04b103cc05a9001f005140100a1f1a1f021e18090f48050f150f020eb8ffe84024090f481a830f1b2f1b3f1b7f1b8f1b051b1b0a83000b300b020b1a 058f108c158f0a0093003f32edfded33012f5ded332f5ded3130002b5d2b5d01222e0223220e0207233e0333321e0233323e0237330e0303022a54504d23171d130a056f05142d4a3b2c54504a21171e 140a047005142b4a04b1252d25101e2c1d2d58472c252d25101f2c1c2c58472d000100aa01c30422024c0003000fb5020000b901bc003fed012f2f313013352115aa037801c389890001fff601c304d6 024c0003000fb5020000b901bc003fed012f2f3130033521150a04e001c389890001018d035e033f05cc0003002ab5060116010201b8fff040110e1148039a0097019900020102019c0000003fed012f 5dedfded31302b5d01032101033fa9fef7013705ccfd92026e0000000001018f035e034105cc00030033402200180e11480900190002090219020202100e114801990297039a00000100039c0100003f ed012f5dedfded31302b5d5d2b01132101018fa90109fec9035e026efd9200000001015dfe95030f01030003003b402800180e11480900190002090219020202100e114801990297039a2f0001000010 000200009c019b040010f6ed012f5d5dedfded31302b5d5d2b01132101015da90109fec9fe95026efd920000000200b1035e041a05cc000300070057b5060516050205b8fff040090e11480601160102 01b8fff040260e1148079a049705992f069f0602000610060206039a009701990002100202020507019c0300003fed3332012f5dedfded2f5d5dedfded31302b5d2b5d01032101210321010263a9fef7 01370232a9fef7013705ccfd92026efd92026e00000200b2035e041b05cc000300070068404b04180e11480904190402090619060206100e114800180e11480900190002090219020202100e11480599 0697079a000410049004030401990297039a2f00010000100002000705039c0100003fed3332012f5d5dedfded2f5dedfded31302b5d5d2b2b5d5d2b01132101211321010269a90109fec9fdcea90109 fec9035e026efd92026efd92000200b2fe94041b010200030007006a404c04180e11480904190402090619060206100e114800180e11480900190002090219020202100e114805990697079a00041004 9004030401990297039a2f000100001000020004009c05019b080010f432ed32012f5d5dedfded2f5dedfded31302b5d5d2b2b5d5d2b01132101211321010269a90109fec9fdcea90109fec9fe94026e fd92026efd920000000101500191037b03bc00130037402515112511351103150d250d350d031a072a073a07031a032a033a03030000100a010a05050f002f332f012f5d332f3130005d5d5d5d01140e 0223222e0235343e0233321e02037b2c4d663a39634b2b2b4b63393a664d2c02aa3a664c2d2d4c663a39644a2b2b4a640001015a008d035d03ac0008002e401800eb0803eb04ec06eb4f010100010101 0201060603ef00ee003fe4393d2f333301182f5d5dedfdedd4ed313025013501331509011502aafeb00150b1feb101518d016d3f01731ffe8cfe911d0001016e008d037103ac00080030401a03eb08ec 0106eb0500eb00016001d00103010807030306ef00ee003fe4393d2f333301182f5dedd4ed10fded31302523350901353301150220b20152feb0b001518d1d016f01741ffe8d3f00000100cc000003fe 054500030027b70203100303050001b8fff0400a00011001020102060018003f3f012f5d383312392f383331302123013301427602bf7305450000000001005bffec0463055a003c0096405569310137 0347035703032b2a2a0c350000390b0c0c1c3e330101396e1c2000170117171c2216161c400b0e481c011773183b183620732133216f18013f210118211821062e73252b2b2507067311300b010b0b11 19003f332f5d10ed3f332f10ed1239392f2f5d5d113310ed32113310ed32012f2b332f3311332f5d3210ed322f331112392f3312392f33113311333130005d5d01211e0333323e0237170e0323222e02 272335332e01353436372335333e0133321e0217072e0123220e02072115210e01151417210369fe35082a4d745034574b421e4c2a58606c3e78b27b470d83770202020277811dfbe538645d572b523a 8a56497253330b01cdfe2501010301da01cf4f7a542b121e2513871c2e2012447db26d901722121a23128eeaec0e1c2c1e8c2a3a1c477a5f8d0e2b152a200000000101f001a402db02cf000300284018 039600000100000405019b0f001f003f000300400e114800002f2b5ded111201392f5ded31300111331101f0eb01a4012bfed50000010125024d02c7054500120044401c111110e002080801010e0002 1002020202131408e40009010909030eb80111b31001e400b80112003fed323f33332f5ded111201392f5d33332f332f10ed322f3130013533110e032335323e0237331133150149870d2f332f0d1230 332f117974024d6b02011a24170a770c1b2c21fd736b0000000100fa024d030405510020004fb90015ffd840200911481f1f17e1080800220ee00f0f001e1e0000100002005f0e010e0e0be414b80113 b3011ee400b80112003fed323fed332f5d012f5d332f11332fed1112392fed322f3130002b13353e0535342623220607273e0333321615140e04072115fa184a5454442a333c3d3b08820627415c3d78 792e4756524410017c024d613755483f40472c39403e3d052f503a21706737594b413f41266b0000000100ea023b02ed05510033008ab9002affd840400911480328091148001c101c201c037b300122 e123230a2de11c181c181c0a00e1110be10a1111354f0a01000a100a020a30181716160e285f220122221fe428b8011340090ee405500b010b0b05b80114003f332f5d10ed3fed332f5d1112392fc411 39012f5d5d12392f10ed10ed1239392f2f10ed11332fed005d015d3130002b2b01140e0223222e0227371e0133323635342e022b013533323635342623220607273e0333321e0215140607151e0102ed 27445e38405c3e22068809413036421929361d2925444036292d420687072c4455303a573a1d4345524b031a3653391d253c4c270d3c3d3c41252f1a0a6d394235323f390c3650361a1f374a2a42551a 02126400000200c5024b03350545000a0017005d401209090801e012066002700280020302021911b80117402004400d11480004100402040004e408050f111f112f119f11bf11051111010b06ba0111 00010112003f3f3312392f5d3333ed32012f5d2bed12392f5d3333ed32322f31300115233521350133113315030e03070321113c023602bb7ffe8901698d7af80615181707b901090102eca1a16301f6 fe0c6501d9091f22200aff0001040d201f1b00000000001e016e00010000000000000035006c0001000000000001000700b20001000000000002000700ca0001000000000003001200f8000100000000 00040007011b0001000000000005000c013d00010000000000060007015a00010000000000070050020400010000000000080014027f0001000000000009000e02b2000100000000000a016305890001 00000000000b001c0727000100000000000c002e07a2000100000000000d0035083d000100000000000e001a08a90003000104090000006a00000003000104090001000e00a20003000104090002000e 00ba0003000104090003002400d20003000104090004000e010b0003000104090005001801230003000104090006000e014a000300010409000700a00162000300010409000800280255000300010409 0009001c0294000300010409000a02c602c1000300010409000b003806ed000300010409000c005c0744000300010409000d006a07d1000300010409000e00340873004400690067006900740069007a 006500640020006400610074006100200063006f007000790072006900670068007400200028006300290020003200300031003000200047006f006f0067006c006500200043006f00720070006f0072 006100740069006f006e002e00004469676974697a6564206461746120636f7079726967687420286329203230313020476f6f676c6520436f72706f726174696f6e2e000043006f007500730069006e 00650000436f7573696e65000052006500670075006c006100720000526567756c6172000041007300630065006e0064006500720020002d00200043006f007500730069006e00650000417363656e64 6572202d20436f7573696e65000043006f007500730069006e00650000436f7573696e650000560065007200730069006f006e00200031002e00300030000056657273696f6e20312e3030000043006f 007500730069006e00650000436f7573696e65000043006f007500730069006e006500200069007300200061002000740072006100640065006d00610072006b0020006f006600200047006f006f0067 006c006500200061006e00640020006d006100790020006200650020007200650067006900730074006500720065006400200069006e0020006300650072007400610069006e0020006a007500720069 007300640069006300740069006f006e0073002e0000436f7573696e6520697320612074726164656d61726b206f6620476f6f676c6520616e64206d6179206265207265676973746572656420696e20 6365727461696e206a7572697364696374696f6e732e000041007300630065006e00640065007200200043006f00720070006f0072006100740069006f006e0000417363656e64657220436f72706f72 6174696f6e00005300740065007600650020004d00610074007400650073006f006e00005374657665204d61747465736f6e000043006f007500730069006e0065002000770061007300200064006500 7300690067006e006500640020006200790020005300740065007600650020004d00610074007400650073006f006e00200061007300200061006e00200069006e006e006f0076006100740069007600 65002c002000720065006600720065007300680069006e0067002000730061006e0073002000730065007200690066002000640065007300690067006e00200074006800610074002000690073002000 6d006500740072006900630061006c006c007900200063006f006d00700061007400690062006c00650020007700690074006800200043006f007500720069006500720020004e006500772122002e00 200043006f007500730069006e00650020006f0066006600650072007300200069006d00700072006f0076006500640020006f006e002d00730063007200650065006e00200072006500610064006100 620069006c006900740079002000630068006100720061006300740065007200690073007400690063007300200061006e00640020007400680065002000700061006e002d004500750072006f007000 650061006e002000570047004c0020006300680061007200610063007400650072002000730065007400200061006e006400200073006f006c00760065007300200074006800650020006e0065006500 6400730020006f006600200064006500760065006c006f00700065007200730020006c006f006f006b0069006e006700200066006f0072002000770069006400740068002d0063006f006d0070006100 7400690062006c006500200066006f006e0074007300200074006f0020006100640064007200650073007300200064006f00630075006d0065006e007400200070006f00720074006100620069006c00 69007400790020006100630072006f0073007300200070006c006100740066006f0072006d0073002e0000436f7573696e65207761732064657369676e6564206279205374657665204d61747465736f 6e20617320616e20696e6e6f7661746976652c2072656672657368696e672073616e732073657269662064657369676e2074686174206973206d6574726963616c6c7920636f6d70617469626c652077 69746820436f7572696572204e6577aa2e20436f7573696e65206f666665727320696d70726f766564206f6e2d73637265656e20726561646162696c6974792063686172616374657269737469637320 616e64207468652070616e2d4575726f7065616e2057474c206368617261637465722073657420616e6420736f6c76657320746865206e65656473206f6620646576656c6f70657273206c6f6f6b696e 6720666f722077696474682d636f6d70617469626c6520666f6e747320746f206164647265737320646f63756d656e7420706f72746162696c697479206163726f737320706c6174666f726d732e0000 68007400740070003a002f002f007700770077002e0061007300630065006e0064006500720063006f00720070002e0063006f006d002f0000687474703a2f2f7777772e617363656e646572636f7270 2e636f6d2f000068007400740070003a002f002f007700770077002e0061007300630065006e0064006500720063006f00720070002e0063006f006d002f007400790070006500640065007300690067 006e006500720073002e00680074006d006c0000687474703a2f2f7777772e617363656e646572636f72702e636f6d2f7479706564657369676e6572732e68746d6c00004c006900630065006e007300 65006400200075006e0064006500720020007400680065002000530049004c0020004f00700065006e00200046006f006e00740020004c006900630065006e00730065002c0020005600650072007300 69006f006e00200031002e003100004c6963656e73656420756e646572207468652053494c204f70656e20466f6e74204c6963656e73652c2056657273696f6e20312e31000068007400740070003a00 2f002f0073006300720069007000740073002e00730069006c002e006f00720067002f004f0046004c0000687474703a2f2f736372697074732e73696c2e6f72672f4f464c0000000002000000000000 fe230054000000010000000000000000000000000000000000d80000000100020003000400050006000700080009000a000b000c000d000e000f0010001100120013001400150016001700180019001a 001b001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f0030003100320033003400350036003700380039003a003b003c003d003e003f004000410042 0043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d005e005f0060006100a30084008500bd009600e80086008e008b 009d00a900a4008a00da0083009301020103008d0097008800c300de0104009e00aa00f500f400f600a200ad00c900c700ae006200630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d3 00d000d100af006700f0009100d600d400d5006800eb00ed0089006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d007c00b800a1007f007e 0080008100ec00ee00ba00d700b000b100d800dd00d900b200b300b600b700c400b400b500c5008700be00bf00bc01050106010701080109010a07756e693030423207756e693030423307756e693030 4239044575726f07756e69323231390b6f6e656672616374696f6e0b74776f6672616374696f6e0d74687265656672616369746f6e0c666f75726672616374696f6e0000000000030008000200110001 ffff0003000000010000000000010000000e000000180000000000020001000100d7000100040000000200000000000100000000c7feb0df00000000bd76892400000000c96f2dc4 ]], ["fonts/DroidSans.ttf"] = [[ 000100000013010000040030474445460026038700023d200000001e47504f5394bda2f000023d400000a8fa475355426c91748f0002e63c000000204c545348c99bb9200000101c000003864f532f32 a0cb958b000001b800000060636d6170ce11d4a2000056780000079e63767420397e3e4c0000680c000001fc6670676d73d323b000005e1800000705676173700004000700023d140000000c676c7966 c293c651000071100001a81e68646d78ef0efaab000013a4000042d468656164ebc60a350000013c00000036686865610c5309a40000017400000024686d7478d2d72e270000021800000e046c6f6361 92fa294c00006a08000007066d617870062a028500000198000000206e616d65b559905600021930000006a2706f7374d850a92700021fd400001d3f7072657082dc211300006520000002ec00010000 000100005e1db5c15f0f3cf50019080000000000c19a330000000000c61b8c03fb89fdd5095a086200000006000200000000000000010000076dfe1d00000964fb89fea2095a00010000000000000000 000000000000038000010000038200a00016007a000500020010002f005a0000021f01390003000100030499019000050008059a05330000011e059a0533000003d0006601f20000020b060603080402 0204e00002ef4000205b00000028000000003141534300400020fffd061ffe140084076d01e32000019f00000000044a05b600000020000204cd00c10000000004140000021400000227009303370085 052b00330468007b069a0066059e006d01cf0085026800520268003d04680052046800660200003f029300520225009302fc001404680062046800b20468006004680052046800170468008304680071 0468005a0468006a0468006a022500930225003f0468006604680066046800660368002506ee006d04dd000004f800c704d3007d057900c7043900c703ee00c70585007d059c00c702b60052022bff48 04a200c703ee00c706f600c705d500c705f0007d049c00c705ee007d04b800c70427006804270014059600b8048b000007120014046000000437000004500052026d00a402fc0017026d003304420029 034afffc049e0189043f005e04b000ae03b4007104b000710448007102a2001d0425002504b600ae021200a00212ffbc03f800ae021200ae072b00ae04b600ae049e007104b000ae04b00071033100ae 039c005a02b6002104b600a403d5000005f800140400002303e9000a0387005202d5003d046801e902d50033046800660214000002270093046800bc046800440468007b0468001d046801e903e30079 049e013306a8006402a6004403e50052046800660293005206a800640400fffa036d007b0468006602a6003102a6001f049e018904c100ae053d00710225009301a4002302a6003f02cd004203e50054 05e5003f05e5002c05e5001f0368004404dd000004dd000004dd000004dd000004dd000004dd000006d1fffe04d3007d043900c7043900c7043900c7043900c702b6003e02b6005202b6001102b60040 0579002f05d500c705f0007d05f0007d05f0007d05f0007d05f0007d0468008d05f0007d059600b8059600b8059600b8059600b804370000049c00c704d100ae043f005e043f005e043f005e043f005e 043f005e043f005e06aa005e03b40071044800710448007104480071044800710212ffde021200ae0212ffbd0212ffee049e006f04b600ae049e0071049e0071049e0071049e0071049e007104680066 049e007304b600a404b600a404b600a404b600a403e9000a04b000ae03e9000a04dd0000043f005e04dd0000043f005e04dd0000043f005e04d3007d03b4007104d3007d03b4007104d3007d03b40071 04d3007d03b40071057900c704b000710579002f04b00071043900c704480071043900c704480071043900c704480071043900c704480071043900c7044800710585007d042500250585007d04250025 0585007d042500250585007d04250025059c00c704b600ae059c000004b6001202b6fff50212ffa302b6003d0212ffeb02b600300212ffde02b600520212004402b60052021200ae04e10052042500a0 022bff480212ffbc04a200c703f800ae03f800ae03ee00c7021200ab03ee00c70212006603ee00c7021200ae03ee00c7026600ae03ee001d0212fff605d500c704b600ae05d500c704b600ae05d500c7 04b600ae0546ffff05d500c704b600ae05f0007d049e007105f0007d049e007105f0007d049e0071071f007d0748007104b800c7033100ae04b800c70331006004b800c70331007204270068039c005a 04270068039c005a04270068039c005a04270068039c005a0427001402b600210427001402b600210427001402b60021059600b804b600a4059600b804b600a4059600b804b600a4059600b804b600a4 059600b804b600a4059600b804b600a40712001405f800140437000003e9000a04370000045000520387005204500052038700520450005203870052024c00ae046800cb04dd0000043f005e06d1fffe 06aa005e05f0007d049e007304270068039c005a049e0102049e01020475011b049e0121021200a0049e016d017b001f049e0102049e00df049e01f8049e011404ddffe90225009304c9ffe70617ffe7 03b2ffe70642ffe70554ffe7064affe7029effe404dd000004f800c703ee00c7048b0025043900c704500052059c00c705f0007d02b6005204a200c7048b000006f600c705d500c7043f005205f0007d 058700c7049c00c70442004e042700140437000006230068046000000623006805f0004e02b600400437000004b0007103a0005a04b600ae029e00a404b800a404b0007104d100ae03e9000a049e006f 03a0005a03a4007104b600ae04870071029e00a403f800ae0417fff204c100ae0423000003a40071049e0071050a0019049e00a403a4007104b400710398001204b800a4059600710431ffec05ec00a4 06060071029e001504b800a4049e007104b800a406060071043900c705a0001403ee00c704d3007d0427006802b6005202b60040022bff4807480000077500c705a0001404a200c704ae0019058700c7 04dd0000049c00c704f800c703ee00c70533000e043900c706850004045c004805d500c905d500c904a200c7055a000006f600c7059c00c705f0007d058700c7049c00c704d3007d0427001404ae0019 0623006804600000059a00c7054800a607fa00c707fa00c7053d0014069600c7049c00c704c1003b081d00c704b80019043f005e048f0075048900ae033300ae046000290448007105c3000403ae0044 04e900ae04e900ae03ee00ae045e001005be00ae04e900ae049e007104c100ae04b000ae03b400710387002903e9000a059300710400002304d100ae04ac009a06f400ae070400ae056d002905fe00ae 048900ae03b20037067900ae043f00230448007104b60012033300ae03b40071039c005a021200a00212ffee0212ffbc0683001006e500ae04b6001203ee00ae03e9000a04c100ae03ee00c7033300ae 0712001405f800140712001405f800140712001405f800140437000003e9000a040000520800005208000052034afffc01660017016600170200003f0166001902e7001702e700170381003f03e3007b 03f8007b03020096066f0093095a006601cf008503370085024e0052024e005203f60093010afea002f8006a0468006004680044060000960468003f0668008d0400007707e700c705fe002505f0004e 04f40066060e0053060e0033060e004f060e007104a60062048b002905ee00c7050c004a046800660464002505a80077031900100468006604680066046800660468006604aa006d04b4001d04b4001d 049e00cf0212ffbc040001870400016f0400017d02a6002502a6000c02a6003b02a6002502a6002f02a6003102a600210400000008000000040000000800000002ab0000020000000155000004680000 02250000019a000000cd0000000000000000000008000054080000540212ffbc0166001704cd000a0452000006a0001206f600c7072b00ae04dd0000043f005e0642fed302aa0073033300930756001d 0756001d05f0007d04aa007105f400b8052f00a40000fc8f0000fd480000fc460000fd040000fd31043900c705d500c90448007104e900ae07db007d066f00000525001404dd0014072700c705b600ae 052f00000464000a072900c7061200ae057f001404f0000a078b00c706a200ae045e003903ae00170623006805ec00a405f0007d049e007104c1000003dd000004c1000003dd00000964007d08580071 063f007d0519007107b2007d0650007107db007d066f000004d3007d03b4007104df0068047500c9049e00f4049e01e1049e01e107e9002907a6002905e700c904fc00ae049c002f04890012049c00c7 04b000ae03ee002f03330012050000c7040800ae06e9000406230004045c004803ae0044050a00c7044a00ae04a200c7042b00ae04a2002f03f800120544001404d1002905cd00e504fa00ae065c00e5 05ac00ae084400c706b800ae05ec007d04f2007104d3007d03b4007104270014038700290437000003d500000437000003d5000004d30000043d002306890014058b0029054800a604bc009a054800a6 04ac009a054800c704ac00ae0677003d051d00330677003d051d003302b600520685000405c30004054a00c7042d00ae056a000004710010059c00e504e900ae05cb00e504fc00ae054800a604ac009a 070600c705d100ae02b6005204dd0000043f005e04dd0000043f005e06d1fffe06aa005e043900c704480071058f007104480066058f0071044800660685000405c30004045c004803ae0044045c0048 03b8001b05d500c904e900ae05d500c904e900ae05f0007d049e007105f0007d049e007105f0007d049e007104c1003b03b2003704ae001903e9000a04ae001903e9000a04ae001903e9000a054800a6 04ac009a03ee00c7033300ae069600c705fe00ae03ee002f0333001204c30000042f00230460000004000023049c008904b0007106f4008906fe007106fc004e0646005004c5004e0410005007a40000 06a4001007e500c7072f00ae05c3007d04e100710581001405120029045c006f03ae005c055a0000045e001004dd0000043f005e04dd0000043f005e04dd0000043f005e04dd0000043f001204dd0000 043f005e04dd0000043f005e04dd0000043f005e04dd0000043f005e04dd0000043f005e04dd0000043f005e04dd0000043f005e04dd0000043f005e043900c704480071043900c704480071043900c7 04480071043900c7044800710439002704480012043900c704480071043900c704480071043900c70448007102b600520212006202b600520212009e05f0007d049e007105f0007d049e007105f0007d 049e007105f0007d049e003305f0007d049e007105f0007d049e007105f0007d049e007105f0007d04aa007105f0007d04aa007105f0007d04aa007105f0007d04aa007105f0007d04aa0071059600b8 04b600a4059600b804b600a405f400b8052f00a405f400b8052f00a405f400b8052f00a405f400b8052f00a405f400b8052f00a40437000003e9000a0437000003e9000a0437000003e9000a04b00071 0000fbdb0000fc6a0000fb890000fc6a0000fc640000fc730000fc730000fc730000fc6401a4003100100010000003820101011a281801010a012b01010a0b160114050b0b0b0b0b0b0b0b0b0b14140b 0b0b1c0b2622140b01120b15191515141c1922131e161b1b151710102612010501200101110b1c0b152a192e0c0c0a0c182e150b0b122a0b2e190b1a16121918190b1a280b0b0b0b1815010414270b01 0401100b111101120b1401110a2701010a1c262626262626011401010101191919190b1922222222220b2215151515261316111111111111161c151515150c0c0c0c152e15151515150b152e2e2e2e16 0b16261126112611141c141c141c141c0b0b0b0b011501150115011501150b190b190b190b19152e152e190c190c190c190c190c1517150c150a0a140c140c140c1424140c192e192e192e18192e2215 221522152a281612161216121b2a1b2a1b2a1b2a1b0b1b0b1b0b152e152e152e152e152e152e100b261626121212121212300b2611011622151b2a01012401010101010101012614152d0c150d151626 221917011215221915191c1911221513201b261910192219260b162e16120b0c161516162e17160a2d12181815181318180112191313181612151218010e19141b19191528190e153015261322191f01 1812191915101c15221513141b30191015141919171019162416111419141615191a19190a16131915120b1c1916191a16121919171819111911152e141c2a0c0c0c18182e0a16121701100b100b100b 2616010101011515191515151919191919142b1819190c01190b0b110b01012a1922010c0c0c0c26171e2b010117170b0b0b0b191414190c010101111111111111110101010101012e01010101010101 010c151116181c18261101010114142215191c0101010101011915191d17202601011c18181619191714011a19132215181618161801141519011d18141c0d240101012e0116190117130b1214151919 19121a15011519150a0b18181919192e191213141c1b192619261919192a151316141219180a160a16191819201818141519181914121515192611261101160115151515151819121a12111919191922 1522152215161130163016301614121914101812141601101a130b1715181819161718271915191317121a10162611261126112611261126112611261126112611261126110115011501150115011501 1501150115190c190c221522152215221522152215221522152215221522152215152e152e191c191c191c191c191c2616261626160b0101010101010101010101010000000000130000038406070400 0302020204030504010202030302020202030303030303030303030202030303030504040404030304040202030305040404040403030404050303030202020302030404030403020304020203020504 0404040203020403040403030203020302020303030303030305020303020503030303030304040201030203040404030404040404040504030303030202020204040404040404030404040404030304 0404040404040503030303030202020204040404040404030404040404030403040404040404040304030403040304040404030303030303030303030403040304030403040404040202020202020202 0202040402020303030302030203020302030204040404040405040404040404040405050402040204020303030303030303030203020302040404040404040404040404050403030303030303030302 0304030505040403030303030302030103030303040204050305040502040403040303040402030405040304040404030306030604020304030402040404030403030404020304040403040404030403 0405040506020404040603050304030202020606050304040404040304030503040403040504040404040304060304040606050604040604040404020303040304040304050404040403030305040404 0606040503030604030402030302020205050403030403020504050405040303030606020101020102020303030206070102020203010203030503050306050404050505050404040403030402030303 0304040403020303030303030303030303060306020201030201010000060602010403060505040405020206060404040400000000000304030406050404050404030505040406050303060504040403 0403070605040605060504030403030303060604040303040403020403050503030403030303030404040404040605040404030303030303030403050404040404040405040504020504040304030404 0404040405050204040404050503030403040305040303030304040404040404040404040304030403040304040302060503020403030403040606050504030605060604040405030304040404040404 0404040404040404040404040404040404040403030303030303030303030303030303020202020404040404040404040404040404040404040404040404040404040404040404040404040404030303 0303030400000000000000000001010107090400040202030504060502020204040202020304040404040404040404020204040403060504040504040505040204030605050405040404050506040404 0203020403040404030404030404020204020604040404030302040406040403020402040202040404040403040602030402060403040303040405020103020305050503050505050505060404040404 0404040405050505050505040505050505040404040404040404060304040404020202020404040404040404040404040404040405040504050404030403040304030504050404040404040404040404 0504050405040504050405040402040204020402040205040202040404030203020302030203020504050405040505040504050405040606040304030403040304030403040304020402040205040504 0504050405040504060604040404030403040302040504060605040403040404040204010404040405020405050505060205040305040405050404050605040505040404040604060504040403040204 0404040403030404020404040403040404030403040604060602040404060405030404040402070705040405050404030504060405050405060505050404040406040505080805060404070404040403 0404060304040304050404040403030406040404060605060403060404040303030202020606040304040303060606060606040404070703010102010303030303030608020302020301030404050406 0407050504050505050405050404040503040404040404040402040404030303030303030407040702020104020101000007070201040406060605040502030606050405040000000000040504040606 0504060505040605060407050404060605040504050409070504060606060403040404040407070504040404040403040406060403040404030403050405040504070606060403040304040404040407 0606040504050406050605040606050405040504050405040605040504050406060404050405040606040304040504050405040504050404030404040404040504030306060403040404040404060606 0504040706070605040505040305040504050405040504050405040504050405040504050405040404040404040404040404040404040404020402050405040504050405040504050405040504050405 040504050405040504050405040504050404040404040404000000000000000000010101080a050004020203050407060202020404020302030404040404040404040402020404040407060505050404 0606040205040806060506050404060608050405020302040305040504050403040502020402080505050503040305040604040403040304020204040404040405070304040307040304040405050502 0204030406060604060606060606070504040404040404040506060606060604060606060604050504040404040407040404040402020202050505050505050405050505050405040604060406040504 0504050405040505050504040404040404040404060406040604060406050605040204020402040204020504020205040404020402040204020402060506050605060605060506050605070705030503 0503040404040404040404030403040306050605060506050605060508060404040504050405040204060407070605040405050405020501050505050602050605060506020605040604050606040506 0806040606050504040605060604040504050205050504050404050502040405040405050504050405060406060205050506040604050404040208080605050606050504060408040606050608060606 0505040506050605080806070505080504050503040406040505040506050505050404040604050508080506040407040405030404020202070705040405040308060806080604040408080301010201 0303040404030609020302020401030404060406040806060506060606050606050404060304040404050505050204040404040404040404040804080302010402020100000808020105040708080604 0603030707060506050000000000040604050806050507060604070506060807040406060605060406040a08060508060806050405040505050808060505050505040305040806040405040504050405 0506050605080607060504040404040404050407070605050505050705070504080605040605060506050505080604060406040707040406040604080604040404060506050605060506050504050405 0405040505040307060403050405040505070806060404080709070605050504040605060406040604060406040604060406040604060406040604040404040404040404040404040404040402040206 0506050605060506050605060506050605060506050605060506050605060506050605060504040404040405000000000000000000020202090c05000502020406050806020303060502030203050505 0505050505050502020505050408060505060505060604030504080607050705050406060806060503030305040505050405050405050202050208050505050404040505060505040305030502020505 0505050405070405050307050405040405050602020404050707080406060606060608050505050504040404060607070707070507060606060605050505050505050804050505050202020205050505 0505050505050505050505050605060506050504050405040504060506050505050505050505050506050605060506050605060504020402040204020402060403020505050402040204020403040206 0506050605060605070507050705090805040504050405040504050405040404040404040605060506050605060506050806060506050405040504020506050808070505040505050502050205050505 0602060705080708020605050605050607040506080605070605050406060606070406050405020505050505040405050205050505040506050405040506060606020505050605060505050404030909 0605060606050505060508050606050708060706050504060606060608080707050509050505050405050604050505050605050505040405060505050808060705040705050504040402020208080505 0505050408060806080606050509090402020202040404040403060b02040303040104050508050705090807060808080805060606050507030505050506060604020505050404040404040405090509 03020205020201000009090202060606080806050703040909070506050000000000050605050807060508060606080706060807050406060705060506050c0907050807080705040505050505090906 0505050505050405050806050406050505050506060605060509080706050404040604060406050807070606050605080608060408060605070506050605060508060406050605080805050705070508 060504050406050605070507050705050406050605060506050504070705040505060505050808080705050a070908060506050504070506050605060506050605060506050605060506050605060505 050505050505050505050505050505040204020705070507050705070507050705070507050705070507050605060506050605060506050605060506050605050000000000000000000202020a0c0600 0503020406060807020303060502030204050505050505050505050202050505040806060606050506060403050408060705070505040606080606050304030504060505040505040505020205020805 0505050404040505060505040405040503020505050505050608040505030805040504040605060202040405070707040606060606060906050505050404040406060707070707050706060606060505 0505050505050804050505050202020205050505050505050505050505050505060506050605060406040604060406050605050505050505050505050605060506050605060506050402040204020402 0402060503020505050402040204020404040206050605060507060507050705070509080504050405040504050405040504040404040404060506050605060506050605080606050605040504050402 0506050908070505040606060603060206060606060206070508070802060605060505060704050608060507060505040608060807040605040502050505050504040505020505050504050605040504 0506060606020505050605070506050404030909070506060606060506050805060605070806070605060406080606060a0a070806060a05050505040505060405050505060505050504040506050505 0808070705040805050504040402020208080505050505040806080608060605050a0a0402020202040404040403090c0204030304010405050805080509070706080808080506070606050703050505 05060606060205050504040404040404050a050a0303020603020100000a0a0202060606080806050803040909070506050000000000050605050a07060609070606090808060a070504080607050605 06050c0a07050a080a07060406060606060a0a06050606050505040605080605040605050505050606060507060a08070606040404060406040605080707060605060508060806040806060507050605 0605060508060406050605090805050705070508060504050406050605070507050705060406050605060506050504080705040605060505050808080705050a08090807050705050407050605060506 0506050605060506050605060506050605060505050505050505050505050505050505040204020705070507050705070507050705070507050705070507050605060506050605060506050605060506 050605050000000000000000000202020b0e07000603030507060908030303060603040304060606060606060606060303060606050a0707070806050808030307050a08090609070605080709060707 0304030605060606050606040606020205020a06060606040504060608060605040504060303060606060505060904050604090605060404060607030204040508080805070707070707090706060606 03030303080809090909090609080808080706060606060606060a0506060606020202020606060606060606060606060606060607060706070607050705070507050806080606060606060606060606 0806080608060806080608060302030203020302030207050302070505050205020502050305020806080608060808060906090609060a0a070407040704060506050605060505040504050408060806 0806080608060806090807060707050705070502060706090a09060605060606060306020606060607030709040908090407070607060708090307070a08050908060605070906090903070605060406 06060606050506060405060606050608060506050608060808040606060806080607060303030a0a080706080707070607060906080807070a08090806070506090608080b0b080907070c0706060604 07060805060605060706060606050606080606060a0a08080605090606060405050202020a090605060605040908090809080706060b0b0502020202040404050505090d030503030601040606090609 060b09090709090909060708070606080406060606070606060206060604040404040404060b060b0403020603020100000b0b02020707080a0a07060904040a0a090608070000000000060806060b08 07070a0807060a0807080a0a060509080906080608060e0b09060b090b08070506060606060b0b08060606060605040706090806050706070507050707080609070b0a0907070505060706070606060a 0908070806080609070907030908070607060806080608060a070307060706090a0606090609060908060506050806080609060906090607050606060606060806060409080504070606060606090a09 0906060a090b0908060807060507060706070607060706070607060706070607060706070607060606060606060606060606060606060603020302090609060906090609060906090609060906090609 0609060806080608070807080708070807070607060706060000000000000000000202020c0f07000603030508070a08030404070703040304070707070707070707070303070707050a070707080606 0808040307060b0909070907070708070b0707070404040605070707060707030607030306030b07070707040604070509060506040704070303070707070706070a040607040a060507040407070803 02040406090909050707070707070a070606060604040404080909090909090709080808080707070707070707070b060707070703030303070707070707070707070707070507050707070707070706 07060706070608070807060706070607060706070806080608060806080708070403040304030403040307060303070606060306030603060406030907090709070809070907090709070b0b07040704 070407060706070607060704070407040807080708070807080708070b09070507070607060706030707070a0b0907070607070707030702070707070703070906090909040707060706070809040707 0b0907090807070707090709090407070607040707070507060507070406050706060708070607050709060909040707070906090607070404030b0b090707080707070608060907090907080b080908 07070707090708080b0b080a07070c070707070506070906070706070907070707060505090607070b0b080907060a0707070506060303030b0b0706050706050b090b090b090705060c0c0502020202 040404050505090f0305040406020407070a070a060d0a090709090909070708080707090507070707070707070306060604040404040404060c060c0403020703020100000c0c03020707090b0b0707 0904050b0b090709080000000000060907070b0907070b0907070a0a07070a0a070609090907080508050e0d09070b090b09070606070707070c0b090707070707060507070a09070608060706070608 07080709080c0b0a09070607050705070507060a080907080708070a080a08040909080708070807080708070b0904070707070a0b060709070907090907060706090709070907090709070706070507 050705080706050a0906050706070607070b0b0a0907060b0a0c0b0907090707060807070707070707070707070707070707070707070707070707060706070607060706070607060706070403040309 07090709070907090709070907090709070907090709070807080709080908090809080908070507050705070000000000000000000202020d1008000703040508070b09030404070703040305070707 070707070707070303070707060b0808080907060909050308060b090a070a08070709070b0707070405040705080708060807040708030306030b0808080805060408060a0706060507050703040707 07070706080b050607040b070607050508080903030505060a0a0a060808080808080b08070707070505050509090a0a0a0a0a070a090909090707080707070707070b06070707070303030308080808 0808080708080808080608060807080708070806080608060806090809080707070707070707070709070907090709070908090805030503050305030503080603030806060603060306030604060309 08090809080909080a080a080a080c0c08050805080507060706070607060704070407040908090809080908090809080b0a070607070607060706040708070b0b0a0807060808070803080208080808 0803080a060a090a04080807070707090a0508080b09070a09070707070a070a0a050708060804080808060806060808040607080706080808060806080a070a0b040808080b070a0708070505030c0c 0a0808090808080708070b07090908090b090a09070807080a0709090d0d090b08080d080708070507070906080806070908080808060506090708080b0b080a07060b0707080506060303030b0b0806 060806050b0a0b0a0b0a0706070d0d050202020205050505050509100305040406020507070b070a070d0a0a080a0a0a0a080709080707090507070707070707070307070705050505050505070d070d 0403020703030100000d0d030208070b0b0b08070a04050b0b0a080a090000000000070907080d0a08080c0908070c0a09070c0a07060a0a0a08080608060f0e0a080d0a0d0a080608070808080d0c0a 0807080708060508070b090706080708060806090709080a090d0b0a0a080607050706070607070b090908090809080b090b09050b09080809070908090809080b0905080708070b0b07070a070a070b 0907060707090809080a080a080a080806080608060806090807050b0a06050807070707080b0c0b0a08070d0b0d0c090809080706090708070807080708070807080708070807080708070807080707 070707070707070707070707070707050305030a080a080a080a080a080a080a080a080a080a080a080a08090809080a090a090a090a090a09070607060706080000000000000000000303030e110800 0704040609080c0a030404080804050405080808080808080808080404080808060c0909080a07070a0a050308070c0a0b080b0807070a080d0807080405040706080708070808040708040407040d08 08080805070508070a070707050705080404080808080707080c050708050c070608050508080904030505070a0a0a060909090909090c0807070707050505050a0a0b0b0b0b0b080b0a0a0a0a070808 0707070707070c0708080808040404040808080808080808080808080807080709070907090708070807080708070a080a08070807080708070807080a070a070a070a070a080a080504050405040504 050408080304080707070407040704070507040a080a080a080a0a080b080b080b080c0d08050805080507070707070707070705070507050a080a080a080a080a080a080d0a07070708070807080704 0809070c0c0b08070708080808040803080808080904080b060b090b040909070907080a0b0508090c0a080b0a080807070b080b0b050708070804080808070807060808040707080707080908070806 080a070a0b040808080b070a0708070505030d0d0a08080a0908090709070b080a0a08090c0a0b0a080807080b080a090d0d090c09080f080708080508080907080807080a0808080807050709070808 0b0b090b08070b0808080507070404040c0c0807070807060d0a0d0a0d0a0707070e0e06030303030606060707060c110306040407020508080c080b070e0a0b090b0b0b0b08090a0908080a05080808 08070808080407070705050505050505070e070e0504020804030100000e0e040308080b0c0d09070b05060d0d0b080b090000000000070a08080d0b09080d0a09070c0a09090d0c08070b0a0b080907 0907110f0b080d0b0d0b080709080808080e0d0a0808080808070509080b0a080709080807080709080a080b0a0f0c0b0a080707050707070708070b0a0a0909080a080b090b09050b09090809080a08 0a0809080c0a05090709070c0c07080b080b080b09080708070a080a080b080b080b080807080708070807090807050c0b07050807080708080c0c0c0b08070d0c0e0c0a080a09080709080907090709 0709070907090709070907090709070907090707080708070807080708070807080708050405040b080b080b080b080b080b080b080b080b080b080b080b080a080a080b090b090b090b090b09070707 070707080000000000000000000303030f120900080404070a080c0b040505080804050406080808080808080808080404080808060d0a0a090a08080a0b060409070d0b0b090b0907080b090e090808 0506050806090809070908040808040407040d0809090906070508070b070707050705080404080808080707090c050708050c080708050509080a04030505070b0b0b060a0a0a0a0a0a0d0908080808 060606060a0b0b0b0b0b0b080b0b0b0b0b0809090808080808080d070808080804040404090809090909090809080808080709070a080a080a0809070907090709070a090a0908080808080808080808 0a080a080a080a080b080b080604060406040604060409080404090707070407040704070507040b080b080b080a0b080b090b090b090d0e09060906090607070707070707070805080508050b080b08 0b080b080b080b080e0b08070808070807080704080a080d0d0b09070709090809040903090909090a04090c070c0a0c040a0a080a08080b0b06090a0d0b080b0b090808080b090b0b06080907080408 0909070907070809040707080807090909070907080b080a0c040809080c080b0809070606040e0f0b09090b0a090a080a080c080b0b090b0d0b0b0b090908090b090b0a0e0e0a0d0a09100908090806 08080b07080807080b080908090707070b0708080d0d0a0b08070c0808080607070404040c0d0807070807060e0b0e0b0e0b0807080f0f06030303030606060808070c120407040407020508080c080c 080f0c0b090b0b0b0b090a0b0908080b0608080808090909090408080805050505050505080f080f0504030804030200000f0f040309080c0d0d0a080c05060e0e0b090b090000000000080b08080f0c 0a090d0b0a080d0a0a090e0c08070b0a0b090907090712100b090d0c0f0c090709080909090f0e0b080909090908060a080c0b08070908090709070a090b080c0a100d0b0a090708070807080709070d 0a0a090a080b080c090c09060c0b0a080b080b080b080a080d0b060a080a080d0d08080b080b080c0b080708070b080b080b090b090b0909070907090709070a0808060d0b08060908090709090e0e0e 0c09080f0c0f0c0b090b0a08070b080a080a080a080a080a080a080a080a080a080a080a080a0808080808080808080808080808080808060406040b090b090b090b090b090b090b090b090b090b090b 090b090b080b080b090b090b090b090b090807080708070900000000000000000003030310140a00080404070a090d0b040505090904050406090909090909090909090404090909070e0b0b0a0b0808 0b0b060409080e0c0b090b0a08080b0a0e0908090506050907090909080909040809040408040e0909090906070509080c080808060906090404090909090908090d060809050d080709060609090a04 030606080c0c0c070b0b0b0b0b0b0e0a08080808060606060b0c0b0b0b0b0b090b0b0b0b0b08090a0909090909090e080909090904040404090909090909090909090909090809080b090b090b090a08 0a080a080a080b090b09080908090809080908090b080b080b080b080b090b09060406040604060406040a080404090808080408040804080608040c090c090c090b0c090b090b090b090e0f0a060a06 0a0608070807080708070805080508050b090b090b090b090b090b090e0c08080809080908090805090b090e0e0b09080709090909040903090909090b040a0c070d0b0d050b0b080a08090b0b06090a 0e0c090b0b090908080d090d0b06080907090509090a080907070909050808090808090a09080907090b080c0c050909090c080b080a080606040f0f0b090a0b0b090b080a080e090c0c090b0e0b0b0b 090a080a0d090b0a10100b0d0a0a100a0909090609090b07090908090b090909090807080b0809090e0e0b0c09080d0909090608070404040e0e0908080908060e0c0e0c0e0c08080810100703030303 0606060808070c140407050508020609090d090d08100d0b0a0c0c0c0c090a0b0a09090b06090909090909090a0408080806060606060606081008100504030904030200001010040309090c0e0e0b09 0d05060e0e0b090b0a0000000000080c0909100d0b090e0b0b090e0c0b090f0e09070d0c0b090a080a0813110b090e0d100d0a080a09090909100f0c090909090908060b080e0b09070a09090809080b 0a0b090c0b110d0d0a0a0808070807080709080d0b0b0a0a090b090d0a0d0a060e0b0b090b090b090b090a090e0b060b090b090e0e08090b090b090e0b090709080c090c090b090b090b090a080a080a 080a080a0908060d0c08060a08090809090e0e0f0d0a08100e100e0b090b0a09070b090b090b090b090b090b090b090b090b090b090b090b090b0908090809080908090809080908090809060406040b 090b090b090b090b090b090b090b090b090b090b090b090b090b090b0a0b0a0b0a0b0a0b0a0808080808080900000000000000000003030311140a00090404070b090e0c040505090904050406090909 090909090909090404090909070f0a0b0a0c09090c0c06050a080f0d0d0a0d0b09090c0a0f09090a05060509070a090a080a09060809040408040f090a0a0a06080609080d0808080609060904040909 090909080a0e060809050e09070906060a090b04030606080d0d0d070a0a0a0a0a0a0e0a09090909060606060c0d0d0d0d0d0d090d0c0c0c0c090a0a0909090909090e0809090909040404040a090a0a 0a0a0a090a09090909080a080a090a090a090a080a080a080a080c0a0c0a090909090909090909090c080c080c080c080c090c09060406040604060406040b0805040a0808080408040804080608040d 090d090d090b0d090d0a0d0a0d0a0f0f0b060b060b0609080908090809080906090609060c090c090c090c090c090c090f0d0908090a080a080a0805090a090e0e0d0a09080a0a090a040a030a0a0a0a 0a040a0d080d0b0d050a0b090a090a0c0d060a0a0f0d090d0c0a0909090e090e0d06090a080905090a0a080a0808090a0508090908080a0b0a080a08090c090c0d05090a090d090c090a090606050f10 0c0a0a0c0a0a0b090b090e0a0d0d0a0b0f0c0d0c0a0a090a0e090c0b11110b0e0b0a120b090a090609090c08090908090c090a090a0808080c0809090f0f0b0c09080e0909090608080404040e0e0908 080908070f0d0f0d0f0d090809111107030303030606060808060f140407050508020609090d090e09120e0d0b0d0d0d0d0a0a0c0b09090c0709090909090a0a0a040909090606060606060609110911 060403090503020000111104030a0a0d0f0f0a090d060710100d0a0c0a0000000000090d0909110e0b0a0f0c0a090f0c0c0b110e09080e0c0d0a0a080a0814120d0a0f0d110e0a080a090a0a0a11100e 090a0a0a0a09060b090e0c0a080b090a080a080b0a0c090d0b120f0e0b0a0809080907090709080d0c0c0a0b090c090e0a0e0a060e0c0b090b090c090c090b090f0c060a090a090e0e09090d090d090e 0c0a080a080d090d090d0a0d0a0d0a0a080a080a080a080b0909060e0c09060a0909080a0a0f0f100d0b09100e110e0c0a0d0b0a080b090a090a090a090a090a090a090a090a090a090a090a090a0909 090909090909090909090909090909060406040d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0c090c090c0a0c0a0c0a0c0a0c0a0908090809080a00000000000000000003030312160b00 090504070c0a0f0d0405050a0a040604070a0a0a0a0a0a0a0a0a0a04040a0a0a08100b0b0b0c0a090c0d06050a09100d0d0b0d0b09090d0a100a090a0507050a070a0a0b080b0a070a0b05050905100b 0a0b0b0709060b0a0d090a08060a060a05040a0a0a0a0a090a0f060a0a060f09080a06060a0b0c040406060a0d0d0d080b0b0b0b0b0b0f0b0a0a0a0a060606060c0d0d0d0d0d0d0a0d0d0d0d0d090b0b 0a0a0a0a0a0a0f080a0a0a0a050505050a0b0a0a0a0a0a0a0a0b0b0b0b0a0b0a0b0a0b0a0b0a0b080b080b080b080c0b0c0b0a0a0a0a0a0a0a0a0a0a0c0a0c0a0c0a0c0a0d0b0d0b0605060506050605 06050b0a05050a0909090509050905090609050d0b0d0b0d0b0d0d0b0d0a0d0a0d0a10100b070b070b0709090909090909090906090609060d0b0d0b0d0b0d0b0d0b0d0b100d090a090a080a080a0805 0a0b0a0f0f0d0a09090a0a0a0a050a030a0a0a0a0b040b0e080e0c0e060b0b0a0b0a0a0d0d060a0b100d0a0d0d0b0a09090e0a0e0d06090b080b060b0b0b0a0a08080b0a0609090b09080a0c0b080a08 0b0d0a0c0d060b0a0b0d0a0d0a0b0906060510110d0a0b0d0b0b0b0a0c0a0e0a0d0d0a0c100d0d0d0b0b090b0e0a0d0c12120c0f0b0b130b0a0a0a070a0a0d080b0b090a0e0b0a0b0b08080a0d090b0b 10100c0e0a080f0a0a0b0708090505050f100b090a0b0907100d100d100d090a09121207030304030606060808070f15040706060902070a0a0e0a0e09130e0d0b0e0e0e0e0a0b0d0b0a0a0d070a0a0a 0a0b0b0b0b0509090906060606060606091209120605030a0504020000121205030b0a0f10100b0a0e060711110d0a0d0c00000000000a0d0a0b120e0c0b100d0b0a100e0c0b110e0a080e0c0d0a0a0a 0a0a16130d0a110e120e0b080b0a0a0a0a12110d0b0a0b0b0b09070b090e0d0a080b0a0a090a090c0b0d0b0e0c130f0d0c0b080908090909090a090f0d0d0b0c0b0d0b0f0c0f0c060e0d0c0a0c0a0d0b 0d0b0c0b100e060b0a0b0a0f0f0a0a0d0a0d0a0e0d0a080a080d0b0d0b0d0a0d0a0d0a0b080b0a0b0a0b0a0c0b0a070f0e09070b090a090b0b1011100f0b09120f13100d0a0d0c0a080c0a0b0a0b0a0b 0a0b0a0b0a0b0a0b0a0b0a0b0a0b0a0b0a0b0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a060506050d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0a0d0b0d0b0d0c0d0c0d0c0d0c0d0c090a09 0a090a0b00000000000000000004040413170b000a0504080c0a100d0406060a0a040604070a0a0a0a0a0a0a0a0a0a04040a0a0a08100c0c0c0d0a090d0e06050b0a110e0e0b0e0c0a0a0e0b110a0a0a 0607060a080b0a0b090b0a070a0b05050905110b0a0b0b0809060b0a0e0a0a08070a070a05040a0a0a0a0a0a0b10070a0a06100a080a06060b0b0c040406070a0e0e0e080c0c0c0c0c0c100c0a0a0a0a 060606060d0e0e0e0e0e0e0a0e0e0e0e0e0a0b0b0a0a0a0a0a0a10090a0a0a0a050505050a0b0a0a0a0a0a0a0a0b0b0b0b0a0b0a0c0a0c0a0c0a0c090c090c090c090d0b0d0b0a0a0a0a0a0a0a0a0a0a 0d0a0d0a0d0a0d0a0e0b0e0b060506050605060506050b0a05050b09090a050a050a050a060a050e0b0e0b0e0b0d0e0b0e0a0e0a0e0a11110c080c080c080a090a090a090a090a060a060a060e0b0e0b 0e0b0e0b0e0b0e0b110e0a0a0a0a080a080a08050a0c0a10100e0a0a090b0b0b0b050b040b0b0b0b0c040b0e090f0d0f060c0c0a0b0a0a0e0e060b0c110e0a0e0e0b0a0a0a0e0a0e0e060a0b080b060b 0b0b0a0a08090b0a06090a0b0a090a0c0b090a090b0d0a0e0e060b0a0b0e0a0d0a0c0a06060511120d0b0b0e0c0b0c0a0c0a100a0e0e0b0d110e0e0e0b0c0a0b0e0a0e0c12120c100c0c140c0a0a0a07 0b0a0e080b0b090a0e0b0a0b0b09090a0d0a0b0b11110d0f0a090f0a0a0b0709090505050f100b090a0b0a08110e110e110e0a0a0a131308030304030707070808070f17040806060902070a0a0e0a0f 0a130e0e0c0e0e0e0e0b0b0e0b0a0a0d070a0a0a0a0b0c0c0b050a0a0a060606060606060a130a130605030a0504020000131305030b0a1011110c0a0f060812120e0a0e0c00000000000a0e0a0b130f 0c0b110e0c0b110f0e0d13110a080e0e0e0a0b0a0b0a16140e0b120f130f0c090c0b0b0b0b13120e0b0b0b0b0b09070c0a100e0a080c0a0b090b090d0b0e0b0f0c14100e0c0c090a090a090a090a0a10 0d0d0b0c0b0e0b0f0c0f0c06100e0d0a0d0a0e0b0e0b0c0b110e060c0a0c0a10100a0a0e0a0e0a100e0a080a090e0b0e0b0e0a0e0a0e0a0c090b0a0b0a0b0a0c0b0a07100f09070b0a0a0a0b0b111111 0f0b09131014110e0a0d0c0a080d0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0c0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a060506050e0a0e0a0e0a0e0a0e0a0e0a0e0a0e0a0e0a0e0a0e 0a0e0a0e0b0e0b0e0c0e0c0e0c0e0c0e0c0a0a0a0a0a0a0b00000000000000000004040414180c000a0505080d0b110e0506060b0b050605070b0b0b0b0b0b0b0b0b0b05050b0b0b09110d0c0c0e0b0a 0e0d07060b0a110e100c100c0b0b0d0c120b0b0b0607060b080c0b0c090c0a070b0c05050a05130c0b0c0c0809070c0a0f0a0a09070b070b05050b0b0b0b0b090c11070a0b06110a090b07070c0c0d05 0407070a0f0f0f090d0d0d0d0d0d110c0b0b0b0b070707070e0e10101010100b100d0d0d0d0b0c0c0b0b0b0b0b0b11090a0a0a0a050505050b0c0b0b0b0b0b0b0b0c0c0c0c0a0c0a0d0b0d0b0d0b0c09 0c090c090c090e0c0e0c0b0a0b0a0b0a0b0a0b0a0e0b0e0b0e0b0e0b0d0c0d0c070507050705070507050d0a06050b0a0a0a050a050a050a060a050e0c0e0c0e0c0e0e0c100b100b100b12120c080c08 0c080b090b090b090b090b070b070b070d0c0d0c0d0c0d0c0d0c0d0c120f0b0a0b0b090b090b09060b0d0b1111100b0b090c0c0b0c050c040c0c0c0c0d050d0f09110d11060d0c0b0c0b0b0d10070b0c 110e0b100d0c0b0b0b0f0b0f10070b0c080c060c0c0c0b0b08090c0b060a0a0c0a090b0d0c090b090c0d0a0f0f060c0b0c0f0b0e0b0c0b07070613130e0b0c0d0d0c0c0b0d0b110b0e0e0b0d110d100d 0c0c0b0c0f0b0d0d13130d100c0d150c0b0b0b080b0a0f080c0c0a0b0e0c0b0c0c09090a0f0a0c0c11110e100b09110b0a0c08090905050511110c0a0a0c0908120f120f120f0b0a0a14140804040404 0808080a0a080f17050806060a03070b0b0f0b100a140f100c0f0f0f0f0c0c0e0c0b0b0e080b0b0b0b0b0c0c0c050a0a0a070707070707070a140a140705030b0504020000141405040c0b1111130d0b 1007081212100b0f0d00000000000b0e0a0c13100d0c120e0d0b120f0f0d13110b080f0f100b0c0a0c0a1815100c121013100c090c0b0c0c0c14130e0c0c0c0c0c0a080c0a110f0b080c0b0b0a0b0a0d 0c0d0c0f0e15110f0c0c090b090b0b0b0b0b0a110f0d0d0d0c0d0c100d100d07110f0d0b0d0b0d0c0d0c0d0c110e070d0b0d0b11110b0a0f0a0f0a110f0b080b090e0c0e0c100b100b100b0d090c0a0c 0a0c0a0d0c0b0810100a080c0a0b0a0c0c1212110f0b09131113120f0b0e0e0b080d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0b0a0b0a0b0a0b0a0b0a0b0a0b0a0b0a0705070510 0b100b100b100b100b100b100b100b100b100b100b100b0d0c0d0c0f0d0f0d0f0d0f0d0f0d0b0a0b0a0b0a0c000000000000000000040404151a0d000b0506080e0c110f0406060c0c060706080c0c0c 0c0c0c0c0c0c0c06060c0c0c09120d0d0d0e0b0a0e0f08060c0a120f0f0c0f0d0b0a0f0c130b0c0b0608060b090c0b0c0a0c0b070b0c05050a05130c0c0c0c0809070c0b100b0b09070c070c05060c0c 0c0c0c0a0c11070a0c07110b090c07070c0c0e060407070a0f0f0f090d0d0d0d0d0d120d0b0b0b0b080808080e0f0f0f0f0f0f0c0f0f0f0f0f0c0c0c0b0b0b0b0b0b120a0b0b0b0b050505050c0c0c0c 0c0c0c0c0c0c0c0c0c0b0c0b0d0b0d0b0d0b0d0a0d0a0d0a0d0a0e0c0e0c0b0b0b0b0b0b0b0b0b0b0e0b0e0b0e0b0e0b0f0c0f0c080508050805080508050d0b06050c0a0a0a050a050a050a060a050f 0c0f0c0f0c0e0f0c0f0c0f0c0f0c13140d080d080d080b090b090b090b090a070a070a070f0c0f0c0f0c0f0c0f0c0f0c13100c0b0c0b090b090b09060c0d0b12120f0c0b090c0c0c0c050c040c0c0c0c 0d060d100a100e11060d0d0b0c0b0b0f0f080c0d120f0b0f0f0c0b0a0c100b100f080c0c090c060c0c0d0b0c09090c0c060a0b0c0b0a0c0d0c0a0c090c0f0b100f060c0c0c0f0b0f0b0d0b0808061314 0f0c0c0f0d0c0d0b0e0b120b0f0f0c0e120f0f0f0c0d0a0c100b0f0e14140e110d0d150d0b0c0b080c0b0f090c0c0a0c0f0c0c0c0c0a090b0f0b0c0c11110e100b0a120b0b0c080a0905050511120c0a 0b0c0a081310131013100c0b0b151509040404040808080a0a091219040806060a03070c0c100c110b15110f0d101010100c0c0f0c0c0c0f080c0c0c0c0b0c0c0c050b0b0b070707070707070b150b15 0705040c0604020000151505040d0c1112130d0b10070813130f0c100d00000000000b0f0b0c14110d0c130f0d0b120f0e0d14110b0910100f0c0c0b0c0b1a16100d131114110d0a0d0c0c0c0c151410 0c0c0c0c0c0a080d0b120f0b090d0b0c0a0c0a0e0d0f0c110e1612100d0d0a0a090c0b0c0b0b0b110f0e0d0e0c0f0c110e110e08120f0e0b0e0c0f0c0f0c0e0c120f080d0b0d0b12120b0b0f0b0f0b12 0f0b090b0a0f0c0f0c0f0c0f0c0f0c0d0a0c0b0c0b0c0b0e0c0b0811100a080d0b0b0b0c0c121212100c0a141215120f0c0e0e0b090e0c0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0b 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b080508050f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c0f0c100d100d100d100d100d0c0b0c0b0c0b0c000000000000000000040404161a0d00 0b0606080e0c120f0407070c0c060706080c0c0c0c0c0c0c0c0c0c06060c0c0c09130d0e0d0f0c0b0f0f08060d0b1310100d100d0b0b0f0d130c0c0c0708070c090d0c0d0a0d0c070b0d06060b06140d 0d0d0d090a070d0b100b0b0a080c080c06060c0c0c0c0c0b0d12070b0c07120b090c07070d0d0e060507080b101010090d0d0d0d0d0d130d0c0c0c0c080808080f1010101010100c100f0f0f0f0c0d0d 0c0c0c0c0c0c120a0c0c0c0c060606060d0d0d0d0d0d0d0c0d0d0d0d0d0b0d0b0d0c0d0c0d0c0d0a0d0a0d0a0d0a0f0d0f0d0c0c0c0c0c0c0c0c0c0c0f0b0f0b0f0b0f0b0f0d0f0d0806080608060806 08060d0c06060d0b0b0b060b060b060b070b06100d100d100d0f100d100d100d100d14150d090d090d090b0a0b0a0b0a0b0a0b070b070b070f0d0f0d0f0d0f0d0f0d0f0d13100c0b0c0c0a0c0a0c0a06 0c0d0c1312100d0b0a0d0d0c0d060d040d0d0d0d0d060d110a110f11070d0e0c0d0c0c0f10080d0d13100c100f0d0c0b0c100c1010080c0d0a0d070d0d0d0b0d0a0a0d0d070b0b0d0b0a0d0e0d0a0d0a 0d100c1010070d0d0d100c0f0c0d0b08080614150f0d0d0f0d0d0e0c0e0c120c10100d0f130f100f0d0d0b0d100c0f0f16160f120e0d170d0c0d0c090c0c100a0d0d0b0c100d0d0d0d0a0a0b100b0d0d 14140e110c0a130c0c0d090a0a06060612130d0b0b0d0a091310131013100c0b0b161609040405040808080b0b08121a040807070b03080c0c110c120b1611100e111111110d0d0f0d0c0c0f080c0c0c 0c0d0d0d0c060b0b0b070707070707070b160b160706040c0604020000161606040d0c1213140d0c1107091414100d100e00000000000c100c0d16110e0d14100d0c13110e0e14120c0a1010100d0d0b 0d0b1a17110e151116120d0a0d0c0d0d0d1615100d0d0d0d0d0b090e0c12100c0a0e0c0d0b0d0b0e0d0f0d110f1713100e0d0a0b0a0c0a0c0a0c0b120f0f0d0f0d0f0d120e120e0812100f0c0f0c0f0d 0f0d0f0d1310080d0c0d0c13120c0c0f0c0f0c12100c0a0c0a100d100d100d100d100d0d0a0d0b0d0b0d0b0f0d0c0912110b090d0c0c0b0d0d141314110d0b16121613100d0f0f0c0a0f0c0d0c0d0c0d 0c0d0c0d0c0d0c0d0c0d0c0d0c0d0c0d0c0d0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c08060806100d100d100d100d100d100d100d100d100d100d100d100d0f0d0f0d100e100e100e100e100e0c0b0c 0b0c0b0d000000000000000000050505171c0e000c0606080f0d13100407070d0d060706090d0d0d0d0d0d0d0d0d0d06060d0d0d0a140e0e0e100c0b101008060d0b1411110d110e0c0c100d140d0c0c 0709070c090d0c0d0b0d0c080c0e06060b06140e0d0d0d090a080e0b110b0b0a080c080d06060d0d0d0d0c0b0d13080b0d07130c0a0d08080d0e0f060508080b1111110a0e0e0e0e0e0e140e0c0c0c0c 08080808101111111111110d11101010100c0d0e0c0c0c0c0c0c130b0c0c0c0c060606060d0e0d0d0d0d0d0d0d0e0e0e0e0b0d0b0e0c0e0c0e0c0e0b0e0b0e0b0e0b100d100d0c0c0c0c0c0c0c0c0c0c 100c100c100c100c100e100e080608060806080608060e0c06060d0b0b0b060b060b060b080b06110e110e110e10110e110d110d110d14150e090e090e090c0a0c0a0c0a0c0a0c080c080c08100e100e 100e100e100e100e14110c0b0c0c0a0c0a0c0a070d0e0c1413110d0c0a0d0d0d0d060d040d0d0d0d0e060e120b120f12080e0e0c0d0c0c1011080d0e14110c11100d0c0c0c120d1211080c0d0a0e080e 0d0e0b0d0a0a0e0d080b0c0e0b0b0d0f0d0b0d0a0e100c1110080e0d0e100c100c0e0c0808061516100d0d100e0d0e0c0f0c120d11110d0f141011100d0e0c0d120d100f16160f130e0e180e0c0d0d09 0d0c100b0e0e0b0d110e0d0e0d0b0a0b100b0e0d141410120d0b130c0c0e090b0a06060614150e0b0b0e0b091411141114110c0b0c171709040405040808080a0a0a121b040808080b03080d0d110d12 0c1712110e111111110d0d100e0d0d10090d0d0d0d0d0e0e0d060c0c0c080808080808080c170c170806040d0605020000171706040e0c1214140e0c1208091515110d110f00000000000c110c0e1612 0e0d15100e0c1411100e16130d0b1211110d0d0b0d0b1c18120f151216130e0b0e0d0d0d0d1716110e0d0d0d0d0b090e0d12100d0b0e0c0d0b0d0b0f0d100e12101814110e0e0b0c0a0c0b0c0b0d0b13 100f0e0f0d100e130f130f0812100f0d0f0d100e100e0f0d1411080e0c0e0c14130c0c100c100c12100d0b0d0b110e110e110d110d110d0e0b0d0b0d0b0d0b0f0d0c0913120b090e0c0d0b0d0d141415 130e0c16141715110d100f0d0b0f0d0e0c0e0c0e0c0e0c0e0c0e0c0e0c0e0c0e0c0e0c0e0c0e0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c08060806110d110d110d110d110d110d110d110d110d110d11 0d110d100e100e110f110f110f110f110f0c0b0c0b0c0b0d000000000000000000050505181c0e000c06060a100d14110507070d0d060806090d0d0d0d0d0d0d0d0d0d06060d0d0d0a150f0f0e100d0c 111109070e0c1512120e120e0d0d110e150d0d0d0709070d0a0e0d0e0b0e0d080d0e06060c06160e0e0e0e0a0b080e0c120c0c0b090d090d06060d0d0d0d0d0c0e14080c0d08140c0a0d08080e0e1006 0508080c1212120a0f0f0f0f0f0f140e0d0d0d0d09090909101212121212120d12111111110d0e0e0d0d0d0d0d0d140b0d0d0d0d060606060e0e0e0e0e0e0e0d0e0e0e0e0e0c0e0c0f0d0f0d0f0d0e0b 0e0b0e0b0e0b100e100e0d0d0d0d0d0d0d0d0d0d110d110d110d110d110e110e090609060906090609060f0c07060e0c0c0c060c060c060c080c06120e120e120e10120e120e120e120e15160e0a0e0a 0e0a0d0b0d0b0d0b0d0b0d080d080d08110e110e110e110e110e110e15120d0c0d0d0b0d0b0d0b070d0f0d1414120e0d0b0e0e0d0e060e040e0e0e0e0f060e120b131013080f0f0d0e0d0d1112090e0f 15120d12110e0d0d0d130d1312090d0e0b0e080e0e0e0c0e0b0b0e0e080c0c0e0c0b0e0f0e0b0e0b0e100d1212080e0e0e120d110d0e0d0909071617110e0e110f0e0f0d100d140d12120e1015111211 0e0e0d0e130d1110171710140f0e190e0d0e0d0a0d0d100b0e0e0c0d110e0e0e0e0b0a0c100c0e0e141410120d0b140d0d0e0a0b0b06060614150e0c0c0e0c0a1512151215120d0c0c18180a04040504 0909090b0b0a121c050a08080c03080d0d120d130c1813120f121212120e0e110e0d0d11090d0d0d0d0f0e0e0d060c0c0c080808080808080c180c180806040d0605020000181806040e0d1415160f0d 13080a1616120e110f00000000000d120d0e17130f0e15110f0d1512110e17140d0b1312120e0e0c0e0c1c19130f161317130e0b0f0d0e0e0e1817120e0e0e0e0e0c0a0f0d14100d0b0f0d0e0c0e0c10 0e110e12101915120f0e0b0d0a0d0c0d0c0d0c1411100e100e110e130f130f091410100d100d110e110e100e1511090f0d0f0d14140d0d110d110d14100d0b0d0b120e120e120e120e120e0e0b0e0c0e 0c0e0c100e0d0a14120c0a0e0d0d0c0e0e151515130d0c17141815110e110f0d0b100d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0f0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0906090612 0e120e120e120e120e120e120e120e120e120e120e120e110e110e110f110f110f110f110f0d0c0d0c0d0c0e00000000000000000005050500000003000000030000001c00010000000002d800030001 000004e2000402bc00000090008000060010007e017f019201a101b001f001ff021902bc02c702c902dd02f3030103030309030f0323038a038c03a103ce03d203d6040d044f045f0486049105131e01 1e3f1e851ef11ef91f4d200b2015201e2022202620302033203a203c2044207f20a420a720ac21052113211621222126212e215e22022206220f2212221a221e222b22482260226525cafb04fefffffd ffff0000002000a0019201a001af01f001fa021802bc02c602c902d802f3030003030309030f03230384038c038e03a303d103d60400040e04500460048804921e001e3e1e801ea01ef21f4d20002013 201720202026203020322039203c2044207f20a320a720ab21052113211621222126212e215b22022206220f2211221a221e222b22482260226425cafb01fefffffcffffffe3ffc2ffb000bf00b20061 ff49ff31ff96fe85fe84fe76ff68ff63ff62ff5d0067ff44fdd0fdcffdcefdcdfe82fe7f0000fd9a0000fe0c0000fe09e458e418e37ae47d0000e30de242e1efe1eee1ede1eae1e1e1e0e1dbe1dae1d3 e199e176e1740000e118e10be109e0fee0fbe0f4e0c8e025e022e01ae019e012e00fe003dfe7dfd0dfcddc690000034f0253000100000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000060000000780000009400000000000000000000009c00000000000000000000000000000000000000000000000000000000008e0000000000000000 00000000000000000000000000000000000000000000000000000000006c0000000000000268019c019d019e019f01a001a101a201a301a401a501a601a70269026a01ea01eb01ec01ed01ee01ef01f0 01f101f201f301f401f5026b01f601f70293029402950296029702980299029a01f801f902000201036f037003710372037303740375021c02340235025d025e0006020a000000000100000100000000 000000000000000000000001000200020000000000020000000000000000000000000000000000000000000000000000000000000001000000000003000400050006000700080009000a000b000c000d 000e000f0010001100120013001400150016001700180019001a001b001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f003000310032003300340035 0036003700380039003a003b003c003d003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d 005e005f006000610000008600870089008b00930098009e00a300a200a400a600a500a700a900ab00aa00ac00ad00af00ae00b000b100b300b500b400b600b800b700bc00bb00bd00be020d00720064 00650069020f007800a10070006b02200076006a02300088009a022d007302310232006700770227022a0229018d022e006c007c022100a800ba00810063006e022c0142022f0228006d007d02100062 0082008500970114011502020203020a020b0206020700b9023300c1013a0217021c0214021502340235020e00790208020c02110084008c0083008d008a008f00900091008e0095009600000094009c 009d009b00f3014b01520071014e014f0150007a01530151014c000402bc00000090008000060010007e017f019201a101b001f001ff021902bc02c702c902dd02f3030103030309030f0323038a038c 03a103ce03d203d6040d044f045f0486049105131e011e3f1e851ef11ef91f4d200b2015201e2022202620302033203a203c2044207f20a420a720ac21052113211621222126212e215e22022206220f 2212221a221e222b22482260226525cafb04fefffffdffff0000002000a0019201a001af01f001fa021802bc02c602c902d802f3030003030309030f03230384038c038e03a303d103d60400040e0450 0460048804921e001e3e1e801ea01ef21f4d20002013201720202026203020322039203c2044207f20a320a720ab21052113211621222126212e215b22022206220f2211221a221e222b224822602264 25cafb01fefffffcffffffe3ffc2ffb000bf00b20061ff49ff31ff96fe85fe84fe76ff68ff63ff62ff5d0067ff44fdd0fdcffdcefdcdfe82fe7f0000fd9a0000fe0c0000fe09e458e418e37ae47d0000 e30de242e1efe1eee1ede1eae1e1e1e0e1dbe1dae1d3e199e176e1740000e118e10be109e0fee0fbe0f4e0c8e025e022e01ae019e012e00fe003dfe7dfd0dfcddc690000034f02530001000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000780000009400000000000000000000009c00000000000000000000000000000000 000000000000000000000000008e000000000000000000000000000000000000000000000000000000000000000000000000006c0000000000000268019c019d019e019f01a001a101a201a301a401a5 01a601a70269026a01ea01eb01ec01ed01ee01ef01f001f101f201f301f401f5026b01f601f70293029402950296029702980299029a01f801f902000201036f037003710372037303740375021c0234 0235025d025e0000404559585554535251504f4e4d4c4b4a494847464544434241403f3e3d3c3b3a393837363531302f2e2d2c28272625242322211f181411100f0e0d0b0a090807060504030201002c 4523466020b02660b004262348482d2c452346236120b02661b004262348482d2c45234660b0206120b04660b004262348482d2c4523462361b0206020b02661b02061b004262348482d2c45234660b0 406120b06660b004262348482d2c4523462361b0406020b02661b04061b004262348482d2c0110203c003c2d2c20452320b0cd442320b8015a51582320b08d44235920b0ed51582320b04d44235920b0 042651582320b00d44235921212d2c20204518684420b001602045b04676688a4560442d2c01b10b0a432343650a2d2c00b10a0b4323430b2d2c00b0282370b101283e01b0282370b10228453ab10200 080d2d2c2045b00325456164b050515845441b2121592d2c49b00e23442d2c2045b0004360442d2c01b00643b00743650a2d2c2069b04061b0008b20b12cc08a8cb8100062602b0c642364615c58b003 61592d2c8a03458a8a87b0112bb0292344b0297ae4182d2c4565b02c234445b02b23442d2c4b525845441b2121592d2c4b515845441b2121592d2c01b005251023208af500b0016023edec2d2c01b005 251023208af500b0016123edec2d2c01b0062510f500edec2d2c462346608a8a462320468a608a61b8ff8062232010238ab10c0c8a70456020b0005058b00161b8ffba8b1bb0468c59b0106068013a2d 2c2045b0032546524bb013515b58b0022546206861b00325b003253f2321381b2111592d2c2045b00325465058b0022546206861b00325b003253f2321381b2111592d2c00b00743b006430b2d2c2121 0c6423648bb84000622d2c21b08051580c6423648bb82000621bb200402f2b59b002602d2c21b0c051580c6423648bb81555621bb200802f2b59b002602d2c0c6423648bb84000626023212d2c4b5358 8ab004254964234569b0408b61b08062b020616ab00e23442310b00ef61b21238a121120392f592d2c4b535820b0032549646920b00526b0062549642361b08062b020616ab00e2344b0042610b00ef6 8a10b00e2344b00ef6b00e2344b00eed1b8ab00426111220392320392f2f592d2c4523456023456023456023766818b08062202d2cb0482b2d2c2045b0005458b040442045b04061441b2121592d2c45 b1302f4523456160b0016069442d2c4b5158b02f2370b01423421b2121592d2c4b515820b0032545695358441b2121591b2121592d2c45b01443b0006063b0016069442d2cb02f45442d2c452320458a 60442d2c45234560442d2c4b235158b90033ffe0b134201bb3330034005944442d2cb0164358b00326458a586466b01f601b64b020606620581b21b04059b001615923586559b02923442310b029e01b 2121212121592d2cb0024354584b53234b515a58381b2121591b21212121592d2cb0164358b004254564b020606620581b21b04059b0016123581b6559b0292344b00525b00825082058021b0359b004 2510b005252046b0042523423cb00425b0072508b0072510b006252046b00425b0016023423c2058011b0059b0042510b00525b029e0b02920456544b0072510b00625b029e0b00525b0082508205802 1b0359b00525b003254348b00425b0072508b00625b00325b0016043481b2159212121212121212d2c02b00425202046b004252342b0052508b003254548212121212d2c02b0032520b0042508b00225 43482121212d2c452320451820b00050205823652359236820b040505821b04059235865598a60442d2c4b53234b515a5820458a60441b2121592d2c4b545820458a60441b2121592d2c4b53234b515a 58381b2121592d2cb000214b5458381b2121592d2cb002435458b0462b1b21212121592d2cb002435458b0472b1b212121592d2cb002435458b0482b1b21212121592d2cb002435458b0492b1b212121 592d2c208a08234b538a4b515a5823381b2121592d2c00b0022549b000535820b04038111b21592d2c014623466023466123201020468a61b8ff80628ab140408a704560683a2d2c208a2349648a2353 583c1b21592d2c4b52587d1b7a592d2cb012004b014b54422d2cb1020042b123018851b1400188535a58b910000020885458b202010243604259b12401885158b920000040885458b2020202436042b1 2401885458b2022002436042004b014b5258b2020802436042591bb940000080885458b202040243604259b94000008063b80100885458b202080243604259b94000010063b80200885458b202100243 604259b94000020063b80400885458b202400243604259595959592d2c451868234b51582320452064b04050587c59688a6059442d2cb00016b00225b0022501b001233e00b002233eb10102060cb00a 236542b00b234201b001233f00b002233fb10102060cb006236542b0072342b00116012d2c7a8a104523f5182d000000401009f803ff1f8ff79ff7027ff30160f201b8ffe8402beb0c1046df33dd55de ffdc5530dd01dd010355dc03fa1f30c2016fc0efc002fcb6181f30b70160b780b702b8ffc04038b70f1346e7b1011faf2faf3faf034faf5faf6faf0340af0f1346ac51181f1f9c5f9c02e09b01032b9a 011f9a01909aa09a02739a839a0205b8ffea40199a090b46af97bf9702032b96011f96019f96af96027c960105b8ffea408596090b462f923f924f920340920c0f462f91019f91018786181f407c507c 020310742074307403027401f274010a6f01ff6f01a96f01976f01756f856f024b6f010a6e01ff6e01a96e01976e014b6e01061a0118551913ff1f0704ff1f0603ff1f3f67011f672f673f67ff670440 665066a066b066043f65010f65af650205a064e0640203b8ffc0404f64060a46615f2b1f605f471f5f50221ff75b01ec5b01545b845b02495b013b5b01f95a01ef5a016b5a014b5a013b5a0106133312 5505010355043303551f03010f033f03af03030f571f572f570303b8ffc0b356121546b8ffe0b356070b46b8ffc0b354121546b8ffc0406d54060b4652502b1f3f504f505f5003fa4801ef4801874801 6548015648013a4801fa4701ef47018747013b4701061c1bff1f1633155511010f5510330f550201005501470055fbfa2b1ffa1b121f0f0f011f0fcf0f020f0fff0f02066f007f00af00ef0004100001 8016010501b80190b154532b2b4bb807ff524bb006505bb00188b02553b00188b040515ab00688b000555a5b58b101018e59858d8d00421d4bb0325358b0601d594bb0645358b0401d594bb0805358b0 101db11600425973735e7374752b2b2b2b2b2b2b2b015f7373737373737373737300732b012b2b2b2b5f730073742b2b2b015f73737373737373737373002b2b2b012b5f735e7374737374002b2b2b2b 015f737373737473737373737400737474015f732b0073742b73012b5f737374745f732b5f73737474005f7373012b002b73740173002b73742b017300732b2b732b2b012b737373002b185e0614000b 004e05b60017007505b605cd0000000000000000000000000000044a0014008f0000ffec00000000ffec00000000ffec0000fe14fe000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000ac00b600bc000000d5000000000000005500830097009f 007d00e500ae00ae007100710000000000ba00c500ba0000000000a4009f008c0000000000c700c7007d007d00000000000000000000000000b000b9008a00000000009b00a6008f0077000000000000 000000000096000000000000000000000069006e009000b400c100d500000000000000000066006f0078009600c000d5014700000000000000fe013a00c5007800fe011601f600000000000000000000 00000000000000000000000000ee00000096008800ae00960089010c009601180000031d0094025a00820396000000a8008c00000000027900d900b4010a00000183006d007f00a000000000006d0088 00000000000000000000000000000000009300a00000008200890000000000000000000005b6fc940011ffef0083008f00000000006d007b0000000000000000000000bc01aa03540000000000bc00b6 01d7019500000096010000ae05b6febcfe6ffe83006f02ad0000002a002a002a002a006f00a1012901e202710329034d037c03ac03e2040f0444045b049504b40506053f05940612066506cc073f0767 0811088208da093d097909bb09f70a6a0b340ba00c170c740cb30cec0d390d970dcd0e100e490e970eb70f2b0f7c0fd51022108b10fc116611a711e5123812ee134d139e13d113f71417143b14591470 14951508156915ae160e166b16ce17a217e31814185f18af18c81939197719c01a221a831ac91b391b8e1bcf1c271cd41d651dce1e1b1e751e991ef51f481f481f901ff4206a2101217421a4225d22a1 234a23b424082435243d250c2523257e25ba260a267f26a426ee272b276527ab27e2282a287a28a328c828f7296d2985299c29b429cb29e42a092a722a852a9d2ab42acc2ae52afd2b142b2b2b442ba8 2bbf2bd72bee2c052c1d2c362c9b2d1c2d342d4b2d632d7c2d932ddd2e782e8f2ea52ebb2ed12ee92f012fb12fc42fdb2ff13007301f3037304e3065307e310e3124313b31513168317f319832093282 329932af32c532de32f4335933713389339f33b633cc33e334003417342f3446345e3475348e34a534bd34d534e834f035693580359635ad35c335da35f136053626363d3653366a3680369736ae36c5 36dd36f03706371e373b378c37e737fe3815382c3843385a38713884389838af38c838f13915392c39433956396939b239ca39e739fa3a0e3a263a3e3a513a743ac13b0e3b253b3b3b4f3b623b793b90 3bb23c133c6c3c833c993cb03cc73ce03cf83d693df73e0f3e253e383e4c3e643e7c3e933ea93ec03ed63eea3efd3f143f2a3f3d3f513f683f7a3fd1403b405340694081409740ae40c440dd40f5410e 41264139414c4163417a419141a741c041d741ed4204421b42324248427b42df43c1449644ae44c544dc44f245054518454e4584459c45d745fe464e467b46c24705473247a347bc47f6481b48414882 48b348e7490f492849304938496a49b649be49c649ce4a3d4a454a4d4a994aa14aa94af64afe4b294b314b794b814b894c184c204c8e4d104d294d424d584d6e4d844d9c4db14e234ea54f044f8c5008 506e50ae5120515e516651e2523052725312531a536e53c85437549054da551c559a562e568f57195732574b57615777579557ae5828583f58aa58b258ba58d358db597259d15a2f5a465a5d5aa65aae 5b015b095b115b845b8c5c195c9c5cfb5d135d5b5dbf5dc75dcf5dd75ddf5de75def5df75e675e6f5e775eac5ef35f3b5f915fe7603d608b60ee616561e261ea626562d762ff6365636d63e2646064a4 64bb64f5654065a565eb65f3661c6624662c666b667366f066f86732677267bd6816687368d5691f698869fc6a536a6b6ada6af06b4c6b546b5c6b756b7d6bf56c546cae6cc46cda6d1f6d546d7f6d97 6dae6dc56ddc6df66e106e286e406e5b6e766e916eba6ee56f116f446f726fce702a709470ef717571b8725d732a7332733a736d73a273b473d27415747074f77581761576c3774177f7787e788678e9 791279417970799b7a157a627a917adb7b017b2d7bc97c1a7ca37d1b7d607da47df07e0f7e2d7e707ea37ec97eee7f137f567f9f7ffc805b808a81278191819181918191819181918191819181918191 819181918191819182db834e835a8362840b84888524853b85528566857a85a785f48647867486a08715877c87db883e8863888888cf890e892e8946895e8975898c8a298ae48b658bda8c4b8cbc8d40 8dd38e6b8f178fb8905c910a91ba92a49393939b93a39410947094d095389552956c962c964296c89746984a993399f99ae69b489b979c569c9b9cde9d0d9d3e9e1d9ebb9f619fe9a044a0a8a124a1b2 a211a261a2cfa333a3d1a486a49ca4b2a526a591a5ffa672a6d8a744a78ea7e0a82ea887a8d0a91ea989a9fcaaadab57ab6bab7fabceac1dac25ac88acf9ad68ae0faecfaf36af94aff3b04fb0b6b119 b167b1adb22fb2bfb34cb3e6b3eeb405b41cb48ab4f9b56cb5c4b616b677b6beb717b771b7bdb841b8c1b8c9b8e0b8f6b90fb927b92fb937b94eb964b9caba28ba42ba5bba74ba8ebaa8bac2bb2cbb94 bbacbbc3bbddbbf6bc0fbc28bc30bc38bc51bc69bc83bc9dbcb5bccbbce5bcfdbd16bd2ebd47bd5fbda6bde1bdfabe13be25be37be50be66bee7bf9abfe4bfecc066c0f2c18bc21dc2a2c328c3bbc428 c484c4ebc54fc5cbc626c687c705c789c79dc7b1c7c8c7dfc7f6c80dc827c840c85ac873c88dc8a6c8c0c8d9c8fdc91ec937c950c969c982c99bc9b4c9cdc9e6ca08ca29ca40ca57ca6eca85ca9dcab3 cacdcae6cb00cb19cb33cb4ccb66cb7fcba3cbc4cbdbcbf2cc0acc22cc39cc51cc68cc7fcc98ccb2cccbcce5ccfecd18cd31cd4bcd6dcd91cda8cdbfcdd7cdeece06ce1ece36ce4dce65ce7dce94ceac cec3cedacef2cf07cf1fcf34cf4acf60cf78cf8dcfa5cfbdcfd5cfebd002d019d030d046d05ad09dd0f6d14bd1bad22fd27ad2c8d329d392d3bfd3e7d40f0000000200c10000040a05b600030007002b 400b0502020904700380030203b8ffc04009060948030403070003003f322f33012f2b5d3311332f3331301321112137211121c10349fcb7680279fd8705b6fa4a6804e600020093ffe3019105b60003 0017003ab90001fff040130a1448101980199019a01904030e9a04020204b8ffc0400a070a480401099b130203003f2ff5ce012f2b332f10e1325d31302b0123033303343e0233321e0215140e022322 2e0201507933dff014222e1b1a2f221414222f1a1b2e2214019e0418fab92635210f0f21352625352210102235000002008503a602b205b600030007003740230498070709d009e009022f096f097f09 03009800031003e003f0030403060202070303003f33332f33012f5de15d5d12392fe131300103230321032303014a297329022d29722905b6fdf00210fdf002100000020033000004f805b6001b001f 0099405803031a1a18161e1d070406171706190001040405b1181821151f1c0804091414120f0e0b0413b10a50100110100c0c09500a010a1c01480d010dae0c08040c1f0010ae111915113f114f11df 11030c110c11051713060a05002f333f331239392f2f5d11333310e1323211333310e15d3232012f5d33332f332f5d10e41739321112173911332fe4173932331112173911332f332f31300103211521 03231321032313213521132135211333032113330321150121132103d73f0118fecd529354fedd52904efefe011d41feee012b52935201255490540106fceb012340fedd037dfeb889fe5401acfe5401 ac8901488901b0fe5001b0fe5089feb801480003007bff8903d90612002d0036003f00b44033342f2901292f21012106702f3c013c2f1e011e1320070107070d2e6e240f001f0002ff00010000010700 410d0d376ee0190119b8ffc04030080b4819331414293c3c132e37083d28732125211f400e11481f1f1e5021010f211f21020821341373080e0806060508b8ffc0b30a0d4808002f2b33332f113310e1 322f5e5d5d33332f2b113310e13212393912391133331133012f2b5de1332f10d65e5d5d7132e111392f5d33335d335de1325d325d32313001140e0207152335222e0227351e0333112e0335343e0237 35331516161707262627111e0307342e022711363601141e021711060603d9325d85548a3266605420215760652f5983562a315b814f8a64a94342388c4a58875b2eb0142b46335d5bfe121128423159 5301be467254370ce6dd09121a11ac10211a1101b21e42556e4a436f533509b4b0052a1f91192906fe5a1f42536b4821372d2612fe8b0e6202a324392f2611017110590000050066ffec063305cb0009 001d0027003b003f005db23c103eb8fff040333c3e3c3e28141eb432b523b428410f410105b40ab500b410142014301403143f063e1825b637b721b62d1903b60fb707b61907003fe1f4e13fe1f4e13f 3f012f5de1f4e15d10dee1f4e1111239392f2f383831301314163332111023220605140e0223222e0235343e0233321e020114163332111023220605140e0223222e0235343e0233321e0201012301fa 47509c9c504701c7244a734f49704c262349714e4b714d2701ac47509c9c504701c6234a734f4a704b262349714e4b714c27ff00fcd59e032c0402a5a5014a0148a3a56cac763f3f76ac6c6caa753e3e 75aafd4aa5a401490148a3a56cab763f3f76ab6c6caa753e3e75aa0392fa4a05b6000003006dffec057d05cd0011002100530080404d2718174a04492c49480a4736414742204201364236421d053b3c 4704480047002c102c02082c2c2220480148551d4810222022022241413112514f162718174a040f473c3b05043149150f5031002fe13f1217391217393fe111392f012f5de110c65d11392f5e5de111 17391239392f2f5d10e110e1113311121739313001141e02173e0335342e0223220613323e0237010e0315141e0225343e02372e0335343e0233321e0215140e0207013e0337330e03070123270e0323 222e0201a6102134243b56381c192f422a5664873a62544820fe7d3450371c234260fe7d284d6f471f3c2d1c325e8a5853835b3032546d3c01601b2b221b0ab80f293541270115e1a831606c7c4e69a7 733d048d2241414325233e404629243d2c1959fbaf1728361f0197213f485538365b4124f04e7a64562a244d5763394b77532b2b53774b406d5d4f24fe8c1d3c444e2f426f625529fedbac2d47311b35 67950001008503a6014a05b60003002a401cc005d005e005032f056f0502009800031003e003f003040302020303003f332f012f5de15d5d313001032303014a29732905b6fdf002100000010052febc 022b05b60013001a400d060ef209f03f0001000ef905f8003f3f012f5de1e432313013343e023733060215141e0217232e0352244a714eac8c9125476a45aa4e714a2402317df3e5d35dc1fe32f477ec e2d45e5acee1f0000001003dfebc021705b60013001c400e060ef20bf0b0000100150ef805f9003f3f0110de5de1e432313001140e0207233e0335340227331e030217244b714eaa456a4824908dac4e 714b2402317cf0e1ce5a5ed4e2ec77f401cec15dd3e5f30000010052027704140614000e002440151f10010098000e800e900e03080e1f060106060000003f322f5d012f5e5de55d3130010325170513 07030327132537050302982b018d1afe86f5b2b09eb8f2fe891d01872b0614fe776fc11cfeba600166fe9a6001461cc16f018900000100660106040204a2000b00294018100d010609aa03ef00012000 6000a00003000900ad0603b3003f33e132012f5d5d32e1325d313001213521113311211521112301e9fe7d0183960183fe7d960287960185fe7b96fe7f000001003ffef8017900ee000c00384014cf0e 01100e900ea00e031b0c2b0c020c01970607b8ffc0400d1014485f070110070107069c0c002fed012f5d5d2b33ed325d5d5d313025170e0307233e0337016a0f0e272f33198a0f1d1b1608ee17367a7c 7b383d84837d35000001005201d10242027900030015400902054000010000b901002fe1012f5d10ce3130133521155201f001d1a8a800010093ffe3019100fa00130035401b80159015a01503111501 0a96c000d0000234004400640074000400b8ffc0b6070a4800059b0f002fed012f2b5d5ded5d5d313037343e0233321e0215140e0223222e029314222e1b1a2f221414222f1a1b2e22146f2635210f0f 2135262535221010223500010014000002e705b60003001eb10102b8fff04009020300100005010003003f2f11013338322f383331300101230102e7fde0b3022105b6fa4a05b60000020062ffec0408 05cd00130027002640151e6f0029102901146f200a010a23730f0719730519003fe13fe1012f5de15d10dee13130011402060623222626023534123636333216161205141e0233323e0235342e022322 0e0204083371b27f76af7339336fb17e77b0743afd131e426b4d4d6c451f1f456c4d4d6b421e02ddb1fee8c26666c20118b1b10118c16665c1fee8b296e0954b4a94e19796e0944a4a94e000000100b2 000002c705b60010003540214012010f010e0e006ebf01ff01027e010100011001200140010406010d0f060018003f3fcd012f5e5d5d5de1332f11335d3130212311343e02370e03070727013302c7b0 01030301111a1b1e159460017f9603912b62615922121a181b12797b012b00010060000003f005cb0023003c402023086f1b1b25102501226f0121011111200101010822100d7316070222740118003f e1323fe1331239012f5d332f113310ed5d11332fe1333130212135013e0335342e0223220607273e0333321e0215140e020701152103f0fc70015e4b76532c223f56355f994566285c6a7641609b6c3b 355d814bfee702b19c017d518680814c3b5a3f204d3c77243f2e1b3665915b559a959651fed5080000010052ffec03ee05cb0039005d400b21302130121a6f09276f00b8ffc040281417480000093b20 3b014f120112062073ab21017921010b2101082121152f2c7335071573120e19003f33e13fe13312392f5e5d5d5de139012f5d5d10ce322f2be110e11139392f2f313001140e020715161615140e0223 22262735161633323e0235342e0223233533323e0235342e0223220607273e0333321e0203c12e537447b1b84184ca8a6dc15557cb5d5c86572935628d598585517e552c24425c386ba34a5c265d6e7d 466ca36e380460497858390c0616b59160a07440222daa2e32284a6c4344613f1e97284a663d3452391e43367d1f362918366185000200170000043f05be000a0018004e402c095600010000026e110c 0b0720030103031a101a017718871802185f05010509061874010505021107060218003f3f3312392f33e13232012f5d335d5d12392f5d33333333e1322f5d3231300123112311213501331133211134 3e0237230e030701043fd5b0fd5d0297bcd5fe7b03040501090715191a0bfe650148feb801489f03d7fc300164387b7566221431312e10fda00000010083ffec03f605b6002a004e4018261a6f052c10 2c01272424286823015923012323f00f010fb8ffc04012080b480f1d73000015277424061573100a19003f33e13fe112392fe1012f2b5d332f5d5d333311335d10dee133313001321e0215140e022322 2e0227351e0333323e0235342623220e02072713211521033636022163ab7f484486c58033635b5221215962632a4f7c562eb0a81b3f3f39155a3702b2fdec2720690381376ca06972b67e430a131e14 ac1724180d254e76518f97050809043902b0a6fe5d060e0000020071ffec040a05cb002b003f00374020316e0c2241104101173b6f000010002000030036751d1d072c73271910730707003fe13fe111 392fe1012f5de1325d10de32e1313013343e0433321e021715262623220e0407333e0333321e0215140e0223222e0201323e0235342e0223220e0215141e027115355c8ec685132e2f2b1123582b5a89 64432a14030c14394c5f3b5f9a6c3b3e74a46664af804a01db3c63482721426342436f4e2b25496e027169d0bfa47945020507059b0c0c2b4e6c839450243f2d1a3b72a56a72b67f444ea0f2feb92953 7f57466f4e2a2f4b603043856a430001005a0000040605b60006002bb10600b8fff040110000020105081008010205027403060018003f3fe132012f5d10ce3211392f38333130210121352115010119 0233fd0e03acfdd50510a691fadb0003006affec040005cd0027003a004a008040531e23326e0f0a28486ec305d30502b5050105050f4c104c01286e193e6ed52301cc2301ba23012323101920190219 0a1e6838983802593801283838384838033893430126435643024343002d7314193b730007003fe13fe111392f5d5dc15d5d5d3939012f5d332f5d5d5de110e15d10ce322f5d5de1123910e111393130 01321e0215140e02071e0315140e0223222e0235343e02372e0335343e0203141e0233323e0235342e022727060601220615141e02173e03353426023554957142284660383a6f57354379a9666eab75 3d2d4c683a31563f25437295c720446848466b48242749663f1e7e8001166a7d233e573330553f247e05cd2c588458436c57451c1f4c5f76495c9568383665925c4b78604a1c1f495a6d425783582cfb a635593f2323415c38345448401f0e3c9b03546a6539524033181634425436656a000002006affec040405cb0029003d0035401e39156f003f103f012f6e0c10202020022034751b1b072a7325071075 071a003fe13fe111392fe1012f5d33e15d10dee132313001140e0423222e022735161633323e0237230e0323222e0235343e0233321e0201220e0215141e0233323e0235342e02040415355c8ec68513 2e2e2c1123582b87ae662b050d14384c603b5f9a6c3b3f73a56665ae804afe253c63482721426342446e4e2b25496e034669d1bea57845020506059c0d0c5ea1d677243e2e1a3b72a56a72b77f444ea0 f3014728547f57466f4e2a2f4b603043856b420000020093ffe30191046600130027003e401c102980299029a029041e0a9614c000d0000234004400640074000400b8ffc0400b070a4800239b191005 9b0f002fed3fed012f2b5d5d33e5325d313037343e0233321e0215140e0223222e0211343e0233321e0215140e0223222e029314222e1b1a2f221414222f1a1b2e221414222e1b1a2f221414222f1a1b 2e22146f2635210f0f2135262535221010223503912735210e0e213527253422101022340002003ffef801910466000c00200061402f102280229022a022041796c00dd00d02640d740d02500d01440d 013b0d011f0d2f0d020d0d1b0c2b0c020c01970607b8ffc040111014485f0701100701071c9b1210069c0c002fed3fed012f5d5d2b33ed325d332f5d5d5d5d5d5de55d313025170e0307233e03370334 3e0233321e0215140e0223222e02016a0f0e272f33198a0f1d1b16081114222e1b1a2f221414222f1a1b2e2214ee17367a7c7b383d84837d3502ed2735210e0e213527253422101022340001006600ee 040204dd0006004e40300008400801400101010201050503066f007f0002300001000004200301500370038003d003f003053f03010003010603002f5e5d5d5d7133332f5d5d3212393d2f333301182f 5d5d10ce3130250135011501010402fc64039cfd2102dfee01a86601e1a0fe94febe0002006601ba040203e900030007005c403d07020940090104c60001bb0001a900018600017b0001680001420001 3900010004ad1f052f05027f0501000510050206050500adf001010f016f010201002f5d5de1332f5e5d5d71e1012f5d5d5d5d5d5d5d5d335d10ce323130133521150135211566039cfc64039c035495 95fe669696000001006600ee040204dd0006004e40300508400801400601060504010103006f067f0602300601060602200301500370038003d003f003053f03010003010603002f5e5d5d5d7133332f 5d5d3312393d2f333301182f5d5d10ce3130130101350115016602e0fd20039cfc64018f0142016ca0fe1f66fe5800020025ffe3032505cb0027003b003e4021329a282827460000140b461c3d2f3d01 140b170f00010600002d9b371310511704003fe1332fe5322f5e5d1239012f5d10dee111392fe1332fe131300135343e02373e0335342e022322060727363633321e0215140e02070e03151503343e02 33321e0215140e0223222e0201190f27423230442b151e3955385396463f51bc615d9568381b3650363442260ebb14222e1b1a2f221414222f1a1b2e2214019e25395c504d2a2943454f35304f391f34 22912a3b33608b5743695a542f2d433f422c12fed12635210f0f213526253522101022350002006dff4a068105b600570068006f403f581760271f17017f2701172746462717034e31200001006a406a 013b404e014e2c0c5b120712641c0f121f12bf120306001c0107121c121c40365303404549002f33c13fc11239392f2f5e5d5e5d10c1113310c13232012f5dc15d10de71c11117392f2f2f5d5d10c110 c1313001140e0423222e0227230e0323222e0235343e0233321e0217030606141415141e0233323e0235342e02232204060215141e0233323e0237150606232224260235341236243332041612011416 33323e023737262623220e0206811325394c613a2d493421060412364759354d77522b3b6f9e622d5a52451717010115222b172e462f185698d17ba9fefeaf5a4f99e3933d776f642b56d882b3fee7c3 6676db0137c19c0106bf6afc156555374e321a040e1c4d2a4a653f1c02db3e7d716148291e3241232542311c38658e5665a87a44080e1108fe60161b1008033544280f3d688c4e8edd984f6fc7feefa2 97eaa0520e181f118d262c66c30119b3bc0145ee8865bdfef1fed585772d537345fd080d3a5e780000020000000004dd05bc000700140084402406054602014614010214034908014901010801000e0e 03000010070180079007d0070307b8ffc04018060a4807100707160f161f162f168f169f16df1606070304b8fff0401104025f0e200a0e480e0514140503040012003f323f392f12392be1012f38335e 5d11332f382b5d71331112393d2f1239395d5d1239395d5d33333130210321032301330101032e03270e030703041fa0fddfa2bc0219aa021afe6794061112120807121211069101c5fe3b05bcfa4402 6a01a812343c411f1f423d3311fe5800000300c70000048705b600170022002f0062403e0b1e5a050601e506f50602d606010606242a5b70118011021167317f318f310210310118245a1764300b2360 7918010b1801081818002460171222600003003fe13fe111392f5e5d5de1390110f6e1325d5d10f65de112392f5d5d71e13231301321321e0215140e0207151e0315140e0223211333323e0235342623 23111121323e0235342e0223c7018f80c38342274a6d4545795a34417bb06ffe1bbaf45472461f9aa6df010a58774920214b7c5c05b627578d673e6c5237090a0c2d4f7856649d6d3a034a1e3b593b78 68fd97fdf02848653d385e4325000001007dffec049805cb0023004c4014af0e010e401518480e0e18ba2001602070200220b8ffc04018060a48202025af2501055b18662421005f1d040d0a5f131300 3fe1333fe1330110f6e15d11332f2b5d5d12392f2b5d313001220e0215141e0233323637150e03232226260235341236363332161707262603196bae7b433b76b07659a04e274e55613ba4f09d4c57a9 faa26cc44f4e3f9405275198da898ddb964e2317a20f170e076cc60116a9a60114c66e2c2a9c202e000200c7000004fc05b6000c0017002640150d5b006719101901145a066418136007031460061200 3fe13fe10110f6e15d10f6e131300114020604232111213216161207342e0223231133200004fc60b6fef7a8fe92019799f8ae5fc5427eb875c9a20108010c02e9b9fee9bb5e05b65cb5fef4b692d58a 43fb89012400000100c7000003be05b6000b004240261408010808010400670d060a5a01640c095f4f06010f06af06020806060a055f02030a5f0112003fe13fe112392f5e5d71e10110f6e13210e632 11392f5d313021211121152111211521112103befd0902f7fdc30217fde9023d05b6a4fe3ca2fdf8000100c7000003be05b60009007040110808010f0301ff030180039003d0030303b8ffc04038070a 4803030b0f0b2f0b8f0baf0b040706005a01640a095f0f06010f063f066f06ff06040806401a1d480640101548060600055f02030012003f3fe112392f2b2b5e5d71e10110f6e1325e5d11332f2b5d5d 7112392f3130212311211521112115210181ba02f7fdc30217fde905b6a4fdfca4000001007dffec04f205cb002b0037401e2b2b0c295a1402672d102d011f5b0c662c2b5f0000241a5f1104245f0713 003fe13fe112392fe10110f6e15d10f632e111392f31300121110e032322262602353412362433321617072e0323220e0215141e0233323e02371121030e01e4377076824b9df2a6565fb6010bab6fcc 58482453585d2e7abc7f423778be862c493e371afed50304fd33121c130a69c30117aeac0116c3692c2aa2111e170e5198da8982d89c5605080b0501b400000100c7000004d505b6000b003d40230901 5a00650dc00d01bf0d01200d0108045a05640c035f0f08010808080a0603050012003f323f33392f5e5de10110f6e1325d5d5d10f6e132313021231121112311331121113304d5bafd66baba029aba02 aafd5605b6fd98026800000100520000026405b6000b005740260b0d2b0d027b0d9b0dab0dfb0d04540d012b0d3b0d4b0d031f0d0102080b0a5a0502c9030103b8fff840100d10480003010603090406 03030a0012003fc1323fc132012f5e5d2b5dc132f1c1325f5d5d5d5d7131302121353711273521150711170264fdeeacac0212acac6629049829666629fb68290001ff48fe7b017305b60013002f401c df150160157015022f15010f5a0c0303000c100c02070c0d03075f00002fe13f012f5e5d332f10e15d5d5d31300322262735161633323e0235113311140e021d334c1c224e2d254b3d26bb3b6993fe7b 0d0ba0090b1332584405b6fa5e699a653100000100c7000004a205b6000c0064402d020c660c010c000a0b100b0b01000010000207001000000eb00e012f0e01100e0108045a05640d02100b104808b8 fff0400c0b10480208050a0603000512003f333f331239392b2b0110f6e1325d5d5d11332f385e5d33332f383311395d113331302123010711231133113701330104a2d3fe3d8bbaba7901c4d1fdf802 ba72fdb805b6fd25a80233fd8300000100c7000003be05b60005002340130407af0701100701035a0064060103035f0012003fe13f0110f6e15d5d11333130331133112115c7ba023d05b6faf0a60001 00c70000062f05b60019008b4013361901390001170e080c0f48390e010e115a19b8fff8401c0c0f481900080c0f48000d0d0c0910651b4f1b01201b010f1b01080bb8fff8401a0c0f48260b010b0208 5a09641a18010110091248010e0b03110cb8fff0b60912480c080012003f32322b323f33332b11330110f6e132325d2b5e5d5d5d10f611393911332b332be1325d2b3231305d5d210123161716161511 23112101330121112311343637363723010323fe450806040405ac0114019c06019e0114ba0403040308fe4105004a493f8b39fc9605b6fb5804a8fa4a037734863d4749fb02000100c70000050e05b6 0017005140290e28010101155a006519b019018f19010019101902270c010c03095a0a6418160210061848020b030db8fff0b60618480d0a0012003f32322b3f332b330110f6e132325d5d5d5d10f6e1 325d32313021230123161716161511231133013326272e03351133050ed7fd310806040405acd502cc07030401030301ae04ba4d4c418e39fce705b6fb4c4c4a2043433e1a0320000002007dffec0571 05cd00130027003440201e5b006729c02901bf29017029012f295f2902145b0a6628235f0f04195f0513003fe13fe10110f6e15d5d5d5d10f6e131300114020606232226260235341236363332161612 05141e0233323e0235342e0223220e02057151a0ed9ba3ef9d4c4c9ef0a39beba051fbd1346ba57272a56b32326aa47272a66c3402dda9feeac66c6cc60117aaaa0115c46b6bc5feebab89db99515199 db898ada97515197da00000200c70000043305b6000e00190046402c155b2800380048000300671bcf1b01401b010f1b01060f075a08641a0f603006400602060607196009030712003f3fe111392f5d e10110f6e1325e5d5d5d10f65de1313001140e02232311231121321e020133323e0235342623230433377ecf9896ba016a86c27e3cfd4e815d8b5b2ea4aea0040a5ba8814dfdc705b6396da0fe672047 71518e890002007dfe62057105cd001d003100384022285b006733c03301bf33017033012f335f33021e5b1466322d5f1904235f050f1309002f3f33e13fe10110f6e15d5d5d5d10f6e1313001140e02 0716161707262627060623222626023534123636333216161205141e0233323e0235342e0223220e020571315f8e5d2b895a7967ad33112912a3ef9d4c4c9ef0a39beba051fbd1346ba57272a56b3232 6aa47272a66c3402dd83e2b584265e8f3c8e49c67f02026cc60117aaaa0115c46b6bc5feebab89db99515199db898ada97515197da00000200c7000004a005b6000f001c00824056090f190f02f90f01 0f080b0f480f0c090c01070c01165b08071807020707090e01e90ef90e020e080b0f480e0d100d1e3f1e8f1e9f1ebf1edf1e05201e0110015a02641d0c031060000001080000011c6003030e0112003f 333fe111392f5e5de112390110f6e1325d5d10ce38322b5d71322f5de112395e5d11332b5d7131300111231121201615140e02070123012733323e0235342e0223230181ba0164010afe31516837018e dbfea1e5a45a7e512529537f57a0025cfda405b6ced157825d3e14fd71025c9e234567454864401d00010068ffec03c905cb00330042402759230123115a006735bf35ff35026035013f35012a5a091b 6634112a05275f2420040e60090513003f33e13f33e11239390110f632e15d5d5d10f6e1335d313001140e0223222627351e0333323635342e02272e0335343e023332161707262623220615141e0217 1e0303c94580b8736fc1412257606632a0991d497a5d598355294074a16177be4a4341a5587a861e4673545b895c2f018761996a372322b2101f180f78703650433f252353688454588a5f322d239c1d 2b71603953433b21244c607e000100140000041205b60007005e40320f0901d009014f09cf090210092009300903af06ef06028406010606075a024003e003020f03010803035702670277020302b8ff c0400b070a480207035f04030012003f3fe132012f2b5d332f5e5d5d10e1322f5d5d5d5d5d71313021231121352115210271bbfe5e03fefe5f0512a4a400000100b8ffec04dd05b80017002f401c165a 016519b019016f19af19021019010e5a0b6418115f06130c0003003f323fe10110f6e15d5d5d10f6e131300111140e0223222e0235113311141633323e02371104dd4285c98880c48544bbadaf598052 280105b8fc4c72c490524d8ec77a03aefc48afc03662885103b8000100000000048b05b6000c006c401003020909040060017001b001f0010401b8ffc04016060a48011001010e2f0e7f0ebf0e030e40 0609480504b8fff0b40405040309b8ffe0b30a114809b8fff0400a06094809020312000103003f333f33332b2b3f33012f38332b5d11332f382b5d3312393d2f33333130013301230133011616173636 3703c5c6fe17bbfe19c501271d2a110f2e1f05b6fa4a05b6fc615ba94a4aa96100010014000006fe05b6002a00dfb61008151848100fb8fff8b51518480f0701b8fff840121518480100081518480016 1d081518481d1cb8fff8402f1518481c2514070104074407b40703070425142524254425542505071625251607031e0d000e01700e800ec00e030eb8ffc04018070a480e100e0e2c6f2c7f2c02202c30 2c020f2c01081f1eb8fff040131e16200a11481610060948160d001e03072525b8ffe0b30a114825b8fff0b606094825101d12003f33332b2b11333f3333332b2b012f38335e5d5d5d11332f382b5d71 331217393d2f2f2f5d5e5d7111332b332b11332b332b11332b332b31300133131e03173e033713330123032626272627060706060703230133131e03173e03370329c5e50f1d191306040c10130bc8c7 fe91bcfe0e1a0b0c0b0b0b0a190ef2bcfe7ec5df0c14110e05050f14170d05b6fca83870695e26265a6367310372fa4a03aa336c2f373433372f7036fc5c05b6fc872e63625b2625626c6f3100010000 0000046005b6000b0081401d090a100a0a00370b010b083805010502020100000170008000c0000300b8ffc04014070a48001000000d0f0d1f0d2f0d7f0d04080706b8fff0b306060304b8fff0401004 280201270801020804090603040012003f323f331239395d5d012f3832322f38335e5d11332f382b5d7133393d2f335d33335d1133182f383331302123010123010133010133010460d3fe9efe91bc01 c5fe5ac6014c014ebefe5b027bfd8502fc02bafdd1022ffd4c00000100000000043705b6000800734019ef0a010a40090c4808ab07019807014007011b07010f070107b8fff0402f070705018002014f 02011b02010210020200045a770587059705034f05010005100502070536000100010412070103003f333f12395d012f5e5d5d5de139322f385d5d5d3311332f385d5d5d5d5d332b5d31300101330111 23110133021b0154c8fe42bbfe42cb02d302e3fc83fdc7022f03870000010052000003fe05b600090038402009090307670b0f0b3f0b4f0b9f0b040808040401660a07045f050302085f0112003fe139 3fe1390110e6322f325e5d10e632322f31302121350121352115012103fefc5402c7fd4d0383fd3a02db91047fa691fb8100000100a4febc023905b60007002640170400f306f100011001b001c00104 0105f502f806f501f9003fe13fe1012f5de1ed32313001211121152311330239fe6b0195dfdffebc06fa95fa310000010017000002e905b600030021b70201011001050003b8fff0b40302010003003f 2f2f012f38331133381133313013012301c90220b2fde005b6fa4a05b60000010033febc01c905b60007002440140300f301f16006700602060900f507f903f504f8003fe13fe10110d65de1ed323130 173311233521112133dfdf0196fe6aae05cf95f90600000100290225041905c100060012b603030800000106003fcd012f11332f3130130133012301012901cb6601bfa1feaffea30225039cfc6402df fd210001fffcfebc034eff4800030012b60000050101ba02002fe1012f11332f313001213521034efcae0352febc8c000001018904d903120621000d0016400a000608800f005f000200002f5d1acc01 2fcd313001232e032735331e031703127823524d3f10db102b2e301504d91c5358511b152251514c1d000002005effec039c045e0023003200544011100129472355340f346f34020630480c1ab8ffd0 401e0d11481a10090c481a1a0c56331916501d2a5210101d1024500207160015003f3f33e13f392fe110e1320110e6322f2b2b10e15e5d10f6e1323231302127230e0323222e02353436373735342e02 2322060727363633321e02151125323e023535070e031514160319250821424e603f45745530e7ecb81d375134538f42404ab66466956130fe2f3d684c2b8f5a7a492061982d412a1427517b54a4b008 0745435a3718302289283829598a62fd107f264d754f630704203951335c5600000200aeffec043f0614001f002f0038b52d4805573131b8ffb840170a4915102547125430130012152a500f0a162050 1b0010003f32e13f33e13f3f0110f6e132322b10f6e1313001321e0215140e0223222e02272307231133111406070607333e0317220e0215141e02333236353426029e5e9a6d3c3c6d9a5e3b604d3b17 0c2585b60202020208173a4d6019506b411b1b416c51877f7f045e488fd48c8dd590491a2b3a208b0614fe88234f222826233c2c199733689c69659d6b37daccd0ce00010071ffec036f045e001f002a 40181d0d215f217f2102102101164805562013510a1019510016003fe13fe10110f6e15d5d10ce32313005222e0235343e0233321617072e0323220615141633323637150606025265b0824a4c85b266 4e95323617383c3a1a9d909194518336367b143f89d5969ddb893e22199a0a130f09c9d4d3c32519a21d1e0000020071ffec04020614001f00300034401d26001b471e55321032012e480b56311f151c 002b501610102050010616003f33e13f33e13f3f0110f6e15d10f6e13232313025230e0323222e0235343e0233321e02173326272626351133112325323e023735342e02232206151416035408163b4d 603c5d9a6e3c3c6e9a5d3b604d3c160c03030204b693fec64c69411f021b416c51877f7f93223d2e1a488fd48c8dd590491a2c3a20221f1a371001b4f9ec832e5e8d5e29659d6b37daccd1cd00020071 ffec03e1045e001e002700434028234819105729e029016f290122114805562811501b222b22020f2201062222141f500a1014510016003fe13fe112392f5e5d5de10110f6e1325d5d10f632e1313005 222e0235343e0233321e02151521161633323e0237150e030322060721342e0202606eb683484278a765639e6e3bfd4c0599973357514c27284d51576072850b01ec1b3958144a8ed28788d6954e4781 b56e71c1b60a131d12a2131c120803db9c954471502c0001001d000002f0061f001b0070404ecf1ddf1d02601d801d901da01d041f1d3f1d4f1d031b1b7f10bf100210101a02470307030f051f052f05 af0504050500031003200380039003a00306060301054f07001a01071a0f14500d010215003f3fe13f5e5d33e132012f5e5d332f5d113310e132322f5d392f5d5d5d3130012311231123353735343e02 3332161707262623220e02151533028bf5b7c2c22d557c4e3b63272f1f4928283a2613f503c1fc3f03c14b44606b8d5423170e8d0b1113305341680000030025fe1403fc045e003f0052005e00a74019 0d3205534737122f60377037803703372f372f27481d594705b8ffc0404d070a480505010a1d01fd1d01b01d01881d01201d301d401d031d1d601f6001bf60df6002a060014027400c0f48270205320d 043c56520a0a225c4f3c2c4e0f17010717173c10454f221b01000f003fc13fe13f392f5e5dc13910e111392fe1121739012f2bc15d5d7111332f5d5d5d5d7133392f2be110c11139392f2f5d10c110e1 1239393130011507161615140e02232226270e0315141e023333321e0215140e0223222e0235343e02372626353436372e0335343e023332161701141e0233323635342e022323220e02131416333236 35342623220603fcc51c262f5f8c5d162c0e11211b111829381fb05d8051244186cd8b6ba06a352742572f2a3640452b47311b32629261254f1bfe401a3b6148bab918375a41b0234c3f295c6c636467 6964636a044a711b236d454c815e3501030a192028181b2112062f506d3d588c61342a5071473c5b422a0b1352353d592a123f516033598c62340b09fb0225402e1b736c2e3a210c102c4d036073706f 777b7478000100ae00000412061400190032401d004719551b101b601b801b030f0e0a470b541a10045015100c000b0015003f323f3fe1330110f6e132325d10f6e131302111342623220e0215112311 331107333e033332161511035c6970516e431db6b6080a1945525c30b7b902c3828234669460fdc70614fe32902b3f2a14bfd2fd3300000200a00000017505e5000300110025401410132013020c0047 0401541207530f0f020f0015003f3f332fe50110f632e1325d31302123113303343633321e021514062322260164b6b6c43d2d16271d113f2c2d3d044a01293c360d1c2b1e3a39380002ffbcfe140175 05e500130021002e401910232023021c0f470c1403030c542217531f1f0d0f0750001b003fe13f332fe50110e6322f3210e1325d31301322262735161633323e0235113311140e0213343633321e0215 140623222642303f171a36231b2e2313b622486d133d2d16271d113f2c2d3dfe140e0b940a0b0f27413304f4fb184d7b572f075f3c360d1c2b1e3a393800000100ae000003f00614000e005e400b0704 040203030644050105b8ffc04017070a4805100505100f102f1002070d09470a540f0b0000b8fff840100c0f4807080c0f48000703060a15030f003f3f331239392b2b3f0110f6e1325e5d11332f382b 5d3333113339113331300137013301012301071123113311030156870125d3fe6f01acd1feb06db4b4100237aa0169fe25fd9101f852fe5a0614fd36feed000100ae0000016406140003001a400e1005 200502004701540402000015003f3f0110f6e15d3130212311330164b6b60614000100ae00000687045e002c0065403f230a47b90b01960ba60b02890b01670b770b020b0b1600472c552ef02e01cf2e 01202e502e020f2e010819154716542d231a1a040f50281f10170f160b0015003f32323f3f33e1323211330110f6e1325e5d5d5d5d10f6e111392f5d5d5d5de13231302111342623220e021511231134 2623220e02151123113317333e0333321617333e03333216151105d164694966411eb763694d683f1bb6941a0a18424f592e789f26081a49576032afb102c382822f5b8758fda202c3828234669460fd c7044a942b3f2a14585e2f442d16bfd2fd33000100ae00000412045e00180030401c004718551a101a601a801a030e0a470b54190f045014100c0f0b0015003f323f3fe1330110f6e1325d10f6e13130 2111342623220e02151123113317333e033332161511035c6970516e431db6941a0a1945525c30b7b902c3828234669460fdc7044a942b3f2a14bfd2fd3300020071ffec042d045e0013001f0030401d 1a480057214021d021e021030f21010614480a56201d500f1017500516003fe13fe10110f6e15e5d5d10f6e1313001140e0223222e0235343e0233321e02051416333236353426232206042d437db26f 67ae7f47437cb36f67ae7f47fd00899a9a87899a9a87022789d5914c4c91d58988d3914b4b91d388d1d3d3d1d1cfcf00000200aefe14043f045e001f00300036401e2e481b57321032012610060c470d 543120501116100e0f0c1b2b50050016003f32e13f3f3f33e10110f6e13232325d10f6e1313005222e02272316171616151123113317333e0333321e0215140e0203220e020715141e02333236353426 029e3b604d3b170c03030204b6941a08173a4d603c5e9a6d3c3c6d9a814c69411f021b416c51877f7f141a2b3a20221f1a3710fe2b063694233d2d1b488fd48c8dd5904903db2e5e8c5f29659d6b37da ccd0ce0000020071fe140402045e001000300036401e2b200525472455321032010e48165631241b220f200b501b102c00501116003fe1333fe1333f3f0110f6e15d10f6e1323232313025323e023735 342e0223220615141617222e0235343e0233321e02173337331123113436373637230e0302354c69411f021b416c51877f7f665d9a6e3c3c6e9a5d3b604c3c17081b93b6040203030c163b4d60832e5e 8d5e29659d6b37daccd1cd97488fd48c8dd590491b2d3d2394f9ca01d5133a1b2022223d2e1a000100ae00000308045e00160041400bb203c203029003a0030203b8ffc0401b070b4803031830185018 801803110d470e54170f0f0d1512070010003fc1333f3f0110f6e1325d11332f2b5d5d31300132161707262623220e02151123113317333e0302891d481a181c3b1a3f684b29b694160819394758045e 0505a80507335f8551fdb0044ac92b503d250001005affec033f045e00350048402d2513479000a000020057373f375f379f37031037012c47099f1daf1d021d5636262950132c052210090e50051600 3fe1323f123939e1320110f65d32e15d5d10f65de133313001140e0223222627351e0333323e0235342e02272e0335343e023332161707262623220615141e02171e03033f3a6d9a606d9c3b1f4c5459 2c415b391a14355c484873502b37648c5661a1483f418947666217385e464871502a012d507851282322a6101f180f16293b241f3231321f1f3c4a6143466d4a262a22931d2b433e23342e2f1d1e3c4b 600000010021ffec028f0546001d0050b11905b8ffc0402f080b4805051f3f1f4f1f02171b47141f122f120212001010102010b010c010d0100606101a124f1614170f00500b16003fe13f3333e13201 2f5e5dc65d33e1325d11332f2b33313025323e0237150e0323222e02351123353737331521152111141601fa122d2a23090d283034193e6a4d2c9b9b4e690114feec3f81040608038a060c0905204e85 65027d514ee6fc89fd836162000100a4ffec0408044a001a0030401c0117471a551c101c601c801c030f470c541b180d0f12500207160015003f3f33e13f330110f6e15d10f6e13231302127230e0323 222e0235113311141633323e023511331103751b0a1945525c305b8a5c2fb66a6f516e431db6932b3f29142e62986902cdfd3d828234659460023afbb60000010000000003d5044a0011006db90011ff f8400f0a0e481100080a0e48000909010f10b8ffc0b312154810b8ffc0401c070b481010101013bf13cf13ef13035013010f132f134f1303070201b8fff0400a01470901090f010f0015003f3f33395d 012f38c15e5d5d5d11332f382b2bc112393d2f332b332b3130210133131e0317333e03371333010177fe89bcc70b1e1e19040705181e1e0bc7bcfe89044afd9d21686c601919606c68210263fbb60001 0014000005e3044a002f00c3b9002ffff8400c0a0e482f0008090e48002720b8fff84012090e48201f08090e481f0910080a0e48100fb8fff84009090e480f1854270127b8ffe04015070a485b180118 20070a4827091818092703112d2eb8ffc0b31215482eb8ffc04013070b482e102e2e3120313031020f3101071211b8fff04016112d1f09090109110f27190619661976190319001015003f33335d1133 3f335d3333012f38335e5d5d11332f382b2b331217393d2f2f2f2b5d2b5d11332b332b11332b332b11332b332b313021032e0327262723060706060703230133131e0317333e03371333131e0317333e 033713330103f0a8040c0c0d060e0f060e0d0b190bacd3fee7bf830a14120e0406051115160ab3c4ac091716120406030d12150b89bafee40268122d3234193a3e3f3a326a25fd9c044afdb82d69675b 1d1a57615f21026bfd95225c5f581d1a57686d2f0248fbb600010023000003db044a000b00e540a1890901860301060401f70401e504013604010405e806010603e700010009090201f80201ea020139 020102016b057b05025705013a054a050264017401025801013501450102050109010905030b060801f70801e5080136080108074016194807400e11486b077b07025707013a074a0702070d100d300d 02900db00d020f0d0106d90a01c80a01ba0a01090a010a3b0b4b0b02280b01050b150b020b0715010f003f3f012f5d5d5dc15d5d5d5d5e5d5d7110de5d5d5d2b2bc15d5d5d711217393d2f182f2f5d5d 5d5d5d5d10c15d5d5d7111335d33335d10c15d5d5d713130005d5d0101331313330101230101230198fe9fcffafacffe9d0175cffef4fef2cf02330217fe66019afde9fdcd01b4fe4c000001000afe14 03df044a00220064b622100808000e0fb8ffc0b31215480fb8ffc0401d070b480f100f0f24bf24cf24ef24035024010f242f244f240307180100b8fff0400c00221008231c50151b0e000f003f323fe1 11333333012f38c1335e5d5d5d11332f382b2bc112393d2f333331301333131e0317333e03371333010e032322262735161633323e0237370abdd70e1d1912040605161b1d0bc7bcfe4e1c4156745034 4c1b154023304634250f39044afd9b28585852231956615e210263fb2751815a310b06910507172c4029a0000001005200000335044a0009006c400b099703010308090d480307b8ffc04011070a4807 070b3f0b5f0b7f0b0398080108b8fff8b5090d48080402b8ffc0b71215483f02010207b8fff04012070c4807044f050f0210070c4802084f0115003fe1322b3fe1322b012f5d2b33332b5d5d11332f2b 332b5d333130212135012135211501210335fd1d0218fe0902b0fdf4021e7d03448992fcd1000001003dfebc02a205b60027004040251a0505f72027f123130ff6100c010c230ff5d910010f105f1002 1010291af519f805f506f9003fe13fe112392f5d5de139012f5de63333f132e22f32313005141e0217152e0335113426233532363511343e0237150e0315111406071516161501f4182d41284d835f36 837d7d83365f834d28412d187773737710303d230d01960121476e4e014e67569b5667014d4e6e47210195010d233d30feb4697b140c147a6a00000101e9fe14027f06140003002d401f000501300540 05700580050402aa0003100340038003c003050703021b0000003f3f012f5e5de15d7131300133112301e996960614f8000000010033febc029805b60029004040250d2424f70700f11af61403901d01 1d041af5ef19ff1902d9190119190e24f523f90df50ef8003fe13fe111392f5d5de139012f5d3333e6f132e22f323130133436373526263511342e0227351e031511141e02331522061511140e020735 3e0335e177737377182d41284d835f362141603e7d83365f834d28412d18013b6a7a140c147b69014c303d230d01950121476e4efeb334482d149b5667feb24e6e47210196010d233d3000010066024a 0402035a0023003c400d1d25102501100a010a17ad0a1fb8ffc040161013481f1f05ad1c0f0d1f0d3f0d4f0d6f0d8f0d060d002f5d33f1c82f2b32e1012f5d5d10ce3130012e0323220e020735363332 1e02171e0333323e0237150623222e02021225372d29161c3c3b381964941d3237432f25372f28161c3c3b381863951d323743028b10160d0513212c19a26c050d191410160d0513212c19a26c050d19 00020093fe8b0191045e000300170041b90000fff040130a14483019a019b019c0190402049a0e03030eb8ffc0400f070a480e00099b1300021002020702002f5e5d2ff5ce012f2b332f10e1325d3130 2b1333132313140e0223222e0235343e0233321e02d57933dfef13232e1b1a2e231414232e1a1b2e231302a4fbe705482635210f0f2135262534221010223400000100bcffec03ba05cb0025005a4025 1203460f04040a2515274027011e48000a300a400ad00a04060a1b730f120f21730502050fb8ffc0400c0f12480f050f050310070319003f3f1239392f2f2b113310e1113310e1012f5e5de15d10c632 11392f33e13231302406071523352e0335343e0237353315161617072e03232206151416333236371503766e4c89578a623435618b568948882e3517383c3b199d909194518336d41e02c8ce0d4b85c7 898dcb884b0daca40321179a0a130f09cad4d2c32518a100000100440000042305c90028007540110d116f230f0f1f0f02071f0f1f0f190317b8ffc0b30a0e4817b8ffc8403006094817172a102a0121 19400b0e481919291021750d2f227f228f22af22bf22df22ff22072222001674191807730007003fe13fe111392f5d33e1321101332f2b335d11332f2b2b331239392f2f5e5d33e13231300132161707 262623220e02151121152115140e0207211521353e03353523353311343e02029a6aae4242388d4b30523c210178fe881727331b02ecfc212c49351ec6c63b699205c92d23901d2b1b3b5e42fed989d3 3e59402b10a69a0b29446143d589014457895f320002007b011d03ec048b00230037008640230e8f160116162eab150f0c18061e21030800701201121239103901042024aa80000100b8ffc04031060a 4800003817801f011f0c06181e0f06040929ae001b011b0d0533aecf09ef09029009a009b009031f093f096f090309002f5d5d5de1c6322f5de11217391133c65d321101332f2b5de1c6325d11332f5d 121739f1c02f5d32313013343637273717363633321617371707161615140607170727060623222627072737262637141e0233323e0235342e0223220e02ba231f81627f2f6c3c3c6b2e8163821f2523 217f60812e6b3c3c6e2d7f607f1f238a2541573233594226264259333257412502d33b6b2f816281202424208160812e6d3c3c6e2d7f607f1f2324207f607f2d6c3c3257412626415732335942262642 59000001001d0000044c05b600160095405b3018010f130c16aa150115150c040801ab02011f020102029800010007030b5a99140114100f0c018a0c01000c100c400c03070c0a0e600f070f06126013 0300137f0f8f0f02301301d013010f131f13020f130f13010b12150103003f333f1239392f2f5d5d715d11333310e132113310e132012f5e5d5d7133335de13232395d322f5d5d33393911332f5d3312 39395d313001013301331521152115211123112135213521353301330233015abffe7feffed3012dfed3b2fed3012dfed3eafe85c002d302e3fd00899e89fefa0106899e89030000000201e9fe14027f 061400030007003940250009013009400970098009040206aa030007100740078007c00705070704030403061b0000003f3f39392f2f012f5e5d33e1325d713130013311231133112301e99696969606 14fcf4fe19fcf30000020079fff6035e061f0045005a0079404b055608514621264c463c46292910ff2101a021b02102215cc05c01bf5c014646001746080831000001000010003000c000d000f00006 08005b264c055617564c29040d37502e1514500d01003fe13fe1121739113311330110c65e5d7132322fe110e15d5d10ce5d5d32322fe112393910e1113939313013343e0237262635343e0233321617 07262623220615141e02171e0315140e0207161615140e0223222627351e0333323e0235342e02272e0337141e0217173e0335342e02270e03891a2d3a1f4b5537648c56619d4838418c47636618395f 4648714e2a1829341c454c3b6c9b606c9c3b1f4c54592b455d371711335e4c497350299a1c3f654823142921151a416c52192f261703293353402d0f2672543d62442528208b1c273b391b2e2c2f1d1c 414e613e3455443110266d4e476f4d2821209e0f1e170e1827331b1d2d2d311f1f3e4e6459253f3a371e0f0d242e382226403b391e081f2d3a0000020133050c036a05d9000b0019003540210c86af14 0114c0068600001000400050000406000f0391179f09cf090230090109002f5d5d33e532012f5e5de11adc5de1313001343633321615140623222625343633321e0215140623222601333828273a3a27 28380177382813231a103a2628380573363031353532323536300c19261b3532320000030064ffec064405cb002500410055006a404305c51a0f0f221a221a22264cc3003401c03401345742c3260ac9 1500c91f0f151f152f157f158f159f150608001f101f601f701f801f05151f151f2d47c83b51c82d04003fe12fe11139392f2f5d5e5d10e110e1012fe110de5d71e11139392f2f11332f10e131300122 0e0215141e0233323e0237150e0323222e0235343e023332161707262601343e0433321e0415140e0423222e0437141e0233323e0235342e0223220e02037b3d5e40211d3d5f4317363938191831353c 2366986533366999643f843b3e3461fcbe36618aa7c06868c0a78a613636618aa7c06868c0a78a61366d65afea8585eaaf6565afea8585eaaf65041d2c53784b4e78522b070c1109830b120e07427aaa 6765a77843211d7f1a1cfebe68c0a78a613636618aa7c06868c0a7896235356289a7c06885eaaf6565afea8585eaaf6565afea00000200440310024205c7001e002d004e402f2d010fe0001d101d021d 2f0f2f1f2f4f2f7f2faf2f0524e00b1717600b010b2e2de40f0f1a0127e40006c013e41ade003fe11adcc4e13911392fe10110c65d322f10e15d10d65de13232313001270e0323222e02353436373735 3426232206072736363332161511030e0315141633323e02353501e71c12272f38232b48341d8d8f633d38305a2a3033753c7d77c933442912322a223a2b19031d521623190d1a334d33666c05041f48 391d16641a246a7afe3a013903121e2b1d332d152c412c31000200520073039303c70006000d0060401102040deb0a5004600402040a040a060b09b8ffc04021090c48090f0f0f9f0faf0f0306eb9f03 01030600030d070a0a050303010c050801002f332f3312393d2f123911333311333301182f5de15d10c62b321139392f2f5d10e111333130130117031307012501170313070152013575eeee75fecb01 97013674eded74feca0229019e4efea4fea44e019b1b019e4efea4fea44e019b0001006601060402031d00050039402402aa01071007019604018b04017904015604014b040138040112040109040104 04ad05b3003fe1012f5d5d5d5d5d5d5d5d5d10dee13130011123112135040295fcf9031dfde901819600ffff005201d10242027902060010000000040064ffec064405cb0008001e003a004e00c2407d a416b416c41603b417c4170217160152150e170e16c5150e1415150e0e090019c51a09c5041504001a01001ac01ad01a03078f04011a041a041f45c3002d01c02d012d503bc31f0e18c90000161b1615 1a08c91b001a010f1a1f1a2f1a7f1a8f1a9f1a0608001b101b601b701b801b051a1b1a1b2640c834134ac82604003fe13fe11139392f2f5d5e5d7110e111333311123910e132012fe110de5d71e11139 392f2f5d5e5d71113910e110e132113987102b1000c187052b10c4015d31305d01333236353426232305140e020716171e02171723032311231133321601343e0433321e0415140e0423222e0437141e 0233323e0235342e0223220e0202e7485b4f53594601921b2d391f4335172a210a0ab3ce5f9de9a89efbeb36618aa7c06868c0a78a613636618aa7c06868c0a78a61366d65afea8585eaaf6565afea85 85eaaf65030048454a3b81304b39280d6e5725473811110160fea0037d82fec368c0a78a613636618aa7c06868c0a7896235356289a7c06885eaaf6565afea8585eaaf6565afea000001fffa06140406 06a000030012b60000050101ba02002fe1012f11332f3130012135210406fbf4040c06148c000002007b035602f205cb001300270043402c1eab0a299f290114aa30004000020019ae100f200f02e00f f00f026f0f01000f100f200f03060f0f23ae0504003fe1332f5e5d5d5d71e1012f5de15d10d6e1313013343e0233321e0215140e0223222e0237141e0233323e0235342e0223220e027b325573414173 563232567341417355327b1e3446282846351e1e3546282846341e048f417356323256734141725531315572412745341e1e3445272847351f1f3547000200660000040204a2000b000f003a40211011 010f08080609aa0c010103ef000120006000a00003000dad0c0900ad0603b3003f33e1322fe1012f5d5d33331133e1323211335d31300121352111331121152111230135211501e9fe7d0183960183fe 7d96fe7d039c0287960185fe7b96fe7ffefa969600010031024a026d05c9001e0040401508e10017204f207f20022040060a481de1010f0f01b8ffc0400e15184801081d0be512de1de501dd003fe13f e11239012f2b332f10e12b5d10de32e13130012135373e033534262322060727363633321e0215140e02070721026dfdc4d13948280f4236335d2d4e3685523c6144251d364f3394018c024a70e43e55 433b22414032265e3041213f5b393256555b379d0001001f0239026805c900300061403c030019190e061ee1000015e106325f328f32023240060a4827270e401920480e0319e40f1a1f1a2f1a5f1adf 1a05081a1a122623e52cde12e50f0bdf003f33e13fe13312392f5e5de139012f2b332f2b5d10dee1332fe11112392f1239313001140607161615140e0223222627351616333236353426232335333236 35342e0223220607273e0333321e02024e5145585828537e56467b393f843562586b6062625c5414232f1b3b6133451d3d444c2c4569462304e74e6a18176a4e3c644728191f85222653494a43714f40 202f1e0e29256017251a0f223c530001018904d903120621000d0016400a060005800f0c5f0c020c002f5d1acd012fcd3130013e033733150e0307230189162f2f2a10db103f4d51237904f41d4c5151 22151b5158531c00000100aefe140412044a001d003740220d09470a551f101f201f601f701f801f05141d471c541e1a1b035011160b151c090f003f333f3fe13f0110f6e1325d10f6e1323130011416 33323e023511331123272306062322262716171616151123113301646a6f526e431cb6931b0a309067486a2301020201b6b60187828234659460023afbb69353542e2a262823552afec0063600010071 fefc0466061400130037402104990005300540055005040605050d01990015101501000d100d020d0312000500002f323fc1012f5d5d10d6e112392f5e5de13130012311231123110623222e0235343e 023321046678cf793d555f9b6d3c4177a6640233fefc0679f9870333123376c08c93c57832000001009302480191035e00130033401a101580159015a015040a96c000d0000234004400640074000400 b8ffc0b6070a4800059b0f002fe5012f2b5d5ded5d313013343e0233321e0215140e0223222e029314222e1b1a2f221414222f1a1b2e221402d32635210f0f213526253422101022340000010023fe14 0198000000190039401f141313157f128f12021212060d84001b061a128c1540090e481515130a8d03002fe12f392f2be10110c610d6e111392f5d333311333130011406232226273516163332363534 2e02273733071e0301988d96162d0f0f311047501a2e3f255a7939223a2b19fee1616c06036c03032b3118231a1309b073081a293a000001003f024a01ba05b6000e003440214f107f10021040060a48 0e0e02e1007f038f030220033003020302dd0d09e500dc003fe1cd3f012f5d5d33e1332f2b5d31300133112311343e0237060607072701338791010303010e26165e4a05b6fc940204193c3c38161128 11496000000200420310028b05c70013001f002eb21ae000b8ffc04014090f4800210f210114e00a2017e405c01de40fde003fe11adce10110d6e15d10d62be1313001140e0223222e0235343e023332 1e02051416333236353426232206028b294d6d443f6a4e2b294c6d443e6b4e2cfe3a4b56554b4b55564b046d5382592f2f5982535381582e2e5881537779797778737300000200540073039603c70006 000d0056402f0f0f9f0faf0f0307eb04020a020a02030b090e00eb9f030110032003400303030d070a0600030a030a03010c050801002f332f331239393d2f2f11333311333301182f5d5de110c63211 39392f2f1133e15d313001012713033701050127130337010396feca74eded740136fe68fecb75eeee750135020efe654e015c015c4efe621bfe654e015c015c4efe6200ffff003f0000058b05b60026 007b000000270217024a00000107023c02fcfdb70030401d030216180302bf16018f16013f16011601401101001101110040000100115d35115d5d35115d5d5d3535003f3535ffff002c000005a005b6 0026007bed000027021702350000010700740333fdb700284018021418020014011401b01101401101110070000140000100115d5d35115d5d35115d35003f35ffff001f000005ce05c9002600750000 0027021702a800000107023c033ffdb7003c40270302381803027038015038013801b43301a43301843301643301503301303301203301330f4c015d115d5d5d5d5d5d5d35115d5d3535003f35350002 0044fe770344045e0027003b00444012329a2828274600000b143d0f3d01080b461cb8ffc040100f1b481c0b1727272d9b371013105117002fe1333fe5322f1239012f2be15e5d10ce11392fe1332fe1 31300115140e02070e0315141e023332363717060623222e0235343e02373e03353513140e0223222e0235343e0233321e0202501027413230442b151e3955375496454052bc615d9567381b35513634 42260eba13232e1b1a2e231414232e1a1b2e231302a4253a5b514c2a2943454f35304f391f3323922a3a33608a5844685a542f2d433e432b13012f2635210f0f21352625342210102234ffff00000000 04dd077302260024000001070043ffbd01520015b40215052602b8ff9cb41b15040725012b35002b3500ffff0000000004dd077302260024000001070076008d01520013400b02210526026c151b0407 25012b35002b3500ffff0000000004dd07730226002400000107014b001f01520015b40215052602b8ffffb41d15040725012b35002b3500ffff0000000004dd07350226002400000107015200060152 0013400b021d052602011e2c040725012b35002b3500ffff0000000004dd072b0226002400000107006a002101520017400d03021e05260302011529040725012b3535002b353500ffff0000000004dd 0704022600240000010601501f7d003140200302ef1a01df1a01501a01401a01201a01101a01001a011a0302001f15040725012b353500115d5d5d5d5d5d5d3535000002fffe0000065605b6000f0013 0084402a06130a0e5a01110110030413a9130124133413541303100101140c0113010c0c01130305080067150405b8fff040200509135f06035f100d5f0a4f0a010f0aaf0a0208100a100a0603040e5f 050112003f33e12f3f39392f2f5e5d7110e110e110e132012f383310e6321117392f2f2f5d5d5d5d7d87c4c411013310e1321133313021211121032301211521112115211121012111230656fd08fe25 cbba028f03c9fdc30216fdea023dfb7501936c01c5fe3b05b6a4fe3ca2fdf801c602a800ffff007dfe14049805cb0226002600000107007a01fc0000000bb6014f2a24182025012b3500ffff00c70000 03be077302260028000001070043ffb701520015b4010c052601b8ffc2b4120c010025012b35002b3500ffff00c7000003be077302260028000001070076003f01520013400b01180526014a0c120100 25012b35002b3500ffff00c7000003be07730226002800000107014bfff101520015b4010c052601b8fffdb4140c010025012b35002b3500ffff00c7000003be072b0226002800000107006afff50152 0017400d02011505260201010c20010025012b3535002b353500ffff003e0000026407730226002c000001070043feb501520015b4010c052601b8ffa8b4120c010025012b35002b3500ffff00520000 028a07730226002c000001070076ff7801520013400b01180526016a0c12010025012b35002b3500ffff0011000002a907730226002c00000107014bff0f01520013400b010c05260102140c01002501 2b35002b3500ffff004000000277072b0226002c00000107006aff0d01520017400d02011505260201000c20010025012b3535002b3535000002002f000004fc05b60010001f005d403a1a1a0e115b08 6721202101181c5a0e1010010e64201b105f180f00010f003f006f00af00df00ff00060800401a1d480000021c600e1217600203003fe13fe111392f2b5e5d7133e1320110e632322f10e1325d10f6e1 11392f3130133311213216161215140206042321112325342e02232311211521113320002f98019799f8ae5f60b6fef7a8fe92980408427eb875c90150feb0a20108010c032502915cb5fef4b0b9fee9 bb5e02836092d58a43fe0ea2fe1d0124ffff00c70000050e073502260031000001070152008b01520013400b01200526010a212f0a0025012b35002b3500ffff007dffec057107730226003200000107 0043005401520015b40228052602b8ffabb42e280a0025012b35002b3500ffff007dffec0571077302260032000001070076010201520013400b023405260258282e0a0025012b35002b3500ffff007d ffec057107730226003200000107014b00ae01520013400b02280526020530280a0025012b35002b3500ffff007dffec0571073502260032000001070152007d01520015b40230052602b8fff0b4313f 0a0025012b35002b3500ffff007dffec0571072b0226003200000107006a00aa01520017400d0302310526030201283c0a0025012b3535002b3535000001008d012d03dd047b000b0087b90006fff0b3 14174806b8ffe040180f1248001014174800200f1248091014174809200f124803b8fff0b314174803b8ffe040300f1248400d01070505030b010150030103080a0a0402022000010000200050007000 8000a000c000d000f000090600b300193f5e5d71321133321133012f5d331133113311335d3130002b2b2b2b012b2b2b2b01013701011701010701012701cbfec269013d014268febf013f66febefec3 6702d3013f69fec2013e67febffec066013dfec567000003007dffb4057105fc001a00260031005c403a291f2a1e041b275b01190b0e0411046733c03301bf33017033012f335f33021b5b1166321f29 1e2a042d225f19010e0b04091a16042d5f0c0913003f33e13f33121739e11117390110f6e15d5d5d5d10f6111739e1111739313001071612151402060623222707273726023534123636333216173701 14161701262623220e0205102701161633323e0205145c5b5e51a0ed9bbd854e895a615b4c9ef0a35ea14250fcb72e30024330724772a66c34036a58fdbe2f724572a56b3205ae9563fedeb7a9feeac6 6c477f4e9164012abeaa0115c46b2a267ffce183d14e03b11d205197da8a010197fc541c1e5199dbffff00b8ffec04dd077302260038000001070043003d01520015b40118052601b8ffc0b41e180b00 25012b35002b3500ffff00b8ffec04dd07730226003800000107007600c501520013400b012405260148181e0b0025012b35002b3500ffff00b8ffec04dd07730226003800000107014b007901520015 b40118052601b8fffdb420180b0025012b35002b3500ffff00b8ffec04dd072b0226003800000107006a007d01520017400d0201210526020101182c0b0025012b3535002b353500ffff000000000437 07730226003c000001070076003101520013400b011505260163090f070225012b35002b3500000200c70000043305b60010001b003c4021175b00671d9f1d01101d01110b075a08641c1160061b600b 060b060b0709030712003f3f1239392f2f10e110e10110f6e132325d5d10f6e1313001140e022323112311331533321e020133323e0235342623230433377ecf9896babab086c27e3cfd4e815d8b5b2e a4aea0030e5ba8814dfec305b6fc396da0fe67204771518f8800000100aeffec0475061f004b006d404807462e3547000f191f192f190319400d13485f2e6f2e020f001f002f000308192e00002e1903 41244711574d104d204dc04d03404741544c24073503163a50470141151f501a1616003f33e13f3fe11217390110f6e15d10f6e11217392f2f2f5e5d5d2b5d10e110e1313001140e0415141e02171e03 15140e0223222627351e0333323e0235342e02272e0335343e0435342e0223220e0215112311343e0233321e0203f22b3f4b3f2b0e27463938583d2138658d55618b351a41484c2538513418112b4838 3f553516293e483e29213c533331584227b63f719c5c5c986c3c04ec3959493c37361e1521273126254852603e577e51272322a6101f180f192d4028243b383a23284443462a364f3f363a432c2a3e29 1313305341fb4e04b0688d5525264c74ffff005effec039c06210226004400000106004394000015b40233112602b8ffe5b439330c2225012b35002b3500ffff005effec039c06210226004400000106 007635000013400b023f1126028533390c2225012b35002b3500ffff005effec039c06210226004400000106014be2000013400b0233112602333b330c2225012b35002b3500ffff005effec039c05e3 02260044000001060152bd000013400b023b112602293c4a0c2225012b35002b3500ffff005effec039c05d90226004400000106006ade000017400d03023c112603022f33470c2225012b3535002b35 3500ffff005effec039c068702260044000001060150de000017400d03023811260302303d330c2225012b3535002b3535000003005effec0644045e003800470050007c401a2f144b1e48044242004c 48261d57524f525f529f52033948000eb8ffc0402e0d11480e0e0056510042104202421e500004100402040f4b1f4b02074b4b11213c502f2c3416480d0a5017141110003f3333e132323f3333e13211 392f5e5d335de1325d0110e6322f2b10e15d10f632e111392f33e13239393130133436373735342e022322060727363633321617363633321e02151521161633323e0237150e03232226270e0323222e 0237141633323e023535070e030122060721342e025ee7ecb81d375134538f42404ab66483a62b33a667619a6c39fd6005939331554e4a25274b4f55318aca3e224c5f744a477b5a34bd614f3d684c2b 8f5a7a492003856e7f0b01d71a37540133a4b0080745435a37183022892838555d555d4781b56e71c1b60a131d12a2131c1208727336553b1f27517b525c56264d754f63070420395102639c95447150 2c00ffff0071fe14036f045e0226004600000107007a01420000000bb6012f2620050d25012b3500ffff0071ffec03e106210226004800000106004394000015b40228112602b8ffb9b42e28050f2501 2b35002b3500ffff0071ffec03e106210226004800000106007652000013400b023411260276282e050f25012b35002b3500ffff0071ffec03e106210226004800000106014bde000013400b02281126 02033028050f25012b35002b3500ffff0071ffec03e105d90226004800000106006ada000017400d0302311126030200283c050f25012b3535002b353500ffffffde000001670621022600f300000107 0043fe5500000015b40104112601b8ff9ab40a04010025012b35002b3500ffff00ae000002420621022600f3000001070076ff3000000013400b011011260174040a010025012b35002b3500ffffffbd 000002550621022600f300000107014bfebb00000013400b0104112601000c04010025012b35002b3500ffffffee0000022505d9022600f300000107006afebb00000017400d02010d11260201000418 010025012b3535002b3535000002006fffec042d062300270039007440461228480023201619041c22181c22221c18030a00573b403bd03be03b030f3b010632480a563a20192316041721211d2d500f 120faf0fbf0f02300f01170f170f1d0137500516003fe13f39392f2f5d5d113310e11133111217390110f6e15e5d5d10e61117392f2f2f1112173910e132313001140e0223222e0235343e0233321617 37262627052737262627371616173717071e0307342e0223220e0215141e02333236042d437db26f68af7f473f76a869669a2b081f785aff004ad928552f46417a3be34ac3436f4f2cbc22466e4b4d6d 462121476d4c9a87023d8edc984f427fb97777b87e413b3c0476c0519972831c371a7b20482c8a7175419cbbddb0386b52322e5883554c7d5a31c700ffff00ae0000041205e302260051000001060152 f9000013400b01211126010222300b1725012b35002b3500ffff0071ffec042d062102260052000001060043d8000015b40220112602b8ffd7b426200a0025012b35002b3500ffff0071ffec042d0621 0226005200000106007650000013400b022c1126024e20260a0025012b35002b3500ffff0071ffec042d06210226005200000106014bfb000015b40220112602b8fffab428200a0025012b35002b3500 ffff0071ffec042d05e302260052000001060152e2000015b40228112602b8fffdb429370a0025012b35002b3500ffff0071ffec042d05d90226005200000106006af9000019b603022911260302b8ff f9b420340a0025012b3535002b3535000003006600f8040204ac00030017002b00604015302d0122aa18180eaa560366030228033803020300b8fff04028090d48000427ad101d010f1d011d1d0109ad 0013101320136013b013c013d0130707131300ad01b3003fe1332f5e5de111332f5d71e1012f332b335d5de1332fe15d31301335211501343e0233321e0215140e0223222e0211343e0233321e021514 0e0223222e0266039cfdbf121f2918172a201212202a1718291f12121f2918172a201212202a1718291f1202879696feee232f1e0d0d1e2f23212f1f0e0e1f2f02db232f1e0d0d1e2f23212f1f0e0e1f 2f0000030073ffb4042f0491001a0024002d005c403b271f281e041b25481718161507080a09080d00572f402fd02fe02f030f2f01061b480d562e281e271f042b2250070a181504051612102b500805 16003fc6e13fc6121739e11117390110f6e15e5d5d10f6111739e1111739313001140e02232227072737262635343e0233321617371707161605141617012626232206053427011616333236042f437d b26f7d624483503f46437cb36f3f71314483503e45fd001316018d1d4b2d9a87024427fe721f482d9a87022789d5914c356d4a8348d58988d3914b1d1c6c498149d18654833302871112cfd19f63fd7b 1110d300ffff00a4ffec0408062102260058000001060043a3000015b4011b112601b8ff9bb4211b0c1925012b35002b3500ffff00a4ffec040806210226005800000106007660000013400b01271126 01571b210c1925012b35002b3500ffff00a4ffec040806210226005800000106014b08000013400b011b11260100231b0c1925012b35002b3500ffff00a4ffec040805d90226005800000106006a0200 0019b602012411260201b8fffbb41b2f0c1925012b3535002b353500ffff000afe1403df06210226005c0000010600760e000013400b012f112601672329000f25012b35002b3500000200aefe14043f 0614002000310038401f2f480a573310330127201f151b471c54321d001b1b2c50150f162150000510003f33e13f33e13f3f0110f6e1323232325d10f6e13130013e0333321e0215140e0223222e0227 23161716161511231133110725220e020715141e023332363534260164173a4d603c5e9a6d3c3c6d9a5e3b604d3b170c03030204b6b608011f4c69411f021b416c51877f7f03b6233d2d1b488fd48c8d d590491a2b3a20221f1a3710fe2b0800fe3694112e5e8c5f29659d6b37daccd0ce00ffff000afe1403df05d90226005c00000106006ab1000017400d02012c112602010b2337000f25012b3535002b35 3500ffff0000000004dd06c10226002400000107014d003301520015b40217052602b8ffffb41516040725012b35002b3500ffff005effec039c056f0226004400000106014de6000013400b02351126 022333340c2225012b35002b3500ffff0000000004dd07400226002400000107014e002101520013400b021a052602001f15040725012b35002b3500ffff005effec039c05ee0226004400000106014e d4000013400b0238112602253d330c2225012b35002b3500ffff0000fe4204dd05bc02260024000001070151036200000014400d02802701302701002727000025012b5d5d35ffff005efe4203b8045e 02260044000001070151025a00000020401602f04501a04501904501804501304501004545000025012b5d5d5d5d5d35ffff007dffec0498077302260026000001070076010a01520013400b01300526 01cd242a182025012b35002b3500ffff0071ffec036f0621022600460000010600764a000017400e012c112601102001a72026050d25012b5d35002b3500ffff007dffec049807730226002600000107 014b00b401520013400b0124052601772c24182025012b35002b3500ffff0071ffec038f06210226004600000106014bf5000017400e0120112601102801532820050d25012b5d35002b3500ffff007d ffec049807370226002600000107014f020001520013400b012f05260180242c182025012b35002b3500ffff0071ffec036f05e50226004600000107014f013300000017400e012b1126011020014d20 28050d25012b5d35002b3500ffff007dffec049807730226002600000107014c00a801520013400b01290526016b2f24182025012b35002b3500ffff0071ffec03a006210226004600000106014c0600 0017400e0125112601102b01642b20050d25012b5d35002b3500ffff00c7000004fc07730226002700000107014c004a01520015b4021d052602b8ffb7b42318060025012b35002b3500ffff0071ffec 055206140226004700000107023802d90000000bb6025e3e3e1d1d25012b3500ffff002f000004fc05b602060092000000020071ffec049e061400270038005540311f1b002d47261d1d0b2226553a10 3a0136480b56392715251d4f221e1e1020003350160010101020100310102850000616003f33e13f5d33e13f12392f33e1323f0110f6e15d10e63211392f10e1323232313025230e0323222e0235343e 0233321e021733262726263535213521353315331523112325323e023735342e02232206151416035408163b4d603c5d9a6e3c3c6e9a5d3b604d3c160c03030204fe85017bb69c9c93fec64c69411f02 1b416c51877f7f93223d2e1a468acc8687ce8b47192c3a20211f1a37109e89b6b689fb2b832c59855a2761956634cfc3c6c3ffff00c7000003be06c10226002800000107014d000a01520013400b010e 052601020c0d010025012b35002b3500ffff0071ffec03e1056f0226004800000106014d00000013400b022a112602112829050f25012b35002b3500ffff00c7000003be07400226002800000107014e fffb01520013400b011105260106160c010025012b35002b3500ffff0071ffec03e105ee0226004800000106014eea000013400b022d1126020f3228050f25012b35002b3500ffff00c7000003be071a 0226002800000107014f013f01350013400b0117052601070c14010025012b35002b3500ffff0071ffec03e105e50226004800000107014f012b00000013400b02331126020c2830050f25012b35002b 3500ffff00c7fe4203be05b60226002800000107015102210000000eb90001ffc1b41212000025012b35ffff0071fe6103e1045e02260048000001070151023b001f0027401302f03b01e03b01a03b01 903b01503b01003b01b8ffcab43b3b1a1a25012b5d5d5d5d5d5d3500ffff00c7000003be07730226002800000107014cfff901520013400b011105260104170c010025012b35002b3500ffff0071ffec 03e106210226004800000106014ce4000013400b022d112602093328050f25012b35002b3500ffff007dffec04f207730226002a00000107014b00d701520013400b012c0526016d342c0c0125012b35 002b3500ffff0025fe1403fc06210226004a00000106014bc6000013400b035f11260303675f270025012b35002b3500ffff007dffec04f207400226002a00000107014e00c901520013400b01310526 015f362c0c0125012b35002b3500ffff0025fe1403fc05ee0226004a00000106014eb1000015b40364112603b8ffefb4695f270025012b35002b3500ffff007dffec04f207370226002a00000107014f 020c01520013400b01370526015f2c340c0125012b35002b3500ffff0025fe1403fc05e50226004a00000107014f00f200000015b4036a112603b8ffecb45f67270025012b35002b3500ffff007dfe3b 04f205cb0226002a00000107023901170000000bb601512c320c0125012b3500ffff0025fe1403fc06210226004a00000106023a2d000013400b03641126031c655f270025012b35002b3500ffff00c7 000004d507730226002b00000107014b007f01520015b4010c052601b8ffffb4140c050025012b35002b3500ffff00ae0000041207aa0226004b00000107014b002b0189001f4014700d01700c010170 1a011a02260119221a0b1825012b35002b5d355d5d00000200000000059c05b6001300170056402f14040c5a070b6519b01901af190110190117030f5a001064180e5f17160a12601307031317131713 01100b12050103003f333f331239392f2f11333310e1323210e10110f632e132325d5d5d10f632e132323130133533152135331533152311231121112311233501352115c7ba029abac7c7bafd66bac7 041bfd6604c3f3f3f3f396fbd302aafd56042d96fe8bdfdf00010012000004120614002100554034130b0047215523102360238023031716120a470f0b5422150d4f12bf0ecf0e020e0e10170450001d 101d201d031d1010000b0015003f323f3f5de13312392f5d33e1320110f632e13232325d10f6e1123931302111342623220e02151123112335333533152115211507333e033332161511035c6970516e 431db69c9cb6017bfe85080a1945525c30b7b9029a828234669460fdf004d589b6b689b8902b3f2a14bfd2fd5c00fffffff5000002c407350226002c000001070152fef301520013400b011405260101 1523010025012b35002b3500ffffffa30000027205e3022600f3000001070152fea100000013400b010c112601010d1b010025012b35002b3500ffff003d0000027c06c10226002c00000107014dff22 01520013400b010e052601010c0d010025012b35002b3500ffffffeb0000022a056f022600f300000107014dfed000000013400b0106112601010405010025012b35002b3500ffff00300000028a0740 0226002c00000107014eff0f01520013400b011105260102160c010025012b35002b3500ffffffde0000023805ee022600f300000107014efebd00000013400b0109112601020e04010025012b35002b 3500ffff0052fe42026405b60226002c000001070151009c0000000bb601001912010025012b3500ffff0044fe42018305e50226004c00000106015125000010400a026f2501002525000025012b5d35 ffff00520000026407370226002c00000107014f005001520013400b0117052601000c14010025012b35002b3500000100ae00000164044a0003001a400e10052005020047015404020f0015003f3f01 10f6e15d3130212311330164b6b6044affff0052fe7b042905b60026002c00000107002d02b600000038400e01187f18014f1801184007074818b8ffc04017060648bf2101a021018f21015021010f21 0121400707482b5d5d5d5d5d2b2b5d5d1135ffff00a0fe14038705e50026004c00000107004d02120000002e402003021ecf1e01df35019f35018035015f350140350120350100350135400606482b5d 5d5d5d5d5d5d5d113535ffffff48fe7b026407730226002d00000107014bfeca01520013400b0114052601001c140d0e25012b35002b3500ffffffbcfe14025706210226023700000107014bfebd0000 0013400b0114112601001c140d0e25012b35002b3500ffff00c7fe3b04a205b60226002e0000010602397300000eb90001ffb1b40d13050025012b35ffff00aefe3b03f006140226004e000001060239 2100000eb90001ffc4b40f150a0525012b35000100ae000003f0044a00110049400a0110100e0f0f44110111b8ffc0401c070a4811101111130f132f1302070703470454120c010e050f040015003f32 3f3339390110f6e1325e5d11332f382b5d33113339113331302101071123113311140607060737013301010323feac6db4b405030404830133cdfe6f01ac01e951fe68044afee73c66262c24b00181fe 16fda000ffff00c7000003be07730226002f000001070076ff6501520015b40112052601b8ff70b4060c000425012b35002b3500ffff00ab0000023407ac0226004f000001070076ff22018b001f4014 700301700201017010011002260166040a010025012b35002b5d355d5d00ffff00c7fe3b03be05b60226002f0000010602392d00000eb90001ffddb4060c000425012b35ffff0066fe3b016c06140226 004f000001070239fef70000000eb90001ffe0b4040a010025012b35ffff00c7000003be05b70226002f0000010702380100ffa30016400d010b030110060160060c020425012b5d35003f35ffff00ae 000002b406140226004f0000010602383b00001840110104400e104804400609485e0404030325012b2b2b35ffff00c7000003be05b60226002f00000107014f01e3fd65000bb601ab060e000425012b 3500ffff00ae000002a206140026004f00000107014f012dfd38002b4016ff1301ef13019f13018f13017f13015f13011f130101b8012eb4040c010025012b355d5d5d5d5d5d5d000001001d000003be 05b6000d006140320b06050c050003040d040405050a08080faf0f01100f010c0d0d0603075a0b000a640e05040d0c040c040c01075f0a120103003f3fe11239392f2f113311330110f63232e1323233 2f335d5d11331112392f33107d8704c4c41087c4c431301311331137170511211521110727c7bae34efecf023dfd09614902a40312fd638f7dbefe39a601f83c7d000001fff60000021d0614000b0069 403b400d500d020906050a050003040b0a0b0b0804dd0501bb05cb05020f051f052f050306050506030747090008540c0b0a05040a040a040107150100003f3f1239392f2f113311330110f63232e132 32322f5e5d5d5d3311332f337d8704c4c41087c4c4015d3130131133113717071123110727aeb66b4eb9b66a4e02f6031efd59457978fd3f024a4679ffff00c70000050e077302260031000001070076 00f201520013400b012405260155181e0a0025012b35002b3500ffff00ae000004120621022600510000010600766f000013400b01251126015c191f0b1725012b35002b3500ffff00c7fe3b050e05b6 0226003100000107023900d90000000eb90001ffe1b4181e0a0025012b35ffff00aefe3b0412045e022600510000010602394c00000eb90001ffdeb4191f0b1725012b35ffff00c70000050e07730226 003100000107014c009c01520013400b011d0526010023180a0025012b35002b3500ffff00ae0000041206210226005100000106014c0c000015b4011e112601b8fffab424190b1725012b35002b3500 ffffffff000004a105b600270051008f000001060207e8000029401d00185527ef2701bf27019f27015f27012f2701274008084827400606482b2b5d5d5d5d5d10f63400000100c7fe7b050e05b60025 004a402a180c1f5a20040415206527b027018f2701002710270217130e145a1564261f0d16031512180c12075f00002fe13f333f3f33330110f6e13232325d5d5d10e611392f10e13232313001222627 35161633323e0235012316171616151123113301332627262635113311140e02038b334d1b224e2d254b3d26fd080806040405acd502cc0703040305ae37648ffe7b0d0ba0090b1332584404ba4d4c41 8e39fce705b6fb754141387d340320fa5e699a653100000100aefe140412045e0028003a40220303170c4724552a102a602a802a031a16471754291a10502010180f17150750001b003fe13f3f3fe133 0110f6e1325d10f6e111392f31300122262735161633323e023513342623220e02151123113317333e033332161503140e0202ee303f171a36231b2e2313026970516e431db6941a0a1945525c30b7b9 0222486dfe140e0b940a0b0f274133036d828234669460fdc7044a942b3f2a14bfd2fc954d7b572fffff007dffec057106c10226003200000107014d00bc01520013400b022a0526020028290a002501 2b35002b3500ffff0071ffec042d056f0226005200000106014d14000013400b02221126020020210a0025012b35002b3500ffff007dffec057107400226003200000107014e00aa01520013400b022d 0526020132280a0025012b35002b3500ffff0071ffec042d05ee0226005200000106014e00000015b40225112602b8ffffb42a200a0025012b35002b3500ffff007dffec057107730226003200000107 015300ec01520017400d0302340526030243283c0a0025012b3535002b353500ffff0071ffec042d06210226005200000106015346000017400d03022c112603024520340a0025012b3535002b353500 0002007dffec06a405cd0019002a005b403614160116160014185a2727091200672c1f2c011f5b09662b175f4f14010f14af140208141419125f11031a5f0e04245f0413195f0012003fe13fe13fe13f e112392f5e5d71e10110f6e15d10e63211392fe13211392f5d3130212106062322262602353412363633321721152111211521112101220e0215141e023332363711262606a4fd0a2b5b30a3ef9d4c4c 9ef0a3625402f4fdc20217fde9023efc5672a66c34346ba572345a262659090b6cc60117aaaa0115c46b17a4fe3ca2fdf804855197da8a89db9951120f045810110000030071ffec06e1045e002a0036 003f0064403b13033f1d48d0310131310b3748251c57410f4101ff41014041012b480b56401d501b3f2b3f020f3f01063f3f2e3c345016131010202e5003000616003f3333e1323f3333e13212392f5e 5d5de10110f6e15d5d7110f632e111392f5de1323939313005222627060623222e0235343e0233321617363633321e02151521161633323e0237150e0301141633323635342623220605342e02232206 07056082cc413fc68067ae7f47437cb36f79c33f3cb975639e6e3bfd4c0599973357514c27284d5157fb9a899a968b8c979a8704f01b39583e72850b14706d6d704c91d58988d3914b6f6a69704781b5 6e71c1b60a131d12a2131c1208023bd1d3c9d1dccecf624471502c9c9500ffff00c7000004a0077302260035000001070076005401520015b40229052602b8ffeeb41d23020d25012b35002b3500ffff 00ae00000308062102260055000001060076ce000013400b012311260140171d0e0325012b35002b3500ffff00c7fe3b04a005b6022600350000010602397700000eb90002ffb6b41d23020d25012b35 ffff0060fe3b0308045e02260055000001070239fef10000000eb90001ff08b4171d0e0325012b35ffff00c7000004a007730226003500000107014c000e01520015b40222052602b8ffa9b4281d020d 25012b35002b3500ffff00720000030a06210226005500000107014cff7000000015b4011c112601b8ffe3b422170e0325012b35002b3500ffff0068ffec03c9077302260036000001070076003b0152 0013400b014005260170343a080025012b35002b3500ffff005affec033f062102260056000001060076dc000013400b01421126015d363c080025012b35002b3500ffff0068ffec03c9077302260036 00000107014bffed01520013400b0134052601223c34080025012b35002b3500ffff005affec033f06210226005600000106014b9b000013400b01361126011c3e36080025012b35002b3500ffff0068 fe1403c905cb0226003600000107007a01350000000eb90001fffab43a34080025012b35ffff005afe14033f045e0226005600000107007a00f00000000bb601013c36080025012b3500ffff0068ffec 03c907730226003600000107014cffe601520013400b01390526011b3f34080025012b35002b3500ffff005affec033f06210226005600000106014c97000013400b013b112601184136080025012b35 002b3500ffff0014fe3b041205b602260037000001060239f900000eb90001ffd8b4080e030525012b35ffff0021fe3b028f054602260057000001070239ff5d0000000eb90001fff7b41e2412052501 2b35ffff00140000041207730226003700000107014cffc801520013400b010d052601031308030525012b35002b3500ffff0021ffec02e80614022600570000010602386f00000bb601612424181825 012b3500000100140000041205b6000f0073404c1f1101e011015f11df11022011301140110308bf05ff050205050a065a010f015002f002021f020102020d7701870197010331010100011001200103 07010a0d60070000030b1206025f0303003fe1323f12392f33e132012f5e5d5d5d33332f5d5d123910e132322f5d395d5d5d7131300111213521152111211521112311213501b6fe5e03fefe5f0127fe d9bbfed7033301dfa4a4fe2195fd62029e9500010021ffec028f05460025006ab6141f01201c1c05b8ffc04037080b480505272f273f27021f1b2347130f161f160216181400101010a010b010c01005 071011224f141f1f0b151e4f1a181b0f00500b16003fe13f3333e13212392f33e132012f5e5d3333c45d32e132325d11332f2b331133005d313025323e0237150e0323222e0235352335333523353737 33152115211521152115141601fa122d2a23090d283034193e6a4d2c8b8b9b9b4e690114feec0102fefe3f81040608038a060c0905204e8565fb8af8514ee6fc89f88afb6162ffff00b8ffec04dd0735 02260038000001070152006001520015b40120052601b8ffffb4212f0b0025012b35002b3500ffff00a4ffec040805e302260058000001060152f3000013400b01231126010624320c1925012b35002b 3500ffff00b8ffec04dd06c10226003800000107014d008f01520015b4011a052601b8ffffb418190b0025012b35002b3500ffff00a4ffec0408056f0226005800000106014d21000013400b011d1126 01051b1c0c1925012b35002b3500ffff00b8ffec04dd07400226003800000107014e007d01520013400b011d0526010022180b0025012b35002b3500ffff00a4ffec040805ee0226005800000106014e 0c000013400b012011260104251b0c1925012b35002b3500ffff00b8ffec04dd07d902260038000001070150007b01520017400d02011d052602010022180b0025012b3535002b353500ffff00a4ffec 04080687022600580000010601500c000017400d0201201126020105251b0c1925012b3535002b353500ffff00b8ffec04dd07730226003800000107015300b201520017400d0201240526020136182c 0b0025012b3535002b353500ffff00a4ffec040e06210226005800000106015350000017400d02012711260201481b2f0c1925012b3535002b353500ffff00b8fe4204dd05b802260038000001070151 02190000000bb6010d251e0b0025012b3500ffff00a4fe420416044a0226005800000107015102b80000000bb6010e21211a1a25012b3500ffff0014000006fe07730226003a00000107014b013b0152 0013400b012b05260100332b1e0e25012b35002b3500ffff0014000005e306210226005a00000107014b00ae00000013400b0130112601003830112e25012b35002b3500ffff00000000043707730226 003c00000107014bffd001520013400b0109052601021109070225012b35002b3500ffff000afe1403df06210226005c00000106014ba9000013400b0123112601022b23000f25012b35002b3500ffff 000000000437072b0226003c00000107006affce01520017400d0201120526020101091d070225012b3535002b353500ffff0052000003fe07730226003d000001070076003901520013400b01160526 015e0a10010025012b35002b3500ffff00520000033506210226005d000001060076d6000013400b0116112601600a10010025012b35002b3500ffff0052000003fe07370226003d00000107014f0129 01520013400b01150526010b0a12010025012b35002b3500ffff00520000033505e50226005d00000107014f00cd00000013400b0115112601140a12010025012b35002b3500ffff0052000003fe0773 0226003d00000107014cffe001520013400b010f05260106150a010025012b35002b3500ffff00520000033506210226005d00000106014c86000013400b010f11260110150a010025012b35002b3500 000100ae000002be061f0013002540150909150015101520150313470054140d5006010015003f3fe10110f6e15d11332f31303311343e023332161707262623220e021511ae2d557c4e3b63262f1f48 28283a271304b06b8d5423170e8d0b1113305341fb4e000100cbfe1403e905cb002b004a402a302d01291f1f01471216121414120a0a00121012301240120407121300601629290d23501c070d50061b 003fe13fe112392f33e132012f5e5d332f11332f113310e1322f325d31300111140e022322262735161633323e02351123353735343e023332161707262623220e0215153315028f2d557b4e203d1c1a 391f283b2613c2c22d557c4e3b63262f1f4828283a2713f60344fc3f6b8d5423090699080a1330534103c34b44896b8d5423170e8d0b111330534191890000040000000004dd07aa001600230031003e 0101405e89290129be2a2a3031311d38830f0d1f0d02100d200d020d0d562366230223070859176917020617051d32830f001f006f00030000d60a01370a470a570ac70a040ad90301380348035803c8 0304031d1d090510040180049004d0040304b8ffc04018060a4804100404400f401f402f408f409f40df4006070809b8fff0403109075f231d200a0e481d0a033c193501358c12103c018f12ef120260 12011031203102233c123131123c23040429090412003f332f1217392f2f2f2f5d5d5d5d10e15d113333332b10e1012f38335e5d11332f382b5d713312393d2f335d5d335d5d33182f5de1111239395d 1239395d332f5d71e111332f33332fed5d31300114060701230321032301262635343e0233321e0203032e03270e030703133e033733150e0307231334262322061514161733323603503c3301fcbe9a fdd39cbc01f8333a203b523231543e230c9406111212080712121106918515302f2a10db103f4d512379bc3f32313f33310c323f059c466019fb230187fe7904db196046334f381d1d374ffc5f017d10 2e363b1c1c3c362e0ffe83048b183d41401c101641474216fef6343c3c34333b033c0005005effec039c07aa000d0031004000540060009c402355830f411f412f410341415b834b060d4b0d4b0d1a1e 0f37473155623f62013e481a28b8ffd0403a0d11482810090c4828281a5661588c50500d600d700d030d0d5050055e8c404650460246462724502b38521e1e2b1032500f15160e150f050105002f5d3f 3f33e13f392fe110e132332f5de111392f332f5d10e10110e6322f2b2b10e15d10f6e132321139392f2f10cd10e1332f5de13130013e033733150e0307230127230e0323222e02353436373735342e02 2322060727363633321e02151125323e023535070e0315141601140e0223222e0235343e0233321e0207342623220615141633323601c715302f2a10db103f4d5223780152250821424e603f45745530 e7ecb81d375134538f42404ab66466956130fe2f3d684c2b8f5a7a4920610186233d543132523b21213b523230543e23753f31323f3938313f06b8183d41401c101641474216f95c982d412a1427517b 54a4b0080745435a3718302289283829598a62fd107f264d754f630704203951335c5605083351381d1d384f33334f381d1d374f34353c3c35353c3cfffffffe00000656077302260088000001070076 022501520015b40220052602b80148b4141a050025012b35002b3500ffff005effec06440621022600a8000001070076017500000013400b035d112603715157001c25012b35002b3500ffff007dffb4 057107730226009a000001070076010201520013400b033e052603583238110425012b35002b3500ffff0073ffb4042f0621022600ba00000106007650000013400b033a1126034c2e340d0025012b35 002b3500ffff0068fe3b03c905cb022600360000010602390000000eb90001ffdab4343a080025012b35ffff005afe3b033f045e02260056000001060239bb00000eb90001ffe1b4363c080025012b35 0001010204d9039a06210014002540110f0e040400c008040e80000f085f080208002f5d331acc32012f1acc393d2f33333130012326262706060723353e0337331e0317039a79336c34366a33791a44 433b10c0103b43451904d92261373761221b1d4c5151222251514c1d0001010204d9039a06210014002540110605101000c00b130d80100f065f060206002f5d331acd32012f1acc393d2f3333313001 0e0307232e0327353316161736363733039a1945433b10c0103b43441a79336a36346c337906061d4c5150232350514c1d1b2261383861220001011b04d9035a056f00030015400a0100008f0f035f03 0203002f5de1012fcd313001211521011b023ffdc1056f960001012104d9037b05ee0015002f401c1583ff000100c00b830a007f0a8f0a9f0a030a80108f0f055f050205002f5de11acd5d32012fe11a dc5de13130010e0323222e0227331e0333323e0237037b042c4d6d47496d4927036c041c30432c244133220405ee3d654a292749663f2b321907091b3128000100a00500017505e5000d001c40100887 0003919f0bcf0bef0b03300b010b002f5d5de5012fe1313013343633321e02151406232226a03d2d16271d113f2c2d3d05733c360d1c2b1e3a3938000002016d04d9033106870013001f0040402d1483 0f003f004f005f0004001a83300a010a178c0f0f1f0f3f0f4f0f5f0faf0fff0f07060f1d8c0f055f050205002f5de1d45e5de1012f5de1d45de1313001140e0223222e0235343e0233321e0207342623 22061514163332360331233d543132523b20203b523230543e23753f31323f3938313f05b23351381d1d384f33334f381d1d374f34353c3c35353c3c0001001ffe42015e000000140016400906800084 0d12038e0a002fe12f012fe11acc31301714163332363715060623222635343e02373306b43422192d0e1a401d64641e2f381a818bee2d2b0504710808685a2a4b40341385000001010204d903d105e3 001b003840230f172f1702170009200902070916058f0e401013480e40070b480e0e138f090f000100002f5d32e1332f2b2be133012f5e5dcc5d313001222e0223220607233e0333321e023332363733 0e0302fe284f4c46202d300e680521354a2e2a514c451d2d2e0f690521354a04db232b23353e3c624525232a23343e3c61452600000200df04d903be0621000d001b002d4019140e0e07405000013f00 4f000200130592801b0f0c5f0c020c002f5d331aed32012f5d5d1acd392fcd3130133e033733150e030723253e033733150e030723df162f2f2a10c7103f4d512365016b15302f2a10c6103f4d512364 04f41d4c515122151b5158531c1b1d4c515122151b5158531c00000101f804d903040621000d0027401605100c11480506400c000001000592800f0c5f0c020c002f5d1aed012f5d331acd322b313001 3e033733150e03072301f80a14131004c706212d34186c04f41e4d51502115184e57562000030114050c038906b4000d001b0029006640191c840f241f24020f241f24cf24032440090c4824240d1684 0eb8ffc04027090d480e0e05100c114805060c0d05920c0c1f119127ff19016019b019d019030f191f19020619002f5e5d5d5d33e532392fed012f33cd322b332f2be111332f2b5d71e13130013e0337 33150e03072327343633321e0215140623222625343633321e0215140623222601fe0b19181608cf1230383d2052ea382913231a103a26293801b5382813231a103a26283805871e4b4f512414204d50 51250636300c19261b3532323536300c19261b353232ffffffe9000004dd05bc02260024000001070154fdf1ff970018b6021a0302302201b8ffe9b42222040425012b5d35003f350001009302480191 035e00130033401a101580159015a015040a96c000d0000234004400640074000400b8ffc0b6070a4800059b0f002fe5012f2b5d5ded5d313013343e0233321e0215140e0223222e029314222e1b1a2f 221414222f1a1b2e221402d32635210f0f2135262534221010223400ffffffe70000044d05b800270028008f000001070154fdefff97002eb40111030112b8ffc0b2080f48b8ff9d400f121202022500 00671bbf1b010f1b01015d5d10fe34012b2b35003f35ffffffe70000055005b80026002b7b0001070154fdefff970031b40111030112b8ffc0b2081148b8ffb1401212120606250000656f1b012f1b01 101b011b01105d5d5dfe342b2b35003f3500ffffffe70000036005b80027002c00fc000001070154fdefff970066401601110301c01201a01201301201201201101201001201b8ffa5402f1212060625 00f00001d00001c00001af00017000016000015000014000013f000100201b011b400707481b40070948012b2b5d115d5d5d5d5d5d5d5d5d352b5d5d5d5d5d5d35003f35ffffffe7ffec05c305cd0026 0032520001070154fdefff9700474030022d0302a02e01802e01702e01502e01202e01102e01002e01242e2e0a0a2501005000015000010067bf37010f37013701105d5dfe5d5d34342b5d5d5d5d5d5d 5d35003f3500ffffffe70000055405b80027003c011d000001070154fdefff97004bb4010e03010fb8ffc0b6161748a00f010fb8ffc0b2091148b8ffd6401c0f0f07072500c00501b005017f05012005 01053f18012f18010f1801015d5d5d115d5d5d5d352b2b5d2b35003f3500ffffffe70000060005cd002601765a0001070154fdefff97003540230135030120360110360100360116363613132500501d 01501d011d67bf3f010f3f013f01105d5dfe5d5d342b5d5d5d35003f3500ffffffe4ffec027706b402260186000001070155fed000000018400f030201c0240140240120243a150025012b5d5d353535 ffff0000000004dd05bc020600240000ffff00c70000048705b6020600250000000100c7000003be05b600050043400ac400f40002b000010200b8ffc0401f0813480000070f072f074f076f07040740 111848035a046406025f05030312003f3fe10110f6e12b5d11332f2b5f5d5d313001152111231103befdc3ba05b6a6faf005b600000200250000046805b60005000e0058401105040606020b5b600170 01b001f0010401b8ffc04027060a480101102f105f106f107f109f10bf100610400609480a5b0206200a11480604030a5f0212003fe13f332b012fe12b5d11332f2b5de112393d2f3333313025152135 01330706060703210326260468fbbd01c2bb5e112a1dfe02aefc1f2e7d7d850531cd4aa85bfd0a02f061a800ffff00c7000003be05b6020600280000ffff0052000003fe05b60206003d0000ffff00c7 000004d505b60206002b00000003007dffec057105cd00030017002b00534034000100010e225b04672dd02d01cf2d01802d013f2d6f2d02185b0e662c03600f00af00df00ff00040800001d275f1304 1d5f0913003fe13fe112392f5e5de10110f6e15d5d5d5d10f6e11239392f2f313001211521251402060623222626023534123636333216161205141e0233323e0235342e0223220e0201ec0216fdea03 8551a0ed9ba3ef9d4c4c9ef0a39beba051fbd1346ba57272a56b32326aa47272a66c340339a145a9feeac66c6cc60117aaaa0115c46b6bc5feebab89db99515199db898ada97515197daffff00520000 026405b60206002c0000ffff00c7000004a205b60206002e0000000100000000048b05b6000c005f401c2f0eef0eff0e030e401215480e400d10480e400609480c0b0505090ab8fff040220a012f004f 005f009f00af00cf00ef000710000100100005200a0e48050b030a0012003f323f332b012f385d5d322f3833393d2f33332b2b2b5d313021230126262706060701230133048bc6fedb1f2e0f112a1dfe d9c501e7bb039a61a84b4ba85bfc6005b600ffff00c70000062f05b6020600300000ffff00c70000050e05b602060031000000030052000003ee05b600030007000b0063403e1400011b010100010001 0b0606000801c008013f0801080d4f0d6f0d02300d010707700b800b024f0b010b035f0f00af0002080000040b5f0a12075f0403003fe13fe111392f5e5de1012f5d5d332f5d5d10ce5d5d71322f1139 392f2f5d5d3130132115210321152101152135cd02a6fd5a52034afcb60373fc64034ea2030aa4fb92a4a400ffff007dffec057105cd020600320000000100c7000004c105b600070031401e015a0065 09b009016f099f09af0903100901045a056408035f0603050012003f323fe10110f6e15d5d5d10f6e13130212311211123112104c1bbfd7bba03fa0512faee05b600ffff00c70000043305b602060033 00000001004e0000041205b6000b005a400d085b062014174802060206010ab8ffc040260615480a0a0d0f0d2f0d6f0d8f0d040607095b032f013f01020108020209075f0403095f0012003fe13fe112 393d2f3301182f5d33e1325e5d11332f2b1239392f2f2be131303335010135211521010121154e019efe6e037dfd580185fe6702f7980266022593a4fdeefda4a400ffff00140000041205b602060037 0000ffff00000000043705b60206003c000000030068ffec05ba05cb0021002e003b008140502202671101115a3b219a12018712017a120112121b285b08673d2f3d01003d01d03d01af3dbf3d02903d 015f3d01303d010f3d1f3d0206355b1b663c223b601310132e2f602102211321132111130004003f3f39392f2f113310e132113310e1320110f6e15e5d5d5d5d5d5d717110f6e111392f5d5d5d3333e1 5d3232313001331533321e0215140e04232315233523222e0435343e0233331333323e0235342e022b03220e0215141e02333302b4bb4986c27e3c183454789f652fbb2f659f785435183d7ec2854abb 1a5d8b5b2e29537f5739bb39577f54282e5b8b5d1a05cbb45e99c4663d817b6e5230e1e130526e7b813d66c4995efc533b6994584e8b683c3c688b4e5894693bffff00000000046005b60206003b0000 00010068000005ba05b60025007040471f670901095a1c9a0a01870a017a0a010a0a13235b0067272f2701002701d02701af27bf27029027015f27013027010f271f270206165b1366261f1c60080b0b 09241d14030912003f3f333312392f33e1320110f6e15e5d5d5d5d5d5d717110f6e111392f5d5d5d33e15d32313001140e04232311231123222e0435113311141e02333311331133323635113305ba18 3454789f652fbb2f659f78543518c12e5b8b5d1abb1abab7c003d73d7f776a4e2efe4201be2d4e68777e3d01e3fe21588d6234035afca6c6b101e3000001004e000005a605cd002f007c40510e5b0b22 5b25200b300b02040b012f253f25df25ef25040b2501070b250b25132b5b0623162302231d6731d03101cf31018031013f316f3102090d190d02080d055b136630005f180426220a0d5f250c12003f33 e13232323fe10110f6e1335e5d5d5d5d5d10f6325de11139392f2f5e5d5d5d5d10e110e1313001220e0215141e0217152135212e0335343e0233321e0215140e0207211521353e0335342e0202fa72a4 6a322351835ffdb00162406f502e51a0ec9a9beba0512e506e410162fdb05f835123326aa405294481ba7564bbab974193a43087a8c76f96f4ac5e5eacf4966fc7a88730a4934197abbb6475ba814400 ffff004000000277072b0226002c00000107006aff0d01520017400d02011505260201000c20010025012b3535002b353500ffff000000000437072b0226003c00000107006affce01520017400d0201 120526020101091d070225012b3535002b353500ffff0071ffec049106210226017e00000106015419000013400b024a112602163e44162f25012b35002b3500ffff005affec035c0621022601820000 01060154ca000013400b01461126016d3a40182d25012b35002b3500ffff00aefe14041206210226018400000106015444000013400b012511260162191f0b1725012b35002b3500ffff00a4ffec0277 062102260186000001070154fece00000015b40122112601b8fffdb41622150025012b35002b3500ffff00a4ffec043d06b40226019200000106015510000012b2030201b8ffeeb42c42051b25012b35 353500020071ffec0491045e0010003d0038401e381e05472f283f103f010e4816563e220f1e0b501b0f382f2c0050331116003f33e13232323fe1333f0110f6e15d10d432e13232313025323e023735 342e0223220615141617222e0235343e023332161733363637330e03151114163332363715060623222e0227230e0302354c69411f021b416c51877f7f665d9a6e3c3d71a2647090310c0a21198f0b13 0d0832220e25080f4122263f32240c0c163b4d60832f6298680f659d6b37daccd1cd97488fd48c8dd59049535523521f2168797e37fe5d3c33070385091110274030223d2e1a000200aefe140475061f 001b003d0059403439480508051f332f330233053305152c470c573f203f303f0222154716543e151b0832500f33010833330022275011161c500001003fe13fe13211392f5e5de1393f0110f6e1325d 10f6e11239392f2f5d123910e1313001321e021514060715161615140e0223222627112311343e0217220e0215111e0333323e0235342e0223233533323e0235342e02027760a37643988fb0b93f78ad 6d60a43cb64579a86338644b2c204e525224506f461f3560844f664d52774e2526445f061f3162946295ad170615caba6ca26d37201ffde906347bb27337961f4c7f60fc92121e150b284d6f4750754d 25982849663d3f5e3e1f0001000afe1403df044a001b006340161d40121548501d010f1d2f1d4f1d03071a0501054806b8fff0401506060b0013130c1a001b201b401b03081b101b0d0cb8fff0400a0c 1a0c0f13000b15051b003f3f33333f33012f38332f385e5d3312393d2f333333182f38e15d5e5d5d2b3130250e031523343e02370133131e0317333e0337133302601622180cbe0f1b2515fe60bdd90e 1e1a1404060514191b0bc7bc123e88867e342a79898d3f043efdba285d5a501b1a525d5a21024c000002006fffec042d061f003200440051402e1a46003805052e33480f2457464046d046e046030f46 01063d482e56450024421a0a38380a425029161550100a01003f33e13fe111392f12391239330110f6e15e5d5d10f632e111392f3939e13130012e0335343e0233321e0217072e0323220e0215141e02 171e0315140e0223222e0235343e0201342e02270e0315141e023332360214385d4325335c7d4a44716051234a2049515b332a3c27121b3c624755865c31457fb26d67ae7f4743729901b41e3952353a 7e6844264969438e9903aa204b56623948694622141f27139114261e121725321b253e3d4129316c7e93587fc183433d75aa6e6aa37a53fe51456f59491f103a629167426f512db40001005affec035c 045e0039005940371d23010118102d573ba03bb03bc03b033f3b5f3b02103b0134462323054718563a1e0250bf3901793989390239390a315028100a501316003fe13fe112392f5d5de1390110f6e133 2fe15d5d5d10e63211392f12393130011523220615141e0233323e023715060623222e0235343e0237352e0335343e0233321e021707262623220615141e0233029c818a8529466037335c51471f3b9e 6d71a66c35263f522c2b46331c3a699056355a524d283f4b81476c732748643d0287995b5e33452a120f181f10a02229315675433e583e290f0b0e2b3e5032466d4a2609131c149322264d4d2d402712 00010071fe6f036a061400330039401f2e03031f461a20140114351035c035020a48290000295634192e0300500100003fe132322f0110e6322f10e15d10d65d32e1332f333130133521150e0515141e 02171e0315140e0207233e0335342e02272e033534123636370607060623ae02b680b87e4c280d2d54784b475f3a1915222b16aa182b22140e305b4d59875c2e5c9ac96c2b2f28602f057b998d76cdb3 9a856f30596c4023110f2e3b482a2d58524b1f204848431d1425221f0f11426c9866940101e8d96c03030204000100aefe140412045e00180031401d004718551a101a601a801a030e0a470b54190e04 5014100c0f0b15001b003f3f3f3fe1330110f6e1325d10f6e131300111342623220e02151123113317333e033332161511035c6970516e431db6941a0a1945525c30b7b9fe1404af828234669460fdc7 044a942b3f2a14bfd2fb470000030071ffec0417062b0013001e0027005b403a2519470057290f2901d029017f299f29024029010f290106241a470a56281a50cb2401ba240189249924020f24010824 24141f500f0114500516003fe13fe112392f5e5d5d5d5de10110f6e1325e5d5d5d5d7110f6e1323130011402060623222626023534123636333216161201323e0237211e0313220e0207210202041734 70b37e76af7438336fb17e76b0753afe2b4968452303fdcb022144684a476644230502330984030cbcfed7ce6d6dce0129bcbc0129ce6c6bcdfed7fcb94a94df9593df954b05104589cd890111011300 000100a4ffec02770448001500354023300901090917001710172017601770179017c017d0170808014714541604500f16000f003f3fe10110f6e15e5d11332f5d31300111141633323e0237150e0323 222e023511015a3f48122d2a24090d293034183e6a4d2c0448fcfc6162040608038a060c0905204e85650304ffff00ae000003f0044a020600fa00000001fff2ffec04170621002e0068402a2215151a 121201290a290a2900501a01341a441a02001a101a201a031a1a3060309030020f3001062e00b8fff0400f002e152901010e17501e1607500e01003fe13fe111392f333f012f38335e5d5d11332f5d5d 5d1239393d2f182f113333111239113331302301272e032322060735363633321e02170116163332363715060623222e0227032e032723060607030e01b8350d1f2b3d2b2232141a42234a694f3f1f01 48122e260e2608173725273b2f250f870b1d1b1605060d351fe50433a02943311b070591070a2a59875dfc3636390703850c0e1128402e01a2215e6157194daa4ffdc100000100aefe140412044a001d 003f40260d0c09470a551f101f201f601f701f801f0514001a471b541e1a1b140d035011160b151c090f003f333f3fe133333f0110f6e132325d10f6e13232313001141633323e023511331123272306 062322262716171616151123113301646a6f526e431cb6931b0a309067486a2301020201b6b60187828234659460023afbb69353542e2a262823552afec0063600010000000003cf044a0014003b4016 14130707000d470e5716101601b016010f1601060100b8fff0b6000714150d000f003f323f33012f38325e5d5d7110f6e112393d2f333331301133131e0317333e02123533140202060723bcc90c1f1e 1905065a724219b6255c9a75c0044afdb02163675c1960cde7010597a3fee0fef5fd7f0000010071fe6f036a06140046007e404e323b3b112a014146382d2d241c000110012001030801011c46201101 11483f485f487f48ef480410480107482456473c323850392a00491c591c691c03381c0107241c0316014f000016390016fa003f3f12392fe11117395d5d113910e132320110f6e15d5d10d65df1c02f 5e5d1112392f33e1123911332f333130011523220e0215141e02171e0315140e0207233e0335342e0227262635343e023735262635343e023706070606232335211523220e0215141e02330323a2517f 572d2d54784b475f3a1915222b16aa182b22140e305b4db2b82f4e663765722d4f6b3e222721552e3e0281374991734720467251037789315571414e603b22110f2e3b482a2d58524b1f204848431d14 25221f0f22c7b54d7f6343110c1c8675486649311303030204998d264e754e3551371c00ffff0071ffec042d045e02060052000000010019ffec04c9044a0018005840380a478f160116160e03141400 0310030203031a2f1a9f1aef1a03100d472f0eef0eff0e030e401015480e5419150c1050120f0e1500500716003fe13f3fe132320110f62b5de1335d11332f5d332f1112392f5de13130253236371506 0623222635112111231123353721152311141604501c2f0f0f4a307171fe6db6dd890427d32f810d08900911848202befc5003b04a509afd4e463700000200a4fe14042d045e001a0027003940212548 005729cf29014029010f2901061f090f471054281b5016100f1b2250080516003f33e13f3fe10110f6e132325e5d5d5d10f6e1313001140e0223222627231617161615112311343e0233321e02012206 07111616333236353426042d3f75a7684b8f360601020201b64178a96961a37743fe3b898203368f4b8c7b7d022789d5914c2d2d2b2e27612efedd041388d3914b4b91d30118c4c8feac3331d3d1d1cf 00010071fe6f036f045e0031005140362727154610000a100a200a030a333f335f337f33ef330410330100481f5632282d51370a0128153815481503150a1f00040f24100ffa003f3f1217395d5de132 0110f6e15d5d10d65d32e1332f313001141e02171e0315140e0207233e0335342e02272e0335343e0233321617072e0323220e02012d1c497e61475f3a1915222b16aa182b22140e305b4d4d84623749 83b36a4e95323617383c3a1a50724922020660794e2f160f2e3b482a2d58524b1f204848431d1425221f0f0f4176b4829ae2954922199a0a130f093970a400020071ffec0485044a0016002900364021 242148121000572b102b902ba02bb02be02b0517480a562a1225500f0f1c500516003fe13fe1320110f6e15d10f63232e132313001140e0223222e0235343e02332115211e0305141e0233323e023534 262723220e02042d3e7ab4756baf7d444d90ce8001e9fef62541301cfd0021476e4d4c6d47214f4b3b5f8b5a2b01f86fc08d50468acb859cda8a3e9a295d6c7c365590693b3762864e90d7592c63a100 00010012ffe50366044a001c003a4024010f0d1f0d02060d571e101e012b1a3b1a021a03471018e01802180219501c0f08501316003fe13fe132012f5de1c65d5d10e65e5d32313001152111141e0233 323e0237150e0323222e0235112135370366fe8c192d3e24122a28240d0d272e351b40755934fed786044a9afda23b5233170306070487060c0b061d4d866802734a5000000100a4ffec043d044a001d 0029401810471b571f101f601f801f03084705541e15060f0d500016003fe13f330110f6e15d10f6e1313005222e0235113311141e0233323635342e0227331e03151002025c81aa6429b62042664692 8d0910170fb60f181008f414508cbd6d0258fdb2568c6336e8f7477d75743d3d7277814bfec1fed300020071fe140525045e00250035005e403c312547169600a6000200000626481f57372037010f37 01e037016f377f379f37034037010f371f37020611470656362b500b1a10311650240116001b003f3f33e1323f33e10110f6e15e5d5d5d5d717110f6e111392f5d33e132313001112e0335343e023717 0e0315141e021711343633321e0215140e02071101342e0223220e0215113e0302666db7864b20384e2d8d253f2d1933587440a5915a9266375690be68014f1e36492b1b312516487b5933fe1401da05 4389d59753988a7d37603368727d476f99613007025ebcc15090c97a95d9904a05fe2604256294653317355741fda0073b6b9f000001ffecfe140425044e002800a0401a681f781f021f67097709c709 030906761c01371c011c1c1e0708b8ffc0400e13164834080108100808c0120112b8ffc04019060b4812122a0f2a3f2a4f2acf2a0406b025c0250225251d1eb8fff0401f1e1e291e1b1706270602181c 281c021c091f0604000f50161b070f2350000f003fe13f3fe11217395d5d3f1101332f3833332f5d5e5d11332f2b5d332f385d2b3312393d2f5d5d33335d335d313013321e021713013301131e033332 363715060623222e022703012301032626232207353636bc2d493a31157b011fb2fe73b20e1d2634251a2e10163928435f47331783feb6c201c6a01b4735241c163e044e1f3e5c3dfea8024afcf8fe20 2642331d05038d060b26466641016afd83033e01be4f590a8f070a00000100a4fe14057106120027004c402f0117472618181e0647115729302940299029b029c029050f291f29020621471e54280b1f 0f012650161916171b0000003f3f3f33e1323f330110f6e15e5d5d10f6e111392f33e132313001113e0335342e0227331e0315140e02071123112e0335113311141e02171103564e835f34080f1810b6 101810085793c46db26fbc894cb6365a78420612fa73093c6c9c6747807e834948837e7e449ddc8c4507fe2601da044188d69a021ffdd9729a612e05058f00010071ffec0596044a003b007040483867 1d011d47d51a01b71a01a91a019a1a01031a1a05254830573d043d143d02c43df43d027b3d9b3d02403d0102303d010f3d1f3d0206104805563c1b1b2a0a0f20155039350016003f3232e1323f33392f 0110f6e15e5d5d5f5d5d5d7110f6e111392f5f5d5d5d5de15d39313005222e0235343e0237330e0315141e0233323e0235113311141633323e0235342e0227331e0315140e022322262723060601e95a 8c60320f1f2f20ba202f1f0f1d364b2d2e442c16b263512d4b361d0f1f2f20bb202f1f0f32608d5a6b8b1f0a1f8b145292cb79518f8787484986878e5262966534294862390132fece818b3465966252 8e8786494887878f5179cb9252575b5b5700ffff0015ffec027705d90226018600000107006afee200000017400d02011f1126020132162a140025012b3535002b353500ffff00a4ffec043d05d90226 019200000106006a00000019b602012711260201b8ffdeb41e32051b25012b3535002b353500ffff0071ffec042d0621022600520000010601540e000013400b022c1126023d20260a0025012b35002b 3500ffff00a4ffec043d06210226019200000106015410000013400b012a1126011d1e24051b25012b35002b3500ffff0071ffec059606210226019600000107015400c3000000214009014811260160 3c013cb8ffc04009090b483d3c42053025012b2b5d35002b3500ffff00c7000003be072b0226002800000107006afff501520017400d02011505260201010c20010025012b3535002b35350000010014 ffec050605b600250085405a0404130c5a0f2101df21ff21022155270f276f277f2703061af41801a018b018027418011818125a130015301540155015c015051515b0130167137713025e13013f134f 130200130113115f1a1a0719155f16031312075f0013003fe13f3fe13212392fe1012f5d5d5d5d5d332f5d10e1322f5d5d5d325e5d10f65d71e112392f31300522262735161633323e02353534262321 11231121352115211121321e021515140e02039e2f46191d442720403321697bfebbbbfeac03b1fe5e015a5d926535355f84140d0ba0090c13335745857374fd230512a4a4fe6f315e8b5989699a6531 ffff00c7000003be077302260161000001070076003301520013400b01120526013e060c040025012b35002b35000001007dffec049805cb0026005f40131140131848071107111bca23017023802302 23b8ffc04024070a48232328bf280105085b1b6627085f0f05af05020805050d24005f20040d5f101613003f33e13fe13312392f5e5de10110f6e1325d11332f2b5d5d1239392f2f2b313001220e0207 2115211e0333323637150e03232226260235341236363332161707262603195fa0784d0d0274fd86054076ab7159a04e274e55613ba4f09d4c57a9faa26cc44f4e3f940527417aaf6fa282c98a482317 a20f170e076cc60116a9a60114c66e2c2a9c202effff0068ffec03c905cb020600360000ffff00520000026405b60206002c0000ffff004000000277072b0226002c00000107006aff0d01520017400d 02011505260201000c20010025012b3535002b353500ffffff48fe7b017305b60206002d000000020000ffe906df05b6002a0035008db5252b5a060d08b8fff84053141748085a23991e011e101e2300 0690060206e02301b423c423d42303002350239023a023040706230623152f5b006737cf37013740060948151536355f0f25af25020825252b085f2303196012132b600612003fe13fe13fe112392f5e 5de11101332f2b5d10f6e11139392f2f5e5d5d5d5e5d1133385d10e12b3210e132313001140e02232111210e03070e032322262735161633323e02373636121237211133321e020133323635342e0223 2306df3c7ec286febffec20f1f21221014354f6e4e234a1c173a20303e2a1a0c0c20272b1602936d98cf7e37fd7777aea42e5b8b5d5801ac619e703d051271f4ecd45167a26f3b0e0b9a0d103f627536 39c80106013aaafd98427198fe9d848846613c1b000200c70000070c05b6001600210053403211175a0e06060a1b5b0067230f23010f231f237f23ff23040d095a0a642221085f110f0daf0d02080d0d 0f0b0317600a0612003f33e13f33392f5e5d33e1320110f6e1325d7110f6e111392f33e132313001140e022321112111231133112111331133321e020133323635342e022323070c3c7ec286febffdb8 baba0248ba6d98cf7e37fd7777aea42e5b8b5d5801ac619e703d02aafd5605b6fd980268fd98427198fe9d848846613c1b00000100140000050605b600150073404d085a0755170f176f177f170306f4 1401a014b014027414011414000e5a0f0011301140115011c011051111b00f01670f770f025e0f013f0f4f0f02000f010f15115f120d5f00000712030f0712003f333f12392fe110e132012f5d5d5d5d 5d332f5d10e132322f5d5d5d5e5d10f6e131300121321e02151123113426232111231121352115210223015a5d926535ba697bfebbbbfeac03b1fe5e0381315e8b59fdf201f67374fd230512a4a4ffff 00c7000004a20773022601b4000001070076008901520013400b0117052601220b11040025012b35002b3500ffff0019ffec04ae0769022601bd000001070236002301520013400b01270526010d2c22 130025012b35002b3500000100c7fe7f04c105b6000b00634041c602d60202025ac503d50302a8030196030103100e11484703013a0301030305095a00650db00d016f0d9f0daf0d03100d01085a0564 0c0a0603085f0502020105002f33332f10e13f330110f6e15d5d5d10f6e111392f5d5d2b5d5d5de15d313021211123112111331121113304c1fe5ab1fe5dba0285bbfe7f018105b6faf00510ffff0000 000004dd05bc020600240000000200c70000043305b60010001b004b402e5f0801080811155b00671d0f1d5f1d7f1dcf1d04060b115a06641c1b5f0f0baf0b02080b0b110a5f070311600612003fe13f e112392f5e5de10110f6e1325e5d10f6e112392f5d313001140e022321112115211133321e020133323635342e02232304333c7ec286fe960314fda69698cf7e37fd4ea0aea42e5b8b5d8101ac619e70 3d05b6a4fe3c427198fe9d848846613c1b00ffff00c70000048705b6020600250000ffff00c7000003be05b60206016100000002000efe7f050a05b60011001b008b400b181b281b021b0737140114b8 fff8400b141748145a0e0f07010707b8fff04010300ec00e02070e070e05125a10015a00b8ffc04025101548000010651d201d010f1d0108045a05051c145f0e030951081b10065f030005050312003f 332f3310e132322fe23fe11101332fe15e5d5d10e4322f2be110e11139392f2f5d385e5d10e12b5d11335d313001231121112311333e05372111332111210e0507050ab0fc64b0712f564d41301d0402 65c2fe83fefa041f2e3d464d27fe7f0181fe7f022755c8d9e6e8e369faf0046a4cb9cad1c8b74b00ffff00c7000003be05b6020600280000000100040000068105b6001100cb404e6609760986090337 094709570903090606470df70d020d5a6900790089000338004800580003000303a80eb80e02990e01860e01570e670e770e030e0e110a0708080b000a01700a800ac00a030ab8ffc04026070a480a10 0a0a13f01301bf13cf13df1303a013018f13014013010f131f1302080201011011b8fff0400f11111206030304110a0e1207010403003f33333f3333123911331101332f38333311335e5d5d5d5d5d5d 11332f382b5d71333311331112392f5d5d5d5d3311335d5de15d3211335d5d31300101330111331101330101230111231101230225fdedcd020ab3020acdfded0221d3fdeeb3fdeed302f202c4fd3c02 c4fd3c02c4fd3cfd0e02e5fd1b02e5fd1b0000010048ffec03ec05cb00390068403f275b0005210030210000213003131c5b0b673b9f3b0170138013023f134f135f130313133a052060aa2101782101 0f2101082121192f2c6035041960141013003f33e13fe13312392f5e5d5d5de1391101332f5d5d5d10f6e11217392f2f2f11123910e1313001140e0207151e0315140e0223222627351e033332363534 2623233533323e0235342e0223220607273e0333321e0203d1335b7d4b578a5e324388cd896ec0552b6063632eb2b0cfbabfb05c8e613225445f3a6ea94b5c26627483476da671390460497858390c06 0b3959774860a07440222daa1724180d94878781972748653d36533a1e43367d1f36291836618500000100c90000051005b60017006b401b140b0e5a0d6519d01901af190120193019021609025a1764 181709b8ffe8b314184809b8ffe040230a134806091609260903090d12141814184814200a13480914191429140307140b0003003f32325e5d2b2b3f335d2b2b330110f6e132325d5d5d10f6e1323231 30133311140e020706073301331123113436373637230123c9ae0102020204040702ccd5ac0604040508fd31d705b6fce01a3e4343204a4c04b4fa4a0319398e414c4dfb4600ffff00c9000005100769 022601b2000001070236008901520015b4011d052601b8ffebb42218000c25012b35002b3500000100c7000004a205b6000a005e4021080909100901000010000207001000000cb00c012f0c01100c01 970a01560a010ab8fff84014080c480a0707035a04640b070204080503040012003f323f331239390110f6e13211332b5d5d5d5d5d11332f385e5d33333811333130212301112311331101330104a2db fdbababa0235cffdcb02e5fd1b05b6fd3c02c4fd420000010000ffe9049305b6001f0062b10803b8fff8403b141748035a891901191019e01e01b41ec41ed41e03001e501e801e03071e1e10015a0065 210f211f217f210308101020035f1e031460110d130012003f3f33e13fe11101332f5e5d10f6e111392f5e5d5d5d33385de12b323130212311210e03070e032322262735161633323e02373636121237 210493bafe850f1f21221014354f6e4e234a1c173a20303e2a1a0c0c20272b1602d0051271f4ecd45167a26f3b0e0b9a0d103f62753639c80106013aaa00ffff00c70000062f05b6020600300000ffff 00c7000004d505b60206002b0000ffff007dffec057105cd020600320000ffff00c7000004c105b60206016e0000ffff00c70000043305b6020600330000ffff007dffec049805cb020600260000ffff 00140000041205b602060037000000010019ffec04ae05b60021006f401012011b1b132160007000b000f0000400b8ffc04010060a4800100000230f237f2302140913b8fff0400c131322e71af71a02 d61a011ab8ffe040100a0e4812011a03000d5f0a0613130003003f323f33e11117392b5d5d1101332f3833335d11332f382b5d331239113333313001010e032322262735161633323e02370133011e03 17333e03370104aefe542653709c6f335a25255934355242381cfdeecc017f050a09090402030b0b0b03013705b6fbfa5da47b480f0fb914191735563f043ffcd70a181a1709091f211d07031800ffff 0068ffec05ba05cb020601730000ffff00000000046005b60206003b0000000100c7fe7f057105b6000b003b4021035a0202095a000db00d01af0d01100d01085a05640c0a060300085f050202051200 3f332f10e1323f330110f6e15d5d5d10d4e1332fe1313025331123112111331121113304c1b0b0fc06ba0285bba6fdd9018105b6faf00510000100a60000048105b600150048401d13015a0065177017 a017022f17011017010d5a600a700aa00ab00a040ab8ffc0400e070a480a13105f0505140b030012003f3f33392fe133012f2b5de15d5d5d10f6e1323130212311060623222e02351133111416333236 3711330481ba73c3625d926535ba697b5ab970ba02562c2e315f8a590247fdd17374282802c6000100c70000073305b6000b00604042560801085a17050186059605a605036705770502050501095a00 650d000d100d02200d500d700d800dc00dd00de00d070f0d0107045a01640c0a06020308045f0112003fe1323f33330110f6e15e5d5d7110f6e111392f5d5d71e15d3130212111331121113311211133 0733f994ba021fba021fba05b6faf00510faf0051000000100c7fe7f07e305b6000f0071404b560c010c5a17090186099609a6090367097709020909050d5a00035a0202006511001110110220115011 70118011c011d011e011070f110107085a0564100e0a06030c00085f0502020512003f332f10e132323f33330110f6e15e5d5d7110e4322fe110e111392f5d5d71e15d31302533112311211133112111 33112111330733b0b0f994ba021fba021fbaa6fdd9018105b6faf00510faf005100000020014000004d505b60010001b005240330b115a900601060608155b00671d0f1d010f1d2f1d3f1d5f1daf1d05 0608081c1b5f0f0baf0b02080b0b11085f090311600612003fe13fe112392f5e5de11101332f5e5d7110f6e111392f5de132313001140e022321112135211133321e020133323635342e02232304d53c 7ec286fe95feac020f9598cf7f37fd4ea0aea32d5c8a5d8101ac619e703d0512a4fd98427198fe9d848846613c1b000300c7000005cf05b6000e0019001d0049402b135b0000010000061a5a1d651f0f 1f9f1f0206090f5a06641e195f0f09af09020809091b07030f601a0612003f33e13f33392f5e5de10110f6e1325e5d10f6e111392f5de1313001140e02232111331133321e020133323635342e022323 0111331104333c7ec286fe96ba9698cf7e37fd4ea0aea42e5b8b5d810393bb01ac619e703d05b6fd98427198fe9d848846613c1bfd5605b6fa4a000200c70000043305b6000e00190048402e135b9000 0100671b0f1b5f1b02061b401518481b400d1348090f5a06641a195f0f09af090208090907030f600612003fe13f392f5e5de10110f6e1322b2b5e5d10f65de1313001140e02232111331133321e0201 33323635342e02232304333c7ec286fe96ba9698cf7e37fd4ea0aea42e5b8b5d8101ac619e703d05b6fd98427198fe9d848846613c1b0001003bffec044405cb00240051402f1d205b0c161e161e040c 6726bf26cf26df26030404251e5faa1f01781f010f1f01081f1f071a5f17111303005f0704003fe1333f33e111392f5e5d5d5de11101332f5d10e61139392f2f10e13231300122060727363633321616 12151402060623222e0227351616333212132135212e0301ba5e943f4e4fc46ca2f4a25252a5f7a43a61564e274ea059edf706fd8b02710947739d05272e209c2a2c6dc1fef69db3fee0ca6d070e170f a2172301170106a26fb07a40000200c7ffec079e05cd001a002e005e403c1b5b0a90110111110d255b0067300f30013f306f307f30ef30ff30053040111448100c5a0d642f2a5f16040b5f0f10010810 100d0e030d12205f0513003fe13f3f12392f5e5de13fe10110f6e1322b5d7110f6e111392f5d33e131300114020606232226260227211123113311213e03333216161205141e0233323e0235342e0223 220e02079e4f9be59697e1985006feaebaba01560b5598db9195e59a4ffbfa31679d6c6d9d663030659d6c6d9e673102dda9feeac66c64b70103a0fd5605b6fd9892eca75a6bc5feebab89db99515199 db898ada97515197da0000020019000003f205b6000f001c009b4009060001e600f6000200b8fff840240b0f481c0e5a030000080d651e3f1e8f1e9f1ebf1edf1e05201e01060101e601f6010201b8ff f8400d0b0f48014b02010240080b4802b8fff040260202165bdf08ef08ff080308400f134807081708020808661d1c60030f0f0111600b030e0112003f333fe112392f33e10110f65e5d2b5de1332f38 2b5d332b5d715d5d10f611391133e1322b5d713130010123012e0335343633211123111123220e0215141e0233330242feb2db017d37634b2cfdfb0175bbbc4a734f29274e7751b4025cfda4028f143e 61885dc6c9fa4a025c02bb1d3e614442694a2800ffff005effec039c045e02060044000000020075ffec042106230027003b0049402c2d48091e573dd03d017f3d01403d010f3d010613374800563c32 50131919082850231609080b104809510801003fe12b3fe111392f33e10110f6e1325e5d5d5d5d10f632e13130133412363637363637170e03070e0307333e0333321e0215140e0223222e0201323e02 35342e0223220e0207141e02753168a2717df26621327b7d752c3e644829040d123e546b4063966532457cae686bad7b4201e13c6246261a3a5a413d6a53390d1941720293b50119cb7e191b3114a008 1618180a0e4271a5711d3c31204983b46c89ce8a4559adfdfe9427588f6954865f333044491a64bc9359000300ae00000419044a00150020002b005c403a031b214600000f164709572d202d01402d90 2db02dd02df02d050f2d0106261b470f542c031a50bf2601792689260226261b2550100f1b500f15003fe13fe112392f5d5de1390110f6e1325e5d5d7110f6e112392fe11239313001140607151e0315 140e0223211121321e0203342623211121323e0203342623211133323e0203f67b6b386147292f659f71fe3901c5538e673b908280ff000104385d43261e6d6cfef5ec3e5c3f1f03356875120707243d 5b3f43745630044a1c406bfdc75c48fea8122a45020c4d40fed70f243c00000100ae0000030a044a0005002f401c0000100002000007a0070181070150070102470354060150040f0215003f3fe10110 f6e15d5d5d11332f5d3130012111231121030afe5ab6025c03b0fc50044a00020029fe830437044a000f001700794010170712460c2f073f07020b071b070207b8fff04039a20cb20c02040c140c0207 0c070c0510470e01460000200e010e5519af19cf19023019012f19010446050518124f0c0f170e065003150500fb003f323fe132323fe11101332fe15d5d5d10e45d322fe110e11139392f2f5d5d385d 5d10e11133313001231121112311333e0212372111332111230e03070437aefd4eae564163432201021797feb2c007243a5134fe83017dfe8302175fdff301007ffc50032467d7d1c253ffff0071ffec 03e1045e02060048000000010004000005be044a0011009c401f0603030a460f0000d60b01b90bc90b02a60b01970b010b0b0e070405050807b8ffc0b312154807b8ffc04024070b480f070106071007 07130013101302df1301301370139013030f1301071110100d0eb8fff0400f0e0e12030000010d080a151104010f003f33333f3333123911331101332f38333311335e5d5d5d7111332f385e5d2b2b33 3311331112392f5d5d5d5d331133e13211333130011133110133010123011123110123010133028fa401a0c5fe5801cecefe43a4fe44cf01cffe58c502350215fdeb0215fdebfdcb022dfdd3022dfdd3 0235021500010044ffec0352045e0039005f403a0546161b16391639160c344721573bb03bc03bd03b036f3b01203b01290c563a1b3850cf390189399939020f3901083939112f50261608501110003f e13fe111392f5e5d5d5de1390110e6325d5d5d10f6e11239392f2f123910e1313001323e0235342623220607273e0333321e0215140e0207151e0315140e0223222627351e0333323e02353426232335 01713d644827736c47814b3f284d525a355690693a1c33462b2c523f26356ca6716daf3a1f4c57613337604629858a8102871227402d4d4d262293141c1309264a6d46324d3b290e0b0e2c425a3e4375 56312322a6101f180f122a45335e5b99000100ae0000043b044a000b0051401b031009184803064605550d000d100d200da00dc00dd00df00d070db8ffc0b30e114809b8fff040110918480900460a54 0c08030b0f06020a15003f33333f33330110f6e1322b2b5d10f6e1322b3130011107013311231113012311015a0c0204e9ac0bfdfeea044afd64fc0398fbb60287010ffc6a044a00ffff00ae0000043b 0617022601d200000106023625000015b40111112601b8ffffb4160c0a0425012b35002b3500000100ae000003e5044a000a00414023000101040003100302031003030c0f0c010a02064707540b0502 0a0a0700080f040715003f333f3312391133330110f6e132325d11332f385d333311333130013301012301112311331102fac4fe6101c6cefe4bb4b4044afdf1fdc5022dfdd3044afdeb00010010fff2 03b0044a0014004c40310346041301f4130180139013c013d0130454130113130b01470055160f162f16ff1603060b0b150350130f0e4f08160115003f3fe13fe11101332f5e5d10f6e111392f5d5d5d 71e1313021231121020206062322262735163332363612372103b0b6fefe14405f82561c3110171b3759453312025403b0fefdfe94e6690606830675f1016ffa000100ae00000510044a0020005e403f 1f0146005522cf220140225022020f220106131046115421020f3b0f4b0f5b0f03090f190f290f030f1f120f34194419541903061916192619031909011115003f3333335d5d3f33335d5d11330110f6 e1325e5d5d5d10f6e13231302123110e03070123012e032711231133011e03173e033701330510a10611141207fef887fef70511141207a2dd010b0d16130f04060e13160d010ed9038115393b3612fd 5002b00d313b3e1afc7f044afd4722433c321011313b412102bd000100ae0000043b044a000b005b401702064705550d000d200d02300d400d500dd00df00d050db8ffc040230e11480109470a540c08 50eb0101a901b901020f011f012f01030601010a051503000f003f323f33392f5e5d5d5de10110f6e1322b5d7110f6e132313001112111331123112111231101640221b6b6fddfb6044afe3901c7fbb6 01e9fe17044affff0071ffec042d045e020600520000000100ae00000412044a0007002d401c0547045509100920096009700980090500470154080750020f050015003f323fe10110f6e15d10f6e131 3021231121112311210164b60364b6fe08044afbb603b000ffff00aefe14043f045e020600530000ffff0071ffec036f045e020600460000000100290000035e044a00070058403c200901df09017009 8009025f09010f0001cc00010f00bf000206000002470360057005d005031f0501050500031003b003c0030403010550060f0215003f3fe132012f5d332f5d5d10e1322f5e5d5d715d5d5d7131300121 112311213521035efec1b7fec1033503b0fc5003b09affff000afe1403df044a0206005c000000030071fe14052306140019002200290074404b27000b461d170c0d1349b90cc90c02970ca70c020c0c 12234805572b202b010f2b019f2bef2b02802b016f2b01402b010f2b1f2b02061a4812562a1800261e50001710271d500a0d160b1b003f3f33e1323f33e1323f0110f6e15e5d5d5d5d5d717110f6e111 392f5d5d2b3333e132323130011e0315140e02071123112e0335343e0237113301141617110e0305342627113636032171bd884c4786be77aa72bf894c4785c179aafe0c9cae587d502503399baaac99 045a0c558fc67d7dc891560bfe2401dc0a5690c97e7dc78f550b01bafc13bbd213033c093d67915ebacc14fcc614d100ffff0023000003db044a0206005b0000000100aefe8304b2044a000b0044402b 01470f000106000007478f0a010a0d100d200d600d700d800dc00d06064703540c08040f0a0650031501fb003f3fe1323f330110f6e15d10d45de1332f5e5de1313001231121113311211133113304b2 b6fcb2b601f8b6a0fe83017d044afc5003b0fc500001009a000003fe044a00180031401c080c470b551a101a601a801a03014717541908035012120b1509000f003f323f392fe1330110f6e15d10f6e1 32313001111433323e023711331123110e0323222e0235110150b82d504c4d2ab6b62c50555e3a4e7a522b044afe66ae0f1c2c1c01d5fbb601e91e3020112f54734401a6000100ae00000646044a000b 006640430047b609c60902a90901037409840994090367090106090905014704550d200d010f0d01800df00d026f0d01400d010f0d2f0d0206084705540c00085005150a06020f003f33333fe1320110 f6e15e5d5d5d5d717110f6e111392f5f5d5d5f5d5de1313025211133112111331121113303d501bab7fa68b601bbb69a03b0fbb6044afc5003b0000100aefe8306e5044a000f0077404e0a47b607c607 02a907010374078407940703670701060707030b470e01470e00010000bf0e010e112011010f110140118011e011f011040f112f11020606470354100c08040f0e0a0650031501fb003f3fe132323f33 330110f6e15e5d5d717110c45d322f5de110e111392f5f5d5d5f5d5de131300123112111331121113311211133113306e5b6fa7fb601bbb601bab79ffe83017d044afc5003b0fc5003b0fc5000020029 000004fc044a000e001b005c403e0f4704571d501d601d901de01d043f1d010016470a000c100c02b00cf00c020c0c000a100a500a600aa00a05080a1550bf00010000160c500d0f16500a15003fe13f e112392f5de1012f5e5d332f5d7110e1325d5d10f6e131300121321615140e0223211121352101342e0223211121323e0202480114d4cc2f659f71fe39fe98021f020221416040ff000104375d442602 879c9b4d7c582f03b09afcf831422811fea811294200000300ae00000550044a000c0010001d0061404018470004100420047004d004050604040a0e470d551f0f1f01bf1fcf1fdf1fff1f04a01f010f 1f7f1f02070012470a541e1150bf000100000f0b0f12500e0a15003f33e13f33392f5de10110f6e1325e5d5d5d7110f6e111392f5e5de131300133321615140e022321113301231133011133323e0235 342e02230164ecd4cc2f659f71fe62b603ecb6b6fc14db385d43262141604002879c9b4d7c582f044afbb6044afda4fea8112942303142281100000200ae00000419044a000c00190040402914470457 1b001b01001b201b701b901bb01bd01b0608000e470a541a0d50bf000100000b0f0e500a15003fe13f392f5de10110f6e1325e5d7110f6e131300121321615140e0223211133111121323e0235342e02 2301640115d4cc2f659f71fe39b60104385d43262141604002879c9b4d7c582f044afda4fea8112942303142281100010037ffec0342045e0026005e403e0e0e040c0f482257288f28af280240280118 0f041f042f040304400c11480458270d50ef0e01a90eb90e020f0e1f0e2f0e03060e0e0712511d1007510016003fe13fe112392f5e5d5d5de10110e62b71325d5d10f6e13211392f3130052226273516 1633323e0237213521262623220e0207273e0333321e0215140e020142597c363683524974523004fe2301db0d928c193b3c3817351840484e2666b3844d518cba141e1da219252854845c9aa697090f 130a9a0c1610093e89db9d92d48a4300000200aeffec0608045e001a00260072404b1b480a2011014f110111110d21480057280f282f2802ef28ff28024728010f282f2802100c470d5427245016100b 50ef1001a910b910022c10010b101b10020610100d0e0f0d151e500516003fe13f3f12392f5e5d5d5d5de13fe10110f6e1325d5d5d7110f6e111392f5d7133e1313001140e0223222e02272111231133 11213e0333321e0205141633323635342623220606084078ab6a62a2754607feefb6b601130a4876a06362a77944fd29808e8f7e808f8e7e022789d5914c4281be7cfe17044afe3974b1783e4b91d388 d1d3d3d1d1cfcf000002002300000391044a0011001c0053401402111107180f470e551e0f1e6f1e8f1e03060001b8fff0401901011246074012154807561d02105018180019500d0f0f0015003f323f e112392fe1320110f62be1332f38335e5d10f6e1321139113331303323012e0335343e0233211123112303141e02333311232206e9c601232d54412838648a5301bcb6f4dd25415a36dbfe6b6801cd0c 304c6c474e79512afbb601b0015430462e1601665f00ffff0071ffec03e105d90226004800000106006ada000017400d0302311126030200283c050f25012b3535002b35350000010012fe1404120614 0031005340321f170c472d55331033603380330323221e16471b17543221194f1e1a1a1c23105000291029202903290f1c0017150750001b003fe13f3f3f5de13312392f33e1320110f632e13232325d 10f6e1123931300122262735161633323e023511342623220e02151123112335333533152115211507333e033332161511140e0202f0303f171a36231b2e23136970516e431db69c9cb6017bfe85080a 1945525c30b7b922486dfe140e0b940a0b0f2741330344828234669460fdf004d589b6b689b8902b3f2a14bfd2fcbe4d7b572f00ffff00ae0000030a0621022601cd000001060076d4000013400b0112 11260145060c030025012b35002b350000010071ffec036f045e0022004f40311717161f0d248f24af24024024011619480556231950ef1601a916b916020f161f162f16030616161c13510a101c5100 16003fe13fe112392f5e5d5d5de10110f6e1325d5d10ce3211392f313005222e0235343e0233321617072e0323220607211521161633323637150606025265b0824a4c85b2664e95323617383c3a1a8b 920e01dbfe2309928a518336367b143f89d5969ddb893e22199a0a130f0997a69ab8a42519a21d1effff005affec033f045e020600560000ffff00a00000017505e50206004c0000ffffffee00000225 05d9022600f300000107006afebb00000017400d02010d11260201000418010025012b3535002b353500ffffffbcfe14017505e50206004d000000020010fff20612044a001d002a006b40450c461c00 25470ad41c01901ca01c02241c01001c011c0a1c0a141e4704572c0f2c2f2c3f2c5f2c7f2cbf2cef2c0714142b2450bf00010000250c501c0f174f111625500a15003fe13fe13fe112392f5de1110133 2f5d10f6e11139392f2f5d5d5d5d10e13210e131300133321615140e0223211123020206062322262735163332363612372101342e0223231133323e020387ecd4cb2e659f71fe62d914405f82561c31 10171b3759453312022b01d921416040d7db385d432602879c9b4d7c582f03b0fefdfe94e6690606830675f1016ffafcf831422811fea8112942000200ae00000675044a0014002100534030051c4702 0f0f131547095723ef23018023013f23011023010112471354221b115005bf01010101001c50130f1503000f003f323f33e111392f5d33e1320110f6e1325d5d5d5d10f6e111392f33e1323130011121 11331133321615140e022321112111231101342e0223231133323e02016401cfb6ecd4cc2f659f71fe62fe31b605152141613fd8dc375d4426044afe3901c7fe3d9c9b4d7c582f01e9fe17044afcf831 422811fea811294200010012000004120614002100534032681401140b0047215523102360238023031716120a470f0b5422150d4f120e0e10170450001d101d201d031d0f10000b0015003f323f3f5d e13312392f33e1320110f632e13232325d10f6e111395d31302111342623220e02151123112335333533152115211507333e033332161511035c6970516e431db69c9cb6017bfe85080a1945525c30b7 b9029a828234669460fdf004d589b6b689b8902b3f2a14bfd2fd5c00ffff00ae000003e50621022601d400000106007608000013400b01171126010c0b11070325012b35002b3500ffff000afe1403df 06170226005c000001060236b1000013400b01281126010a2d23000f25012b35002b3500000100aefe830412044a000b0059403dd60601b706c706020647b507c507d5070376078607024a075a070207 0709014704550d100d200d600d700d800d05004709540c050050091506fb0a020f003f333f3fe1330110f6e15d10f6e111392f5d5d5de15d5d3130252111331121112311211133016401f8b6feb3b7fe a0b69a03b0fbb6fe83017d044a00000100c7000003be06e300070044402c005adf03ef03ff03030003100302030309b009d009020f09af0902055a066408045f07200101010107030612003f3f332f5d 10e10110f6e15d5d11332f5d5de131300111331121112311030eb0fdc3ba05b6012dfe2dfaf005b6000100ae0000030a058900070030401c05470000100002000009024703540810062006020606014f 040f0215003f3fe1332f5d0110f6e111332f5de131300121112311211133030afe5ab601a6b603c1fc3f044a013fffff0014000006fe07730226003a00000107004300e701520015b4012b052601b8ff acb4312b1e0e25012b35002b3500ffff0014000005e306210226005a0000010600434c000015b40130112601b8ff9eb43630112e25012b35002b3500ffff0014000006fe07730226003a000001070076 01a001520013400b0137052601642b311e0e25012b35002b3500ffff0014000005e306210226005a000001070076011700000013400b013c112601693036112e25012b35002b3500ffff0014000006fe 072b0226003a00000107006a013901520019b602013405260201b8ffffb42b3f1e0e25012b3535002b353500ffff0014000005e305d90226005a00000107006a00ac00000019b602013911260201b8ff ffb43044112e25012b3535002b353500ffff00000000043707730226003c000001070043ff7201520015b40109052601b8ffa4b40f09070225012b35002b3500ffff000afe1403df06210226005c0000 01070043ff4b00000015b40123112601b8ffa4b42923000f25012b35002b35000001005201d103ae02790003001db90002ffc0400b060c480202050000b901bd003fe1012f11332f2b31301335211552 035c01d1a8a80001005201d107ae02790003001db90002ffc0400b060c480202050000b901bd003fe1012f11332f2b31301335211552075c01d1a8a80001005201d107ae02790003001db90002ffc040 0b060c480202050000b901bd003fe1012f11332f2b31301335211552075c01d1a8a80002fffcfe31034effd300030007002a401804000009050105baef06ff06020602ba0001100120010301002f5de1 2f5de1012f3311332f3331300121352135213521034efcae0352fcae0352fe318b8c8b000001001703c1015005b6000c002540175f0e01060f075f076f07bf07cf0705070c98010c9c0603003fe5012f e12f5d335d313013273e0337330e0307250e0e272e3419890f1d1a160803c116367a7c7b383d84837c350001001703c1015005b6000c002540175f0e0106070c980f015f016f01bf01cf010501069c00 03003fe5012f5de12f335d313001170e0307233e033701420e0e272f3319890e1d1b160805b61637797d7a383c84847c35000001003ffef8017900ee000c0035b9000effc040140a18480c980f015f01 6f017f01cf010501010607b8ffc0b710154807069c00a8003fe5012f2b33332f5de12b313025170e0307233e0337016a0f0e272f33198a0f1d1b1608ee17367a7c7b383d84837d350001001903c10152 05b6000c002b401c5f0e01060f055f056f057f05bf05cf05df0507050500980b069c0003003fe5012fe1332f5d335d3130131e0317232e032737ee08161a1d0f8919342e270e0e05b6357c84843c387a 7d7937160002001703c102d105b6000c001900624048bf1b01901b010f1b5f1b6f1b03130f145f146f147f14bf14cf14df1407141419980e0c980001500160017001b001c001d001070101060f075f07 6f07bf07cf070507190c9c130603003f33e532012f5d33332f5de12fe1332f5d335d5d5d313001273e0337330e030721273e0337330e030701a60e0e272e3419890f1d1a1608fdb80e0e272e3419890f 1d1a160803c116367a7c7b383d84837c3516367a7c7b383d84837c350002001703c102d105b6000c001900624048bf1b01901b010f1b5f1b6f1b03130014501460147014b014c014d01407141419980f 0e5f0e6f0ebf0ecf0e050e0c980f015f016f017f01bf01cf01df01070101060713069c0d0003003f32e532012f33332f5de12f5de1332f5d335d5d5d313001170e0307233e033721170e0307233e0337 01420e0e272f3319890e1d1b160802480e0e272f3319890e1d1b160805b61637797d7a383c84847c351637797d7a383c84847c350002003ffef802fa00ee000c0019007e4051d01be01bf01b03a41bb4 1bc41b03901b0102201b301b401b601b701b801b06130014501460147014c014d0140614141998900ee00ef00e030f0e5f0e020e0c980f015f016f017f01cf01df010601010607b8ffc0400a10184807 13069c0d00a8003f32e532012f2b33332f5de12f5d5de1332f5d335d5f5d5d5d313025170e0307233e033721170e0307233e0337016a0f0e272f33198a0f1d1b160802480e0e272f3319890e1d1b1608 ee17367a7c7b383d84837d3517367a7c7b383d84837d35000001007b000003680614000b007c4052900da00de00df00d046f0d01100d300d400d030706c004080803e40bf40b02d60b01770b016a0b01 540b01450b01260b010bc0090a01090936020102be00031003a003030304010005bf0b0a0706c2080003002f3ff6323232e1323232012f5de15d3211333310e65d5d5d5d5d5d5d11332f33e6335d5d5d 31300125132313053505033303250368feb537d937fec9013737d937014b03dd1ffc0403fc1fb41e01a1fe5f1e000001007b0000037d0614001500b04071001701a017b017f017037f17012017401750 1703080dc00e0b0f0f0501041201f41201e612018712017a1201641201551201361246120212c0101411101015030004be050a0a09060005010005100520055005a005b00506080514130b0cbf12110e 0dc20f0009010008bf06030207c205002ff6323232e13232323ff6323232e1323232012f5e5d713333332f10e13232323211333310e65d5d5d5d5d5d5d713211332f3333e6325d5d5d71313001251525 1323130535050313053505033303251525130231014cfeb437d938feb4014c2f2ffeb4014c38d937014cfeb42f01f01eb41ffe8701791fb41e012201131fb41e0178fe881eb41ffeed000001009601e5 026d03f20013004640242f155f156f157f15cf15ef15ff15071015015f0a6f0a9f0aaf0adf0aef0a060ad0000100b8ffc0400c070a48001f0f010f10050105002f5dc55d012f2b5dc55d5d5d31301334 3e0233321e0215140e0223222e0296243f5632315640252540563132563f2402ec47643f1c1c3f644746643f1e1e3f6400030093ffe305db00fa00130027003900a84076143b243b02fb3b01e43b01bb 3bcb3b02a43b018b3b01643b743b024b3b01343b010b3b011e9666147614021414002896243201fb3201e03201d43201bb3201a432018b32017232016632014b3201303201022032010f320106320a96 e000f0000254006400020000100020000307002d19059b37230f002f3333ed3232012f5e5d5d5ded2f5e5d5d5f5d5d5d5d5d5d5d5d5d5d71ed11392f5ded5d5d5d5d5d5d5d5d5d71313037343e023332 1e0215140e0223222e0225343e0233321e0215140e0223222e0225343e0233321e0215140e022322269314222e1b1a2f221414222f1a1b2e2214022514222e1b1a2f221414222f1a1b2e221402251323 2e1b1a2f221414222f1a36496f2635210f0f21352625352210102235252635210f0f21352625352210102235252635210f0f213526253522104200070066ffec08f405cb0009001d0027003b003f0049 005d0089405c40b454b54a1eb432b523b428a03e01303c403cb03c0330284028023e3c28283c3e031445b44a5f3f5f4f5f5f5f7f5faf5f0505b40ab500b4101420143014031447b659b743b64f193f06 3e1825b637b721b62d1903b60fb707b61907003fe1f4e13fe1f4e13f3f3fe1f4e1012f5de1f4e15d10dee11217392f2f2f5d5d5d10e1f4e110f4e131301314163332111023220605140e0223222e0235 343e0233321e020114163332111023220605140e0223222e0235343e0233321e02010123010114163332111023220605140e0223222e0235343e0233321e02fa47509c9c504701c7244a734f49704c26 2349714e4b714d2701ac47509c9c504701c6234a734f4a704b262349714e4b714c27ff00fcd59e032c029747519b9b514701c7234a734f4a704b262349714e4a724c270402a5a5014a0148a3a56cac76 3f3f76ac6c6caa753e3e75aafd4aa5a401490148a3a56cab763f3f76ab6c6caa753e3e75aa0392fa4a05b6fc02a5a401490148a3a56cab763f3f76ab6c6caa753e3e75aaffff008503a6014a05b60206 000a0000ffff008503a602b205b602060005000000010052007301fc03c70006003cb10402b8ffc0401f090c4802083f089f08af08df08ef08ff080606eb9f03010306000303010501002f2f12393d2f 333301182f5de15d10c62b3231301301170313070152013575eeee75fecb0229019e4efea4fea44e019b00010052007301fc03c70006003f402800ebdf03ef03ff03031003200302033f089f08af08df 08ef08ff0806043f02010206000303010501002f2f12393d2f333301182f5d335d2f5d5de131300101271303370101fcfecb75eded750135020efe654e015c015c4efe62ffff0093ffe3036205b60027 000401d100000106000400000009b52f31011031015d5d000001fea00000026805b60003001db10102b8fff04009020300100001120003003f3f012f38322f38333130010123010268fcd59d032b05b6 fa4a05b60001006a031d029305c700140041401700e000140114166016c016e016f016040f16010e0ae00bb8ffc0400e0a0f480b0a00c00e04e411de0cdc003f3fe1331acc32012f2be1325d5d10d65d e131300111342623220e0215112311331733363332151102143f3f2d412a157f6910094082e5031d01a6514415345741fea6029d5865fafe5000000100600000040005b6001100764048021002100500 0b100b200b030b0b133013010e00045a050905df0701070700051005c005030705030760080008115f0e0f0e3f0e6f0e03080e40101548080e080e040d5f0a030412003f3fe11239392f2f2b5e5d10e1 113310e132012f5e5d332f5d113310e132325d11332f5d1239392f2f313001211521112311233533112115211121152101c30124fedcb3b0b002f0fdc30216fdea018f89fefa0106890427a4fdfca400 000100440000042305c9003000874010110d156f2b27230f13231323131e031bb8ffc0403e090e481b1b3210320129251e400b0e481e1425752611261029752a0d2a6f2601d02a010f2a1f2a3f2a4f2a af2abf2a06262a262a001e1a741d1807730007003fe13fe1321139392f2f5d5d5d113310e132113310e132012f2b33335d11332f2b331239392f2f1133113333e1323231300132161707262623220e02 15152115211521152115140e0207211521353e0335352335333523353335343e02029a6aae4242388d4b30523c210178fe880178fe881727331b02ecfc212c49351ec6c6c6c63b699205c92d23901d2b 1b3b5e42c0899e89133e59402b10a69a0b2944614315899e89dd57895f3200030096ffec05b605b6001b002a003500794018316f1c12100f6e1815181c181c1824ff0501054012154805b8ffc0402c09 0e480505370f370137400b10482b236e247c360f18751512152b7322152215222435732506241800750919003fe13f3fe11239392f2f10e1113310e1320110f6e1322b5d11332f2b2b5d1239392f2f11 3310e1323210e1313025323e023715060623222e02351123353737331533152311141601140e02232311231133321e020133323e023534262323053b0f24231e0717503f355840249c9c416bd1d134fe 8c347ccc982fb2fb86bf7b3afdbd1a5d8b5b2ea4ae3981040608038a0c1422466a4801bf524dbdd389fe564c4e03895ba8814dfdc705b6396da0fe67204771518e890001003fffec044a05cb00390086 b41207283619b8ffc0404b090d4819193b103b012c232313050d6f2e2263280128283a132360241024082c602d052d5f247f248f24ef24ff24050f2d1f2d2f2d5f2d9f2dcf2d06242d242d1637007433 07165f191d19003f33e13fe1331239392f2f5d5d113310e132113310e1321101332f5d3333e132323311335d11332f2b33123939313001220e0207211521140706141514141721152116163332363715 060623222e02272335332634353436352335333e0333321617072626030845765e431201b0fe410101020181fe9222b9954b873b3b855b73b6875815a494020294a0125887b87261a04f503377052734 638f5b890f0e0c1a0913291689afb8201aa21c1f4987c17989171e1d162e08897dca904e2b31921f2b000004008dfff805db05c100030017002b00480086400a0102394618b40e030002b8fff0404a70 469046a046d04604df0e01001002460e00000e4602043122b40f0401ef04ff0402044a40b4003101003110312031e031f03105083142fc2cfd3dfc360727fc13fd1dfc091903060118003f3f3fe1f4e1 3fe1f4e1012f5e5d71e110de5d71e11117392f2f2f2f385d5d38113310e11133113331300101230101140e0223222e0235343e0233321e0205141e0233323e0235342e0223220e0201222e0235343e02 33321617072626232206151433323637150606050afcd59d032b016e2d5070443f6e512f2c5071443e6e522ffe3311263c2b2a3c251111253c2a2b3c2611fdcb45795a34355c7d48336420211f552267 5fc2335a23236305b6fa4a05b6fb98537f572d2d577f53537f572d2d577f5333563e23233e563334553d21213d5501922652805a5f845226160f6b0d147476e511106b12130000020077ffec037b05cb 002d003a005540322e70234010144823231105063c35286e191410112011301180119011051118153676141128280030761e0700750b06060b19003f332f10e13fe112392f3333e13232012f5dc533e1 3210d6c112392f2be1313025323e0237330e0323222e0235350606073536363711343e0233321e0215140e020711141e02133423220e0215113e03026f20392e1e036404264669463a6a51302e613134 5f2d1c40684b36573d21355c7c47112437636620291709364e3318771632523b53835a3025548863e7111c0c790e1e0f01ee3b6c53312a4f6f4563a6866826fed330513b210421bc1b32452afe6a214e 6279000400c70000078905b60017002b0037003b00ba40720e01155a0039392ce122100001b000019f00013000400002002200220a32e1180f3a1f3a2f3a033a3aef180118673d6f3dbf3dcf3d03403d 010c0803095a0a643c2fe51d35e527cf1ddf1def1d031d40060b480f271f275f276f277f27ef2706061d271d27160310061848030b0339e5380eb8fff0b60618480e010a12003f33332b33e03f332b33 39392f2f5e5d2b5d10e110e10110f6e13232325d5d10e65d322f7110e11139392f2f5d5d5d7110e1332f10e13232313021230123161716161511231133013326272e0335113301140e0223222e023534 3e0233321e020514163332363534262322060335211504a8cdfd870806040405a6cf027606030401030201a402e1294d6d443f6b4d2c294d6d443e6b4e2cfe4248515147475151486301f004ba4d4c41 8e39fce705b6fb4c4c4a2043433e1a0320fcb95382592f2f5982535381582e2e58815371737371726d6dfd1f93930002002502e5055005b60007002000a3405d00c401130a10c411c006d006e006036f 0601300640065006031f06010406012011d0110201061111060103031e191518c49f17af170217220f222f223f2203224015184822400f1248cf03ef0302031f0909200c1848090703c8041814b8ffe0 400c0c1848141108010115120403003f3333332f3333332b3310e132332b1133012f5d2b2b5d10d65de13232321117392f2f2f5d5d5d5d5d5d10e1323210e1313001231123352115230103231e031511 231133131333112311343e0237230301687fc4020ac70240ba07010201017bbab4bfb27f0101010106c302e502656c6cfd9b022510221e1806fe4902d1fdd90227fd2f01ac091e23230cfddbffff004e 000005a605cd02060176000000020066ffdd048b04480022002f003b4021234a1e11312f134a100501051d1d18124e2b2f3b2f022f2f18294e0c0f184e0016003fe13fe112392f5de111392f012f5de1 3210de32e1313005222e0235343e0433321e021521111e0333323e0237170e0313112e0323220e020711027982c686452c4c6676803f71c28e51fcc516404d582e4a745e4d224824536e8fcc133b4d5d 353357493c18235e9dcc6e63a07e5c3c1d4f93d183fe9c182c2215203c57372939654d2c028b0115142a231613212a17fee9ffff0053ffec05d305b60026007b140000270217025e0000010702400362 fdb30030401f040302271901f41101e41101d01101b01101a01101301101112f59010f59015d5d115d5d5d5d5d5d35003f353535ffff0033ffec05d305c900260075140000270217028b000001070240 0362fdb3003c4028040302491901f03301d03301c43301b43301a03301943301603301303301243301332f7b010f7b015d5d115d5d5d5d5d5d5d5d5d35003f353535ffff004fffec05d305b60026023d 140000270217028b0000010702400362fdb3003c40280403023d1901f02701d02701c42701b42701a02701942701602701302701242701272f6f010f6f015d5d115d5d5d5d5d5d5d5d5d35003f353535 ffff0071ffec05d305b60026023f42000027021702390000010702400362fdb3003440220403021f1901f40901eb0901cb0901b409019b09017f09012b0901092f51010f51015d5d115d5d5d5d5d5d5d 35003f35353500020062ffec043b05c5002b0043003b40213319470057454045010f4501063f48210c5644384f13132c211c5027042c500716003fe13fe13312392fe10110f632e15e5d5d10f6e13231 3001140e0423222e0235343e0433321617363435342623220e0207353e0333321e0201323e04372e0323220e0415141e02043b2041658ab16d6a8c53221732517399625b932d028b891f4443411b1843 4b4f257da6632afd9e355e514335250a0a293b492a3e664f3a2512152d4603a66ae1d4bc8d52426e8f4c3c8d8d83653d4f45132a0bbec90c161f13ae0c17110a5996c4fc732c4d687a85432845331e30 51686f6e2f3256402400000200290000046205b60005000e0058401102010909050e5b60047004b004f0040404b8ffc04027060a480404102f105f106f107f109f10bf100610400609480d5b050d5f05 1209200a1148090103003f332b3fe1012fe12b5d11332f2b5de112393d2f333331303701330115210126262706060703212901bebb01c0fbc70277202d0f112a1dfa02a6710545fab96f039a61a84b4b a85bfd04000100c7fe14052705b6000700374011005a076509000930094009700980090509b8ffc0400f141848035a046408025f050304001b003f323fe10110f6e12b5d10f6e1313001112111231121 11046dfd14ba0460fe1406fcf90407a2f85e0001004afe1404e305b6000b005c400b085b70060102060206000ab8ffc0b7090e480a0a0d0709b8ffe040090f1848090300000c0db8ffc0400f13184808 020209075f0403095f001b003fe13fe112393d2f33012b1133182f33332b3211332f2b1239392f2f5de131301335010135211521010121154a0270fda00448fcbc023afdb0039bfe14730392032b72a4 fd09fc9da4000001006602870402031d00030032401f02059600018b00017900015600014b00013800011400010900010000ad01b3003fe1012f5d5d5d5d5d5d5d5d10ce31301335211566039c028796 960000010025fff204c506a00008002c40130100060502060206070810080303ae04040700002f2f392fe1012f2f38333939192f182f331133333130052301233521130133027385feebb40129e50200 920e030a8ffd6905ac000003007701910531040e0023003300430076404f491701480d01f045012f455f45023a274a276a27032a3701371a0827043f772f972f022faa201230120212783f013fab0034 2aae173a24ae0837271a041705000d100d02070d0d1f9f170120170117002f5d5d33332f5e5d33121739e13210e132012fe15d2f5de15d1217395d5d5d5d31305d5d01140e02232226270e0323222e02 35343e02333216173e0333321e0205323637262623220e0215141e0201220607161633323e0235342e0205312b4d6d425d9b411d464e532b416e4f2d2b4e6f43559e3e1d444f5730426d4d2bfc7b3f6c 34316b4528402c18152c41027c3f6b37336c4427402d18192e4002cd3f7257346973304f381e2c527548417356316b70304e381f2d5275f957615e5a1d3344262442321e016a57615d5c1d3344272643 311c00010010fe14030606140023003740231025d02502140401060401040dac1b150109150115101e201e021e19ae121c07ae0000003fe13fe1012f5d335d5de1325d5d5d3130013216171526262322 0e021511140e022322262735161633323e023511343e020283224b16123d243342271032597c4a244b17143e2333452a122f5779061409099309112741542dfad75e8656290b08930810254054300527 5e86562800020066017b0402042500230047004b402e411d491049012e100a200a020a4029ad31af4317ad0a1faf1c05addf0def0dff0d030d400f12480d0d3bad2e43b3003f33e1332f2b5de133f532 e110f5e133012f5d335d10ce323130012e0323220e0207353633321e02171e0333323e0237150623222e02032e0323220e0207353633321e02171e0333323e0237150623222e02021225372d29161c3c 3b381964941d3237432f25372f28161c3c3b381863951d3237432f25372d29161c3c3b381964941d3237432f25372f28161c3c3b381861971d32374301bc10160d0513212c19a26c050d191410160d05 13212c19a26c050d1901ae10150d0513202c1aa26d050e191410150d0513202d19a26c050d190001006600a404020504001300a640110a0d0e1112091212000304070813080913b8fff0404f09101309 130906100b1540150101c60601bb0601a906018606017b0601680601420601390601060908080d04ad071312121100ad0e1f032f03027f030100031003020603030af007010f076f070207002f5d5d33 332f5e5d5d7133e13232113310e132331133012f5d5d5d5d5d5d5d5d335d10ce321139392f2f383811337d87c4c4c4c401331087c4c4c4c431300123352113213521131707331521032115210327015e f8013e79fe4901fc858a69fafec17b01bafe00818901ba96010495011b3be095fefc96feea39000200660000040204dd0006000a0052403209000c400c0108400101010201050503066f007f00023000 01000004200301500370038003d003f003053f03010003010603002f5e5d5d5d7133332f5d5d3212393d2f333301182f5d335d10ce323130250135011509023521150402fc64039cfd2102dffc64039c ee01a86601e1a0fe94febefe71969600000200660000040204dd0006000a0052403209050c400c0108400601060504010103006f067f0602300601060602200301500370038003d003f003053f030100 03010603002f5e5d5d5d7133332f5d5d3312393d2f333301182f5d335d10ce32313013010135011501153521156602e2fd1e039cfc64039c018f0142016aa2fe1f66fe58ee9696000002006d0000043f 05c300050009005d403602010905040709070306ac000bff0b01400b500b800bb00bc00b050f0b2f0b0208aa1003010303080006080608060207ad040709ad02002fe13fe11239393d2f2f1133113301 182f5de15d5d5d10dee112393911333311333331300101230101330903043ffe3c4cfe3e01c24c010cfecffecf013102e1fd1f02df02e4fd1e0200fe00fdfe00ffff001d00000417061f002600490000 0107004c02a20000002440180201af1d01501d011f1d010f1d011daf2f01402f010f2f015d5d5d115d5d5d5d3535ffff001d00000406061f0026004900000107004f02a200000022401701af1d01501d 011f1d010f1d011daf21014021010f21015d5d5d115d5d5d5d35000100cf04d903cd06170015003f40290017201702af17cf170230177017020f00010000000a300a02060a0a7f000100400609480000 108e05002fe1332f2b5d33012f5e5d332f5d5d5d713130010e0323222e0227331e0333323e023703cd06315d8d64678c582905aa051b324c352c4936220606174e7651292750775039492910132b4835 0001ffbcfe140164044a00130023401310152015020f470c03030c54140d0f0750001b003fe13f0110e6322f10e15d31301322262735161633323e0235113311140e0242303f171a36231b2e2313b622 486dfe140e0b940a0b0f27413304f4fb184d7b572f000001018704cd02790614000d0019400c05853f0601060c000c920500003fe5012f33dd5de13130013e033733150e03072301870912110e04b406 1f292e166004e71e4d51502114194e5656200001016ffe3b0275ff83000d001640090c00000585060c9205002fe5012fe1322f333130013e033733150e030723016f0b1a181304b2061f2c361d62fe56 194c54532114194d575621000001017d04d902830621000d0017400a0c000005850605920c00003fe5012fe1322f333130010e030723353e03373302830c1a181204b2051f2d371c620606194c545321 15184e565621000200250239027f05c7000b001d002a401906e10c1f4f1f7f1f021f40060a4800e11609e51bde03e511df003fe13fe1012fe12b5d10dee1313013141633323635342623220605140e02 23222e0235343e02333216b847514e4e4e4e514701c7234a734f4a704b262349714e959a0402a5a19fa7a59f9fa56caa753e3e75aa6c6ca9743cec000002000c024a028f05bc000a00150046402a0902 e10b070303175f178f17021740060a4815e1050104e5090f0b1f0b2f0b03080b0b020fe507dc02dd003f3fe112392f5e5d33e132012fe12b5d12392f3333e13231300123152335213501331133213534 36370e030707028f7d8ffe8901798d7dfef4030305141618099b030ac0c06f0243fdcdc32a63310b252a280ff0000001003b0237026605b60024004a40172122221e1d1d0b2014e105264f267f260226 40060a480bb8ffc040111218480b17e500001121e51edc11e508df003fe13fe112392fe1012f2b2b5d10dee13312392f33331133313001321e0215140623222627351e0333323635342623220e020727 1321152107363601423d6b4f2da6a13f792c1a3c3d3b18555f5f590d2527250e432101bafebe121439046d234465418c9d1c1a8d121b130a4c584d55040607022b01a87bd7030600000200250239027f 05d5001d002d00384020100a21e1002f4f2f7f2f022f40060a481529e10a24e4151919100fde1ee505df003fe13f33392f33e1012fe1322b5d10dee11239313001140e0223222e0235343e0237170e03 0733363633321e0205323635342623220e0215141e02027f2a4e6f44406e522f457eb26e2d4f7f60400f0b1b634a365a4024fedb44544d47273f2d19192d3d0366416f502d2d5880536eb38f6d276d1b 404f603b2b31254869f75c56525a1929371e2c49351d0001002f024a026405b600060038b90000fff0401f00000201e105084f087f08020840060a48d002e002f002030202e503dc00dd003f3fe1012f 5d2b5d10dee111392f383130130121352115018d0140fe620235febf024a02f17b64fcf8000300310239027105c70025003400440077402238e12142e1050a3d321c040521052105172ce10f464f467f 46024640060a4826e117b8ffc04027151848170a1c3d324b325b326b329b32ab3205321435b63dc63dd63d033d0029e514df35e500de003fe13fe111395d1112395d11123939012f2be12b5d10dee112 39392f2f12173910e110e1313001321e0215140e02071e0315140e0223222635343e02372e0335343e0203141633323635342e022727060613220615141e02173e033534260152345e462a1627341e22 3e301c2a4d693f8b96192a381f1b2e23132b485f624a484a4b162737210f414294383f12202d1a182c20134105c71b375438253e322811132d37452a395d422483732a45382b11142b353e253853371c fd683b46463b1e3027200f06224d01e837361b2a241d0d0c1c232c1c3637000200210239027b05c900250035003b40223111e0091c00374f377f37023740060a4829e11c2ce41117170526e521de0ce5 05df003fe13fe112392f33e1012fe12b5d10de1139e132313001140e022322262735161633323e0237230e0323222e0235343e0233321e0225220615141633323e0235342e02027b215aa28119401515 3619536c401d03090d24303d263c604424294b6c4341725430fecb44564a4c263f2d18152a3e044260bb935b08077d0d0a3557723d12241b1125476641426f512d2f6193ac5e584c581929331a24483b 240000160054fe8107c105ee0005000b00110017001b001f00230027002b002f00330037003b003f004300470053005f006f00780081009000e44059342c201c381857517a706f74676464827e6b7051 c051d05103516f6b6b6f51035d894f8c5f8c028c8c44282409175d504b604b024b4b413d31000c2a42463e2632868f8f6f796770707a607a6f544848706f806f02616f016fb8ffc04025070c486f6f60 5a4e4e8a781f602f603f606f60046060012c1c18120c393521070f01010701002f5e5d333333332f3333333312392f5d3333332f3311332f2b5d5d332f3311331112392f333311332f332f332f332f33 012f33333333332f5d332f33333333332f5d331217392f2f2f5d113333332f333311333311332f332f332f33313013112115231525352111233501113315331521353335331121352115213521150135 2115012311331123113301352115012311330135211533352115012311333523113301231133012226353436373216151406273236353426232206151416013332161514060715161615140623231333 3236353426232315153332363534262305351616333236351133111406232254012fc005ce01306df9006fc0050ec36dfd490111fbe1010efef2010e04b76d6d6d6dfbc20110fc306f6f02c001107701 11faa86f6f6f6f06fe6d6dfa997f87877f7f87877f483f3f48454242019fac6d702d2d38336d5ecf7b422e2429303b4a31252634010e10201425317d685f3d04be01306fc1c16ffed0c1f902012fc26d 6dc2fed16d6d6d6d06fe6f6ffaa8010e0202010ffa3b6d6d01a6010e044a6f6f6f6ffc2f011079010ffd680110fe8a9f8e919b019c918e9f68675e5e66665e5e6701ea4353314408040b443a51590162 2220221de39a2b25202afc66030524320192fe725e6400030054fec107aa061400030023002f0050402804232324202a302a402a032a2a4f24012424021c0b0b021515022323302d012d2d2727031910 100300192f33182f3311332f332f5d332f01192f33182f11332f3311332f5d332f5d11332f33313009030535343637363635342e0223220e020717363633321615140607060615150314163332363534 2623220603fe03acfc54fc5603eb214c634d315b83512b5a57522252447e383f3e2752454a1b47464447474446470614fc56fc5703a9fb2f2c3e3a4c8359456b4a27101b2314b2222e3a2f3144413579 503bfeed3e49493e40494900ffffffbcfe14025506210226023700000007014cfebb0000ffff001703c1015005b60206020700000002000affec04b2062b000c004f007540474d0d43103e003b084743 431a3b474f001001101051a051013f51013347001a101a201a031a2250293e4f4f4e004e002910293029402950290506294e294e380550480138501516003fe13fe11239392f2f5e5d113310e13210e1 012f5de15d5d11332f5d33e111392fe1113939111239393130012e0323220615141e02051616151402060623222e0235343e023534262322060727363633321e0215140e0215141e0233321211342627 2e0335343e0233321e02173315036a0d394d5b304c562e6aab013c02024081c4836f9256220a0b0a1f1f1836102525643632452c130a0b0a15304e3aa4a40202aef2964327517f5968a1754b128f03d1 6caa743d5848386952338a163a1f9ffeeec973375f7d45285d594b182d210f0a7f111a1c32442823565d612d2a4a361f01320130173e14024b789a514370522e549cdf8b8900000100000000044805c3 0022008f401baf24ef24022440090c4822ab21019821014021011b21010f210121b8fff040442121001f1b0d010f0d010d201216489f0daf0d027d0d016b0d015a0d014f0d012b0d3b0d020d0d1e5a77 1f871f971f034f1f01001f101f02071f1d001f21031f12110a04003fc13f3f123939012f5e5d5d5de1322f5d5d5d5d5d5d2b71711139332f385d5d5d5d5d332b5d3130013e03373e0333321617152626 23220e02070e05071123110133021d193d3f3c18162f354029232b110d200d0b1c2023130d283236363213bbfe42cb02db4ba8a0892c283d2714090891030507172a2318556e8085853cfde3022f0387 00020012ffec0660044a001c003c008f404719672f012f47d52c01b72c01a92c019a2c01032c2c033748ab12bb120212123e143e01543e643e843ea43eb43e05403e0102303e010f3e01224800031003 300340035003050603b8ffc04015121548031a002d2d271d0e08500b0f322750160016003f32e1323fe1323212392f1239012f2b5e5de15d5d5f5d5d7111332f5de111392f5f5d5d5d5de15d39313005 222635343e02372135372115231e0315140623222627230606030e0315141e0233323e0235353315141633323e0235342e02270229b6c312202b1afeeb8605c8f318261b0fc4b56a8b1f0b1f8bba1628 1f121d364b2d2e442c16b362522d4b361d0f19241514eaf3397d7e7b384a509a387b7e7d39f3ea575b5b5703c43676797a3a62834e2129486239b0b0828a214e83623a7a79763600ffff00c70000062f 077502260030000001070076017901540013400b01270526014b1a20090f25012b35002b3500ffff00ae0000068706210226005000000107007601c700000013400b013a1126017a2d33162b25012b35 002b3500ffff0000fdd504dd05bc0226002400000107025b011b0000000db70302011f15040725012b353500ffff005efdd5039c045e0226004400000107025b00bc0000000db70302143d330c222501 2b353500fffffed3ffec05c305cd0026003252000107025cfe400000003fb603022d03030235b8ffc0b2090f48b8ff21401a35350a0a250100b000018000017f00015000014000011f000100115d5d5d 5d5d5d35352b2b3535003f35350000020073fdd50237ff830013001f003a402814830f003f004f005f0004001a83300a010a1d8c00051005300540055005a005f005070605178c0f002fe1d45e5de101 2f5de1d45de1313001140e0223222e0235343e0233321e020734262322061514163332360237233d543132523b20203b523230543e23744031323f39383140feae3351381d1d384f33334f381d1d374f 34353c3c35353c3c00020093046802d905c7000d001f0042400915300e400e020e111ab8ffc0401c0910481a1a2b0d01040d140d020d06050c050c3f114f115f1103111d002fcc5d39392f2f012fcd5d 5d322f2b33cd5d393130013e033733150e0307232534363715060615141e0215140623222601b00b19181608cf1230383e1f52fee3787a3c391f251f322f3a4504891e4b4f512414204d505125784e73 1f4c162e181312101a1c25274600ffff001d000006b9061f0026004900000027004902a200000107004c054400000038402603028f39017039014039012f39010f39013901e01f01b01f011faf4b0170 4b01404b010f4b015d5d5d5d115d5d35115d5d5d5d5d3535ffff001d000006a8061f0026004900000027004902a200000107004f0544000000364025028f39017039014039012f39010f39013901e01f 01b01f011faf3d01703d01403d010f3d015d5d5d5d115d5d35115d5d5d5d5d350002007dffec0625061400200034004b402c1b061309205b01012b5b096736c03601bf36017036012f365f3602215b13 6635061b0e305f201804265f0e13003fe13fcee11239390110f6e15d5d5d5d10f6e1332fe111123939313001170e03071616151402060623222626023534123636333216173e033501141e0233323e02 35342e0223220e0206170e0c283f5a3f2b2d51a0ed9ba3ef9d4c4c9eefa49eec5129311908fbf2346ba57272a56b32326aa47272a66c340614163c70614c1859d87faafeebc66c6cc60117aaaa0115c4 6b6f660c354a5d34fcc989db99515199db898ada97515197da0000020071ffec04f404f20020002c004a402c174a19191e120a274800001000020700002e102e902ea02eb02e0421480a562d121e052a 50170f1024500516003fe13fc6e11239390110f6e15d11332f5e5de1123939332fe1313001140e0223222e0235343e02333216173e033533170e03071616051416333236353426232206042d437db26f 67ae7f47437cb36f64a93f2e341906c60f102d3f56392024fd00899a9a87899a9a87022789d5914c4c91d58988d3914b47440d374b5d33174a785e4314419e5ed1d3d3d1d0d0d000000100b8ffec064e 0614002400514032065b0808235a019f0e01b00e01af0e010e0e2670268026f026035f260100261026021b5a186425010d0d240619031e5f1313003fe13fce33332f330110f6e15d5d5d11332f5d5d71 33e1332fe1313001153e033533170e030711140e0223222e0235113311141633323e02371104dd343e200ac60f0f3255805b4285c98880c48544bbacb0598052280105b6c406324e6438164782694a0f fd9172c490524d8ec77a03aefc48b0bf3662885103b6000100a4ffec057904f20027005440331f4a21210117471a2727291029018029a029e029036f290100292029302903070f470c54281a26261f18 0d0f12500207160015003f3f33e13f33c6332f330110f6e15e5d5d5d7111332f33e132332fe131302127230e0323222e0235113311141633323e02351133153e033533170e03071103751b0a1945525c 305b8a5c2fb66a6f516e431db6343e200ac60f0f3255805b932b3f29142e62986902cdfd3d828234659460023a7b06324e65381747886d4807fcb0000001fc8f04d9fe190621000d0016400a00060880 0f005f000200002f5d1acc012fcd313001232e032735331e0317fe197923514d4010db102b2e301604d91c5358511b152350514c1d000001fd4804d9fed10621000d0016400a060005800f0c5f0c020c 002f5d1acd012fcd3130013e033733150e030723fd4815302e2b10db103f4d52227904f41d4c515023151b5158531c000001fc4604d9ff1405e3001b003840230f172f1702170009200902070916058f 0e401013480e40070b480e0e138f090f000100002f5d32e1332f2b2be133012f5e5dcc5d313001222e0223220607233e0333321e0233323637330e03fe42284f4c471f2d300e680521354a2e29514d45 1d2d2e0f680521354904db232b23353e3c614526232a23343e3c614526000001fd0404b8fe79068f001b002640120508080d0015050808120f191f1902198006002f1acc5d32391133012fcc32391133 313001140e02070723273e0335342e0223220607353636333216fe791b2d3c220a710e253c2a171524321d1c3410103229858505d3273a291b076fb006101821181820130703036c03055b000001fd31 fe98fe06ff7d000d000fb50887000b9103002fe5012fe1313005343633321615140e02232226fd313e2d2b3f111d27152d3ef63c37373c1d2b1c0e37ffff00c7000003be077302260028000001070043 ffb701520015b4010c052601b8ffc2b4120c010025012b35002b3500ffff00c9000005100773022601b2000001070043004201520015b40118052601b8ffa3b41e18000c25012b35002b3500ffff0071 ffec03e106210226004800000106004394000015b40228112602b8ffb9b42e28050f25012b35002b3500ffff00ae0000043b0621022601d2000001060043ca000015b4010c112601b8ffa3b4120c0a04 25012b35002b35000001007dffec075e05c90045007140481404395a25c536019636a6360289360136361d415b0c674700471047020047204750477047d047e04706072e5b1d664637373300295f0326 260722041420090e48143c335f111813003f33e132322b3f33331133e13212392f0110f6e15e5d7110f6e111392f5d5d5d33e13239313001220607273636333216161215140206062322262723060623 2226260235341236363332161707262623220e0215141e0233323637113311161633323e0235342e0205683c5e2a4c3b8f5177b77d403f81c6886faa49024ba86e88c6813f407db777518f3b4c295f3c 4571502b2e5c8a5c39762ebb2e763b5c8b5c2e2c507105252e209c2a2c63b8fef8a6aafedfd2773230303277d20121aaa60108b8632c2a9c202e468acf888de5a459242601bdfe43262459a4e58d88cf 8a4600010000000005f4044a002c00e74009651001c922f9220221b8fff0b30a10482cb8fff0b3121b482cb8fff040190a0f4800100a1b48260d220e2122152c0006560f660f020f0eb8fff040481f0e 016f0e7f0e9f0edf0e04590e014f0e017415016b1501241534150224063406440674069406050e0615150e0603011b47001c101c02071c1c2e102e202e302ed02ee02e050201b8fff0401e012640151d 4826200c1448260d10031b0e010f1506260636060206220015003f32325d11333f333317392b2b012f38335d11332f5e5de11217393d2f2f182f5d5d5d5d5d5d5d7138335d113333113333111239392b 2b2b2b5d31305d21013313161617333e0337130333131e0317333e033533140202060723032626350e0307030177fe89bce01c26090707151a1d0f77a2bcc90c1f1e1805075a724119b7255c9a75c077 0c0d0106090a0498044afd56579d33163a414520010c01cffdb02163675c1967d0e2ff98a3fedffef5fc7f015420350301131b1d0afeaa0000020014000004bc061400160021009b400a1300175a0c15 1506100cb8ffc0400d1a2748200c0102900ca00c020cb8ffc0b31318480cb8ffc040400b0e480c0c0e1b5b0667230023302350236023802305e023019f23015023010e215f00160d5f101310b0000189 00014f00010f10010700100010110017600c12003fe13f39392f2f5e5d5d5d5d113310e13210e1012f5d5d5d7110f6e111392f2b2b5d5f712b3312392f10e1323231300133321e0215140e0223211121 35211133112115211133323635342e022323020a9698cf7e373c7ec286fe96fec4013cba0179fe87a0aea42e5b8b5d81034e42719857619e703d0460a40110fef0a4fc40848846613c1b000200140000 046d052700140021008140091302164710000c010cb8ffc040470d1a480c000c000e1c47065723002310230270239023c023e023040e155002010d501013100f021f020202400c1e480f10010f101f10 0207021002107f11013011011116500c15003fe12f5d5d39392f2f5e5d712b5d113310e13210e1012f5d7110f6e11239392f2f2b5d33e13232313001211121321615140e022321112335333533152101 1121323e0235342e022302e3fed50115d3cd2f659f71fe39eeeeb6012bfed50104375e43262141604003b0fed79c9b4d7c582f03b09addddfda4fea81129423031422811000100c7ffec06ec05cb002d 0058402f08055b1b220711110722031e2a2a2f211d5a1e642e2b005f27041b081c5f22050f21010821211f031e120d5f101613003f33e13f3f392f5e5d3333e132323fe1330110f6e13211337d2f1217 39182f2f2f33e132313001220e02072115211e0333323637150e03232226260227211123113311213e0333321617072626056d5fa0784d0d0274fd86054075ac7159a04e274e56613a9eeb9d5205feb0 baba01560e63a7e9956cc44f4e3f950527417aaf6fa282c98a482317a20f170e0764b801039ffd5605b6fd988feba75c2c2a9c202e00000100aeffec0571045e002900644039201d48054f0c010c1f0c 1f082714142b0b074708542a1a51151110200506501d0ca90bb90b020f0b1f0b2f0b03060b0b090f08152351260016003f32e13f3f392f5e5d5d3333e132323f33e10110f6e13211337d2f3312393918 2f2f5d33e132313005222e0227211123113311213e0333321617072e0323220607211521161633323637150606045461a9814f07fef1b6b601130c5581a55e4e95323617383c3b198c910e01dbfe2309 928a528236357c143a7bc187fe17044afe3980b5723422199a0a130f0997a69ab8a42519a21d1e00000200000000052f05b6000b001800ae4049080601d806e80602070701d707e70702a607019b0101 7700a700020d0a090c03040706131308a70001000101050900080100081008200870088008c00806081008081a901aa01a021ab8ffc0400f1518488f1a01401a010f1a01080405b8fff04013050b035f 13100a0e48130c0c06040009120603003f3f333312392f392be132012f38335e5d5d5d2b5d11332f385d713312392f335d11393d2f33331239391239395d5d5d5d715d71313021231123012301330123 01232721272e03270e030702eca67ffefec50239bb023bc7fefe7ae8012335121c161107091115191102aafd5605b6fa4a02aaa48f304c434125254143492d000002000a0000045a044a000b001700cf 40383902590279028902041b022b0202b505019605a60502870501090319030206081608020912191202061116110207120302110809b6000100b8fff8401b0a0f48b90b010b080a0f48000bb40c010c 0c050506060a01100201b8ffc0b312154801b8ffc04018070b48010119c019e01902af19015019010f191f1902090ab8fff0400f0a0408500c0b1111010b0f0a060115003f33333f12392f1239e13201 2f38335d5d5d5d11332f2b2b333812392f3312393d2f5d33332b5d2b5d1239391239395e5d5d5d5d5d5d5d31305d5d010123032311231123032301170e0307332e032702a601b4bcbb60a260babd01b4 71051b23250df00e25231b04044afbb601e9fe1701e9fe17044a791955605e22225f60541900000200c70000072905b60013002000bf401b9b01017700a700020d060e0515121114031b04040500010f 0e1b05b8fff0405d800101cb1b01841b012b1b7b1b020f051f052f057f05cf05df05ff05070805011b1b010503111010001010107010b010f0100510102230225022c022d022e022050c085a09642113 06035f0d1b200910481b14140e09040111120a0e03003f333f33333312392f392b33e132320110f6e1325d11332f5d383317393d2f182f2f5e5d5d5d5d5d381133331133113311123939113939111239 395d5d313021231123012301211123113311211333012301232721272e03270e030704e7a581fefdc40108fe7fbaba01c1f1bb023bc7fefe79e9012335131c151108081115191102aafd5602aafd5605 b6fd980268fa4a02aaa48f304c434125254143492d00000200ae00000608044a0013001f00eb4031a505018605960502770501060916090219022902490269027902050b02011a030219081409120b13 0a110d470ec6000100b8fff840170a0f48c9130113080a0f480013c414011414050506090ab8fff040132f0a3f0aaf0a030a060a06010e542002011001b8ffc0b312154801b8ffc0402c070b48010121 d02101bf2101602170219021034f2101002101080b0408501214131919020f130f0e09060215003f3333333f3312392f123933e13232015e5d5d5d5d5d11332f2b2b383310e61139392f2f5d38331133 12393d2f5d33332b5d2b5d10e13211123939111239391139395d5d5d5d5d5d31300101230323112311230323132111231133112113170e0307332e0327045401b4bcbb60a260babdc3fee9b6b60154b5 70051b23250df00e25231b04044afbb601e9fe1701e9fe1701e9fe17044afe3901c7791954605f22225f60541900000200140000056a05b60023002600c04011862201861a0159128912022510090c48 26b8fff0402c090c48250a0b0624241a5a1b2607000a100a200a030a1b07071b0a0300121011201102d01101801190110211b8ffc0403b070a481111281f2801f02801cf28df2802402850287028030f 283f2802072300191c61240b4f06010f06af0602080606000a07265f08031b120012003f32323fe1323212392f5e5d713333e132012f335e5d5d5d5d7111332f2b5d5d71331217392f2f2f5d113310e1 393d2f333311332b2b5d5d31305d33133e033701352115011e03171323032e03232311231123220e020703010121147b1836547c5ffe900449fe8561805637187abe7b1426364f3d18bb183d4f362614 7b01eb014afd6f01c55588623a0601e78b8bfe190638628956fe3b01c1485f3917fd4802b817395f48fe3f035a01b8000002000a000004e5044a0023002600c7400d761a861a961a032510070c4826b8 fff04018070c480912010623010b0624241a461b250a2607a71b010ab8ffc040101619480a1b07071b0a03001220110111b8ffc0b312154811b8ffc0403f070b48111128102801cf28df280260289028 021f284f280223000a07265008191c52162426243624a62404240b0f061f064f065f0604070606080f1b120015003f32323f392f5e5d33335de13210e13232012f335d5d5d7111332f2b2b7133121739 2f2f2f2b5d1133113310e1393d2f33335d5d2b2b5d313033133e033701352115011e03171323032e03232311231123220e0207030113210a7b162c426753fece03cffec95368432c177bba7b14243044 3504a60435463025147a01b4fcfe0a01543d654d310901646969fe9c08314c673dfeac015036482b11fdf6020a112b4836feb00283012d00000200c70000078905b60028002b00ca4015861f01591789 1702100b29291f5a202a10090c482bb8fff04033090c482a0f2b0c000f100f200f03070f0c20200c0f031628b000c000020f001f000200000717001610160270168016c0160316b8ffc04034070a4816 162de02d019f2dbf2d02402d012f2d010a065a07642c0f0c2b5f0d1e05216129100f0b01080b0b080d03071720030012003f17323f33392f5e5d3333e1323210e132320110f6e1325d5d5d5d11332f2b 5d713312392f5d5d331217392f2f2f5e5d113311332b2b10e1393d2f33335d5d313021133636372111231133112101352115011e03171323032e03232311231123220e02070301012102337b13291cfe 7bbaba02a4fe95044afe8561805537187bbe7b1426364f3d19ba193c4f3626147b01eb014afd6f01c544732efd5605b6fd9801dd8b8bfe190638628956fe3b01c1485f3917fd4802b817395f48fe3f03 5a01b800000200ae00000698044a0028002b00cf400d761f861f961f032a10070c482bb8fff0402c070c48091701100b29291f46202a0f2b0ca720010f200c0c200f03161f002f0002ff000100000717 20160116b8ffc0b312154816b8ffc0403f070b4816162dcf2d01b02d019f2d01602d014f2d01002d302d020a064707542c0f0c2b500d1e052152a6290129100f0b1f0b02070b0b080d0f071720030015 003f17323f33392f5e5d33335de1323210e132320110f6e1325d5d5d5d5d5d11332f2b2b713312392f5d711217392f2f2f5d1133113310e1393d2f33335d2b2b5d313021133636372111231133112101 352115011e03171323032e03232311231123220e02070301132101bc7b101d13feedb6b6020bfed503cefec95368432d177bbb7b142430443504a60435453124147b01b4fcfe0a01542a4b20fe17044a fe39015e6969fe9c08314c673dfeac015036482b11fdf6020a112b4836feb00283012d0000010039fe4603ec06d50076009f40272118090e48596259514d4d47513b5b676c5167443567145114675135 4405242e5b726778055a24b8ffc04036141848245d524d8f569f56af56035640070b485656476c34604f35010f35af3502083535294351620340614703150a5f1ffb29600013003fe13fe1333fe11733 12392f5e5d71e13911332f2b5d33e1012f2be110f6e11217393d2f182f2f2f2f11123910e11133332f1133332f3130002b05220e0215141e0233323e0233321e0217152e0323220e0223222e0235343e 0233323e0235342e0223233533323e0235342e0223220607273636372e032735331616173e033332161715262623220e02071e0315140e0207151e0315140e0201e1475a34140e243d2f41615351322b 4231230c081f364d3531474a5c4668884f2031669d6c5980512639679158bfb05c8e613225445f3a6ea94b5c3ba6671837363214793361361a3b434b2a1f2f0e0b22111630302e14527e552b335b7d4b 578a5e324383c4141220291816241a0e040404070a0f07b60712100c030302294860373c6246262648694447653f1d972748643e36533a1e43367d304b111e413f3a171b226138244638230905770507 172938210d3f5c76454a7758390c060b3959774860a0744000010017fe7303520552007000b740714018090e486868626c030c036c584611166c11e05f015f5211336c33116c525f05434d471c5772c0 72d072e072037f72013072010f720107264643400c1148431616515089529952020f5201085252624868075200401014480040070c48005e6c00035b500c6210342b503efb48502116003fe13fe1333f 33e117332f2b2be1331112392f5e5d5de1393d2f01182f2be15e5d5d5d5d10f6e11217393d2f182f2f2f2f5d11123910e11133332f1133332f3130002b0132161715262623220e02071e0315140e0207 151e0315140e0223220e0215141e0233323e0233321617152e0323220e0223222e0235343e0233323e0235342623233533323e0235342623220607273636372e032735331616173e0302cf1f2f0e0b21 11152e2e2d1337593f231c33462b2c523f26356ca6714b592f0f0e223a2c32635d532142470d0922282c132055646f39587040182256906e37644c2c858a81613d644827736c47814b3f396b41173130 2c12793362361a3a434b055209057705071526331f0e31455835324d3b290e0b0e2c425b3d447456310e1a26171623180d0304031613970a0f0a060303032e4756292f59462a132b45335e5b99122740 2d4d4d2622931c22081c3b3732151b22613824463823ffff0068000005ba05b6020601750000ffff00a4fe14057106120206019500000003007dffec057105cd0013001e0029004f403225195b00672b d02b01cf2b01802b013f2b6f2b02241a5b0a662a1a604f24010f24af24df2403082424141f5f0f04145f0513003fe13fe112392f5e5d71e10110f6e1325d5d5d5d10f6e1323130011402060623222626 023534123636333216161201323e0237211e0313220e0207212e03057151a0ed9ba3ef9d4c4c9eefa49aeca051fd876a9e6b3906fc9a063a6b9e6d699c6c3d080364083b699b02ddaafeebc66c6cc601 17aaaa0115c46b6bc5feebfd074786c27a7ac28647049a4380b87575b880430000030071ffec042d045e0013001a0021004f40331f17480057234023d023e023030f23011e18480a56221850ef1e01a9 1eb91e020f1e1f1e2f1e03061e1e141b500f1014500516003fe13fe112392f5e5d5d5de10110f6e1325d5d10f6e132313001140e0223222e0235343e0233321e02013236372116161322060721262604 2d437db26f67ae7f47437cb36f67ae7f47fe238d880afdbe098c8c89880e023e0d8a022789d5914c4c91d58988d3914b4b91d3fdd4b2b2b2b20344a2a4a4a200000100000000050205c3001c005a4029 07060b0d01fb0d010d0d089019d0190219191e001e01b01e010f1e1f1e2f1e4f1e5f1e7f1e06070908b8fff0400c08006016040908030d060712003f33333f333fe1012f38335e5d5d7111332f5d1239 3d2f5d713333313001220e02070123013301161617363637133e0333321617152626049624352a2412fed7cdfe19c501271d2e110e2a1a8d1f3d4c674b23441a1735052d25486742fbe905b6fc615baf 4f4ebc610200719c622b0d0897090d00000100000000040e0452001f006db9001efff840160a0e481f080a0e481f1e07200d1148070700e0160116b8ffe0401a070a48161621bf21cf21ef2103502101 0f212f214f2103070100b8fff0400c001e071f151a4f130f01000f003f323fe13f3333012f38335e5d5d5d11332f2b5d12393d2f2b33332b2b31301133131e0317333e0337133e033332161715262623 2206070323bcc90b201f1a0506041418190956193543583c1a22110b26122f3a18e0f3044afda2216a6e6119195f6c672101405e75421805058703055058fcdfffff0000000005020773022602800000 0107037604b801520019b602011d05260201b8ff82b4311d081925012b3535002b353500ffff00000000040e062102260281000001070376045000000019b602012011260201b8ff94b4342000162501 2b3535002b3535000003007dfe14095a05cd00130027004a00a1400a005b1e384a2f2f372928b8fff040232828400040104002f040011f402f403f4003001e011e401e400a363710d037e0370237b8ff c04034070b4837374c0f4c010f4c1f4c2f4c4f4c7f4cbf4cdf4cef4c0807145b0a664b382f4a4a2844503d1b36280f235f0f04195f0513003fe13fe13f333fe111391133330110f6e15e5d7111332f2b 5d38c11239392f2f5d5d5d7111332f38c112393d2f333310e13130011402060623222626023534123636333216161205141e0233323e0235342e0223220e022533131e0317333e03371333010e032322 262735161633323e023737051f4c96dd9198e093474793e19990dd954cfc232f6196676796602e2e6094676897612f0443bdd70d1d1913040604171b1d0bc7bcfe4e1d40567450344c1b154023304634 250f3902ddaafeebc66c6cc60117aaaa0115c46b6bc5feebab89db99515199db898ada97515197dae3fd9b28585853221956615e210263fb2751815a310b06910507172c4029a000ffff0071fe14084e 045e0026005200000107005c046f00000011b10202b80414b4202f0a0025012b350035000002007dff8305c30631001f003f00524033305b006741b441c44102904101023041804102205b1066401918 010b180104081408020738353b5f1b18150328255f08050b12003f3333e1323f3333e132325e5d5d5d0110f6e15d5f5d5d10f6e1313001140e02070606232226272e0335343e02373636333216171e03 05141e02173636333216173e0335342e02270606232226270e0305c34989c57c0e4a373b480d81c787454587c7810d483b374a0e7bc5894afb7f2d577f531143353145115280572d2d57805210463135 4311537f572d02dd95fcc07d173f36363f167dc0fe9696fbbf7b173f31333d177dbffb9674c09262153026282e156292c07473bf92621632292930166191bf0000020071ff9104a804b6001f00370054 b52c4800573939b8ffc0b30e144839b8ffc04024090c4820481056381918010b1801040814080207322f35501b02150f2926235008050b16003f3333e132323f3333e132325e5d5d5d0110f6e12b2b10 f6e1313001140e02070606232226272e0335343e02373636333216171e0305141617363633321617363635342627060623222627060604a8396b995f093c383a3b085d996e3d396c9a62083b3a373d09 5b986d3cfc856f7b0b393432390c796d6e780c393234390b7b6f022776bf8e5a12392e2d38125a8ec07775bf8d5a1239292a3a125b8dbc75accd1f2c20202a1fccaba9c8202b20202d1fc8000003007d ffec0735083d0045005b006d00da40923714240414041424031c415b0c676f006f106f02006f206f506f806f906fa06fd06fe06f082d5b1c666e636847475c68514052505260520352525f0068106820 6880689068050768e04d014dbf56cf56025652ef46014647474f52015252606bc06bd06be06b046b6f5f7f5faf5fef5f04105f015f323c5f11147f378f37023740070a48373717111325030328005f21 0704003f33e1323311333f33332f2b5d3310e1322f5d5dcc5d322f713310cd5d10dd5dcd5d012f5e5d33332f5dcd10cd322f113910f6e15d7110f6e11217393d2f182f2f113331300122060727363633 321616121514020606232226270606232226260235341236363332161707262623220e0215141e0233323e02371e0333323e0235342e02031523222e0223220615152335343633321e02330514060735 363635342e02353436333216053f3c5e2a4c3b8f5177b77d403f81c68867a24547a06788c6813f407db777518f3b4c295f3c4571502b2e5c8a5c2a564e421717424e562a5c8b5c2e2c5071031056907a 642a2e3a857c6d3a7077854efeef78793c381f241f322e3b4405252e209c2a2c63b8fef8a6aafedfd2772a2c2c2a77d20121aaa60108b8632c2a9c202e468acf888de5a45913232f1c1c2f231359a4e5 8d88cf8a4602a681242a242d3510236b65242a24e24d731f4c162d191312101a1c25264600030071ffec05df070800430059006c00b2406b606745455a674f405050500250505d6f679f670210670167 24150b353f03030b2c483f576e1e480b566d004b014bdf540154500f44014445456f50015050006a01e06af06a026a0f5d7f5d02075d2f1b513416163a1010212951000324401015482440070c482424 060016003f32322f2b2b3310e1323f33331133e1322f5e5dcc5d71322f713310cd7110dd5dcd710110f6e110f6e112393d2f1239123933182f5d5d33332f5dcd10cd322f113931300522262706062322 2e0235343e0233321e0217072e03232206151416333236371e0333323635342623220e0207273e0333321e0215140e02131523222e0223220615152335343633321e023305140607353635342e043534 363332160410516d2b2b6a505fa97f4a3f6d93541f403c34143f11292b2b1270698d884973291631394229858c6970122b2b29114014353c3f2054936d3f4a7ea93a1056907a642a2e3a867c6e397078 854efeef7879740f151a150f322e3b4414232020233f89d5969ddb893e0910160c9a0a130f09cad3d3c33420101e180ec3d3d3ca090f130a9a0c1610093e89db9d96d5893f06aa82242b242e3411236c 65242a24e24d731f4c29330d0f0c0a0f1712262646000002007dffec075e0704000d0053009b40622312475a33c544019644a6440289440144442b4f5b1a000d000d2b1a675500551055020055205550 557055d055e05506073c5b2b66544545410e375f30113409040400800a063f027f02cf02df02ef020502341530044a2320090e4823415f1f2613003f33e1322b323f33332f5d33331acd392f33113310 e13212392f0110f6e15e5d7110e61139392f2f10e111392f5d5d5d33e1323931300115072327230723272307232735012206072736363332161612151402060623222627230606232226260235341236 363332161707262623220e0215141e0233323637113311161633323e0235342e02058b522232b8312331b8322250031c3c5e2a4c3b8f5177b77d403f81c6886faa49024ba86e88c6813f407db777518f 3b4c295f3c4571502b2e5c8a5c39762ebb2e763b5c8b5c2e2c507107041bac67676767ac1bfe212e209c2a2c63b8fef8a6aafedfd2773230303277d20121aaa60108b8632c2a9c202e468acf888de5a4 59242601bdfe43262459a4e58d88cf8a460000020000000005f405a4000d003a0123400d000d000d2a0fb930018230012fb8fff0b30a10483ab8fff0b3131b483ab8fff040190a0f48a90e010e10131b 480e100a0f48301b1c34661d011d1cb8fff040530f1c1f1c3f1c034f1c6f1c7f1c9f1cbf1c051c1c34302f239023017423016b230124233423023a0e1490340124143414441474149414052334141434 23030f2947002a102a02072a2a3c103c203c303c03100fb8fff040350f09040400800a060f027f028f029f02040240141748023440151d4834200c14481b341e030e291c0f0f2314261436140214300e 15003f33335d11333f33331217392b2b2f2b5d33331acd392f33012f38335d11332f5e5de11217393d2f2f2f5d5d1133335d5d5d5d1133331133182f5d7138335d87c0c0012b2b5d2b2b2b5d5d111239 392f2f3130011507232723072327230723273503013313161617333e0337130333131e0317333e033533140202060723032626350e03070304ba522232b8312331b831235004fe89bce01c2609070715 1a1d0f77a2bcc90c1f1e1805075a724119b7255c9a75c0770c0d0106090a049805a41bac67676767ac1bfa5c044afd56579d33163a414520010c01cffdb02163675c1967d0e2ff98a3fedffef5fc7f01 5420350301131b1d0afeaa000001007dfe14049805cb002300544017115a0f10010710400f1248101018ba2001602070200220b8ffc0401a060a48202025af2501055b18662421005f1d040f0a5f1313 101b003f3fe1333fe1330110f6e15d11332f2b5d5d12392f2b5e5de1313001220e0215141e0233323e0237112311232226260235341236363332161707262603196bae7b433b76b0761d2d282515bb10 a4f09d4c57a9faa26cc44f4e3f9405275198da898ddb964e04090d09fd6201d86cc60115aaa60114c66e2c2a9c202e0000010071fe14036f045e001f003e40251d471c400e11481c1c040c215f217f21 0210210115480456201b18511f161c1b12510d0910003f33e13f3fe1330110f6e15d5d10ce11392f2be13130042e0235343e0233321617072e03232206151416333236371123112301edb0824a4c85b2 664e95323617383c3b199d9091943e6823b712143f89d5969ddb893e22199a0a130f09cad3d3c31b14fd5a01d80000010068fffa0479050a0013012540670d111d11020d011d0102020b120b02020712 07020710110c13120b000108030207040f040d110c0a120b090108060207050e050d10110c110a13120b120900010801060302070204050c0b02010e0f4f0101400b01050b010f0f010b050412601170 11f0110311b8ffc0404d070a4811080711152015301502030600090407010102130a100d040b1111120407010707080b0b010b0b0cb00cc00c020f121f120200081008020212080c0c08120204040f0e 40070d480e0504002f332f2b331217392f2f2f2f5d5d5d11332f7111332f7111332f12173911332f121739015d11332f322f2b5d3317392f2f2f2f5d5d11331133113311331087c0c01087c0c01087c0 c01087c0c0108708c008c008c008c0108708c008c008c008c03130005e5d5d5d5d0105072503271325370513253705131703050725024c011c47fee3b481b4fee546011fc6fee447011db67fb6011f4a fee501b0a67ba4fec74a013ba47ba4015aa47da4013949fec4a47ba4000100c9048f03b005b800150042b50f20070a4803b8ffe0401e070a480c121217000006100620069006a00605070606160f0f0b 00030300002f322f10cd322f1101332f5e5d3311332f33002b2b313001060623222635343e023321363633321615140623018b062c3038280917251d01c1052d30382a2b3904ee2c3333381c2516092d 313236392900000100f404e503df05d90015004240118008900802080817001410142014030714b8ffc040120d1048141416151414090e40bf0501058009002f1add5d1acd11332fcd1101332f2b5e5d 11332f5d313001323e0233321615152335342623220e0223233501024e8577703a6d7c853a2e2a65799155100566242b24656c2311342e242b248100000101e104d702d306350011002040120b0e3f06 4f060206003f034f035f0303030f002fcc5d012fcd5d3239313001343633321615140e021514161715262601e1443b2f321f251f393c7a7805b6394626261b1a111113192e154c1f7300000101e104d7 02d30635001300204012073f004f000200030e3f114f115f11031103002fcc5d012f33cd5d3931300114060735363635342e0435343633321602d3787a3c390f151a150f322e3b4405b64d731f4c152e 190d0f0c0a0f17122626460000080029fec107c1059100130027003b004f00630077008b009f0000012e0323220e020723363633321e0217032e0323220e020723363633321e0217012e0323220e0207 23363633321e0217212e0323220e020723363633321e0217012e0323220e020723363633321e0217212e0323220e020723363633321e0217012e0323220e020723363633321e0217212e0323220e0207 23363633321e0217046f0318242e191e2f2114034b056467314d361e034f0318242e191e2f2114034b056467314d361e0301f40317242e191f2f2113034c056567314d361e03fb2f0317242e191f2f21 13034c056567314d361e0304310317242e191f2f2113034c056567314d361e03fb2f0317242e191f2f2113034c056567314d361e0304f00318242d191f2f2114034b056468314c361f03f9be0317242e 191f2f2113034c056567314d361e0304cf1c2313060512231e5a681c33482bf9f21c2313060512231e59691d33472b01161c2313060512231e5a691d33482b1c2313060512231e5a691d33482b03db1c 2313060512231e5a691d33482b1c2313060512231e5a691d33482bfe191c2313060512231e5a681d33472b1c2313060512231e5a681d33472b0000080029fe7f077d05d3000c0019002600330040004d 005a0067000005170e0307233e033703273e0337330e030701371e0317152e032705072e0327351e031701373e0337170e030701070e0307273e033703272e0327371e031701171e0317072e03270437 0b0a1c202312610a151210053b0b0a1c202312610a1512100502230e26555757272a5d5b5725fb680e27555756272a5d5b572503a602225054562845254f4e491efcea02234f54562845254f4e491e2b 11142927240f431733343217036a11142827250f431734343216230e27555756272a5d5b572504980e26555757272a5d5b5725fe160b0a1c202312610a151210053b0b0a1c202312610a1512100501aa 10142927250f441733343216fc9510142927250f44173334321602de02225054552846254f4e491efce902234f54552846254f4e491e000200c9fe7f05d30768001b003100b340481c1c302601d02601 af26cf2602202630268026032626170a191a1a181b1507005a176533d03301af3301203330330213080c5a096432269f1c011c400609481c1c2c8e21051afb13b8ffe8b314184813b8ffe040260a1348 061316132613030913175f0012061814184806200a1348090619062906030706160a03003f33335e5d2b2b3fe133335d2b2b3f3fe1332f2b5d330110f6e132325d5d5d10f4e132323333392f33111239 2f5d5d5d71332f313021113436373637230123113311140e020706073301331133032313030e0323222e0227331e0333323e023704640504040608fd31d7ae0103030104030702ccd5c38fdaa69d0631 5d8d64678c582a04aa041c324c352b493722060319388f414c4dfb4605b6fce01a3e43441f4a4c04b4faf0fdd9018107684d775029274f775039482910122c473500000200aefe8304f20617000f0025 0096403a1010041a341a841a03071a1a0b050d0e0e0f0c0910091848090200460b5527a427c427d427f42704802701020027102720275027602770270603b8fff04025091848030807460454261a7f10 0110400609481010208e15110efb0902050f0b6008040015003f3232e13f33333f3fe1332f2b5d330110f6e132322b5d5f5d5d10f4e132322b3333392f331112392f5e5d332f31302111130123113311 0701331133032313030e0323222e0227331e0333323e0237038f0bfdfeeaac0c0204e9b77bb67a4706315d8d64678c582a04aa041c324c352b493722060287010ffc6a044afd64fc0398fc50fde9017d 06174e7651292750775039492910122c48350002002f0000043305b6001600210052402c1300175a0c151506100c0c0e1b5b0667230e215f00160d5f1013108900010f10010700100010110317600c12 003fe13f39392f2f5e5d5d113310e13210e1012f10f6e111392f3312392f10e1323231300133321e0215140e022321112335333533152115211133323635342e02232301819698cf7e373c7ec286fe96 9898ba013bfec5a0aea42e5b8b5d81034e42719857619e703d0460a4b2b2a4fc40848846613c1b0000020012000004190614001400210061403b01010e1c470857236f23bf23df23ff23040300164712 110e5422155004030f5012001204400724480f12010f121f12020704120412130016500e15003fe13f39392f2f5e5d712b113310e13210e10110f6c433e132325d10f6e112392f313001211521112132 1615140e022321112335333533111121323e0235342e022301640117fee90115d3cd2f659f71fe399c9cb60104375e432621416040052189fdef9c9b4d7c582f049889f3fbdafea81129423031422811 000200c70000043305b6001300220088404f1b051a061a180819070706190619060c1e5b28003800480003006724cf24014024010f240106140c5a0d642319181baf1a011a1a142206b0070107070c05 081460300b400b020b0b0c22600e030c12003f3fe111392f5de1393912392f5d331112392f5d3939330110f6e1325e5d5d5d10f65de11239392f2f1133111239393211123939313001140e0207170727 06232311231121321e020133323637273717363635342623230433162f4b366e6a815d7c96ba016a86c27e3cfd4e8126441f5c6d703334a4aea0040a3a6f6456209b4eb61bfdc705b6396da0fe670505 854ca02473578e89000200aefe14043f045e002300390072404034353233332a201e1f1f3748212a1b573b303b012a100c470d543a3335322f0f341f346f34cf34040734342f24501016100e0f1f2020 000c1b211e2f50060016003f32e139393f12392f333f3f33e111392f5e5d123939330110f6e132325d10f61139e1392f393311392f393933313005222e02272316171616151123113317333e0333321e 0215140607170727060603220e020715141e023332363727371736353426029e3b604d3c160c03030204b6941a08163b4d603c5e996e3c5a526d6a751f41464c69411f021b416c5111210f6a6d6e547f 14192c3a20221f1a3710fe2b063694223e2d1b488fd48caff2449a4ea6090b03db2e5e8d5e29659d6b370305984c9e6aeed0ce000001002f000003be05b6000d008940151f052f05020505080f001f00 029000a000e0000300b8ffc0401e070a4800000f1f0f3f0f9f0fbf0f0403075a0c000a01060a8008c0080208b8ffc04026060a480806095f030f0c2f0c3f0c4f0c040f0c3f0caf0cdf0cff0c05080c0c 07025f0d030712003f3fe112392f5e5d7133e132012f2b5dc65e5d33e1325d11332f2b5d7112392f5d3130011521112115211123112335331103befdc30150feb0ba989805b6a6fe15a2fd7d0283a202 9100000100120000030a044a000d006e401d0b0b00200630060206060f700fa00fc00f03090d4704df02ef02020200b8ffc0b312154800b8ffc04021060b48000c014f094f045f04020440171c480b04 1b0402070404000850050f0015003f3fe112392f5e5d2b5d33e132012f2b2bc65d33e1325d11332f5d12392f31303311233533112115211121152111ae9c9c025cfe5a0117fee901e18901e09afeba89 fe1f000100c7fe00049805b600260066404109150107070705225b1228c028017f288f280210284028021c1c0a045a0564271d205f171c00600f0d2f0d3f0d030f0d3f0ddf0dff0d04080d0d05095f06 030512003f3fe112392f5e5d71e13fe1330110f6f132c02f5d5d5d10dee112392f3130005e5d0122060711231121152111363633321e0215140e0223222e0227351616332011342e0201fc253c1aba02 f7fdc31d472d9af0a5575292c976314e443d1f3f7f480177437bae02830505fd8705b6a6fe0b05035cabf297aaf8a24f060c130ca2171801ef79b97e4000000100aefe0a03c5044a0023005c40390922 19222922031414120a481f250f251f25025f257f25ff2503030317114712542404000d510b1a1b1a02071a1a121650130f12150751001b003fe13f3fe112392f5e5de911330110f6e132392f5d7110de e112392f3130005d012226273516163332363534262322060711231121152111363633321e0215140e0202294b6a2e2b6a427675909d1a3e1fb6025cfe5a1d3b1f66b3854c406f96fe0a1f1da11825c3 d2d4ca0a08fe35044a9afec305053e8adb9d96d5884000010004fe7f06cb05b6001500e24057114014184811200913480a111a1102004014184800200913480a001a000207100d0d025a070a0aa803b8 03029903018d0301570367037703030303031206000e0f100f400c18480f110f155a04120174128412c4120312b8ffc04027070a48121217041701f01701e41701a01701022017301760177017901705 0f1701080908050806b8fff0401306061613fb0d0a0a000f080b03115f05030012003f3232e13f3333123911333f1101332f38333311335e5d5d5f5d5d5d7111332f2b5d71e133332f2b383332111239 2f5f5d5d5d5d331133e13211335e5d2b2b5d2b2b31302101112311012301013301113311013301013311231105aefdeeb3fdeed30221fdedcd020ab3020acdfded01a8c3b002e5fd1b02e5fd1b02f202 c4fd3c02c4fd3c02c4fd3cfdb4fdd901810000010004fe830604044a00150111406c2710371002290e390e022609360902270a370a02270437040227043704022701370102114014184811200913480a 111a1102004014184800200913480a001a0002100d0d0246070a0acd0301b90301a903019603018703010303031206000e0f100f400a18480f110f154612b8ffc0b312154812b8ffc04017070b481212 17101701001701e417f41702b417c4170217b8ffc040130d1148301701022017010f1701070908050806b8fff0401306061613fb0d0a0a000f080b0f116005030015003f3232e13f3333123911333f11 01332f38333311335e5d5d5f5d2b5d5d717111332f2b2be133332f2b3833321112392f5f5d5d5d5d5d331133e13211335d2b2b5d2b2b3130005d5d015d5d5d5d5d210111231101230101330111331101 3301013311231104f0fe43a4fe44cf01cffe58c5019fa401a0c5fe58014fc5ae022dfdd3022dfdd302350215fdeb0215fdeb0215fdebfe65fde9017dffff0048fe4203ec05cb022601b100000107037f 014800000011b10101b8ffffb44842130b25012b35003500ffff0044fe420352045e022601d100000107037f00f200000011b10101b8fff8b44842292125012b35003500000100c7fe7f04ec05b60010 00a640590540141848bd05cd05dd050305200910481a052a05020040141848bd00cd00dd000300200910481a002a0002061010080e0f107f0f9f0f02000f300f400f03060f0f05045a00000110010207 010112b012010c085a0964110cb8fff040160b104806100b10480c06090f0a03005f0505091202fb003f3f332fe13f331239392b2b0110f6e1325d11332f5e5d33e132332f5e5d5d3833123911335d2b 5d2b5d2b5d2b313025331123112301071123113311370133010435b7b16cfe3d8bbaba7901c4d1fdf8a6fdd9018102ba72fdb805b6fd25a80233fd83000100aefe83042b044a000e0099406a08401418 48bd08cd08dd080308200910481a082a08020340141848bd03cd03dd030303200910481a032a0302080746000176018601026d01015501012b013b014b01031401010b01010603010004100402040410 0e020a470b540f09020e0e000b0350081505fb0c000f003f323f3fe13312391133330110f6e1323211332f5d33335e5d5d5d5d5d5d1133e1325d2b5d2b5d2b5d2b313001330101331123112301112311 331102fac4fe61014bc1ae66fe4bb4b4044afdf1fe5ffde9017d022dfdd3044afdeb000100c7000004a205b600120097b9000fffe0405d121548500f600f02220f320f420f030240090d480b075a0834 12541202120f570301030c1d04010b0401040400086413101111010010000010000207000014b014012f14011014010b05090820043004400403040d040d100903080012003f323f3339392f2f5d1112 3939015d5d5d11332f5e5d383333113310e611392f5d5d33c15d32325d10e1323130002b5d5d2b2123011523110711231133113711331501330104a2d3feae8577baba77850141d1fdf801f4cd016462 fdd705b6fd06a40163b301a6fd65000100ae00000423044a0013009cb511400b11480ab8ffc0b30b11480eb8fff04057080d480e0a261201120789139913a913031f132f133f13030b130113130f0602 470354140b0c0c100f10200f300f020f0f1500151015020015401560158015a015c015e01507070e0d06060813081308020b040f100215003f333f331239392f2f1239113333015e5d7111332f5d3833 33113310f6e13212392f5d5d5d33c15d32322b3130002b2b012711231133113711331513330115012301152301cf6db4b46d7debc5fe5001d7cffef87d01b27bfdd3044afdeb7b0146b9010dfe1649fd e90127cd0001002f000004a205b60014008540400214661401141304400e500e020e0e00100c045a09070564151213101313010010000010000207000016b016012f16011016010f065f0c0909000210 0b104810b8fff0400c0b1048100205120a03050012003f323f331239392b2b12392f33e132015d5d5d11332f5e5d3833332f383310f6c633e1323212392f5d1112395d11333130212301071123112335 33353315331523113701330104a2d3fe3d8bba9898bad5d57901c4d1fdf802ba72fdb80460a4b2b2a4fe7ba80233fd8300010012000003f0061400160084400f110e0e0f0408090313471400060106b8 ffc0b310154806b8ffc04035090e4806060f16011454170c0d100d0f10350f01000f100f200f03080f0f180f180109110214140f07154f040101020f150c0f0200003f3f3f12392f33e1321133111239 39015d11332f5e5d5d383333113310f632c612392f2b2b7110e117321139113331301333353315211521110333370133010123010711231123129cb4017bfe851004870125d3fe6f01acd1feb06db49c 055eb6b689fe75feedaa0169fe25fd9101f852fe5a04d500000100140000054405b6000e00574033020e0e0d0a045a2005300540058005f00505050500070c0d0d010010000010000207000010101001 020a050c075f0803050012003f323fe133123939015d11332f5e5d38333311332f12392f5de1321139113331302123010711231121352111370133010544d3fe3d8bbbfeac020f7901c4d1fdf802ba72 fdb80512a4fd25a80233fd8300010029000004c9044a000d00674040020d0d0b06470007010007100720076007c0070508070703090001d501f5010201040310000310030203030f400fe00f020f0f01 020d0d070950000a0f070315003f333f33e112391133015d5d11332f5d3833335d11332f12392f5e5d71e1323211333130013301012301112311213521071103ddc5fe6001c7cffe4cb5fe98021f0204 4afdf1fdc5022dfdd303b09a02fded00000100e5fe7f05a405b6000f0063403f045a040101740184019401030101110d055a0011e411f41102c01101021011201140118011040c085a096410075f0f0c 01080c0c050e0a0309005f051202fb003f3fe1333f3312392f5e5de10110f6e1325d5f5d5d10dce13211332f5d71e131302533112311231121112311331121113304f4b0b0bbfd67bbbb0299bba6fdd9 018102aafd5605b6fd980268000100aefe8304db044a000f00794052080047040b010b0b0f47c40cd40c020c0c110411241102d411f41102b011010230114011501180119011a011060703470454100d fb0250eb0701a907b907020f071f072f07030607070009050f0b50040015003f32e13f3312392f5e5d5d5de13f0110f6e1325d5f5d5d7111332f5de1332f5de132313021112111231133112111331133 1123110385fddfb6b60221b6a0b601e9fe17044afe3901c7fc50fde9017d000100e50000064805b6000d005d403b09015a000005400b01e00b010b0f200f01000f100f300f400f600fa00fb00fe00f08 0608045a05640e0d5f0a0a06035f0f08010808080603050012003f323f392f5e5de111332fe10110f6e1325e5d7110c65d7111392fe1323130212311211123113311211121152104f4bbfd67bbbb0299 020ffeac02aafd5605b6fd980268a400000100ae000005a4044a000d006840210804470509014700000b05540e0b0b0f000f200f02900fb00fc00fd00ff00f050fb8ffc0401f070c480350eb0801a908 b908020f081f082f0803060808000d0a060f050015003f323f33c412392f5e5d5d5de1012b5d7111332f10e611392fe13210e13231302123112111231133112111211521043bb6fddfb6b60221021ffe 9701e9fe17044afe3901c79a000100c7fe0007db05b60027005f403a090b0107121200205a212125185b08296f2901245a2564281d600f032f033f03030f033f03df03ff030408030325235f26032125 1213165f0d1c003fe1333f333fe112392f5e5d71e10110f6e15d10dee111392fe132392f3130005e5d01363633321e0215140e0223222e0227351616332011342e02232207112311211123112104c11e 492e9af0a5565292c976314e433d1f3f7e490177437cae6b4b33bbfd7bba03fa031b05035cabf297aaf8a24f060c130ca2171801ef79b97e400cfd890512faee05b6000100aefe0a0675044a00240077 404e0b231b23020303191147021201c21201a612b6120277128712021212160a4820260f261f26024f265f26af26ff260410260115471654250d510b1b1b1b02071b1b161450170f121615040751001b 003fe1333f333fe112392f5e5de10110f6e15d5d7110dee111392f5d5d5d71e132392f3130005d01222627351616333236353426232206071123112111231121113633321e0215140e0204d94b6a2e2b 6a427675909d1c3e1fb6fe08b603643a3f66b3854c406f96fe0a1f1da11825c3d2d4ca0a08fe3503b0fc50044afe270c3e8adb9d96d588400002007dffac059605cd003e0052007a4050054e10320400 495b002010200235203520183f5b0067540f541f544f545f547f549f54af5407072b5b18665344604e05003a103a203a603a703a803a063a3a07265f211d041032305f13075f0e0e1313003f332fe110 e132393f33e112392f5d3939e10110f6e15e5d10f6e11139392f2f5de1121739313001140e0207163332363715060623222706062322262602353412363633321617072e0323220e0215141e02333237 260235343e0233321e0207342e0223220e0215141e02173e03056f2741552d365125461f1d4f26a68b327c3c96e89d514d9ef2a6427825350a2830331576a96c333c70a06430264f5b3760834c4b8562 39c5162a3d27293d29151829361f2a422e1802a665af906f24190e0baa0d0c6211116ac0010ea5b5011fc769160f9c050a0905519ade8d94da9046076901169b85c17b3b387bc6955489633637628750 4885766527216277880000020071ffc504a4045e000d004d0079404944051132043f00485421642102352135211908483f4a4a3f574f7b4f8b4fbb4f035f4f6f4f021b4f010f4f0107022a4819564e0b 44053a3a472550221e1011322f501447500e0e1416003f332fe110e132393f33e912392f3939c10110f6e15f5e5d5d5d5d10e6322f10e11139392f2f5de1121739313001141e02173636353426232206 01222627060623222e0235343e023332161707262623220e0215141e0233323637262635343e0233321e0215140e020716163332363715060602dd14202a153948383d3e41014c45883928624775b37a 3f3c78b47942521a29134a2a5470431c1e436e50253203394a31557241406f522e1e34452714371d1a391c194201f4355c4b391228966b677a7afd682a2511175797cc7583d6975310069605103a6fa0 6759946b3c080242b4775e88592b27568a634678634d1b0a0d0608930907ffff007dfe42049805cb0226002600000107037f022f0000000eb7010175322c182025012b350035ffff0071fe42036f045e 0226004600000107037f01710000000eb70101522e28050d25012b35003500010014fe7f041205b6000b006f40391f0d01e00d015f0ddf0d02200d300d400d03045a0f011f0102070101af0aef0a020a 0a0b5a064007e007020f07010807075706670677060306b8ffc0400f070a48060b075f0803005f051202fb003f3fe13fe132012f2b5d332f5e5d5d10e1322f5d392f5e5de15d5d5d7131302533112311 231121352115210271b0b0bbfe5e03fefe5fa6fdd901810512a4a40000010029fe83035e044a000b006f404df00d01af0d01400d500d022f0d010b47af08bf08cf08030840070a480808df05019d0501 8f0501050507470060027002d002031f0201020200001000b000c000040009fb060250030f07500015003fe13fe1323f012f5d332f5d5d10e1322f5d5d5d392f2b5de15d5d5d5d313021112135211521 11331123110168fec10335fec19fb603b09a9afceafde9017d00ffff00000000043705b60206003c000000010000fe1403d5044a0013007c40130a0a0047a60101870197010201010311121012b8ffc0 b312154812b8ffc04020070b48121215f01501df15ef150250159015a015034f15013015010f15010403b8fff040100311030f050a150a0207130a0215001b003f3f33335e5d3f33012f38335d5d5d5d 5d5d11332f2b2b383312392f5d5de1393d2f31300123110133131e0317333e03371333010246b7fe71bcc710201b14050704151b2010c7bcfe71fe1401e8044efdcf2e645e4f19194f5e642e0231fbb2 000100000000043705b60010009f4019ef12011240090c48000004085a090d09960901770987090206b8ffc0400d1518480b090606090b0302100fb8fff04038ab0f01900f01140f010f010210100201 ef0201d00201bf02018002014f025f020214020100020107020212070a5f04000d0d0108120f0103003f333f12392f3933e1321101332f5e5d5d5d5d5d5d5d7138332f5d5d5d38331217392f2f2f2b5d 5d113310e132393d2f2b5d31300101330115211521112311213521350133021b0154c8fe420127fed9bbfeda0126fe42cb02d302e3fc833da4fea80158a43303870000010000fe1403d5044a00190085 40150e0e17014706a60201870297020202020715161016b8ffc0b312154816b8ffc04020070b4816161bf01b01df1bef1b02501b901ba01b034f1b01301b010f1b010807b8fff040130715070f00034f 050e150e02070e170615011b003f3f33335e5de1323f33012f38335d5d5d5d5d5d11332f2b2b383312392f5d5d33e132393d2f3130051123112135210133131e0317333e033713330121150246b7fef6 0108fe73bcc710201b14050704151b2010c7bcfe71010a89fe9d016389044afdcf2e645e4f19194f5e642e0231fbb68900010000fe7f04b405b6000f01064088470f01480901030f000b06050a070e07 0c000b09050a080d080c0f000b000906050a05090c0f0306060e080a0501aa05ba05ca05ea05fa050505300b0e4805045a010d0e100b0e01ab0ebb0ecb0eeb0efb0e050e400b0e480e0a0001aa00ba00 ca00ea00fa000500300b0e480e00040114010207010111d411e411f41103c0110102201140110211b8ffc0400b1014480f11010b0a0a0708b8fff0401408280601270c010c06050d0a0307005f051202 fb003f3fe1333f331239395d5d012f38333311335d2b5d5f5d5d11332f5e5d33332b5d712f2b5d71383310e1322b5d711112393d2f173310870ec004c01087c00ec0108708c008c0108708c008c0015f 5d5d31302533112311230101230101330101330103feb6b077fe9efe91bc01c5fe5ac6014c014ebefe5ba6fdd90181027bfd8502fc02bafdd1022ffd4c0000010023fe83041f044a000f01394025590d 01560301b40c010c200e11483d0c01290c010b0c1b0c020c0b4608000306030d0d0104b8fff04071151848b504019904a904026a047a048a040345045504020604010405db02eb02fb0203c90201bb02 019602a60202650275028502034a025a02020201df05ef05ff050305400e11483b054b05022705010a051a050234014401022801010501150102050105010f3b070107200e11480708b8ffc04049070c 48080811601180119011b011d011e011f01107db0e01c90e01ba0e01650e750e850e034a0e5a0e02090e010e3b0f4b0f02280f01050f150f020f030d010e07500c1509fb04010f003f333f3fe1331239 39012f5d5d5dc55d5d5d5d5d5d5d11332f2b332b5d1239392f2f5d5d5d5d5d5d2b5d10c55d5d5d5d5d5d10c55d5d5d5d5d2b12393d2f173310e1325d5d5d2b5d3130005d5d0101331313330101331123 11230101230198fe9fcffafacffe9d010faaae65fef4fef2cf02330217fe66019afde9fe67fde9017d01b4fe4c0000010014fe7f066005b6000f0094400d015a0404085a100501d0050105b8ffc04044 071248050511df1101a011010f112f114f118f110407100e200e400e500e600e800e060e0e005a090f0b1f0b2f0b5f0b6f0baf0b06080b0b300940095009800990090509b8ffc04011070a48090f0b5f 020c0304005f091206fb003f3fe1323f33e132012f2b5d332f5e5d10e1322f5d5e5d5d5d11332f2b5d71e1332fe131302521113311331123112111213521152102710285bab0b0fc06fe5e03fefe5fa6 0510faf0fdd901810512a4a400010029fe83056d044a000f0080b60b470e0e02470fb8ffc0b30e18480fb8ffc04033070b480f0f110f111f112f114f11bf11df1106076008e008f0080308080a47031f 05ef05ff0503050500031003600370030403b8ffc04011141848030905500c060f0e0a50031500fb003f3fe1323f33e132012f2b5d332f5d10e1322f5d5e5d11332f2b2be1332fe13130012311211121 35211521112111331133056db7fcb2fec10335fec101f8b6a0fe83017d03b09a9afcea03b0fc5000000100a6fe7f053105b6001d006340120b0d1b0d021a045a901da01d021d1d035a00b8ffc0402c07 104800001f0f1f1f1f2f1f4f1f5f1f7f1faf1fbf1f0807125a0f641e155f1a0a0a041b10031d5f041201fb003f3fe13f3312392f33e10110f6e15e5d11332f2be1332f5de13231305d2511231123110e 0323222e0235113311141633323e02371133110531b0ba3a696361315d926535ba697b2d5a5e6638baa6fdd9018102561622160c315e8b590247fdd173740a141e1402c6faf00001009afe83049e044a 001c006140170b091b092b09030715004718181c470019101920190319b8ffc040250e154819191e0f1e5f1e7f1ebf1ecf1e050e470b541d1afb151050060600160c0f18500015003fe13f3312392fe1 333f0110f6e15d11332f2b5de1332fe13231305e5d21110e0323222e02351133111433323e02371133113311231103482c50555e3a4e7a522bb6b82d504c4d2ab6a0b701e91e3020112f54734401a6fe 66ae0f1c2b1d01d5fc50fde9017d000100a60000048105b6001d0070402e0b041b04021c0f1d040e140e02070e0e0613175a16651f701fa01f022f1f01101f01095a60067006a006b0060406b8ffc040 16070a48060e100e1d131b1d030c5f0101171407031712003f3f3312392fe117332f32322f012f2b5de15d5d5d10f6e13211392f5e5d33c13231305d0123222e02351133111416333311331136363711 3311231106060711230250215d926535ba697b0c85387644baba4277398501fc315e8b590247fdd173740158feb409221902c6fa4a02561a250bfec90001009a000003fe044a001c006b40420b041b04 02071b0e1c500d01040d140d240d03080d0d0612165a15551e101e601e801e03095a06541d200d300d400d030d0f0d1c121a1c030b5f01011613070f1615003f3f3312392fe117332f32322f5d0110f6 e15d10f6e13211392f5e5d5d33c13231305e5d31300123222e023511331114333311331136363711331123110606071123020e2f4e7a522bb6b8067d2f5b33b6b63259327d016a2f54734401a6fe66ae 012dfee50e302301d5fbb601e9233310ff00000100c7000004a205b60017005040360407140702070c5a0b65192f195f196f198f199f19af19cf19ef19ff190910190102165a17641815105f00051005 020505170b120003003f3f33392f5de1330110f6e1325d5d10f6e13130005e5d133311363633321e0215112311342623220e02071123c7ba73c3625d926535bb687b2d5a5f6538ba05b6fdaa2d2d315e 8a59fdb8022f73750a141e14fd39000100ae00000412044a0018003fb90014ffe04022070a48004718551aef1a01101a601a801a030d09470a541908035012120b0f0a0015003f323f392fe1330110f6 e1325d5d10f6e13130002b21113423220e020711231133113e0333321e021511035cb82d504c4d2ab6b62c50555e3a4e7a522b019aae0f1c2c1cfe2b044afe161f2f20112f537344fe5a0002003dffec 060605cd002b00360064403e325b140b67380f381f3802292022012222310c5b00701f801fc01f031f371f0c60314f2b010f2baf2bff2b030f2501082b252b2505115f141a132c5f0504003fe13f33e1 1139392f2f5e5d5d7133e1320110d65d32e132332f5dc15d10f632e13130013e0333321616121515211e0333323637150e0323222e022722263534363733060615143301220e020721342e0201660a5b 9cdd8d99d6883efc25073f74a97080cf5b2a5b697c4c98eba45c098f9a120b9c060f6702895b956e4107031225568b03399af4ab5b6bc5feebab457ac286472c20aa0f1a120a61b3fd9b757a2a42170f 3e236101f0417eb97875b880430000020033ffec04b6045e002c00350084402b3148271e5737ff37019037b037021f377f3702301f48050fdf080108081300051005200503400550050205b8ffc04028 1013480536051f50301b122b12020f12011b0b2b0b020f0b0106120b120b222d5018102251270016003f32e13fe11239392f2f5e5d5d5d5d33e1320110c62b5d7132322f5dc110e1325d5d5d10f632e1 313005222e022726263534363733060615141633333e0333321e02151521161633323e0237150e030322060721342e0203356bb3824b04858e120995060e31311b0e4c74985a639e6e3bfd4c05999733 57514c27284d51576072850b01ec1b3959144688c781026f72273f150e3a222f316ca9753e4781b56e71c1b60a131d12a2131c120803db9c954471502c000002003dfe7f060605cd002e003900724046 1b5a1c1c22355b140b673b0f3b1f3b022c2025012525340c5b0070228022c02203223a220c60344f2e010f2e3f2eaf2e030f2801082e282e28051a1411601d121bfb2f5f0504003fe13f3fe133331239 392f2f5e5d5d7133e1320110d65d32e132332f5dc15d10f632e112392fe13130013e0333321616121515211e0333323637150e03071123112e032722263534363733060615143301220e020721342e02 01660a5b9cdd8d99d6883efc25073f74a97080cf5b254e58643ab680c48a4d088f9a120b9c060f6702895b956e4107031225568b03399af4ab5b6bc5feebab457ac286472c20aa0e17110b02fe910173 106db0eb8e757a2a42170f3e236101f0417eb97875b8804300020033fe8304b6045e002d003600924030044705050b32482d245738ff38019038b038021f387f38023125480b15df0e010e0e19000b10 0b200b03400b500b020bb8ffc0402b1013480b370b2550311b182b18020f18011b112b11020f11010618111811282e501e1028512d03061604fb003f3f3333e13fe11239392f2f5e5d5d5d5d33e13201 10c62b5d7132322f5dc110e1325d5d5d10f632e112392fe13130250606071123112e032726263534363733060615141633333e0333321e02151521161633323e02370122060721342e02048542804cb6 5489633803858e120995060e31311b0e4c74985a639e6e3bfd4c0599973357514c27fe8372850b01ec1b395935202304fe950175115484b26f026f72273f150e3a222f316ca9753e4781b56e71c1b60a 131d1202f09c954471502c00ffff00520000026405b60206002c0000ffff0004000006810769022601b000000107023600f401520013400b0117052601001c12110a25012b35002b3500ffff00040000 05be0617022601d0000001070236009300000013400b0117112601001c120e0725012b35002b3500000100c7fe0004e105b600250067403f1b1b05215b11090a100a400c18480a0a0411271027402702 0b0808045a0564261f5f1c161c080300602f0c5f0cef0cff0c040c401015480c0c050906030512003f3f3312392f2b5de133333f33e10110f6e13211335d10ce11392f2b383310e111392f3130012206 07112311331101330133321e0215140e0223222e0227351616332011342e020246415c28baba0235cffdd1069af0a5565292c976314e433d1f3f7f480177437cae026f110efdb005b6fd3c02c4fd5855 a3ec97aaf8a24f060c130ca2171801ef79b3763a000100aefe0a03e9044a0023007240470b081b08022223101f230123231d050d0d1e144805250f25015f256f257f259f25bf25df25ff25070021211d 471e5424211c19510b001b00020700001e221f0f1e1511510e0a1b003f33e13f3f3312392f5e5de133330110f6e13211335d7110dee111392f1112392f7138333130005d011e0315140e022322262735 161633323635342e022322060711231133110133022b5ea378453f6f96574c692f2c69437675234a724e205529b4b40198c4026a054084d09496d588401f1da11825c3d26a97602d100dfe50044afe0a 01f600010000fe7f055605b600230073b10702b8fff84046141748025a891801181018e01d01b41dc41dd41d03001d501d02071d1d1f0f212222005a23201f259025c025f025030f251f257f2503080f 21fb025f1d0313600c131f5f0012003fe13fe13fe13f012f5e5d5d10d43232e1392f331112392f5e5d5d5d33385de12b3231302111210e03070e032322262735161633323e0237363612123721113303 231303d9fe850f2021211014354f6e4e234a1c173a20303e2a1a0c0c20272b1602d0c38fd9a5051271f5ebd45167a26f3b0e0b9a0d103f62753639c80106013aaafaf0fdd901810000010010fe830466 044a0018005840380246d412e4120260127012a012b0120434120112120a1617170047181514551a201ab01a020f1a01080a16fb0250120f0d4f071614500015003fe13fe13fe13f012f5e5d5d10f432 32e1392f3311392f5d5d5de131302111210202060623222627351633323636123721113303231302fafefe14405f82561c3110161c37594533120254b67ab77b03b0fefdfe94e6690606830675f1016f fafc50fde9017d00000100e5fe0004f405b6001b004b402b050510140c5a17651dc01d01bf1d01201d01130f5a10641c0e5f0f1301081313101511031012095f06001c003f32e13f3f3312392f5e5de1 0110f6e1325d5d5d10f6e13211392f313001222e0227351616333236351121112311331121113311140e0202d1314e443d1f3f7f48bbc6fd67bbbb0299bb5292c9fe00060c130ca21718f0f7021ffd56 05b6fd980268faddaaf8a24f000100aefe0a043b044a001b0069401a030310140c4717551d001d201d02301d401d501dd01df01d051db8ffc040280e1148130f4710541c0e50eb1301a913b913020f13 1f132f13030613131015110f1015075104001b003f32e13f3f3312392f5e5d5d5de10110f6e1322b5d7110f6e13211392f31300122262735161633323e02351121112311331121113311140e0202a04c 692f2c69423b5b3d1ffddfb6b60221b63f6f96fe0a1f1da118252d61966901b2fe17044afe3901c7fbf396d58840000100e5fe7f05b605b6000f005240320203030d055a040100111011201140118011 c011e011f011070c085a096410075f0f0c01080c0c050e0a0309005f051202fb003f3fe1333f3312392f5e5de10110f6e1325d10d43232e132392f3331302533032313231121112311331121113304f4 c28fd9a6bbfd67bbbb0299bba6fdd9018102aafd5605b6fd98026800000100aefe8304f2044a000f0076404f0d0e0e0800470f0cab0bbb0b020b110411241102d411f41102b011010230114011501180 119011a011060703470454100dfb0250eb0701a907b907020f071f072f07030607070009050f0b50040015003f32e13f3312392f5e5d5d5de13f0110f6e1325d5f5d5d7110d45d3232e132392f333130 211121112311331121113311330323130385fddfb6b60221b6b77bb67a01e9fe17044afe3901c7fc50fde9017d00000100a6fe7f048105b6001d005940211d5a1a1a16005a19651f701fa01f022f1f01 101f010e5a600b700ba00bb00b040bb8ffc04014070a480b16115f06060c1a1bfb1d5f1a12170c03003f333fe13f1112392fe133012f2b5de15d5d5d10f6e132322fe1313025110e0323222e02351133 11141633323e02371133112311231103c73a696361315d926535ba697b2d5a5e6638babab0a601b01622160c315e8b590247fdd173740a141e1402c6fa4afe7f02270001009afe8303fe044a001c0040 40251b471818141c4717551e101e601e801e030d470a541d19fb140f5005050b1b501815150b0f003f333fe112392fe1333f0110f6e15d10f6e132322fe13130010e0323222e02351133111433323e02 37113311231123113303482c50555e3a4e7a522bb6b82d504c4d2ab6a0b6a001e91e3020112f54734401a6fe66ae0f1c2b1d01d5fbb6fe830217000100c7fe7f06f205b6001f009ab6361f013900011f b8fff8402c0c0f481f00080c0f48000d0d0c10091213130e080c0f48390e010e1d155a141110212021c021020f2101080bb8fff840100c0f48260b010b02085a096420105f0cb8fff040160912480009 0c03151212fb1e010110091248010e0a03003f33332b11333f3f17332be10110f6e132325d2b5e5d5d10d43232e132325d2b392f331112393911332b332b31305d5d2101231617161615112311210133 012111330323132311343e0237363723010323fe450805040406ac0114019c06019e0114c390d9a6ba01020202030408fe4105004a493f8b39fc9605b6fb5804a8faf0fdd901810377193d41421e4749 fb02000100aefe8305c7044a00240087405a0807181810202223231e00462421af20bf20022026e02601cf2601302640265026a026040f260106120f4610542522fb013b0e4b0e5b0e030b0e1b0e2b0e 030e0e1e110f20503418441854180305181518251803081018030015003f17325d5de13f33332f5d5d333f0110f6e1325e5d5d5d5d10d45d3232e132392f33111239113333313021110e03070123012e 032711231133011e03173e033701331133032313046f0611141207fef887fef70511141207a2dd010b0d16130e05060e13160d010ed9b77bb67a038115393b3612fd5002b00d313b3e1afc7f044afd47 22433c321011313b412102bdfc50fde9017dffff00520000026405b60206002c0000ffff0000000004dd076902260024000001070236002101520013400b021a052602001f15040725012b35002b3500 ffff005effec03a1061702260044000001060236d4000013400b0238112602253d330c2225012b35002b3500ffff0000000004dd072b0226002400000107006a002101520017400d03021e0526030201 1529040725012b3535002b353500ffff005effec039c05d90226004400000106006ade000017400d03023c112603022f33470c2225012b3535002b353500fffffffe0000065605b6020600880000ffff 005effec0644045e020600a80000ffff00c7000003c8076902260028000001070236fffb01520013400b011105260106160c010025012b35002b3500ffff0071ffec03e1061702260048000001060236 ea000013400b022d1126020f3228050f25012b35002b350000020071ffec051205cd001e00290049402f241a5b0e672b0f2b8f2baf2bbf2b042b400b0f48255b0319662a255f2f195f197f1903191909 1f5f131303005f0904003fe1333fe111392f5de10110f632e12b5d10f6e132313001220607353e033332161612151402060623222626023535212e0303323e023721141e02027980cf5b2a5a697d4ca0 f4a554519de89699d7873e03db074073a9435b956d4207fced26558c05292c20aa0f1a130a6cc6fee9abaefeebc2686bc40115ab467ac18647fb66417eb97875b87f440000020066ffec03d7045e001e 002700434029221148055729b029013f290123481910562823509f10af10cf10df10041010001f500a161914510010003fe1333fe111392f5de10110f632e15d5d10f6e132313001321e0215140e0223 222e02353521262623220e0207353e031332363721141e0201e76eb683494278a766639e6e3b02b5059a973357504c27284c51576073850bfe141b3958045e4a8ed28788d6954e4781b56e71c0b60a13 1c12a1131c1209fc259c954471502c00ffff0071ffec0512072b022602e100000107006a004601520019b603023305260302b8ffd3b42a3e180e25012b3535002b353500ffff0066ffec03d705d90226 02e200000106006ac4000019b603023111260302b8fff4b4283c0f0525012b3535002b353500ffff000400000681072b022601b000000107006a00f401520017400d02011b05260201001226110a2501 2b3535002b353500ffff0004000005be05d9022601d000000107006a009100000019b602011b11260201b8ffffb412260e0725012b3535002b353500ffff0048ffec03ec072b022601b100000107006a ffbf01520019b602014305260201b8fff4b43a4e130b25012b3535002b353500ffff0044ffec035205d9022601d100000107006aff5500000019b602014311260201b8ffd9b43a4e292125012b353500 2b35350000010048ffec03ec05b600200072402d005b1b1c5b2020401018481d1b20201b1d030d165b0567229f2201700d800d023f0d4f0d5f0d030d201d5f1e1bb8fff04018070d481b19aa00017800 010f00010800001e0313600e0a13003f33e13f392f5e5d5d5d33332b10e132012f5d5d5d10f6e11217392f2f2f2b10e110e13130011e0315140e0223222627351e033332363534262323350121352115 01f473ba84474388cd896ec0552b6063632eb2b0cfba7b01a6fda6033d033b053564976660a07440222daa1724180d948787819701d1a6910001001bfe140375044a00240064403e004a1f204a242440 131848211f24241f21030d18470557266f269f26023026010f2601070d400c11480d242150221f1d0020090c480000220f13500e0a1b003f33e13f392f2b333310e132012f2b5e5d5d5d10f6e1121739 2f2f2f2b10e110e13130011e0315140e0223222627351e0333323e0235342e02232335012135211501a85fa87d494784ba7373b53a1f4e5b66364777563037638b546d0192fdc6030601d5074175a66c 6eb784492422a6101f180f2e577d4e567d52277d01ed9a85ffff00c90000051006c1022601b200000107014d00b001520015b4011a052601b8fffeb41819000c25012b35002b3500ffff00ae0000043b 056f022601d200000106014d39000015b4010e112601b8ffffb40c0d0a0425012b35002b3500ffff00c900000510072b022601b200000107006a009c01520019b602012105260201b8fffeb4182c000c 25012b3535002b353500ffff00ae0000043b05d9022601d200000106006a25000019b602011511260201b8ffffb40c200a0425012b3535002b353500ffff007dffec0571072b0226003200000107006a 00aa01520017400d0302310526030201283c0a0025012b3535002b353500ffff0071ffec042d05d90226005200000106006af9000019b603022911260302b8fff9b420340a0025012b3535002b353500 ffff007dffec057105cd0206027e0000ffff0071ffec042d045e0206027f0000ffff007dffec0571072b0226027e00000107006a00aa01520017400d04033305260403012a3e0a0025012b3535002b35 3500ffff0071ffec042d05d90226027f00000106006a00000017400d04032b112604030022360a0025012b3535002b353500ffff003bffec0444072b022601c700000107006aff9701520019b602012e 05260201b8ffa6b42539040c25012b3535002b353500ffff0037ffec034205d9022601e700000107006aff3800000019b602013011260201b8ffcab4273b032225012b3535002b353500ffff0019ffec 04ae06c1022601bd00000107014d002701520015b40124052601b8fffeb42223130025012b35002b3500ffff000afe1403df056f0226005c00000106014dbb000013400b0125112601012324000f2501 2b35002b3500ffff0019ffec04ae072b022601bd00000107006a001201520019b602012b05260201b8fffdb42236130025012b3535002b353500ffff000afe1403df05d90226005c00000106006aa700 0017400d02012c11260201012337000f25012b3535002b353500ffff0019ffec04ae0773022601bd000001070153006601520017400d02012e05260201512236130025012b3535002b353500ffff000a fe1403df06210226005c00000106015300000017400d02012f112602015a2337000f25012b3535002b353500ffff00a600000481072b022601c100000107006a005401520017400d02011f052602010f 162a0a0025012b3535002b353500ffff009a000003fe05d9022601e100000106006a06000017400d0201221126020108192d170a25012b3535002b353500000100c7fe7f03be05b600090064400b1400 01e40001d000010200b8ffc0403508134800000b2f0b4f0b6f0b8f0b040b40111848075abf04cf04028404010f041f0402070404035a08640a025f0903035f071206fb003f3fe13fe10110f6e1322f5e 5d5d5de12b5d11332f2b5f5d5d7131300115211133112311231103befdc3b0b0ba05b6a6fb96fdd9018105b6000100aefe83030a044a0009004e4032200230020202020bc00b01a10b01700b010947bf 06cf06028406010f061f0602070606054700540a0550091508fb0450010f003fe13f3fe10110f6e1322f5e5d5d5de15d5d5d11332f5d313033112115211133112311ae025cfe5aa0b6044a9afceafde9 017dffff00c7000005cf072b022601c500000107006a00fc01520017400d04032705260403001e32061c25012b3535002b353500ffff00ae0000055005d9022601e500000107006a00b000000017400d 04032711260403001e320a0d25012b3535002b353500ffff002ffe6d03be05b60226029b00000107038000a60000000ab3011f1f0701103c1135ffff0012fe6d030a044a0226029c0000010703810089 0000000ab3011f1f0d01103c1135ffff0000fe6d049a05b60026003b000001070380032300000017b1011db8ffc0b2131548b8ff9eb41d1d000025012b2b3500ffff0023fe6d0411044a0026005b0000 01070381029a00000012b301501d01b8ff9ab41d1d070725012b5d35000100000000046005b6001100b24027460f560f02490959090236000139060106090f00040c0303013011013f07010711071105 010b0ab8fff0b30a0a0405b8fff04014050d0e100e0e02011000010170018001c0010301b8ffc04027070a480101130f131f132f137f13040800065f0f09280301270c01030c0a0909010d0a03050112 003f333f3312392f1139395d5d1133e132015e5d11332f2b5d713833332f38332f3833332f3833111239392f2f5d5d11393d2f3317335d5d5d5d313001012301012301213521013301013301211502c5 019bd3fe9efe91bc019afedf0114fe92c6014c014ebefe8e011c02b4fd4c027bfd8502b4a4025efdd1022ffda2a400010023000003db044a0011011740bf8008900802080008000b0f060501f70501e5 05013605010506070a0a040d0110100d090301f80301ea030139030103026b067b06025706013a064a06026402740202580201350245020206020d020d06030f060c01f70c01e50c01360c010c0b4016 19480b400e11486b0b7b0b02570b013a0b4a0b020b0b1310133013029013b013020f1301090e01f80e01ea0e01390e010e6b0f7b0f02580f01350f450f020f0d0a104f0407ef01010b011b012b015b01 6b0105060101020f0b1505020f003f333f3312392f5e5d5d3333e13232012f5d5d5dc15d5d5d715d5d7110ce2f5d5d5d2b2bc15d5d5d711217393d2f182f2f5d5d5d5d5d5d10c15d5d5d711133113311 3333113310c15d5d5d71111239392f2f5d3130132101331313330121152101230101230121680100fecfcffafacffecd0104fef7014acffef4fef2cf014afefb027b01cffe66019afe3189fe0e01b4fe 4c01f20000020089000003f605b6000e00190040402906195a09651b9f1b01101b01155b00661a0f5f3f064f066f069f06bf06df0606060607195f09120703003f3fe111392f5de10110f6e15d5d10f6 e132313013343e02333311331121222e020123220e02151416333389377fcf9895bbfe9586c27e3c02b2815d8a5b2ea3af9f01ac579871420268fa4a3d709e015f1b3c6146888400ffff0071ffec0402 061402060047000000020089ffec063b05b6002300320063403f1809325a1a1a11225a0165340f34016f349f34ef340340345034020f3401062a5b116633245f1723233f174f176f17bf17df17051717 18031d2d6009060e13003f3333e1323f392f5d332f10e10110f6e15e5d5d5d7110f6e111392fe1393231300111140e02232226270e0323222635343e023333113311141633323e0235110523220e0215 141633323e0235063b2d5b8c5e72992b183f52673fd7e4418ad7967abb67612c48331cfdba815d8b5b2d7e86435b38170350fe18518b663a614d263f2e19d2d667a3723c0268fbb270691e39503201e8 a61e436b4d8082253e4d290000020071ffec065a061400320043005c4039102c3847502e012e2e1b03470655456f457f459f45cf45ef45054045010f452f45020641481b56440404333e502520102c00 003350100b1616003f3333e1323f3f33e112392f0110f6e15e5d5d5d10f6e111392f5de13239313025323635113311140e0223222e0227230e0323222e0235343e0233321e0217332627262635113311 1e0321323e023735342e0223220615141604d36f62b62f5c8b5b4167513d17061b445b79515d9a6e3c3c6e9a5d3b604d3b170c03030204b6010f2c51fda64c69411f021b416c51877f7f8382820135fe c16998622e1e364a2c294a3720488fd48c8dd590491a2c3a20221f1a361101b4fb923e6a4e2d2e5e8c5f29659d6b37daccd1cd000001004effec064405cb003f008540560d5b20005b2b252007202b2b 20070316335a3665417f418f419f41ef41ff41050041204130410370168016023f164f1602161640250660070034013434df0701aa07017807010f07010807071b305f3b131512601b04003fe1333fe1 11392f5e5d5d5d5d332f5d10e1391101332f5d5d5d5d10f6e11117392f2f2f123910e110e1313001342e0223233533323e0235342e0223220607273e0333321e0215140e0207151e0315141e02333236 35113311140e0223222e0203293565925dbfb05c8e613225445f3a6ea94b5c26627483476da67139335b7d4b578a5e3218324f376f62b73866915957946c3c01874d6d4621972748643e36533a1e4336 7d1f3629183661854f4a7758390c060b395977484a68411e778101c9fe2d6998622e2f649c0000010050ffec05a2045e003b00814023154700204631363119003119193100032708470b553d0f3d01d0 3d01bf3d01303d0127b8ffc040291215485f270127273c3619501a0909df1a01991aa91a020b1a1b1a02071a1a052623502c1005501016003fe13fe13312392f5e5d5d5d332f10e1391101332f5d2b5d 5d5d7110f6e11117392f2f2f11123910e110e1313001141e0233323635113311140e0223222e0235342623233533323e0235342623220607273e0333321e0215140e0207151e0303521531503b6960b6 2f5f8f605c906435858a81613d644827736c47814b3f284d525a355690693a1c33462b32533c22014c2749382182820135fec16998622e2b547b4f5e5b991227402d4d4d262293131d1309264a6d4632 4d3b290e0b09293e52000001004efe7f049c05cb0031008340540f5b27092209220918015a702e802e022e2e005a2f2f33003301c033d033029f33010033203330330370188018023f184f1802181832 30fb270860df0901aa09017809010f0901080909011714601d042e5f0112003fe13fe13312392f5e5d5d5d5de1393f1101332f5d5d5d5d5d7111332fe1322f5de11239392f2f1239e13130212311342e 0223233533323e0235342e0223220607273e0333321e0215140e0207151e03151533112303ecbb3867955dbfb05c8e613225445f3a6ea94b5c26627483476da67139335b7d4b578a5e32b0b001a04364 4120972748643e36533a1e43367d1f3629183661854f4a7758390c060b39597748fafdd900010050fe8303f2045e002d008d401a0c461d221d061d061d13004729292d47202a302a402a602a042ab8ff c0400e0f13482a2a2fc02fd02fe02f0313b8ffc0402d1215485f130113132e2bfb220550df06019906a906024f065f06020b061b060207060600120f50181029500015003fe13fe13312392f5e5d5d5d 5de9393f1101332f5d2b5d11332f2b5de1322fe11239392f2f123910e131302111342623233533323e0235342623220607273e0333321e0215140e0207151e03151533112311029c818a81613d644827 736c47814b3f284d525a355690693a1c33462b2c523f26a0b7012b5e65991227402d4d4d262293131d1309264a6d46324d3b290e0b0e2c425b3d91fde9017d0000010000ffe906ec05b6003100924065 d706e7060206070101d701f70102015a1c17101018488b17011710070e48171c315a1eb01e01e01c01b41cc41cd41c03001c501c901ca01c04071c1e1c1e0e245a2765334f336f337f339f33af33df33 062033010f33010e252512015f1c032112602c0b13003f33e1323fe112392f012f5d5d5d10f6e11139392f2f5e5d5d5d5d10e111332b5d2b10e15d71325d313001210e03070e03232226273516163332 3e023736361212372111141633323635113311140e0223222e023503d9fe850f2021211014354f6e4e234a1c173a20303e2a1a0c0c20272b1602d0636e6f62b7386691595792683a051271f5ebd45167 a26f3b0e0b9a0d103f62753639c80106013aaafbd18177778101c9fe2d6998622e2c60996c0000010010ffec0600044a0028005c4039014611284713a01301db1101c411019011a01102241101101101 11131113091b471e552a7f2acf2aef2a03091c1c0c0150110f180c4f230616003f33e1323fe112392f012f5d10f6e11139392f2f5d5d5d5d5d5d10e110e1313001210202060623222627351633323636 12372111141e0233323635113311140e0223222e023502fafefe14405f82561c3110161c375945331202541531503b6960b62f5f8f605c91663603b0fefdfe94e6690606830675f1016ffafd3d416241 2082820135fec16998622e2e62966900000100c7ffec072d05b6001d005c40371b135aa00001000017065a09651fc01f01af1fbf1f02201f010f1f011a165a17641e155f1a07070f1a01081a1a171c18 031712035f0e13003fe13f3f3312392f5e5d332f10e10110f6e1325d5d5d5d10f6e111392f5de132313001141633323635113311140e0223222e02351121112311331121113304d5626f6e63b6386690 595891683afd66baba029aba01878177778101c9fe2d6998622e2c60996c012dfd5605b6fd980268000100aeffec068b044a001f006c4047021a4705051e0d4710552100212021024021502180219021 b021f021060f2101011d471e54201c50010e0eeb0101a901b901020f011f012f01030601011e031f0f1e150a501516003fe13f3f3312392f5e5d5d5d332f10e10110f6e1325d5d7110f6e111392fe132 3130011121113311141e0233323635113311140e0223222e0235352111231101640221b61531503b6a5fb62f5f8f605b926636fddfb6044afe3901c7fd3d4162412082820135fec16998622e2e629669 6efe17044a000001007dffec055205cb002a004740292a2a0c295b011440090e48141401672cbf2c01702c011f5b0c662b2a5f0000241a5f151104245f0713003fe13f33e112392fe10110f6e15d5d10 e6322f2b10e112392f3130012115140206062322262602353412362433321617072e0323220e0215141e0233323e0235210317023b428ede9c9df2a6565fb6010bab6fcc58482453585d2e7abc7f4236 70ab756c955d29fe8802f656a8fefeaf5b69c30117aeac0116c3692c2aa2111e170e5198da8982d89c564277a66400010071ffec047b045e00280081405a28280c27470114400c1148141401572a142a 242a02e42af42a02d02a0102402a502a802aa02ac02a051d480c562928500040151948cb00db00eb0003a900b900028f009f00020b001b002b000306000022185015111022500716003fe13f33e11239 2f5e5d5d5d5d2be10110f6e15d5f5d5d7110e6322f2b10e112392f3130012115140e0223222e0235343e023332161707262623220e0215141e0233323e023521027b02003978ba8187cb88444c95db8f 6fad4d3e3c945b619565342956875e51744a23feb8024a4482c889474f93d38482d3945025278d1d293a6d9d625d9b703e2d5070440000010014ffec04c905b600190065402f065a09651b4f1b7f1b9f 1baf1b04001b01af18ef18028418011818005a134015010f15010815155713671377130313b8ffc04010070a481319155f1607071603035f0e13003fe13f392f10e132012f2b5d332f5e5d5d10e1322f 5d5d5d5d10f6e1313001141633323635113311140e0223222e02351121352115210271626f6e62b7386690595891693afe5e03fefe5f01878177778101c9fe2d6998622e2c60996c0395a4a400010029 ffec046f044a001b006d404a0d4710551d0f1d01cf1def1dff1d03301d401d601d030f1d1f1d020f0301cc03010f03bf030206030305471a60007000d000031f00010000001a101a021a0e0e010a5015 16040050010f003fe1323fe111392f012f5d332f5d5d10e1322f5e5d5d715d5d5d7110f6e13130133521152111141e0233323635113311140e0223222e023511290335fec11531503b695fb72f5f8f60 5c92663603b09a9afdd74162412082820135fec16998622e2e62966902350001006fffec040c05cb0039005db4135b341a00b8ffc0402e171a48001a001a2f0a0a273b9f3b01205b2f663a341b60aa18 017818010f1801081818052360262a130e600b0504003f33e13f33e111392f5e5d5d5de1390110f6e15d10ce322f1239392f2f2b1239e1313013343e0233321e021707262623220e0215141e02333315 23220e021514163332363715060623222e0235343e0237352e039c3b73a96d487b695a265c4ba267395f44262c578257c3bf5d926535aaa46ccc5353c08080c38342315f89574a78542d04604f856136 1829361f7d36431e3a53363e6448279721436543898e312baa26253c6f9c60487b5e3d0b060c395877000001005cffec036a045e0037006db432461e0123b8ffc0403d171a4823012301182b0f39d039 e039f039038f390140390105471856381d0250ef3701a937b937020f371f372f37030637370a2f502c28100a500f1316003f33e13f33e112392f5e5d5d5de1390110f6e15d5d5d10ce321139392f2f2b 1239e13130011523220615141e0233323e023715060623222e0235343e0237352e0335343e023332161707262623220615141e0233029e818a85294660373361574d1e3caf736ea26b35284359302b49 351e3a6990565aa2503f4b8347666d26445f390287995b5e33452a120e161e10a21d28305678473d5b40290d0b0e293b4d32466d4a2625279322264d4d2d40271200ffff0000fe6d052f05b6022601b5 00000107038003b80000000db4010131310001103c1135003500ffff0010fe6d044c044a022601d500000107038102d50000000db4010126260001103c1135003500ffff0000fe9804dd05bc02260024 00000107026704d300000013400b021814270200151b040725012b35002b3500ffff005efe98039c045e02260044000001070267046f00000013400b02361727020d33390c2225012b35002b3500ffff 0000000004dd07e10226002400000107026604d101520013400b021b052602212a15040725012b35002b3500ffff005effec039c068f02260044000001070266047500000013400b0239112602364833 0c2225012b35002b3500ffff0000000004dd07d10226002400000107037704cb01520019b603021505260302b8ffffb41d15040725012b3535002b353500ffff005effec0447067f0226004400000107 0377048900000017400d03023311260302333b330c2225012b3535002b353500ffff0000000004dd07d10226002400000107037804cb01520019b603021d05260302b8ffffb4251d040725012b353500 2b353500ffff0012ffec039c067f02260044000001070378048900000017400d03023b1126030233433b0c2225012b3535002b353500ffff0000000004dd084a0226002400000107037904cb01520019 b603021505260302b8ffffb41d15040725012b3535002b353500ffff005effec040606f802260044000001070379048900000017400d03023311260302333b330c2225012b3535002b353500ffff0000 000004dd08620226002400000107037a04cb01520019b603021d05260302b8ffffb4251d040725012b3535002b353500ffff005effec039c07100226004400000107037a048900000017400d03023b11 2603020b3b330c2225012b3535002b353500ffff0000fe9804dd07730226002400000027014b001f01520107026704d3000000254010032d14270215052603002a3004072502b8ffffb41d1504072501 2b352b35002b352b3500ffff005efe98039c06210226004400000026014bd40001070267046f000000224016034b172702331126030d484e0c222502253b330c2225012b352b35002b352b35ffff0000 000004dd08130226002400000107037b04cb01520017400d03022605260302002921040725012b3535002b353500ffff005effec039c06c10226004400000107037b047b00000017400d030244112603 021e473f0c2225012b3535002b353500ffff0000000004dd08130226002400000107037c04cb01520017400d03022605260302002921040725012b3535002b353500ffff005effec039c06c102260044 00000107037c047b00000017400d030244112603021e473f0c2225012b3535002b353500ffff0000000004dd08580226002400000107037d04cb01520017400d03021a05260302001d15040725012b35 35002b353500ffff005effec039c07060226004400000107037d047b00000017400d030238112603021e3b330c2225012b3535002b353500ffff0000000004dd08620226002400000107037e04cb0152 0017400d03021a05260302001d15040725012b3535002b353500ffff005effec039c07100226004400000107037e047b00000017400d030238112603021e505e0c2225012b3535002b353500ffff0000 fe9804dd075b0226002400000027014e0021016d0107026704d3000000224016032e1427021a052603002b3104072502001f15040725012b352b35002b352b35ffff005efe98039c05ee022600440000 0026014ed40001070267046f000000224016034c172702381126030d494f0c2225021e3d330c2225012b352b35002b352b35ffff00c7fe9803be05b60226002800000107026704aa00000013400b010f 142701030c12010025012b35002b3500ffff0071fe9803e1045e0226004800000107026704be00000013400b022b17270230282e050f25012b35002b3500ffff00c7000003be07e10226002800000107 0266049101520013400b01120526010d210c010025012b35002b3500ffff0071ffec03e1068f02260048000001070266049800000013400b022e1126022d3d28050f25012b35002b3500ffff00c70000 03be073502260028000001070152ffd401520015b40114052601b8fffbb41523010025012b35002b3500ffff0071ffec03e105e302260048000001060152de000013400b02301126021e313f050f2501 2b35002b3500ffff00c70000045c07d102260028000001070377049e01520019b602010c05260201b8fffdb4140c010025012b3535002b353500ffff0071ffec0447067f022600480000010703770489 00000017400d03022811260302033028050f25012b3535002b353500ffff0027000003be07d102260028000001070378049e01520019b602011405260201b8fffdb41c14010025012b3535002b353500 ffff0012ffec03e1067f02260048000001070378048900000017400d03023011260302033830050f25012b3535002b353500ffff00c70000041b084a02260028000001070379049e01520019b602010c 05260201b8fffdb4140c010025012b3535002b353500ffff0071ffec040606f802260048000001070379048900000017400d03022811260302033028050f25012b3535002b353500ffff00c7000003be 08620226002800000107037a049e01520019b602011405260201b8fffdb41c14010025012b3535002b353500ffff0071ffec03e107100226004800000107037a048900000017400d0302301126030203 3830050f25012b3535002b353500ffff00c7fe9803be07730226002800000027014bfff101520107026704aa00000025401002241427010c05260203212701002501b8fffdb4140c010025012b352b35 002b352b3500ffff0071fe9803e106210226004800000026014bde000107026704aa0000002240160340172702281126031c3d43050f2502033028050f25012b352b35002b352b35ffff005200000264 07e10226002c00000107026603b001520013400b011205260113210c010025012b35002b3500ffff0062000001d7068f022600f3000001070266035e00000013400b010a112601131904010025012b35 002b3500ffff0052fe98026405b60226002c00000107026703be00000015b4010f142701b8ffffb40c12010025012b35002b3500ffff009efe98017505e50226004c000001070267036d00000015b402 15172702b8fffeb41218040c25012b35002b3500ffff007dfe98057105cd02260032000001070267055c00000013400b022b14270200282e0a0025012b35002b3500ffff0071fe98042d045e02260052 00000107026704b200000015b40223172702b8ffffb420260a0025012b35002b3500ffff007dffec057107e102260032000001070266054e01520013400b022e052602153d280a0025012b35002b3500 ffff0071ffec042d068f0226005200000107026604a400000013400b02261126021335200a0025012b35002b3500ffff007dffec057107d102260032000001070377055801520017400d030228052603 020530280a0025012b3535002b353500ffff0071ffec0468067f0226005200000107037704aa00000019b603022011260302b8fffab428200a0025012b3535002b353500ffff007dffec057107d10226 0032000001070378055801520017400d030230052603020538300a0025012b3535002b353500ffff0033ffec042d067f0226005200000107037804aa00000019b603022811260302b8fffab430280a00 25012b3535002b353500ffff007dffec0571084a02260032000001070379055801520017400d030228052603020530280a0025012b3535002b353500ffff0071ffec042d06f802260052000001070379 04aa00000019b603022011260302b8fffab428200a0025012b3535002b353500ffff007dffec057108620226003200000107037a055801520017400d030230052603020538300a0025012b3535002b35 3500ffff0071ffec042d07100226005200000107037a04aa00000019b603022811260302b8fffab430280a0025012b3535002b353500ffff007dfe98057107730226003200000027014b00ae01520107 0267055c000000224016034014270228052603003d430a0025020530280a0025012b352b35002b352b35ffff0071fe98042d06210226005200000026014bfb000107026704b200000028400903381727 0220112603b8ffffb5353b0a002502b8fffab428200a0025012b352b35002b352b35ffff007dffec062507730226025f000001070076010601520013400b024105260202353b130125012b35002b3500 ffff0071ffec04f406210226026000000106007650000015b4023a112602b8ffebb42d330a1925012b35002b3500ffff007dffec062507730226025f000001070043005401520015b40235052602b8ff 51b43b35130125012b35002b3500ffff0071ffec04f4062102260260000001060043d8000015b4022e112602b8ffd7b4342d0a0025012b35002b3500ffff007dffec062507e10226025f000001070266 054e01520015b4023c052602b8ffbcb44a35130125012b35002b3500ffff0071ffec04f4068f0226026000000107026604a400000015b40234112602b8ffb0b4422d0a1925012b35002b3500ffff007d ffec062507350226025f000001070152007d01520015b4023d052602b8ff96b43e4c130125012b35002b3500ffff0071ffec04f405e302260260000001060152e2000015b4022d112602b8fffdb43644 0a0025012b35002b3500ffff007dfe98062506140226025f000001070267055c00000015b40238142702b8ffa7b4353b130125012b35002b3500ffff0071fe9804f404f20226026000000107026704b2 00000015b40230172702b8ff9bb42d330a1925012b35002b3500ffff00b8fe9804dd05b802260038000001070267052f00000013400b011b14270100181e0b0025012b35002b3500ffff00a4fe980408 044a0226005800000107026704b800000015b4011e172701b8fffeb41b210c1925012b35002b3500ffff00b8ffec04dd07e102260038000001070266051d01520013400b011e052601112d180b002501 2b35002b3500ffff00a4ffec0408068f0226005800000107026604a600000013400b01211126010e301b0c1925012b35002b3500ffff00b8ffec064e07730226026100000107007600c501520015b401 31052601b8ff90b4252b180825012b35002b3500ffff00a4ffec057906210226026200000106007660000011b10101b8ff9fb4282e0c2125012b35003500ffff00b8ffec064e07730226026100000107 0043003d01520015b40125052601b8ff08b42b25180825012b35002b3500ffff00a4ffec0579062102260262000001060043a3000011b10101b8fee2b42e280c2125012b35003500ffff00b8ffec064e 07e102260261000001070266051d01520011b10101b8ff59b43a25180825012b35003500ffff00a4ffec0579068f0226026200000107026604a600000011b10101b8ff56b43d280c2125012b35003500 ffff00b8ffec064e073502260261000001070152006001520015b4012d052601b8ff47b42e3c180825012b35002b3500ffff00a4ffec057905e302260262000001060152f3000011b10101b8ff4eb431 3f0c2125012b35003500ffff00b8fe98064e061402260261000001070267052f00000015b40128142701b8ff48b4252b180825012b35002b3500ffff00a4fe98057904f20226026200000107026704b8 00000015b4012b172701b8ff45b4282e0c2125012b35002b3500ffff0000fe98043705b60226003c000001070267047f00000015b4010c142701b8ffffb4090f070225012b35002b3500ffff000afe14 03df044a0226005c000001070267058b00000011b10101b80132b42329000f25012b35003500ffff00000000043707e10226003c000001070266047101520013400b010f052601141e09070225012b35 002b3500ffff000afe1403df068f0226005c000001070266044a00000013400b0129112601143823000f25012b35002b3500ffff00000000043707350226003c000001070152ffb301520013400b0111 052601011220070225012b35002b3500ffff000afe1403df05e30226005c0000010601528c000013400b012b112601012c3a000f25012b35002b3500ffff0071febc049e0614022600d3000001070042 00b40000000eb90002ffd2b43a390b2325012b350002fbdb04d9feba0621000d001b002d4019140e0e07405000013f004f000200150792800f0f015f010201002f5d331aed32012f5d5d1acd392fcd31 3001232e032735331e031705232e032735331e0317feba6423514d3f10c6102a2f3015fe966423524d3f10c7102a2f301504d91c5358511b152350514c1d1b1c5358511b152350514c1d0002fc6a04d9 ffbe067f0010001c005240310d0c0410170117402f1c3f1c4f1c031c04041c2f005f008f009f000400c008161b1b047f0c8f0c020c80000f085f080208002f5d331acc5d32392fcd012f1acc5d39393d 2f182f5d1acd5d11333331300123262627060607233536363733161617273e0337331506060723fed964336c34366a3365337530c03074334e14211d1d10b42d6a376504d92254303054221b3b844545 843bc2192d2e3421153c672b0002fb8904d9fedd067f0010001c004a402a04030c1f160116401c0c0c1c2f085f088f089f080408c0001612120c7f038f03020380100f085f080208002f5d331acd5d32 392fcd012f1acc5d39393d2f182f1acd5d11333331300136363733161617152326262706060723372326262735331e0317fc6f337430c030743364336a36356b33644d64386a2db4101d1e201404f43b 844545843b1b225430305422c32b673c1521342e2d190002fc6a04d9ff7d06f800100028005e403816191920060e48191c11802f233f234f2303230404232f005f008f009f000400c0081619191f2618 18047f0c8f0c020c80000f085f080208002f5d331acc5d32392fcc32391133012f1acc5d39393d2f182f5d1acd32392b11333130012326262706060723353636373316161713140e0207072327363635 342623220607353636333216fed964336c34366a3365337530c0307433a414222e1906560a3741392b16270b0b261f636404d92254303054221b3b844545843b01761d2b1e15065183091f2525190303 520303450002fc6404d9fee907100010002c0061403b04030c0c0028282f085f088f089f08040800c01a1a0027168ecf1fdf1fef1f031f40090d481f1f248e1911110c7f038f03020380100f085f0802 08002f5d331acd5d32322f33e1332f2b5de133012f332f1a10cc5d322f11393d2f33333130013636373316161715232626270606072301222e0223220607233e0333321e0233323637330e03fc6f3374 30c030743364336a36356b336401be244745401c282a0e5d051d30412a254a453e1a282a0e5c051c304104f43b844545843b1b225430305422015a1c221c2a3230513b211c221c2b3130513b21000002 fc7304d9fecd06c1000b001f0032401906800b0b1f2f0c010cc01514050b0b1f14801a0f115f110211002f5d331acd32322fcc012f331acc5d32392f1acd3130013e0337331506060723250e03232226 27331e0333323e0237fd5e14201e1d10b42d6a3765016f052b4d6e469291066c041b30442c244133210505f8192c2e3521153c672c063c6345268c7e2b321907091b31280002fc7304d9fecd06c1000b 001f0038401e05800b401316480b0b1f2f0c010cc015140500001f14801a0f115f110211002f5d331acd32322fcd012f331acc5d32392f2b1acd3130012326262735331e0317170e0323222627331e03 33323e0237fdd164386a2db4101d1e2014fc052b4d6e469291066c041b30442c244133210505dd2c673c1521352e2c19153c6345268c7e2b321907091b3128000002fc7304d9fecd07060013002a0042 4021191c1c1f14802525132f0001000908191c1c2228c01b1b1308800e0f055f050205002f5d331acd32392f1acc32391133012f33cc5d32392f1acc323911333130010e0323222627331e0333323e02 3727140e02070723273636353426232206073536333216fecd052b4d6e469291066c041b30442c24413321052b14222e1906560a3841392c15270b153a646305e33c6345268c7e2b321907091b312896 1d2b1f1406295a09202525180303520645000002fc6404d9fee907100013002f004840271c1d1d082a2b2b132f000100c009082a19cf22df22ef220322271c14141308800e0f055f050205002f5d331a cd32322f3333cd5d3232012f331acc5d32322f3311332f333130010e0323222627331e0333323e023727222e0223220607233e0333321e0233323637330e03fecd052b4d6e469291066c041b30442c24 413321052f244745401c282a0e5d051d30412a254a453e1a282a0e5c051c304105e33c6345268c7e2b321907091b3128501c221c2a3230513b211c221c2b3130513b210000010031fe42017100000014 001840090f8000080802120b02002f2f33012f332f331acc3130173427331e0315140623222627351616333236db8b811a392f1e65641d401a0e2d192234ee69851334404b2a5a6808087104052b0001 0010fe6d017700a600110012b60901100d06fa00002f3f33012f33c4313025110e032322262735161633323635110177011a39593f263f160e3b222e32a6fed942664624110996070e3131013c000001 0010fe6d0177009a00110012b60901100d06fa00002f3f33012f33c4313025110e032322262735161633323635110177011a39593f263f160e3b222e329afee542664624110996070e31310130000000 0000001b014a0001000000000000003400000001000000000001000a003400010000000000020007003e0001000000000003001500450001000000000004000a00340001000000000005000c005a0001 000000000006000900660001000000000007004e006f0001000000000008001400bd000100000000000a006700d1000100000000000d002e0138000100000000000e002a01660001000000000012000a 00340003000104090000006801900003000104090001001401f80003000104090002000e020c0003000104090003002a021a0003000104090004001401f80003000104090005002c0244000300010409 0006001202700003000104090007009c028200030001040900080028031e000300010409000a00ce0346000300010409000b00380414000300010409000c005c044c000300010409000d005c04a80003 00010409000e005405044469676974697a6564206461746120636f7079726967687420a920323030372c20476f6f676c6520436f72706f726174696f6e2e44726f69642053616e73526567756c617241 7363656e646572202d2044726f69642053616e7356657273696f6e20312e303044726f696453616e7344726f696420697320612074726164656d61726b206f6620476f6f676c6520616e64206d617920 6265207265676973746572656420696e206365727461696e206a7572697364696374696f6e732e417363656e64657220436f72706f726174696f6e44726f69642053616e7320697320612068756d616e 6973742073616e732073657269662074797065666163652064657369676e656420666f72207573657220696e746572666163657320616e6420656c656374726f6e696320636f6d6d756e69636174696f 6e2e4c6963656e73656420756e6465722074686520417061636865204c6963656e73652c2056657273696f6e20322e30687474703a2f2f7777772e6170616368652e6f72672f6c6963656e7365732f4c 4943454e53452d322e30004400690067006900740069007a006500640020006400610074006100200063006f0070007900720069006700680074002000a900200032003000300037002c00200047006f 006f0067006c006500200043006f00720070006f0072006100740069006f006e002e00440072006f00690064002000530061006e00730052006500670075006c006100720041007300630065006e0064 006500720020002d002000440072006f00690064002000530061006e007300560065007200730069006f006e00200031002e003000300020006200750069006c0064002000310031003300440072006f 0069006400530061006e007300440072006f0069006400200069007300200061002000740072006100640065006d00610072006b0020006f006600200047006f006f0067006c006500200061006e0064 0020006d006100790020006200650020007200650067006900730074006500720065006400200069006e0020006300650072007400610069006e0020006a007500720069007300640069006300740069 006f006e0073002e0041007300630065006e00640065007200200043006f00720070006f0072006100740069006f006e00440072006f00690064002000530061006e0073002000690073002000610020 00680075006d0061006e006900730074002000730061006e0073002000730065007200690066002000740079007000650066006100630065002000640065007300690067006e0065006400200066006f 00720020007500730065007200200069006e0074006500720066006100630065007300200061006e006400200065006c0065006300740072006f006e0069006300200063006f006d006d0075006e0069 0063006100740069006f006e002e0068007400740070003a002f002f007700770077002e0061007300630065006e0064006500720063006f00720070002e0063006f006d002f0068007400740070003a 002f002f007700770077002e0061007300630065006e0064006500720063006f00720070002e0063006f006d002f007400790070006500640065007300690067006e006500720073002e00680074006d 006c004c006900630065006e00730065006400200075006e006400650072002000740068006500200041007000610063006800650020004c006900630065006e00730065002c00200056006500720073 0069006f006e00200032002e00300068007400740070003a002f002f007700770077002e006100700061006300680065002e006f00720067002f006c006900630065006e007300650073002f004c0049 00430045004e00530045002d0032002e003000000002000000000000ff660066000000000000000000000000000000000000000003820000010200020003000400050006000700080009000a000b000c 000d000e000f0010001100120013001400150016001700180019001a001b001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f00300031003200330034 00350036003700380039003a003b003c003d003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c 005d005e005f0060006100ac00a30084008500bd009600e80086008e008b009d00a900a40103008a01040083009300f200f3008d00970088010500de00f1009e00aa00f500f400f600a200ad00c900c7 00ae006200630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d5006800eb00ed0089006a0069006b006d006c006e00a0006f007100700072 0073007500740076007700ea0078007a0079007b007d007c00b800a1007f007e0080008100ec00ee00ba0106010701080109010a010b00fd00fe010c010d010e010f00ff010001100111011201130114 01150116011701180119011a011b011c011d011e011f00f800f90120012101220123012401250126012701280129012a012b012c012d012e012f013000d7013101320133013401350136013701380139 013a013b013c013d013e013f00e200e30140014101420143014401450146014701480149014a014b014c014d014e00b000b1014f01500151015201530154015501560157015800fb00fc00e400e50159 015a015b015c015d015e015f0160016101620163016401650166016701680169016a016b016c016d016e00bb016f01700171017200e600e7017300a6017401750176017701780179017a017b00d800e1 017c00db00dc00dd00e000d900df017d017e017f0180018101820183018401850186018701880189018a018b018c018d018e018f0190019101920193019401950196019701980199019a019b019c019d 019e019f01a001a101a201a301a401a501a601a701a801a901aa01ab01ac01ad01ae01af01b001b101b201b301b401b5009b01b601b701b801b901ba01bb01bc01bd01be01bf01c001c101c201c301c4 01c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301d401d501d601d701d801d901da01db01dc01dd01de01df01e001e101e201e301e401e501e601e701e801e901ea01eb01ec 01ed01ee01ef01f001f101f201f301f401f501f601f701f801f901fa01fb01fc01fd01fe01ff0200020102020203020402050206020702080209020a020b020c020d020e020f02100211021202130214 02150216021702180219021a021b021c021d021e021f022002210222022302240225022602270228022900b200b3022a022b00b600b700c4022c00b400b500c5008200c2008700ab00c6022d022e00be 00bf022f00bc023000f7023102320233023402350236008c009f023702380239023a023b0098023c009a009900ef00a50092009c00a7008f0094009500b9023d023e023f024002410242024302440245 0246024702480249024a024b024c024d024e024f0250025102520253025402550256025702580259025a025b025c025d025e025f0260026102620263026402650266026702680269026a026b026c026d 026e026f0270027102720273027402750276027702780279027a027b027c027d027e027f0280028102820283028402850286028702880289028a028b028c028d028e028f029002910292029302940295 0296029702980299029a029b029c029d029e029f02a002a102a202a302a402a502a602a702a802a902aa02ab02ac02ad02ae02af02b002b102b202b302b402b502b602b702b802b902ba02bb02bc02bd 02be02bf02c002c102c202c302c402c502c602c702c802c902ca02cb02cc02cd02ce02cf02d002d102d202d302d402d502d602d702d802d902da02db02dc02dd02de02df02e002e102e202e302e402e5 02e602e702e802e902ea02eb02ec02ed02ee02ef02f002f102f202f302f402f502f602f702f802f902fa02fb02fc02fd02fe02ff0300030103020303030403050306030703080309030a030b030c030d 030e030f0310031103120313031403150316031703180319031a031b031c031d031e031f0320032103220323032403250326032703280329032a032b032c032d032e032f033003310332033303340335 0336033703380339033a033b033c033d033e033f0340034103420343034403450346034703480349034a034b034c034d034e034f0350035103520353035403550356035703580359035a035b035c035d 035e035f0360036103620363036403650366036703680369036a036b036c036d036e036f0370037103720373037403750376037703780379037a037b037c037d037e037f038003810382038303840385 0386038703880389038a052e6e756c6c07756e6930304144096f76657273636f72650e706572696f6463656e746572656407416d6163726f6e07616d6163726f6e064162726576650661627265766507 416f676f6e656b07616f676f6e656b0b4363697263756d666c65780b6363697263756d666c65780443646f740463646f7406446361726f6e06646361726f6e064463726f6174066463726f617407456d 6163726f6e07656d6163726f6e06456272657665066562726576650a45646f74616363656e740a65646f74616363656e7407456f676f6e656b07656f676f6e656b06456361726f6e06656361726f6e0b 4763697263756d666c65780b6763697263756d666c65780447646f740467646f740c47636f6d6d61616363656e740c67636f6d6d61616363656e740b4863697263756d666c65780b6863697263756d66 6c657804486261720468626172064974696c6465066974696c646507496d6163726f6e07696d6163726f6e064962726576650669627265766507496f676f6e656b07696f676f6e656b0a49646f746163 63656e7402494a02696a0b4a63697263756d666c65780b6a63697263756d666c65780c4b636f6d6d61616363656e740c6b636f6d6d61616363656e740c6b677265656e6c616e646963064c6163757465 066c61637574650c4c636f6d6d61616363656e740c6c636f6d6d61616363656e74064c6361726f6e066c6361726f6e044c646f74046c646f74064e6163757465066e61637574650c4e636f6d6d616163 63656e740c6e636f6d6d61616363656e74064e6361726f6e066e6361726f6e0b6e61706f7374726f70686503456e6703656e67074f6d6163726f6e076f6d6163726f6e064f6272657665066f62726576 650d4f68756e676172756d6c6175740d6f68756e676172756d6c61757406526163757465067261637574650c52636f6d6d61616363656e740c72636f6d6d61616363656e7406526361726f6e06726361 726f6e06536163757465067361637574650b5363697263756d666c65780b7363697263756d666c65780c54636f6d6d61616363656e740c74636f6d6d61616363656e7406546361726f6e06746361726f 6e04546261720474626172065574696c6465067574696c646507556d6163726f6e07756d6163726f6e0655627265766506756272657665055572696e67057572696e670d5568756e676172756d6c6175 740d7568756e676172756d6c61757407556f676f6e656b07756f676f6e656b0b5763697263756d666c65780b7763697263756d666c65780b5963697263756d666c65780b7963697263756d666c657806 5a6163757465067a61637574650a5a646f74616363656e740a7a646f74616363656e74056c6f6e67730a4172696e6761637574650a6172696e676163757465074145616375746507616561637574650b 4f736c61736861637574650b6f736c61736861637574650c53636f6d6d61616363656e740c73636f6d6d61616363656e74066d6163726f6e05746f6e6f730d6469657265736973746f6e6f730a416c70 6861746f6e6f7309616e6f74656c6569610c457073696c6f6e746f6e6f7308457461746f6e6f7309496f7461746f6e6f730c4f6d6963726f6e746f6e6f730c557073696c6f6e746f6e6f730a4f6d6567 61746f6e6f7311696f74616469657265736973746f6e6f7305416c70686104426574610547616d6d6107756e693033393407457073696c6f6e045a6574610345746105546865746104496f7461054b61 707061064c616d626461024d75024e75025869074f6d6963726f6e0250690352686f055369676d610354617507557073696c6f6e03506869034368690350736907756e69303341390c496f7461646965 72657369730f557073696c6f6e64696572657369730a616c706861746f6e6f730c657073696c6f6e746f6e6f7308657461746f6e6f7309696f7461746f6e6f7314757073696c6f6e6469657265736973 746f6e6f7305616c70686104626574610567616d6d610564656c746107657073696c6f6e047a6574610365746105746865746104696f7461056b61707061066c616d62646107756e6930334243026e75 027869076f6d6963726f6e0372686f067369676d6131057369676d610374617507757073696c6f6e037068690363686903707369056f6d6567610c696f746164696572657369730f757073696c6f6e64 696572657369730c6f6d6963726f6e746f6e6f730c757073696c6f6e746f6e6f730a6f6d656761746f6e6f73096166696931303032330961666969313030353109616669693130303532096166696931 3030353309616669693130303534096166696931303035350961666969313030353609616669693130303537096166696931303035380961666969313030353909616669693130303630096166696931 3030363109616669693130303632096166696931303134350961666969313030313709616669693130303138096166696931303031390961666969313030323009616669693130303231096166696931 3030323209616669693130303234096166696931303032350961666969313030323609616669693130303237096166696931303032380961666969313030323909616669693130303330096166696931 3030333109616669693130303332096166696931303033330961666969313030333409616669693130303335096166696931303033360961666969313030333709616669693130303338096166696931 3030333909616669693130303430096166696931303034310961666969313030343209616669693130303433096166696931303034340961666969313030343509616669693130303436096166696931 3030343709616669693130303438096166696931303034390961666969313030363509616669693130303636096166696931303036370961666969313030363809616669693130303639096166696931 3030373009616669693130303732096166696931303037330961666969313030373409616669693130303735096166696931303037360961666969313030373709616669693130303738096166696931 3030373909616669693130303830096166696931303038310961666969313030383209616669693130303833096166696931303038340961666969313030383509616669693130303836096166696931 3030383709616669693130303838096166696931303038390961666969313030393009616669693130303931096166696931303039320961666969313030393309616669693130303934096166696931 3030393509616669693130303936096166696931303039370961666969313030373109616669693130303939096166696931303130300961666969313031303109616669693130313032096166696931 3031303309616669693130313034096166696931303130350961666969313031303609616669693130313037096166696931303130380961666969313031303909616669693130313130096166696931 3031393309616669693130303530096166696931303039380657677261766506776772617665065761637574650677616375746509576469657265736973097764696572657369730659677261766506 796772617665096166696930303230380d756e64657273636f726564626c0d71756f74657265766572736564066d696e757465067365636f6e64096578636c616d64626c096e7375706572696f720961 666969303839343106706573657461044575726f09616669693631323438096166696936313238390961666969363133353209657374696d61746564096f6e656569676874680c746872656565696768 7468730b66697665656967687468730c736576656e656967687468730544656c746107756e694642303107756e69464230320d637972696c6c6963627265766508646f746c6573736a106361726f6e63 6f6d6d61616363656e740b636f6d6d61616363656e7411636f6d6d61616363656e74726f746174650c7a65726f7375706572696f720c666f75727375706572696f720c666976657375706572696f720b 7369787375706572696f720d736576656e7375706572696f720d65696768747375706572696f720c6e696e657375706572696f7207756e693230303007756e693230303107756e693230303207756e69 3230303307756e693230303407756e693230303507756e693230303607756e693230303707756e693230303807756e693230303907756e693230304107756e693230304207756e694645464607756e69 4646464307756e694646464407756e693031463007756e693032424307756e693033443107756e693033443207756e693033443607756e693145334507756e693145334607756e693145303007756e69 3145303107756e693146344407756e69303246330964617369616f78696107756e694642303307756e6946423034054f686f726e056f686f726e0555686f726e0575686f726e07756e69303330300775 6e693033303107756e693033303304686f6f6b08646f7462656c6f7707756e693034303007756e693034304407756e693034353007756e693034354407756e693034363007756e693034363107756e69 3034363207756e693034363307756e693034363407756e693034363507756e693034363607756e693034363707756e693034363807756e693034363907756e693034364107756e693034364207756e69 3034364307756e693034364407756e693034364507756e693034364607756e693034373007756e693034373107756e693034373207756e693034373307756e693034373407756e693034373507756e69 3034373607756e693034373707756e693034373807756e693034373907756e693034374107756e693034374207756e693034374307756e693034374407756e693034374507756e693034374607756e69 3034383007756e693034383107756e693034383207756e693034383307756e693034383407756e693034383507756e693034383607756e693034383807756e693034383907756e693034384107756e69 3034384207756e693034384307756e693034384407756e693034384507756e693034384607756e693034393207756e693034393307756e693034393407756e693034393507756e693034393607756e69 3034393707756e693034393807756e693034393907756e693034394107756e693034394207756e693034394307756e693034394407756e693034394507756e693034394607756e693034413007756e69 3034413107756e693034413207756e693034413307756e693034413407756e693034413507756e693034413607756e693034413707756e693034413807756e693034413907756e693034414107756e69 3034414207756e693034414307756e693034414407756e693034414507756e693034414607756e693034423007756e693034423107756e693034423207756e693034423307756e693034423407756e69 3034423507756e693034423607756e693034423707756e693034423807756e693034423907756e693034424107756e693034424207756e693034424307756e693034424407756e693034424507756e69 3034424607756e693034433007756e693034433107756e693034433207756e693034433307756e693034433407756e693034433507756e693034433607756e693034433707756e693034433807756e69 3034433907756e693034434107756e693034434207756e693034434307756e693034434407756e693034434507756e693034434607756e693034443007756e693034443107756e693034443207756e69 3034443307756e693034443407756e693034443507756e693034443607756e693034443707756e693034443807756e693034443907756e693034444107756e693034444207756e693034444307756e69 3034444407756e693034444507756e693034444607756e693034453007756e693034453107756e693034453207756e693034453307756e693034453407756e693034453507756e693034453607756e69 3034453707756e693034453807756e693034453907756e693034454107756e693034454207756e693034454307756e693034454407756e693034454507756e693034454607756e693034463007756e69 3034463107756e693034463207756e693034463307756e693034463407756e693034463507756e693034463607756e693034463707756e693034463807756e693034463907756e693034464107756e69 3034464207756e693034464307756e693034464407756e693034464507756e693034464607756e693035303007756e693035303107756e693035303207756e693035303307756e693035303407756e69 3035303507756e693035303607756e693035303707756e693035303807756e693035303907756e693035304107756e693035304207756e693035304307756e693035304407756e693035304507756e69 3035304607756e693035313007756e693035313107756e693035313207756e693035313307756e693145413007756e693145413107756e693145413207756e693145413307756e693145413407756e69 3145413507756e693145413607756e693145413707756e693145413807756e693145413907756e693145414107756e693145414207756e693145414307756e693145414407756e693145414507756e69 3145414607756e693145423007756e693145423107756e693145423207756e693145423307756e693145423407756e693145423507756e693145423607756e693145423707756e693145423807756e69 3145423907756e693145424107756e693145424207756e693145424307756e693145424407756e693145424507756e693145424607756e693145433007756e693145433107756e693145433207756e69 3145433307756e693145433407756e693145433507756e693145433607756e693145433707756e693145433807756e693145433907756e693145434107756e693145434207756e693145434307756e69 3145434407756e693145434507756e693145434607756e693145443007756e693145443107756e693145443207756e693145443307756e693145443407756e693145443507756e693145443607756e69 3145443707756e693145443807756e693145443907756e693145444107756e693145444207756e693145444307756e693145444407756e693145444507756e693145444607756e693145453007756e69 3145453107756e693145453207756e693145453307756e693145453407756e693145453507756e693145453607756e693145453707756e693145453807756e693145453907756e693145454107756e69 3145454207756e693145454307756e693145454407756e693145454507756e693145454607756e693145463007756e693145463107756e693145463407756e693145463507756e693145463607756e69 3145463707756e693145463807756e693145463907756e693230414207756e69303330461363697263756d666c65786163757465636f6d621363697263756d666c65786772617665636f6d6212636972 63756d666c6578686f6f6b636f6d621363697263756d666c657874696c6465636f6d620e62726576656163757465636f6d620e62726576656772617665636f6d620d6272657665686f6f6b636f6d620e 627265766574696c6465636f6d6210637972696c6c6963686f6f6b6c65667411637972696c6c6963626967686f6f6b554311637972696c6c6963626967686f6f6b4c43000000000200050002ffff0003 00010000000c000000160000000200010000038100010004000000010000000000010000000a001e002c00016c61746e0008000400000000ffff0001000000016b65726e000800000001000000010004 00020008000100080001a53a0004000001f003ea03ea074c075a08d4075a09320ac00b220c100d3e0e240f0a0ff0117e12ac138214b014de196019ee1d90213623682782074c28682868286e28682880 291a293029362868286829482956286e29d429ea29ea2a002ada2af0074c2bba2bc82bd62e242e242bd6306632ac0b2234fe35e434fe34fe0e240e240e240e2436c237443744374437443744117e389e 389e389e389e39a82868286828682868286828682948286e3e623e623e623e623e6c3e7a3e7a3e7a3e7a3e7a29483e943e943e943e943e9e40240932286809322868404228680b22286e286e286e0b22 286e41d42868286828684252286828680e2442580e240f0a29360ff00ff00ff041d40ff00ff0286828682868117e29482948117e29482948286e286e286e4342286e444c444c41d41960196019601960 1d9029ea23682ada48c2278227824d38504e09322868286e511c514a5158518652185226528c53ca542855ee58b858da59f45a0a5ab45df25e005f1a5ff4609a644064f66520657e65b065be66706a2a 6a3028686a4a6a2a6a9c6aa26ad06ada6b0828686b7a6bbc6be26c186c366c446c5a6c446c6c6c8a6cc46cd629486d2c6d3e294829486d8c6e6e6f6472b67334734a73b474927564762a76a0785679f4 7c1a7cc47d4a7f888092815881f28324847e8594869e8be88d768e208eda8f9c9096911091929220929692fc938294149432947494aa952c95a2962896b29700975e982098b29924999a99f09a4a286e 9ab09b229b68286e9baa9bb8286e286e9c2a9c349cba9d389d3e9db09e2694141d9029ea1d9029ea1d9029ea23682adaa190a190a19ea19e09320932a4aca4ee947483249820911096288594970079f4 79f4809294aa809294aa83249628847e832496288be898208be8982098209820832496288324962883249820a5308eda999a91109628847e9628869e975e762a8eda999a96288eda999a809294aa8092 94aa809294aa8eda999a869e975e762a8324962885949700869e975e869e9820869e98208eda999a8eda999a8eda999a762a83248324734a809294aa762a8eda999a8eda999a8eda999a734a79f479f4 947494748324962883249628809294aa832496288324832496288324962883249628832496288be898208be898208be89820869e975e869e975e8eda999a809294aa832496288be896288eda999a8324 9628832496288324962883249628859497008eda999a093209320932093209320932093209320932093209320932286828682868286828682868286828680e240e24117e2948117e2948117e2948117e 2948117e2948117e2948117e2948a4aca4aca4aca4aca4ac19601960a4eea4eea4eea4eea4ee23682ada23682ada23682ada00d80024ffae002c00290037005200390052003a0066003b0029003c0052 003d00290046ffc30047ffc30048ffc3004affd70052ffc30054ffc30057002900590029005a0014005c00290082ffae0083ffae0084ffae0085ffae0086ffae0087ffae0088ff5c008e0029008f0029 0090002900910029009f005200a8ffc300a9ffc300aaffc300abffc300acffc300adffc300b4ffc300b5ffc300b6ffc300b7ffc300b8ffc300baffc300bf002900c1002900c2ffae00c4ffae00c6ffae 00c9ffc300cbffc300cdffc300cfffc300d5ffc300d7ffc300d9ffc300dbffc300ddffc300ec002900f0002900f20029010fffc30111ffc30113ffc30115ffc301240052012600520136006601370014 0138005201390029013a0052013b0029013d0029013f00290143ffae015fffae0169ffae017100520179ffc3017effc3018000290182ffc3018a0029018cffc3018effc30190ffc3019100290193ffc3 019400290196ffc30199ffc3019bffc3019d005201a4ff9a01a6005201a8003d01aaffae01aeff8501b0003d01b1001401b5ff8501bc005201bd003d01bf002901c4005201cfffc301d8ffc301dbffc3 01dc002901dd002901deffc301eaffc301edffc301fa006601fb001401fc006601fd001401fe006601ff001402000052020100290228ffae0258ffae0260ffc3026affc3026d00290272ffae0276003d 027fffc302810029028300290285ffc30287ffc30289ffc3028b0029028dffc3029f003d02a9005202aa002902b2ffc302b4ffc302b5005202b6002902b7005202b8002902b9005202ba002902bb003d 02bd005202ca003d02ceff8502d9ffae02dbffae02ddffae02e0ffc302e5003d02f0ffc302f2ffc302f4ffc302f7003d02f8002902f9003d02fa002902fb003d02fc00290305003d0307003d030affc3 030cffc3030e0029031000290311ff850316ffc30317005203180029031affc3031bff85031dffae031fffae0321ffae0323ffae0325ffae0327ffae0329ffae032bffae032dffae032fffae0331ffae 0333ffae0336ffc30338ffc3033affc3033cffc3033effc30340ffc30342ffc30344ffc30345002903470029034affc3034cffc3034effc30350ffc30352ffc30354ffc30356ffc30358ffc3035affc3 035cffc3035effc30360ffc3036f005203700029037100520372002903730052037400290003002d007b00f6007b01a3007b005e0026ffc3002affc30032ffc30034ffc30037ff9a0038ffd70039ff9a 003affae003cff9a0089ffc30094ffc30095ffc30096ffc30097ffc30098ffc3009affc3009bffd7009cffd7009dffd7009effd7009fff9a00c8ffc300ceffc300deffc300e0ffc300e2ffc300e4ffc3 010effc30112ffc30124ff9a0126ff9a012cffd70130ffd70132ffd70134ffd70136ffae0138ff9a013aff9a0166ffc3016dffc30171ff9a01b8ffc301bbffc301bcff9a01faffae01fcffae01feffae 0200ff9a025fffc30261ffd7026cffc3027effc30284ffc30286ffc30288ffc3028affc3028cffc302a9ff9a02b1ffc302b3ffc302b5ff9a02b7ff9a02b9ff9a02bdff9a02e1ffc302e3ffc302efffc3 02f1ffc302f3ffc30315ffc30317ff9a0319ffc30349ffc3034bffc3034dffc3034fffc30351ffc30353ffc30355ffc30357ffc30359ffc3035bffc3035dffc3035fffc30361ffd70363ffd70365ffd7 0367ffd70369ffd7036bffd7036dffd7036fff9a0371ff9a0373ff9a00170037ff9a0171ff9a0172ffc301b0ffd701b5ffd701bcff9a01c4ffae0276ffd7029fffd702a9ff9a02b5ff9a02b7ff9a02b9 ff9a02bbffd702bdff9a02caffd702ceffd702e5ffd70305ffd70307ffd70311ffd70317ff9a031bffd700630005ffae000affae0026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffc3 003affd7003cff9a0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec 010effec0112ffec0114ffd70124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70138ff9a013aff9a0166ffec016dffec0171ff8501b8ffec01bbffec01bcff8501faffd701fcffd7 01feffd70200ff9a0207ffae020bffae025fffec0261ffec026cffec027effec0284ffec0286ffec0288ffec028affec028cffec02a9ff8502b1ffec02b3ffec02b5ff8502b7ff8502b9ff8502bdff85 02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0317ff850319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec 0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0371ff9a0373ff9a0018002cffec0037ffec0039ffec003bffec003cffec009fffec0124ffec0126ffec0138ffec013a ffec0171ffec01bcffec0200ffec02a9ffec02b5ffec02b7ffec02b9ffec02bdffec0317ffec0345ffec0347ffec036fffec0371ffec0373ffec003b00050029000a0029000c00290026ffd7002affd7 0032ffd70034ffd700400029006000290089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd700deffd700e0ffd700e2ffd700e4ffd7010effd70112ffd70166ffd7 016dffd701b8ffd701bbffd702070029020b0029025fffd7026cffd7027effd70284ffd70286ffd70288ffd7028affd7028cffd702b1ffd702b3ffd702e1ffd702e3ffd702efffd702f1ffd702f3ffd7 0315ffd70319ffd70349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357ffd70359ffd7035bffd7035dffd7035fffd7004b000fffc30011ffc30024ffec002cffec0037ffc30039 ffec003affec003bffec003cffd7003dffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffc3008effec008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6ffec00ec ffec00f0ffec00f2ffec0124ffc30126ffc30136ffec0138ffd7013affd7013bffec013dffec013fffec0143ffec015fffec0169ffec0171ffc301aaffec01bcffc301faffec01fcffec01feffec0200 ffd70228ffec0258ffec0272ffec02a9ffc302b5ffc302b7ffc302b9ffc302bdffc302d9ffec02dbffec02ddffec0317ffc3031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032b ffec032dffec032fffec0331ffec0333ffec0345ffec0347ffec036fffd70371ffd70373ffd700390005003d000a003d000c0029000fff9a0011ff9a002200290024ffd700390014003a0014003c0014 00400029006000290082ffd70083ffd70084ffd70085ffd70086ffd70087ffd70088ffc3009f001400c2ffd700c4ffd700c6ffd70136001401380014013a00140143ffd7015fffd70169ffd701aaffd7 01fa001401fc001401fe0014020000140207003d020b003d0228ffd70258ffd70272ffd702d9ffd702dbffd702ddffd7031dffd7031fffd70321ffd70323ffd70325ffd70327ffd70329ffd7032bffd7 032dffd7032fffd70331ffd70333ffd7036f00140371001403730014003900050029000a00290026ffec002affec0032ffec0034ffec0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009a ffec00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec0166ffec016dffec01b8ffec01bbffec02070029020b0029025fffec026cffec027effec0284ffec0286 ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357 ffec0359ffec035bffec035dffec035fffec003900050029000a00290026ffd7002affd70032ffd70034ffd70089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd7 00deffd700e0ffd700e2ffd700e4ffd7010effd70112ffd70114ffd70166ffd7016dffd701b8ffd701bbffd702070029020b0029025fffd7026cffd7027effd70284ffd70286ffd70288ffd7028affd7 028cffd702b1ffd702b3ffd702e1ffd702e3ffd702efffd702f1ffd702f3ffd70315ffd70319ffd70349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357ffd70359ffd7035bffd7 035dffd7035fffd700630005ff9a000aff9a0026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffae003affc3003cff9a0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009a ffec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec0124ff850126ff85012cffec0130ffec0132ffec0134 ffec0136ffc30138ff9a013aff9a0166ffec016dffec0171ff8501b8ffec01bbffec01bcff8501faffc301fcffc301feffc30200ff9a0207ff9a020bff9a025fffec0261ffec026cffec027effec0284 ffec0286ffec0288ffec028affec028cffec02a9ff8502b1ffec02b3ffec02b5ff8502b7ff8502b9ff8502bdff8502e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0317ff850319ffec0349 ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0371 ff9a0373ff9a004b000fffc30011ffc30024ffec002cffec0037ffc30039ffd7003affec003bffd7003cffd7003dffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd7008effec 008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6ffec00ecffec00f0ffec00f2ffec0124ffc30126ffc30136ffec0138ffd7013affd7013bffec013dffec013fffec0143ffec015fffec 0169ffec0171ffc301aaffec01bcffc301faffec01fcffec01feffec0200ffd70228ffec0258ffec0272ffec02a9ffc302b5ffc302b7ffc302b9ffc302bdffc302d9ffec02dbffec02ddffec0317ffc3 031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec0333ffec0345ffec0347ffec036fffd70371ffd70373ffd70035000fff330011ff330024 ffae0026ffec003bffec003cffec003dffd70082ffae0083ffae0084ffae0085ffae0086ffae0087ffae0088ff710089ffec009fffec00c2ffae00c4ffae00c6ffae00c8ffec00ceffec0138ffec013a ffec013bffd7013dffd7013fffd70143ffae015fffae0169ffae01aaffae01bbffec0200ffec0228ffae0258ffae0272ffae02d9ffae02dbffae02ddffae031dffae031fffae0321ffae0323ffae0325 ffae0327ffae0329ffae032bffae032dffae032fffae0331ffae0333ffae036fffec0371ffec0373ffec004b000fffc30011ffc30024ffec002cffec0037ffc30039ffd7003affec003bffd7003cffd7 003dffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffc3008effec008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6ffec00ecffec00f0ffec00f2ffec0124ffc3 0126ffc30136ffec0138ffd7013affd7013bffec013dffec013fffec0143ffec015fffec0169ffec0171ffc301aaffec01bcffc301faffec01fcffec01feffec0200ffd70228ffec0258ffec0272ffec 02a9ffc302b5ffc302b7ffc302b9ffc302bdffc302d9ffec02dbffec02ddffec0317ffc3031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec 0333ffec0345ffec0347ffec036fffd70371ffd70373ffd7000b0037ffec0124ffec0126ffec0171ffec01bcffec02a9ffec02b5ffec02b7ffec02b9ffec02bdffec0317ffec012000050052000a0052 000fff9a0010ff9a0011ff9a002200290024ff850026ffc3002affc30032ffc30034ffc30036ffec003700140044ff850046ff850047ff850048ff85004aff9a0050ffae0051ffae0052ff850053ffae 0054ff850055ffae0056ff850058ffae0059ffc3005affc3005bffc3005cffc3005dffc30082ff850083ff850084ff850085ff850086ff850087ff850088ff710089ffc30094ffc30095ffc30096ffc3 0097ffc30098ffc3009affc300a2ff8500a3ff8500a4ff8500a5ff8500a6ff8500a7ff8500a8ff8500a9ff8500aaff8500abff8500acff8500adff8500b3ffae00b4ff8500b5ff8500b6ff8500b7ff85 00b8ff8500baff8500bbffae00bcffae00bdffae00beffae00bfffc300c1ffc300c2ff8500c3ff8500c4ff8500c5ff8500c6ff8500c7ff8500c8ffc300c9ff8500cbff8500cdff8500ceffc300cfff85 00d5ff8500d7ff8500d9ff8500dbff8500ddff8500deffc300e0ffc300e2ffc300e4ffc30106ffae0108ffae010affae010effc3010fff850111ff850112ffc30113ff850114ffc30115ff85011cffec 011dff85011fff850120ffec0121ff850122ffec0123ff8501240014012600140137ffc30139ffc30140ffc30143ff850144ff85014aff85015fff850166ffc30169ff85016dffc3017100140179ff85 017bffae017eff850180ffc30182ff850184ffae018affc3018cff85018eff850190ff850191ffc30193ff850194ffc30196ff850199ff85019bff8501a0ffec01aaff8501b8ffc301bbffc301bc0014 01caff8501cfff8501d8ff8501dbff8501dcffc301ddffc301deff8501eaff8501edff8501eeff8501fbffc301fdffc301ffffc30201ffc30202ffae0203ff9a02070052020b00520228ff850258ff85 0259ff85025fffc30260ff85026aff85026cffc3026dffc30272ff85027effc3027fff850281ffc30283ffc30284ffc30285ff850286ffc30287ff850288ffc30289ff85028affc3028bffc3028cffc3 028dff8502a9001402aaffc302b1ffc302b2ff8502b3ffc302b4ff8502b5001402b6ffc302b7001402b8ffc302b9001402baffc302bd001402d9ff8502daff8502dbff8502dcff8502ddff8502e0ff85 02e1ffc302e3ffc302efffc302f0ff8502f1ffc302f2ff8502f3ffc302f4ff8502f8ffc302faffc302fcffc3030aff85030cff85030effc30310ffc30315ffc30316ff85031700140318ffc30319ffc3 031aff85031dff85031eff85031fff850321ff850322ff850323ff850324ff850325ff850326ff850327ff850328ff850329ff85032aff85032bff85032cff85032dff85032eff85032fff850330ff85 0331ff850332ff850333ff850334ff850336ff850338ff85033aff85033cff85033eff850340ff850342ff850344ff850349ffc3034aff85034bffc3034cff85034dffc3034eff85034fffc30350ff85 0351ffc30352ff850353ffc30354ff850355ffc30356ff850357ffc30358ff850359ffc3035aff85035bffc3035cff85035dffc3035eff85035fffc30360ff850362ffae0364ffae0366ffae0368ffae 036affae036cffae036effae0370ffc30372ffc30374ffc30023000fffd70011ffd70024ffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd700c2ffec00c4ffec00c6ffec0143 ffec015fffec0169ffec01aaffec0228ffec0258ffec0272ffec02d9ffec02dbffec02ddffec031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331 ffec0333ffec00e800050052000a0052000fff9a0011ff9a002200290024ffc30026ffd7002affd70032ffd70034ffd70044ffc30046ffc30047ffc30048ffc3004affc30050ffd70051ffd70052ffc3 0053ffd70054ffc30055ffd70056ffd70058ffd70082ffc30083ffc30084ffc30085ffc30086ffc30087ffc30088ff850089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ffc3 00a3ffc300a4ffc300a5ffc300a6ffc300a7ffc300a8ffc300a9ffc300aaffc300abffc300acffc300adffc300b3ffd700b4ffc300b5ffc300b6ffc300b7ffc300b8ffc300baffc300bbffd700bcffd7 00bdffd700beffd700c2ffc300c3ffc300c4ffc300c5ffc300c6ffc300c7ffc300c8ffd700c9ffc300cbffc300cdffc300ceffd700cfffc300d5ffc300d7ffc300d9ffc300dbffc300ddffc300deffd7 00e0ffd700e2ffd700e4ffd70106ffd70108ffd7010affd7010effd7010fffc30111ffc30112ffd70113ffc30114ffd70115ffc3011dffd7011fffd70121ffd70123ffd70143ffc30144ffc3014affd7 015fffc30166ffd70169ffc3016dffd70179ffc3017bffd7017effc30182ffc30184ffd7018cffc3018effc30190ffc30193ffc30196ffc30199ffc3019bffc301aaffc301b8ffd701bbffd701caffc3 01cfffc301d8ffc301dbffc301deffc301eaffc301edffc301eeffd702070052020b00520228ffc30258ffc30259ffc3025fffd70260ffc3026affc3026cffd70272ffc3027effd7027fffc30284ffd7 0285ffc30286ffd70287ffc30288ffd70289ffc3028affd7028cffd7028dffc302b1ffd702b2ffc302b3ffd702b4ffc302d9ffc302daffc302dbffc302dcffc302ddffc302e0ffc302e1ffd702e3ffd7 02efffd702f0ffc302f1ffd702f2ffc302f3ffd702f4ffc3030affc3030cffc30315ffd70316ffc30319ffd7031affc3031dffc3031effc3031fffc30321ffc30322ffc30323ffc30324ffc30325ffc3 0326ffc30327ffc30328ffc30329ffc3032affc3032bffc3032cffc3032dffc3032effc3032fffc30330ffc30331ffc30332ffc30333ffc30334ffc30336ffc30338ffc3033affc3033cffc3033effc3 0340ffc30342ffc30344ffc30349ffd7034affc3034bffd7034cffc3034dffd7034effc3034fffd70350ffc30351ffd70352ffc30353ffd70354ffc30355ffd70356ffc30357ffd70358ffc30359ffd7 035affc3035bffd7035cffc3035dffd7035effc3035fffd70360ffc30362ffd70364ffd70366ffd70368ffd7036affd7036cffd7036effd700e900050066000a0066000fffae0011ffae0024ffd70026 ffec002affec0032ffec0034ffec0044ffd70046ffd70047ffd70048ffd7004affec0050ffec0051ffec0052ffd70053ffec0054ffd70055ffec0056ffd70058ffec005dffec0082ffd70083ffd70084 ffd70085ffd70086ffd70087ffd70088ffae0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec00a2ffd700a3ffd700a4ffd700a5ffd700a6ffd700a7ffd700a8ffd700a9ffd700aa ffd700abffd700acffd700adffd700b3ffec00b4ffd700b5ffd700b6ffd700b7ffd700b8ffd700baffd700bbffec00bcffec00bdffec00beffec00c2ffd700c3ffd700c4ffd700c5ffd700c6ffd700c7 ffd700c8ffec00c9ffd700cbffd700cdffd700ceffec00cfffd700d5ffd700d7ffd700d9ffd700dbffd700ddffd700deffec00e0ffec00e2ffec00e4ffec0106ffec0108ffec010affec010effec010f ffd70111ffd70112ffec0113ffd70114ffec0115ffd7011dffd7011fffd70121ffd70123ffd70140ffec0143ffd70144ffd7014affd7015fffd70166ffec0169ffd7016dffec0179ffd7017bffec017e ffd70182ffd70184ffec018cffd7018effd70190ffd70193ffd70196ffd70199ffd7019bffd701aaffd701b8ffec01bbffec01caffd701cfffd701d8ffd701dbffd701deffd701eaffd701edffd701ee ffd702070066020b00660228ffd70258ffd70259ffd7025fffec0260ffd7026affd7026cffec0272ffd7027effec027fffd70284ffec0285ffd70286ffec0287ffd70288ffec0289ffd7028affec028c ffec028dffd702b1ffec02b2ffd702b3ffec02b4ffd702d9ffd702daffd702dbffd702dcffd702ddffd702e0ffd702e1ffec02e3ffec02efffec02f0ffd702f1ffec02f2ffd702f3ffec02f4ffd7030a ffd7030cffd70315ffec0316ffd70319ffec031affd7031dffd7031effd7031fffd70321ffd70322ffd70323ffd70324ffd70325ffd70326ffd70327ffd70328ffd70329ffd7032affd7032bffd7032c ffd7032dffd7032effd7032fffd70330ffd70331ffd70332ffd70333ffd70334ffd70336ffd70338ffd7033affd7033cffd7033effd70340ffd70342ffd70344ffd70349ffec034affd7034bffec034c ffd7034dffec034effd7034fffec0350ffd70351ffec0352ffd70353ffec0354ffd70355ffec0356ffd70357ffec0358ffd70359ffec035affd7035bffec035cffd7035dffec035effd7035fffec0360 ffd70362ffec0364ffec0366ffec0368ffec036affec036cffec036effec008c00050029000a00290026ffd7002affd70032ffd70034ffd70046ffec0047ffec0048ffec0052ffec0054ffec0089ffd7 0094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a8ffec00a9ffec00aaffec00abffec00acffec00adffec00b4ffec00b5ffec00b6ffec00b7ffec00b8ffec00baffec00c8ffd700c9ffec 00cbffec00cdffec00ceffd700cfffec00d5ffec00d7ffec00d9ffec00dbffec00ddffec00deffd700e0ffd700e2ffd700e4ffd7010effd7010fffec0111ffec0112ffd70113ffec0114ffd70115ffec 0166ffd7016dffd70179ffec017effec0182ffec018cffec018effec0190ffec0193ffec0196ffec0199ffec019bffec01b8ffd701bbffd701cfffec01d8ffec01dbffec01deffec01eaffec01edffec 02070029020b0029025fffd70260ffec026affec026cffd7027effd7027fffec0284ffd70285ffec0286ffd70287ffec0288ffd70289ffec028affd7028cffd7028dffec02b1ffd702b2ffec02b3ffd7 02b4ffec02e0ffec02e1ffd702e3ffd702efffd702f0ffec02f1ffd702f2ffec02f3ffd702f4ffec030affec030cffec0315ffd70316ffec0319ffd7031affec0336ffec0338ffec033affec033cffec 033effec0340ffec0342ffec0344ffec0349ffd7034affec034bffd7034cffec034dffd7034effec034fffd70350ffec0351ffd70352ffec0353ffd70354ffec0355ffd70356ffec0357ffd70358ffec 0359ffd7035affec035bffd7035cffec035dffd7035effec035fffd70360ffec010600050052000a0052000fff9a0011ff9a002200290024ff9a0026ffd7002affd70032ffd70034ffd70036ffec0044 ff9a0046ff9a0047ff9a0048ff9a004aff9a0050ffc30051ffc30052ff9a0053ffc30054ff9a0055ffc30056ffae0058ffc3005bffd7005cffec005dffc30082ff9a0083ff9a0084ff9a0085ff9a0086 ff9a0087ff9a0088ff710089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ff9a00a3ff9a00a4ff9a00a5ff9a00a6ff9a00a7ff9a00a8ff9a00a9ff9a00aaff9a00abff9a00ac ff9a00adff9a00b3ffc300b4ff9a00b5ff9a00b6ff9a00b7ff9a00b8ff9a00baff9a00bbffc300bcffc300bdffc300beffc300bfffec00c1ffec00c2ff9a00c3ff9a00c4ff9a00c5ff9a00c6ff9a00c7 ff9a00c8ffd700c9ff9a00cbff9a00cdff9a00ceffd700cfff9a00d5ff9a00d7ff9a00d9ff9a00dbff9a00ddff9a00deffd700e0ffd700e2ffd700e4ffd70106ffc30108ffc3010affc3010effd7010f ff9a0111ff9a0112ffd70113ff9a0114ffd70115ff9a011cffec011dffae011fffae0120ffec0121ffae0122ffec0123ffae0139ffec0140ffc30143ff9a0144ff9a014affae015fff9a0166ffd70169 ff9a016dffd70179ff9a017bffc3017eff9a0180ffec0182ff9a0184ffc3018affec018cff9a018eff9a0190ff9a0193ff9a0196ff9a0199ff9a019bff9a01a0ffec01aaff9a01b8ffd701bbffd701ca ff9a01cfff9a01d8ff9a01dbff9a01ddffec01deff9a01eaff9a01edff9a01eeffae0201ffec02070052020b00520228ff9a0258ff9a0259ff9a025fffd70260ff9a026aff9a026cffd7026dffec0272 ff9a027effd7027fff9a0281ffec0283ffec0284ffd70285ff9a0286ffd70287ff9a0288ffd70289ff9a028affd7028bffec028cffd7028dff9a02b1ffd702b2ff9a02b3ffd702b4ff9a02b8ffec02ba ffec02d9ff9a02daff9a02dbff9a02dcff9a02ddff9a02e0ff9a02e1ffd702e3ffd702efffd702f0ff9a02f1ffd702f2ff9a02f3ffd702f4ff9a02f8ffec02faffec02fcffec030aff9a030cff9a030e ffec0310ffec0315ffd70316ff9a0319ffd7031aff9a031dff9a031eff9a031fff9a0321ff9a0322ff9a0323ff9a0324ff9a0325ff9a0326ff9a0327ff9a0328ff9a0329ff9a032aff9a032bff9a032c ff9a032dff9a032eff9a032fff9a0330ff9a0331ff9a0332ff9a0333ff9a0334ff9a0336ff9a0338ff9a033aff9a033cff9a033eff9a0340ff9a0342ff9a0344ff9a0349ffd7034aff9a034bffd7034c ff9a034dffd7034eff9a034fffd70350ff9a0351ffd70352ff9a0353ffd70354ff9a0355ffd70356ff9a0357ffd70358ff9a0359ffd7035aff9a035bffd7035cff9a035dffd7035eff9a035fffd70360 ff9a0362ffc30364ffc30366ffc30368ffc3036affc3036cffc3036effc30370ffec0372ffec0374ffec003900050029000a00290026ffec002affec0032ffec0034ffec0089ffec0094ffec0095ffec 0096ffec0097ffec0098ffec009affec00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffd70166ffec016dffec01b8ffec01bbffec02070029020b0029025fffec 026cffec027effec0284ffec0286ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034dffec034fffec 0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0001000affd700040005003d000a003d0207003d020b003d002600050066000a006600590014005a0014005c001400bf 001400c10014013700140139001401800014018a0014019100140194001401dc001401dd001401fb001401fd001401ff00140201001402070066020b0066026d00140281001402830014028b001402aa 001402b6001402b8001402ba001402f8001402fa001402fc0014030e00140310001403180014037000140372001403740014000500050029000a0029004a001402070029020b00290001000affc30004 00050029000a002902070029020b00290003005bffd7005dffec0140ffec001f00050066000a00660044ffec004affec00a2ffec00a3ffec00a4ffec00a5ffec00a6ffec00a7ffec00c3ffec00c5ffec 00c7ffec0144ffec01caffec02070066020b00660259ffec02daffec02dcffec031effec0322ffec0324ffec0326ffec0328ffec032affec032cffec032effec0330ffec0332ffec0334ffec00050005 0052000a00520057001402070052020b0052000500050052000a00520049001402070052020b0052003600050029000a00290052ffd700a8ffd700b4ffd700b5ffd700b6ffd700b7ffd700b8ffd700ba ffd7010fffd70111ffd70113ffd70115ffd7018cffd7018effd70190ffd70193ffd70196ffd70199ffd7019bffd701d8ffd701deffd702070029020b00290260ffd7026affd7027fffd70285ffd70287 ffd70289ffd7028dffd702b2ffd702b4ffd702e0ffd702f0ffd702f2ffd702f4ffd7030affd7030cffd70316ffd7031affd7034affd7034cffd7034effd70350ffd70352ffd70354ffd70356ffd70358 ffd7035affd7035cffd7035effd70360ffd700050005003d000a003d004900140207003d020b003d00320052ffec00a8ffec00b4ffec00b5ffec00b6ffec00b7ffec00b8ffec00baffec010fffec0111 ffec0113ffec0115ffec018cffec018effec0190ffec0193ffec0196ffec0199ffec019bffec01d8ffec01deffec0260ffec026affec027fffec0285ffec0287ffec0289ffec028dffec02b2ffec02b4 ffec02e0ffec02f0ffec02f2ffec02f4ffec030affec030cffec0316ffec031affec034affec034cffec034effec0350ffec0352ffec0354ffec0356ffec0358ffec035affec035cffec035effec0360 ffec00030171ffd70178ffd70191002900030171ff9a0172ffc30178ffc300930005ffae000affae000dff85000f0044001e00440022ffc30026ffec002affec002d005e0032ffec0034ffec0037ff85 0038ffec0039ffc3003affd7003cff9a003d003b0049ffec0057ffec0059ffd7005affec005cffd70082ffd70089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec 009dffec009effec009fff9a00bfffd700c1ffd700c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec00f6005e010effec0112ffec0114ffd70124ff850126ff85012cffec0130ffec0132ffec 0134ffec0136ffd70137ffec0138ff9a0139ffd7013aff9a013b003b013d003b013f003b0166ffec016dffec0171ff850180ffd7018affd70191ffd70194ffd701a3005e01b8ffec01bbffec01bcff85 01dcffd701ddffd701faffd701fbffec01fcffd701fdffec01feffd701ffffec0200ff9a0201ffd70207ffae020bffae025fffec0261ffec026cffec026dffd7027effec0281ffd70283ffd70284ffec 0286ffec0288ffec028affec028bffd7028cffec02a9ff8502aaffd702b1ffec02b3ffec02b5ff8502b6ffd702b7ff8502b8ffd702b9ff8502baffd702bdff8502e1ffec02e3ffec02efffec02f1ffec 02f3ffec02f8ffd702faffd702fcffd7030effd70310ffd70315ffec0317ff850318ffd70319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec 035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0370ffd70371ff9a0372ffd70373ff9a0374ffd700900005ffae000affae000dff85000f0044001e 00440022ffc30026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003cff9a003d003b0049ffec0057ffec0059ffd7005affec005cffd70089ffec0094ffec0095ffec0096 ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00bfffd700c1ffd700c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffd70124 ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70137ffec0138ff9a0139ffd7013aff9a013b003b013d003b013f003b0166ffec016dffec0171ff850180ffd7018affd70191ffd70194 ffd701a3005e01b8ffec01bbffec01bcff8501dcffd701ddffd701faffd701fbffec01fcffd701fdffec01feffd701ffffec0200ff9a0201ffd70207ffae020bffae025fffec0261ffec026cffec026d ffd7027effec0281ffd70283ffd70284ffec0286ffec0288ffec028affec028bffd7028cffec02a9ff8502aaffd702b1ffec02b3ffec02b5ff8502b6ffd702b7ff8502b8ffd702b9ff8502baffd702bd ff8502e1ffec02e3ffec02efffec02f1ffec02f3ffec02f8ffd702faffd702fcffd7030effd70310ffd70315ffec0317ff850318ffd70319ffec0349ffec034bffec034dffec034fffec0351ffec0353 ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0370ffd70371ff9a0372ffd70373ff9a0374ffd70091 0005ffae000affae000dff7f000f0044001e00440022ffd70026ffec002affec002d005e0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003cff9a003d003b0057ffe50059ffd5005affe5 005cffdb0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00bfffdb00c1ffdb00c8ffec00ceffec00deffec00e0ffec00e2ffec 00e4ffec00f6005e010effec0112ffec0114ffd70124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70137ffe50138ff9a0139ffdb013aff9a013b003b013d003b013f003b0166ffec 016dffec0171ff850180ffdb018affd50191ffd50194ffd501a3005e01b8ffec01bbffec01bcff8501dcffd501ddffdb01faffd701fbffe501fcffd701fdffe501feffd701ffffe50200ff9a0201ffdb 0207ffae020bffae025fffec0261ffec026cffec026dffdb027effec0281ffdb0283ffdb0284ffec0286ffec0288ffec028affec028bffdb028cffec02a9ff8502aaffd502b1ffec02b3ffec02b5ff85 02b6ffd502b7ff8502b8ffdb02b9ff8502baffdb02bdff8502e1ffec02e3ffec02efffec02f1ffec02f3ffec02f8ffdb02faffdb02fcffdb030effdb0310ffdb0315ffec0317ff850318ffd50319ffec 0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a 0370ffdb0371ff9a0372ffdb0373ff9a0374ffdb00940005ff66000aff66000dff7f000f0044001e00440022ffd70026ffec002affec002d005e0032ffec0034ffec0037ff850038ffec0039ffc3003a ffd7003cff9a003d003b0057ffe50059ffd5005affe5005cffdb0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00bfffdb00c1 ffdb00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec00f6005e010effec0112ffec0114ffd70124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70137ffe50138ff9a0139 ffdb013aff9a013b003b013d003b013f003b0166ffec016dffec0171ff850180ffdb018affd50191ffd50194ffd501a3005e01b8ffec01bbffec01bcff8501dcffd501ddffdb01faffd701fbffe501fc ffd701fdffe501feffd701ffffe50200ff9a0201ffdb0206ff660207ffae020aff66020bffae0220ff9a025fffec0261ffec026cffec026dffdb027effec0281ffdb0283ffdb0284ffec0286ffec0288 ffec028affec028bffdb028cffec02a9ff8502aaffd502b1ffec02b3ffec02b5ff8502b6ffd502b7ff8502b8ffdb02b9ff8502baffdb02bdff8502e1ffec02e3ffec02efffec02f1ffec02f3ffec02f8 ffdb02faffdb02fcffdb030effdb0310ffdb0315ffec0317ff850318ffd50319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035f ffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0370ffdb0371ff9a0372ffdb0373ff9a0374ffdb003900050029000a00290010ffd70026ffec0032ffec0034ffec 0084ffec0089ffec008affec008fffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec00c8ffec00ceffec00f6003d010effec0112ffec0166ffec016dffec01a3003d01b8ffec01bbffec 02070029020b0029025fffec026cffec027effec0284ffec0286ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec 034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec003700050029000a00290010ffd70026ffec0032ffec0034ffec0089ffec008bffec0094 ffec0095ffec0096ffec0097ffec0098ffec009affec00c8ffec00ceffec00f6003d010effec0112ffec0166ffec016dffec01a3003d01b8ffec01bbffec02070029020b0029025fffec026cffec027e ffec0284ffec0286ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034dffec034fffec0351ffec0353 ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec00200024ffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec00c2ffec00c4ffec00c6ffec0143ffec015fffec0169ffec 01aaffec0228ffec0258ffec0272ffec02d9ffec02dbffec02ddffec031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec0333ffec0056000c ffd7000fffc30011ffc30024ffec002cffec002dfff60036ffec0037ffc30039ffd7003affec003bffd7003cffd7003dffec0040ffd70060ffd70082ffec0083ffec0084ffec0085ffec0086ffec0087 ffec0088ffd7008effec008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6ffec00ecffec00f0ffec00f2ffec00f6fff6011cffec0120ffec0122ffec0124ffc30126ffc30136ffec0138 ffd7013affd7013bffec013dffec013fffec0143ffec015fffec0169ffec0171ffc301a0ffec01a3fff601aaffec01bcffc301faffec01fcffec01feffec0200ffd70228ffec0258ffec0272ffec02a9 ffc302b5ffc302b7ffc302b9ffc302bdffc302d9ffec02dbffec02ddffec0317ffc3031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec0333 ffec0345ffec0347ffec036fffd70371ffd70373ffd70042000fffd70011ffd70024ffec0030ffec003dffec0044ffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd700a2ffec 00a3ffec00a4ffec00a5ffec00a6ffec00a7ffec00c2ffec00c3ffec00c4ffec00c5ffec00c6ffec00c7ffec013bffec013dffec013fffec0143ffec0144ffec015fffec0169ffec01aaffec01caffec 0228ffec0258ffec0259ffec0272ffec02d9ffec02daffec02dbffec02dcffec02ddffec031dffec031effec031fffec0321ffec0322ffec0323ffec0324ffec0325ffec0326ffec0327ffec0328ffec 0329ffec032affec032bffec032cffec032dffec032effec032fffec0330ffec0331ffec0332ffec0333ffec0334ffec012e000500520009ffc3000a0052000c003d000d0029000fff9a0010ff9a0011 ff9a002200290024ff9a0026ffd7002affd7002dffbe0030ffc30032ffd70034ffd70036ffec0037002700390029003a00140040003d0044ff9a0046ff9a0047ff9a0048ff9a0049ffe5004aff9a0050 ffc30051ffc30052ff9a0053ffc30054ff9a0055ffc30056ffae0058ffc30059ffd7005affec005bffd7005cffec005dffc30060003d0082ff9a0083ff9a0084ff9a0085ff9a0086ff9a0087ff9a0088 ff710089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ff9a00a3ff9a00a4ff9a00a5ff9a00a6ff9a00a7ff9a00a8ff9a00a9ff9a00aaff9a00abff9a00acff9a00adff9a00b3 ffc300b4ff9a00b5ff9a00b6ff9a00b7ff9a00b8ff9a00baff9a00bbffc300bcffc300bdffc300beffc300bfffec00c1ffec00c2ff9a00c3ff9a00c4ff9a00c5ff9a00c6ff9a00c7ff9a00c8ffd700c9 ff9a00cbff9a00cdff9a00ceffd700cfff9a00d5ff9a00d7ff9a00d9ff9a00dbff9a00ddff9a00deffd700e0ffd700e2ffd700e4ffd700f6ffbe0106ffc30108ffc3010affc3010effd7010fff9a0111 ff9a0112ffd70113ff9a0114ffd70115ff9a011cffec011dffae011fffae0120ffec0121ffae0122ffec0123ffae0124002701260027013600140137ffec0139ffec0140ffc30143ff9a0144ff9a014a ffae015fff9a0166ffd70169ff9a016dffd7017100270179ff9a017bffc3017eff9a0180ffec0182ff9a0184ffc3018affd7018cff9a018eff9a0190ff9a0191ffd70193ff9a0194ffd70196ff9a0199 ff9a019bff9a01a0ffec01a3ffbe01aaff9a01b8ffd701bbffd701bc002701caff9a01cfff9a01d8ff9a01dbff9a01dcffd701ddffec01deff9a01eaff9a01edff9a01eeffae01fa001401fbffec01fc 001401fdffec01fe001401ffffec0201ffec02070052020b00520228ff9a0258ff9a0259ff9a025fffd70260ff9a026aff9a026cffd7026dffec0272ff9a027effd7027fff9a0281ffec0283ffec0284 ffd70285ff9a0286ffd70287ff9a0288ffd70289ff9a028affd7028bffec028cffd7028dff9a02a9002702aaffd702b1ffd702b2ff9a02b3ffd702b4ff9a02b5002702b6ffd702b7002702b8ffec02b9 002702baffec02bd002702d9ff9a02daff9a02dbff9a02dcff9a02ddff9a02e0ff9a02e1ffd702e3ffd702efffd702f0ff9a02f1ffd702f2ff9a02f3ffd702f4ff9a02f8ffec02faffec02fcffec030a ff9a030cff9a030effec0310ffec0315ffd70316ff9a031700270318ffd70319ffd7031aff9a031dff9a031eff9a031fff9a0321ff9a0322ff9a0323ff9a0324ff9a0325ff9a0326ff9a0327ff9a0328 ff9a0329ff9a032aff9a032bff9a032cff9a032dff9a032eff9a032fff9a0330ff9a0331ff9a0332ff9a0333ff9a0334ff9a0336ff9a0338ff9a033aff9a033cff9a033eff9a0340ff9a0342ff9a0344 ff9a0349ffd7034aff9a034bffd7034cff9a034dffd7034eff9a034fffd70350ff9a0351ffd70352ff9a0353ffd70354ff9a0355ffd70356ff9a0357ffd70358ff9a0359ffd7035aff9a035bffd7035c ff9a035dffd7035eff9a035fffd70360ff9a0362ffc30364ffc30366ffc30368ffc3036affc3036cffc3036effc30370ffec0372ffec0374ffec00020005ff98000affd700030005ff98000affd7020b ffd700060005ff6f000aff6f0049ffdb005bffd7005dffec0140ffec00020005ffbe000affbe00610005003d000a003d000fffbe0011ffbe0022ffb40046fff60047fff60048fff600490014004afff6 0052fff60054fff60057000600a8fff600a9fff600aafff600abfff600acfff600adfff600b4fff600b5fff600b6fff600b7fff600b8fff600bafff600c9fff600cbfff600cdfff600cffff600d5fff6 00d7fff600d9fff600dbfff600ddfff6010ffff60111fff60113fff60115fff60179fff6017efff60182fff6018cfff6018efff60190fff60193fff60196fff60199fff6019bfff601cffff601d8fff6 01dbfff601defff601eafff601edfff60207003d0208ff8d020b003d020cff8d0210ff810215000c0260fff6026afff6027ffff60285fff60287fff60289fff6028dfff602b2fff602b4fff602e0fff6 02f0fff602f2fff602f4fff6030afff6030cfff60316fff6031afff60336fff60338fff6033afff6033cfff6033efff60340fff60342fff60344fff6034afff6034cfff6034efff60350fff60352fff6 0354fff60356fff60358fff6035afff6035cfff6035efff60360fff600070005003d000a003d000fffbe0011ffbe004900140207003d020b003d00640005ffae000affae0026ffec002affec002d00e1 0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003cff9a0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec 00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffd70124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70138ff9a013aff9a0166ffec016dffec0171ff85 01b8ffec01bbffec01bcff8501faffd701fcffd701feffd70200ff9a0207ffae020bffae025fffec0261ffec026cffec027effec0284ffec0286ffec0288ffec028affec028cffec02a9ff8502b1ffec 02b3ffec02b5ff8502b7ff8502b9ff8502bdff8502e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0317ff850319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec 0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0371ff9a0373ff9a001f00050066000a0066000c008f002200a40040 00a400450052004b0052004c003d004d003d004e0052004f0052006000b800ae00f600b000cd00b100cd00e7005200e900a400eb010a00ed00cd00ef00f600f1002900f5003d00f700e100f9005200fc 005200fe00520100005201020052010400520207008f020b008f0001002d0066003a00050029000a00290026ffec002affec002d00520032ffec0034ffec0089ffec0094ffec0095ffec0096ffec0097 ffec0098ffec009affec00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec0166ffec016dffec01b8ffec01bbffec02070029020b0029025fffec026cffec027e ffec0284ffec0286ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034dffec034fffec0351ffec0353 ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec004200050029000a0029003000140036ffec0037ffd70039ffec003affec003bffd7003cffd70059ffec005cffec009fffd700bfffec 00c1ffec011cffec0120ffec0122ffec0123ffec0124ffd70126ffd70136ffec0138ffd70139ffec013affd70171ffd70180ffec018affec0191ffec0194ffec01a0ffec01bcffd701dcffec01ddffec 01faffec01fcffec01feffec0200ffd70201ffec02070029020b0029026dffec0281ffec0283ffec028bffec02a9ffd702aaffec02b5ffd702b6ffec02b7ffd702b8ffec02b9ffd702baffec02bdffd7 02f8ffec02faffec02fcffec030effec0310ffec0317ffd70318ffec036fffd70370ffec0371ffd70372ffec0373ffd70374ffec011d00050052000a0052000fff9a0011ff9a002200290024ff850026 ffc3002affc30032ffc30034ffc30036ffec003700140044ff850046ff850047ff850048ff85004aff9a0050ffae0051ffae0052ff850053ffae0054ff850055ffae0056ff850058ffae0059ffc3005a ffc3005bffc3005cffc3005dffc30082ff850083ff850084ff850085ff850086ff850087ff850088ff710089ffc30094ffc30095ffc30096ffc30097ffc30098ffc3009affc300a2ff8500a3ff8500a4 ff8500a5ff8500a6ff8500a7ff8500a8ff8500a9ff8500aaff8500abff8500acff8500adff8500b3ffae00b4ff8500b5ff8500b6ff8500b7ff8500b8ff8500baff8500bbffae00bcffae00bdffae00be ffae00bfffc300c1ffc300c2ff8500c3ff8500c4ff8500c5ff8500c6ff8500c7ff8500c8ffc300c9ff8500cbff8500cdff8500ceffc300cfff8500d5ff8500d7ff8500d9ff8500dbff8500ddff8500de ffc300e0ffc300e2ffc300e4ffc30106ffae0108ffae010affae010effc3010fff850111ff850112ffc30113ff850114ffc30115ff85011cffec011dff85011fff850120ffec0121ff850122ffec0123 ff8501240014012600140137ffc30139ffc30140ffc30143ff850144ff85014aff85015fff850166ffc30169ff85016dffc3017100140179ff85017bffae017eff850180ffc30182ff850184ffae018a ffc3018cff85018eff850190ff850191ffc30193ff850194ffc30196ff850199ff85019bff8501a0ffec01aaff8501b8ffc301bbffc301bc001401caff8501cfff8501d8ff8501dbff8501dcffc301dd ffc301deff8501eaff8501edff8501eeff8501fbffc301fdffc301ffffc30201ffc302070052020b00520228ff850258ff850259ff85025fffc30260ff85026aff85026cffc3026dffc30272ff85027e ffc3027fff850281ffc30283ffc30284ffc30285ff850286ffc30287ff850288ffc30289ff85028affc3028bffc3028cffc3028dff8502a9001402aaffc302b1ffc302b2ff8502b3ffc302b4ff8502b5 001402b6ffc302b7001402b8ffc302b9001402baffc302bd001402d9ff8502daff8502dbff8502dcff8502ddff8502e0ff8502e1ffc302e3ffc302efffc302f0ff8502f1ffc302f2ff8502f3ffc302f4 ff8502f8ffc302faffc302fcffc3030aff85030cff85030effc30310ffc30315ffc30316ff85031700140318ffc30319ffc3031aff85031dff85031eff85031fff850321ff850322ff850323ff850324 ff850325ff850326ff850327ff850328ff850329ff85032aff85032bff85032cff85032dff85032eff85032fff850330ff850331ff850332ff850333ff850334ff850336ff850338ff85033aff85033c ff85033eff850340ff850342ff850344ff850349ffc3034aff85034bffc3034cff85034dffc3034eff85034fffc30350ff850351ffc30352ff850353ffc30354ff850355ffc30356ff850357ffc30358 ff850359ffc3035aff85035bffc3035cff85035dffc3035eff85035fffc30360ff850362ffae0364ffae0366ffae0368ffae036affae036cffae036effae0370ffc30372ffc30374ffc3011d00050052 0009ffc3000a0052000c003d000d0029000fff9a0010ff5c0011ff9a002200290024ff9a0026ffd7002affd7002dffbe0030ffec0032ffd70034ffd70036ffec003700270040003d0044ff9a0046ff9a 0047ff9a0048ff9a0049ffe5004aff9a0050ffc30051ffc30052ff9a0053ffc30054ff9a0055ffc30056ffae0058ffc3005bffd7005cffec005dffc30060003d0082ff9a0083ff9a0084ff9a0085ff9a 0086ff9a0087ff9a0088ff710089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ff9a00a3ff9a00a4ff9a00a5ff9a00a6ff9a00a7ff9a00a8ff9a00a9ff9a00aaff9a00abff9a 00acff9a00adff9a00b3ffc300b4ff9a00b5ff9a00b6ff9a00b7ff9a00b8ff9a00baff9a00bbffc300bcffc300bdffc300beffc300bfffec00c1ffec00c2ff9a00c3ff9a00c4ff9a00c5ff9a00c6ff9a 00c7ff9a00c8ffd700c9ff9a00cbff9a00cdff9a00ceffd700cfff9a00d5ff9a00d7ff9a00d9ff9a00dbff9a00ddff9a00deffd700e0ffd700e2ffd700e4ffd700f6ffbe0106ffc30108ffc3010affc3 010effd7010fff9a0111ff9a0112ffd70113ff9a0114ffd70115ff9a011cffec011dffae011fffae0120ffec0121ffae0122ffec0123ffae01240027012600270139ffec0140ffc30143ff9a0144ff9a 014affae015fff9a0166ffd70169ff9a016dffd7017100270179ff9a017bffc3017eff9a0180ffec0182ff9a0184ffc3018affec018cff9a018eff9a0190ff9a0193ff9a0196ff9a0199ff9a019bff9a 01a0ffec01a3ffbe01aaff9a01b8ffd701bbffd701bc002701caff9a01cfff9a01d8ff9a01dbff9a01ddffec01deff9a01eaff9a01edff9a01eeffae0201ffec02070052020b0052020fffd70228ff9a 0258ff9a0259ff9a025fffd70260ff9a026aff9a026cffd7026dffec0272ff9a027effd7027fff9a0281ffec0283ffec0284ffd70285ff9a0286ffd70287ff9a0288ffd70289ff9a028affd7028bffec 028cffd7028dff9a02a9002702b1ffd702b2ff9a02b3ffd702b4ff9a02b5002702b7002702b8ffec02b9002702baffec02bd002702d9ff9a02daff9a02dbff9a02dcff9a02ddff9a02e0ff9a02e1ffd7 02e3ffd702efffd702f0ff9a02f1ffd702f2ff9a02f3ffd702f4ff9a02f8ffec02faffec02fcffec030aff9a030cff9a030effec0310ffec0315ffd70316ff9a031700270319ffd7031aff9a031dff9a 031eff9a031fff9a0321ff9a0322ff9a0323ff9a0324ff9a0325ff9a0326ff9a0327ff9a0328ff9a0329ff9a032aff9a032bff9a032cff9a032dff9a032eff9a032fff9a0330ff9a0331ff9a0332ff9a 0333ff9a0334ff9a0336ff9a0338ff9a033aff9a033cff9a033eff9a0340ff9a0342ff9a0344ff9a0349ffd7034aff9a034bffd7034cff9a034dffd7034eff9a034fffd70350ff9a0351ffd70352ff9a 0353ffd70354ff9a0355ffd70356ff9a0357ffd70358ff9a0359ffd7035aff9a035bffd7035cff9a035dffd7035eff9a035fffd70360ff9a0362ffc30364ffc30366ffc30368ffc3036affc3036cffc3 036effc30370ffec0372ffec0374ffec00c500050029000a00290010ffc30026ffec002affec0032ffec0034ffec0036ffd70038ffec0046ffec0047ffec0048ffec0052ffec0054ffec0059ffd7005a ffd7005cffd70089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec00a8ffec00a9ffec00aaffec00abffec00acffec00adffec00b4ffec00b5 ffec00b6ffec00b7ffec00b8ffec00baffec00bfffd700c1ffd700c8ffec00c9ffec00cbffec00cdffec00ceffec00cfffec00d5ffec00d7ffec00d9ffec00dbffec00ddffec00deffec00e0ffec00e2 ffec00e4ffec010effec010fffec0111ffec0112ffec0113ffec0114ffd70115ffec011cffd70120ffd70122ffd7012cffec0130ffec0132ffec0134ffec0137ffd70139ffd70166ffec016dffec0179 ffec017effec0180ffd70182ffec018affd7018cffec018effec0190ffec0191ffd70193ffec0194ffd70196ffec0199ffec019bffec01a0ffd701b8ffec01bbffec01cfffec01d8ffec01dbffec01dc ffd701ddffd701deffec01eaffec01edffec01fbffd701fdffd701ffffd70201ffd702070029020b0029025fffec0260ffec0261ffec026affec026cffec026dffd7027effec027fffec0281ffd70283 ffd70284ffec0285ffec0286ffec0287ffec0288ffec0289ffec028affec028bffd7028cffec028dffec02aaffd702b1ffec02b2ffec02b3ffec02b4ffec02b6ffd702b8ffd702baffd702e0ffec02e1 ffec02e3ffec02efffec02f0ffec02f1ffec02f2ffec02f3ffec02f4ffec02f8ffd702faffd702fcffd7030affec030cffec030effd70310ffd70315ffec0316ffec0318ffd70319ffec031affec0336 ffec0338ffec033affec033cffec033effec0340ffec0342ffec0344ffec0349ffec034affec034bffec034cffec034dffec034effec034fffec0350ffec0351ffec0352ffec0353ffec0354ffec0355 ffec0356ffec0357ffec0358ffec0359ffec035affec035bffec035cffec035dffec035effec035fffec0360ffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec0370ffd70372 ffd70374ffd700330052ffec00a8ffec00b4ffec00b5ffec00b6ffec00b7ffec00b8ffec00baffec010fffec0111ffec0113ffec0115ffec018cffec018effec0190ffec0193ffec0196ffec0199ffec 019bffec01d8ffec01deffec020b00140260ffec026affec027fffec0285ffec0287ffec0289ffec028dffec02b2ffec02b4ffec02e0ffec02f0ffec02f2ffec02f4ffec030affec030cffec0316ffec 031affec034affec034cffec034effec0350ffec0352ffec0354ffec0356ffec0358ffec035affec035cffec035effec0360ffec000b016200290166ffec01690029016dffec0171ff850172ff9a0173 ffd70175ffd70178ff9a018800290191ffc300030166ffec016dffec0173ffec000b015fffec0164ffec0167ffec016cffec0170ffec0171ffc30172ffd70174ffd70177ffec0178ffd70188ffec0024 0010ffc3006dffc3015fff9a0162ffc30166ffd70169ffc30173ffd70176ffd70179ff9a017aff9a017bffc3017dffc3017eff9a0181ffae0182ff9a0183ffd70184ffc30185ffd70186ffc30187ffc3 0189ffc3018cff9a018eff9a018fff9a0190ff9a0192ffc30193ffae0194ffd70195ffc30196ffae0198ffd70199ff9a019affc3019bffae0202ffc30203ffc300030171ffc30172ffc30178ffc30019 0179ffd7017dffd7017effd70180ffd70181ffd70183ffec0185ffd70186ffd701880029018affd7018bffec018cffd7018dffec018fffec0190ffd70191ffec0192ffd70193ffd70194ffec0195ffd7 0196ffec0198ffd70199ffd7019affd7019bffd7004f0005ffae000affae0026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003cff9a0089ffec0094ffec0095ffec0096 ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffd70124ff850126ff85012c ffec0130ffec0132ffec0134ffec0136ffd70138ff9a013aff9a0166ffec016dffec0171ff850172ff9a0173ffd70175ffc30178ff9a0191ffc301faffd701fcffd701feffd70200ff9a0207ffae020b ffae025fffec0261ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036b ffec036dffec036fff9a0371ff9a0373ff9a00170037ffec0039ffec003bffec003cffec009fffec0124ffec0126ffec0138ffec013affec0167ffec016cffd70170ffec0171ffec0172ffec0174ffec 0177ffec0178ffec0191ffec0194ffec0200ffec036fffec0371ffec0373ffec00710005ff9a000aff9a000fff9a0010ff9a0011ff9a0026ffec002affec0032ffec0034ffec0037ff850038ffec0039 ffae003affc3003cff9a006dff9a007dffae0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0 ffec00e2ffec00e4ffec010effec0112ffec0114ffec0124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffc30138ff9a013aff9a015fff850162ff9a0166ffec0169ff9a016dffec0173 ffae0176ffd70179ff85017aff85017bffae017eff850180ffc30181ff9a0182ff850184ffc30186ffc30187ffc30189ffc3018affc3018cff85018dffc3018eff9a018fff850190ff850191ffc30192 ffc30193ff850194ffc30195ffc30196ff9a019700290198ffc30199ff85019affc3019bff9a01faffc301fcffc301feffc30200ff9a0202ff9a0203ff9a0207ff9a020bff9a025fffec0261ffec0349 ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a0371 ff9a0373ff9a00b200050052000a0052000fff9a0011ff9a002200290024ffc30026ffd7002affd70032ffd70034ffd70044ffc30046ffc30047ffc30048ffc3004affc30050ffd70051ffd70052ffc3 0053ffd70054ffc30055ffd70056ffd70058ffd70082ffc30083ffc30084ffc30085ffc30086ffc30087ffc30088ff850089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ffc3 00a3ffc300a4ffc300a5ffc300a6ffc300a7ffc300a8ffc300a9ffc300aaffc300abffc300acffc300adffc300b3ffd700b4ffc300b5ffc300b6ffc300b7ffc300b8ffc300baffc300bbffd700bcffd7 00bdffd700beffd700c2ffc300c3ffc300c4ffc300c5ffc300c6ffc300c7ffc300c8ffd700c9ffc300cbffc300cdffc300ceffd700cfffc300d5ffc300d7ffc300d9ffc300dbffc300ddffc300deffd7 00e0ffd700e2ffd700e4ffd70106ffd70108ffd7010affd7010effd7010fffc30111ffc30112ffd70113ffc30114ffd70115ffc3011dffd7011fffd70121ffd70123ffd70143ffc30144ffc3014affd7 016200140166ffd7016dffd70171ff9a0172ffc30173ffd70175ffd70178ffc30179ffc301880029018dffd702070052020b00520228ffc30258ffc30259ffc3025fffd70260ffc3031dffc3031effc3 031fffc30321ffc30322ffc30323ffc30324ffc30325ffc30326ffc30327ffc30328ffc30329ffc3032affc3032bffc3032cffc3032dffc3032effc3032fffc30330ffc30331ffc30332ffc30333ffc3 0334ffc30336ffc30338ffc3033affc3033cffc3033effc30340ffc30342ffc30344ffc30349ffd7034affc3034bffd7034cffc3034dffd7034effc3034fffd70350ffc30351ffd70352ffc30353ffd7 0354ffc30355ffd70356ffc30357ffd70358ffc30359ffd7035affc3035bffd7035cffc3035dffd7035effc3035fffd70360ffc30362ffd70364ffd70366ffd70368ffd7036affd7036cffd7036effd7 00080166ffec016dffec0173ffec0192ffd70195ffd7019700290198ffd7019affd70046000fffc30011ffc30024ffec002cffec0037ffc30039ffd7003affec003bffd7003cffd7003dffec0082ffec 0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd7008effec008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6ffec00ecffec00f0ffec00f2ffec0124ffc30126ffc30136ffec 0138ffd7013affd7013bffec013dffec013fffec0143ffec015fffec0162ffd70167ffec0169ffec016cffec0170ffec0171ffc30172ffd70174ffd70178ffd701faffec01fcffec01feffec0200ffd7 0228ffec0258ffec031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec0333ffec0345ffec0347ffec036fffd70371ffd70373ffd700050166 ffec016dffec0173ffec0181ffec01880029002a00050029000a00290026ffd7002affd70032ffd70034ffd70089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd7 00deffd700e0ffd700e2ffd700e4ffd7010effd70112ffd70114ffd70166ffd7016dffd70173ffae0191ffd70197002902070029020b0029025fffd70349ffd7034bffd7034dffd7034fffd70351ffd7 0353ffd70355ffd70357ffd70359ffd7035bffd7035dffd7035fffd700cf0005ffae000affae002200290024ffc30026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003c ff9a0044ffc30046ffc30047ffc30048ffc3004affc30050ffd70051ffd70052ffc30053ffd70054ffc30055ffd70056ffd70058ffd70082ffc30083ffc30084ffc30085ffc30086ffc30087ffc30088 ff850089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00a2ffc300a3ffc300a4ffc300a5ffc300a6ffc300a7ffc300a8ffc300a9 ffc300aaffc300abffc300acffc300adffc300b3ffd700b4ffc300b5ffc300b6ffc300b7ffc300b8ffc300baffc300bbffd700bcffd700bdffd700beffd700c2ffc300c3ffc300c4ffc300c5ffc300c6 ffc300c7ffc300c8ffec00c9ffc300cbffc300cdffc300ceffec00cfffc300d5ffc300d7ffc300d9ffc300dbffc300ddffc300deffec00e0ffec00e2ffec00e4ffec0106ffd70108ffd7010affd7010e ffec010fffc30111ffc30112ffec0113ffc30114ffd70115ffc3011dffd7011fffd70121ffd70123ffd70124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70138ff9a013aff9a0143 ffc30144ffc3014affd70166ffec016dffec0171ff850172ff9a0173ffd70175ffc30178ff9a0191ffd701faffd701fcffd701feffd70200ff9a0207ffae020bffae0228ffc30258ffc30259ffc3025f ffec0260ffc30261ffec031dffc3031effc3031fffc30321ffc30322ffc30323ffc30324ffc30325ffc30326ffc30327ffc30328ffc30329ffc3032affc3032bffc3032cffc3032dffc3032effc3032f ffc30330ffc30331ffc30332ffc30333ffc30334ffc30336ffc30338ffc3033affc3033cffc3033effc30340ffc30342ffc30344ffc30349ffec034affc3034bffec034cffc3034dffec034effc3034f ffec0350ffc30351ffec0352ffc30353ffec0354ffc30355ffec0356ffc30357ffec0358ffc30359ffec035affc3035bffec035cffc3035dffec035effc3035fffec0360ffc30361ffec0362ffd70363 ffec0364ffd70365ffec0366ffd70367ffec0368ffd70369ffec036affd7036bffec036cffd7036dffec036effd7036fff9a0371ff9a0373ff9a00030166ffec016dffec018800290046000fffc30011 ffc30024ffec002cffec0037ffc30039ffd7003affec003bffd7003cffd7003dffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd7008effec008fffec0090ffec0091ffec009f ffd700c2ffec00c4ffec00c6ffec00ecffec00f0ffec00f2ffec0124ffc30126ffc30136ffec0138ffd7013affd7013bffec013dffec013fffec0143ffec015fffec0167ffec0169ffec016cffec0170 ffec0171ffc30172ffd70174ffd70177ffec0178ffd701faffec01fcffec01feffec0200ffd70228ffec0258ffec031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032d ffec032fffec0331ffec0333ffec0345ffec0347ffec036fffd70371ffd70373ffd70036000fff330011ff330024ffae0026ffec003bffec003cffec003dffd70082ffae0083ffae0084ffae0085ffae 0086ffae0087ffae0088ff710089ffec009fffec00c2ffae00c4ffae00c6ffae00c8ffec00ceffec0138ffec013affec013bffd7013dffd7013fffd70143ffae015fffae0162ffae0164ffec0169ffae 0174ffec0178ffec0181ffd70188ffd7018effd70200ffec0228ffae0258ffae031dffae031fffae0321ffae0323ffae0325ffae0327ffae0329ffae032bffae032dffae032fffae0331ffae0333ffae 036fffec0371ffec0373ffec002900050029000a00290026ffd7002affd70032ffd70034ffd70089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd700deffd700e0 ffd700e2ffd700e4ffd7010effd70112ffd70114ffd70166ffd7016dffd70173ffd70188002902070029020b0029025fffd70349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357 ffd70359ffd7035bffd7035dffd7035fffd700e900050052000a0052000fff9a0010ff9a0011ff9a002200290024ff850026ffc3002affc30032ffc30034ffc30036ffec003700140044ff850046ff85 0047ff850048ff85004aff9a0050ffae0051ffae0052ff850053ffae0054ff850055ffae0056ff850058ffae0059ffc3005affc3005bffc3005cffc3005dffc3006dff9a007dffd70082ff850083ff85 0084ff850085ff850086ff850087ff850088ff710089ffc30094ffc30095ffc30096ffc30097ffc30098ffc3009affc300a2ff8500a3ff8500a4ff8500a5ff8500a6ff8500a7ff8500a8ff8500a9ff85 00aaff8500abff8500acff8500adff8500b3ffae00b4ff8500b5ff8500b6ff8500b7ff8500b8ff8500baff8500bbffae00bcffae00bdffae00beffae00bfffc300c1ffc300c2ff8500c3ff8500c4ff85 00c5ff8500c6ff8500c7ff8500c8ffc300c9ff8500cbff8500cdff8500ceffc300cfff8500d5ff8500d7ff8500d9ff8500dbff8500ddff8500deffc300e0ffc300e2ffc300e4ffc30106ffae0108ffae 010affae010effc3010fff850111ff850112ffc30113ff850114ffc30115ff85011cffec011dff85011fff850120ffec0121ff850122ffec0123ff8501240014012600140137ffc30139ffc30140ffc3 0143ff850144ff85014aff85015fff850162ff9a0166ffc30169ff85016dffc3017100140173ffc30176ffc30179ff85017aff85017bffae017dffae017eff850180ffc30181ffae0182ff850184ffae 0186ffae0187ffae018800140189ffae018affc3018cff85018eff85018fff850190ff850191ffc30192ffae0193ff850194ffc30195ffae0196ff850197003d0198ffae0199ff85019affae019bff85 01fbffc301fdffc301ffffc30201ffc30202ff9a0203ff9a02070052020b00520228ff850258ff850259ff85025fffc30260ff85031dff85031eff85031fff850321ff850322ff850323ff850324ff85 0325ff850326ff850327ff850328ff850329ff85032aff85032bff85032cff85032dff85032eff85032fff850330ff850331ff850332ff850333ff850334ff850336ff850338ff85033aff85033cff85 033eff850340ff850342ff850344ff850349ffc3034aff85034bffc3034cff85034dffc3034eff85034fffc30350ff850351ffc30352ff850353ffc30354ff850355ffc30356ff850357ffc30358ff85 0359ffc3035aff85035bffc3035cff85035dffc3035eff85035fffc30360ff850362ffae0364ffae0366ffae0368ffae036affae036cffae036effae0370ffc30372ffc30374ffc3002d000fff9a0010 ffc30011ff9a006dffc3015fff9a0162ffc30166ffd70169ff9a016dffd70173ffc30176ffd70179ff9a017affae017bffc3017cffec017dffd7017eff9a017fffd70181ff9a0182ffae0183ffd70184 ffc30185ffd70186ffc30187ffc3018800140189ffc3018bffec018cff9a018eff9a018fff9a0190ff9a0191ffec0192ffc30193ff9a0194ffd70195ffc30196ffae019700290198ffc30199ff9a019a ffc3019bffae0202ffc30203ffc3000a015fffd70162ffd70167ffec0169ffd70171ffc30172ffc30174ffc30177ffd70178ffc30188ffd700170166ffd7016dffd70173ffc30179ffec017cffec017d ffec017effec0181ffec0185ffec0186ffec01880014018cffec018fffec0190ffec0191ffd70192ffd70193ffec0195ffd70196ffec0198ffd70199ffec019affd7019bffec000c000fffae0011ffae 015fffc30162ffd70169ffc30181ffd7018effd70190ffec0193ffec0196ffec0199ffec019bffec00030171ffc30172ffd70178ffd7002c00050029000a00290026ffec002affec0032ffec0034ffec 0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec0166ffec016dffec0173ffd70180ffec 0181ffec018800140191ffec02070029020b0029025fffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec00ee000500520009 ffc3000a0052000c003d000d0029000fff9a0010ff5c0011ff9a002200290024ff9a0026ffd7002affd7002dffbe0030ffec0032ffd70034ffd70036ffec003700270040003d0044ff9a0046ff9a0047 ff9a0048ff9a0049ffe5004aff9a0050ffc30051ffc30052ff9a0053ffc30054ff9a0055ffc30056ffae0058ffc3005bffd7005cffec005dffc30060003d006dffc3007dffd70082ff9a0083ff9a0084 ff9a0085ff9a0086ff9a0087ff9a0088ff710089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700a2ff9a00a3ff9a00a4ff9a00a5ff9a00a6ff9a00a7ff9a00a8ff9a00a9ff9a00aa ff9a00abff9a00acff9a00adff9a00b3ffc300b4ff9a00b5ff9a00b6ff9a00b7ff9a00b8ff9a00baff9a00bbffc300bcffc300bdffc300beffc300bfffec00c1ffec00c2ff9a00c3ff9a00c4ff9a00c5 ff9a00c6ff9a00c7ff9a00c8ffd700c9ff9a00cbff9a00cdff9a00ceffd700cfff9a00d5ff9a00d7ff9a00d9ff9a00dbff9a00ddff9a00deffd700e0ffd700e2ffd700e4ffd700f6ffbe0106ffc30108 ffc3010affc3010effd7010fff9a0111ff9a0112ffd70113ff9a0114ffd70115ff9a011cffec011dffae011fffae0120ffec0121ffae0122ffec0123ffae01240027012600270139ffec0140ffc30143 ff9a0144ff9a014affae015fff9a0162ffc30166ffd70169ff9a016dffd70173ffc30176ffd70179ff9a017affae017bffc3017cffec017dffc3017eff9a017fffd70180ffec0181ff9a0182ff9a0183 ffd70184ffc30186ffc30187ffc30189ffc3018affec018bffec018cff9a018dffd7018eff9a018fff9a0190ff9a0191ffd70192ffc30193ff9a0194ffd70195ffc30196ff9a019700290198ffc30199 ff9a019affc3019bff9a0201ffec02070052020b0052020fffd70228ff9a0258ff9a0259ff9a025fffd70260ff9a031dff9a031eff9a031fff9a0321ff9a0322ff9a0323ff9a0324ff9a0325ff9a0326 ff9a0327ff9a0328ff9a0329ff9a032aff9a032bff9a032cff9a032dff9a032eff9a032fff9a0330ff9a0331ff9a0332ff9a0333ff9a0334ff9a0336ff9a0338ff9a033aff9a033cff9a033eff9a0340 ff9a0342ff9a0344ff9a0349ffd7034aff9a034bffd7034cff9a034dffd7034eff9a034fffd70350ff9a0351ffd70352ff9a0353ffd70354ff9a0355ffd70356ff9a0357ffd70358ff9a0359ffd7035a ff9a035bffd7035cff9a035dffd7035eff9a035fffd70360ff9a0362ffc30364ffc30366ffc30368ffc3036affc3036cffc3036effc30370ffec0372ffec0374ffec00010188002900060179ffd7017e ffec0181ffec018cffec0190ffec0193ffec00140179ffec017cffec017dffec0180ffec0181ffec0185ffec0186ffec01880029018affd7018cffec018dffec018fffec0190ffec0191ffd70192ffec 0195ffec0197ffec0198ffec0199ffec019affec00010194ffec000b0005003d000a003d004900140181ffec018d0029018effec0191001401940014019600140207003d020b003d00020191ffec0194 ffd7000b0005003d000a003d0179ffd70181ffec018cffd7018fffec0190ffd70193ffd70199ffd70207003d020b003d001c0179ffae017affd7017dffd7017effc30180ffd70181ffc30182ffd70183 ffd70184ffd70185ffd70186ffd70187ffec01880029018affd7018bffd7018cffc3018dffc3018fffc30190ffc30191ffc30192ffc30193ffc30195ffc30196ffc30198ffc30199ffc3019affc3019b ffc3001000050052000a00520179ffd7017dffec017effec0180ffd70185ffd70186ffec01880029018affd7018dffd70191ffd70193ffd70197ffec02070052020b0052000900050029000a00290179 ffd7017effd70181ffd70182ffec018cffec02070029020b0029000d0005003d000a003d00490014017dffec0180ffec0185ffd70188003d018affd7018dffd70191ffc30194ffd70207003d020b003d 00070005003d000a003d00490014018d0014018effec0207003d020b003d0003001e003d017effec018800290005005bffd7005dffec0140ffec0191ffec0194ffd70004017effec01800014018a0029 019100140007005bffd7005dffec0140ffec01800014018a0014018d001401910029000e00050052000a005200490014007d0029018000140181ffec018a0029018cffd7018d0014018fffd70190ffec 0191001402070052020b00520004005bffd7005dffec0140ffec0194ffec001500050052000a0052004900140179ffd7017affd7017effd7018000140181ffd70182ffd70185ffec018cffd7018fffd7 0190ffd70192ffec0193ffec019400290195ffd70196ffd70199ffec02070052020b00520004005bffd7005dffec0140ffec0180001400130179ffec017dffec017effd70180ffd70181ffec0185ffd7 01880029018cffec018dffd7018fffec0190ffec0191ffd70192ffec0194ffec0195ffd70198ffec0199ffec019affec019bffec003800050029000a00290010ffd70026ffec002d003d0032ffec0034 ffec0084ffec0089ffec008affec008fffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec00c8ffec00ceffec00f6003d010effec0112ffec01b8ffec01bbffec01beffec02070029020b 0029025fffec026cffec027effec0284ffec0286ffec0288ffec028affec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034d ffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec003d0005ffc3000affc3019dff8501a6ff8501b0ffd701bcff8501bdffd701bfffec01c1ffc301c4ff85 01dcffc301ddffec01dfffec01e1ffc301e4ffae0207ffc3020bffc3026dffec0276ffd7027cffc3027dffc30280ffc30281ffec0282ffc30283ffec028bffec029fffd702a9ff8502aaffc302b5ff85 02b6ffc302b7ff8502b8ffec02b9ff8502baffec02bbffd702bdff8502bfffc302c0ffc302c1ffc302c2ffc302caffd702d4ffc302d5ffc302e5ffd702f7ffd702f8ffec02f9ffd702faffec02fbffd7 02fcffec02fdffc302feffc30305ffd70307ffd7030dffc3030effec030fffc30310ffec0317ff850318ffc300d400050052000a00520010ff5c0026ffec002affec0032ffec0034ffec0037ff850038 ffec0039ffae003affc3003cff9a0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2 ffec00e4ffec010effec0112ffec0114ffec0124ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffc30138ff9a013aff9a019fffec01a4ff9a01aaff8501aeff8501b5ff8501b8ffd701bb ffec01beffc301caff8501cbffd701ccffc301cdffc301ceff5c01cfff8501d0ffc301d1ffc301d2ffc301d3ffc301d4ffc301d5ff5c01d6ffc301d7ffc301d8ff8501d9ffc301daffc301dbff8501dc ffc301ddffc301deff8501dfffc301e0ffc301e1ffc301e2ffc301e3ffc301e4ffc301e5ffc301e6ffc301e7ffc301e8ffc301e9ff9a01eaff8501ecffc301edff8501eeffae01f0003d01f2ff5c01f3 ffc301f5ffc301f7ffc301f9ffc301faffc301fcffc301feffc30200ff9a02070052020b0052025fffec0261ffec026aff85026bffc3026cffd7026dffc30272ff85027dffc3027effd7027fff850281 ffc30283ffc30284ffd70285ff850286ffd70287ff850288ffd70289ff85028affd7028bffc3028cffd7028dff850296ffc3029affc302a0ffc302a4ffc302a6ffc302aaffc302acffc302aeffc302b0 ffc302b1ffd702b2ff8502b3ffd702b4ff8502b6ffc302b8ffc302baffc302bcffc302c0ffc302c2ffc302c4ffc302c5ffae02c6ff7102c7ffae02cbffc302ceff8502cfff5c02d1ffc302d3ffc302d5 ffc302d7ffc302d9ff8502daff8502dbff8502dcff8502ddff8502e0ff8502e1ffd702e3ffd702e6ffc302ecffc302eeffc302efffd702f0ff8502f1ffd702f2ff8502f3ffd702f4ff8502f8ffc302fa ffc302fcffc302feffc30300ffc30306ffc30308ffc30309ff5c030aff85030bff5c030cff85030effc30310ffc30311ff850312ff5c0314ffc30315ffd70316ff850318ffc30319ffd7031aff85031b ff85031cff5c0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036d ffec036fff9a0371ff9a0373ff9a001f00050029000a0029019fffd701b8ffec01bbffd701beffec01deffd701e1ffd702070029020b0029026cffec027dffd7027effec0284ffec0286ffec0288ffec 028affec028cffec02b1ffec02b3ffec02c0ffd702c2ffd702d5ffd702e1ffec02e3ffec02efffec02f1ffec02f3ffec02feffd70315ffec0319ffec000501a0ffec01dcffd702aaffd702b6ffd70318 ffd7001a019fffec01dcffd701ddffec01e1ffd701e4ffec026dffec027dffd70281ffec0283ffec028bffec02aaffd702b6ffd702b8ffec02baffec02c0ffd702c2ffd702c5ffd702c7ffd702d5ffd7 02f8ffec02faffec02fcffec02feffd7030effec0310ffec0318ffd7003700050029000a00290026ffec002affec0032ffec0034ffec0089ffec0094ffec0095ffec0096ffec0097ffec0098ffec009a ffec00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec019fffec01b8ffec01bbffec020b0029025fffec026cffec027effec0284ffec0286ffec0288ffec028a ffec028cffec02b1ffec02b3ffec02e1ffec02e3ffec02efffec02f1ffec02f3ffec0315ffec0319ffec0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035b ffec035dffec035fffec00340005ff9a000aff9a01a6ff8501a8ffd701b0ffd701b5ffec01bcff8501bdffec01bfffec01c1ffae01c4ff8501dcffd701e1ffd701e4ffc30207ff9a020bff9a0276ffd7 027cffae027dffd70280ffae0282ffae029fffd702a9ff8502aaffd702b5ff8502b6ffd702b7ff8502b9ff8502bbffd702bdff8502bfffae02c0ffd702c1ffae02c2ffd702caffd702ceffec02d4ffae 02d5ffd702e5ffd702f7ffec02f9ffec02fbffec02fdffae02feffd70305ffd70307ffd7030dffae030fffae0311ffec0317ff850318ffd7031bffec00310005ff9a000aff9a019dff8501a6ff8501a8 ffd701b0ffec01bcff8501bdffd701c1ffae01c4ff8501dcffd701dfffec01e1ffec01e4ffd70207ff9a020bff9a0276ffec027cffae027dffec0280ffae0282ffae029fffec02a9ff8502aaffd702b5 ff8502b6ffd702b7ff8502b9ff8502bbffec02bdff8502bfffae02c0ffec02c1ffae02c2ffec02caffec02d4ffae02d5ffec02e5ffec02f7ffd702f9ffd702fbffd702fdffae02feffec0305ffec0307 ffec030dffae030fffae0317ff850318ffd7001d019dff9a01a6ff9a01c4ff8501dcffd701ddffec01e1ffd701e4ffc301f6ffec026dffec027dffd70281ffec0283ffec028bffec02aaffd702b6ffd7 02b8ffec02baffec02c0ffd702c2ffd702c5ffd702c7ffd702d5ffd702f8ffec02faffec02fcffec02feffd7030effec0310ffec0318ffd7006d00050029000a00290026ffd7002affd70032ffd70034 ffd70089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd700deffd700e0ffd700e2ffd700e4ffd7010effd70112ffd70114ffd7019fffd701a4002901b5002901b8 ffd701bbffd701beffae01cbffec01ce001401cfffd701d8ffd701dbffd701dcffd701ddffd701deffd701e1ffc301e4ffd701eaffd701edffd702070029020b0029025fffd7026affd7026cffd7026d ffd7027dffc3027effd7027fffd70281ffd70283ffd70284ffd70285ffd70286ffd70287ffd70288ffd70289ffd7028affd7028bffd7028cffd7028dffd702aaffd702b1ffd702b2ffd702b3ffd702b4 ffd702b6ffd702b8ffd702baffd702c0ffc302c2ffc302ce002902d5ffc302e0ffd702e1ffd702e3ffd702efffd702f0ffd702f1ffd702f2ffd702f3ffd702f4ffd702f8ffd702faffd702fcffd702fe ffc3030affd7030cffd7030effd70310ffd7031100290315ffd70316ffd70318ffd70319ffd7031affd7031b00290349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357ffd70359 ffd7035bffd7035dffd7035fffd7006700050052000a005201a4ff9a01aaff8501aeff7101b5ff9a01bbffd701bc002901beffd701c4001401c9ffec01caffae01ccffd701cdffd701ceff5c01cfffae 01d1ffd701d2ffd701d3ffd701d4ffd701d5ff5c01d6ffd701d7ffd701d8ffae01d9ffd701daffd701dbffae01deffae01e0ffd701e1ffd701e2ffd701e3ffd701e5ffd701e6ffd701e8ffd701e9ffd7 01eaffd701ecffd701edffae01eeffd701f0005201f2ff7101f3ffd701f5ffd701f7ffd701f9ffd702070052020b0052026affae026bffd70272ff85027dffd7027fffae0285ffae0287ffae0289ffae 028dffae0296ffd7029affd702a4ffd702a6ffd702a9002902acffd702aeffd702b0ffd702b2ffae02b4ffae02b5002902b7002902b9002902bd002902c0ffd702c2ffd702c4ffd702ceff9a02cfff5c 02d1ffd702d3ffd702d5ffd702d7ffd702d9ff8502daffae02dbff8502dcffae02ddff8502e0ffae02ecffd702eeffd702f0ffae02f2ffae02f4ffae02feffd70300ffd7030affae030cffae0311ff9a 0312ff5c0314ffd70316ffae03170029031affae031bff9a031cff5c00890005ffae000affae0026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffc3003affd7003cff9a0089ffec0094 ffec0095ffec0096ffec0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffd70124 ff850126ff85012cffec0130ffec0132ffec0134ffec0136ffd70138ff9a013aff9a019dff9a019fffec01a4003d01a6ff8501ae002901b5002901b8ffec01bbffec01bcff8501beffd701c1ffae01c4 ff9a01d5002901dcffd701e1ffc301e4ffc301e7002901f2002901faffd701fcffd701feffd70200ff9a0207ffae020bffae025fffec0261ffec026cffec027cffae027dffc3027effec0280ffae0282 ffae0284ffec0286ffec0288ffec028affec028cffec02a9ff8502aaffd702b1ffec02b3ffec02b5ff8502b6ffd702b7ff8502b9ff8502bdff8502bfffae02c0ffc302c1ffae02c2ffc302c5ffae02c6 ffc302c7ffae02ce002902cf002902d4ffae02d5ffc302e1ffec02e3ffec02efffec02f1ffec02f3ffec02fdffae02feffc3030dffae030fffae03110029031200290315ffec0317ff850318ffd70319 ffec031b0029031c00290349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036b ffec036dffec036fff9a0371ff9a0373ff9a002a019dffd701bcffd701bdffd701bfffec01c1ffc301c4ffd701d0ffec01dcffd701e1ffd701e4ffd7027cffc3027dffd70280ffc30282ffc302a0ffec 02a9ffd702aaffd702b5ffd702b6ffd702b7ffd702b9ffd702bcffec02bdffd702bfffc302c0ffd702c1ffc302c2ffd702cbffec02d4ffc302d5ffd702e6ffec02f7ffd702f9ffd702fbffd702fdffc3 02feffd70306ffec0308ffec030dffc3030fffc30317ffd70318ffd700210037ffec0039ffec003bffec003cffec009fffec0124ffec0126ffec0138ffec013affec01b0ffec01bcffec01bdffec01bf ffec0200ffec0276ffec029fffec02a9ffec02b5ffec02b7ffec02b9ffec02bbffec02bdffec02caffec02e5ffec02f7ffec02f9ffec02fbffec0305ffec0307ffec0317ffec036fffec0371ffec0373 ffec008f00050052000a00520010ff5c019fffec01a4ff9a01aaff8501aeff8501b5ff8501b8ffd701beffc301caff8501ccffc301cdffc301ceff5c01cfff8501d0ffc301d1ffc301d2ffc301d3ffc3 01d4ffc301d5ff5c01d6ffc301d7ffc301d8ff8501d9ffc301daffc301dbff8501dcffc301ddffc301deff8501dfffc301e0ffc301e1ffc301e2ffc301e3ffc301e4ffc301e5ffc301e6ffc301e7ffc3 01e8ffc301e9ff9a01eaff8501ecffc301edff8501eeffae01f0003d01f2ff5c01f3ffc301f5ffc301f7ffc301f9ffc302070052020b0052026aff85026bffc3026cffd7026dffc30272ff85027dffc3 027effd7027fff850281ffc30283ffc30284ffd70285ff850286ffd70287ff850288ffd70289ff85028affd7028bffc3028cffd7028dff850296ffc3029affc302a0ffc302a4ffc302a6ffc302aaffc3 02acffc302aeffc302b0ffc302b1ffd702b2ff8502b3ffd702b4ff8502b6ffc302b8ffc302baffc302bcffc302c0ffc302c2ffc302c4ffc302c5ffae02c6ff7102c7ffae02cbffc302ceff8502cfff5c 02d1ffc302d3ffc302d5ffc302d7ffc302d9ff8502daff8502dbff8502dcff8502ddff8502e0ff8502e1ffd702e3ffd702e6ffc302ecffc302eeffc302efffd702f0ff8502f1ffd702f2ff8502f3ffd7 02f4ff8502f8ffc302faffc302fcffc302feffc30300ffc30306ffc30308ffc30309ff5c030aff85030bff5c030cff85030effc30310ffc30311ff850312ff5c0314ffc30315ffd70316ff850318ffc3 0319ffd7031aff85031bff85031cff5c0042019dffd701a300f601a4002901a6ffd701aa001401ae002901b5002901b8ffec01bbffec01bcffd701beffec01c1ffd701c4ffd701ce002901d5002901e1 ffd701e7002901f1006601f20029026cffec02720014027cffd7027dffd7027effec0280ffd70282ffd70284ffec0286ffec0288ffec028affec028cffec02a9ffd702b1ffec02b3ffec02b5ffd702b7 ffd702b9ffd702bdffd702bfffd702c0ffd702c1ffd702c2ffd702c6ffd702ce002902cf002902d4ffd702d5ffd702d9001402db001402dd001402e1ffec02e3ffec02efffec02f1ffec02f3ffec02fd ffd702feffd7030dffd7030fffd703110029031200290315ffec0317ffd70319ffec031b0029031c002900310005003d000a003d0010ffd7019fffd701a4002901b5002901b8ffd701bbffd701beffc3 01cbffd701d5002901dcffd701e1ffae01f200290207003d020b003d026cffd7027dffae027effd70284ffd70286ffd70288ffd7028affd7028cffd702aaffd702b1ffd702b3ffd702b6ffd702c0ffae 02c2ffae02c5ffc302c6ff9a02c7ffc302ce002902cf002902d5ffae02e1ffd702e3ffd702efffd702f1ffd702f3ffd702feffae03110029031200290315ffd70318ffd70319ffd7031b0029031c0029 002600050029000a002901b1ffec01b5ffd701bcffd701bdffec01beffec01bfffd701c1ffec01c4ffec01c7ffec02070029020b0029027cffec0280ffec0282ffec02a1ffec02a9ffd702b5ffd702b7 ffd702b9ffd702bdffd702bfffec02c1ffec02ceffd702d4ffec02e7ffec02e9ffec02f5ffec02f7ffec02f9ffec02fbffec02fdffec030dffec030fffec0311ffd70317ffd7031bffd7004c00050029 000a00290010ffd70026ffd7002affd70032ffd70034ffd70089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd700deffd700e0ffd700e2ffd700e4ffd7010effd7 0112ffd70114ffd7019fffd701a4003d01b5002901b8ffd701bbffd701beffae01cbffd701d5002901e1ffae01e4ffd701f2002902070029020b0029025fffd7026cffd7027dffae027effd70284ffd7 0286ffd70288ffd7028affd7028cffd702b1ffd702b3ffd702c0ffae02c2ffae02ce002902cf002902d5ffae02e1ffd702e3ffd702efffd702f1ffd702f3ffd702feffae03110029031200290315ffd7 0319ffd7031b0029031c00290349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357ffd70359ffd7035bffd7035dffd7035fffd70056000fffc30011ffc30024ffec002cffec0037 ffc30039ffd7003affec003bffd7003cffd7003dffec0082ffec0083ffec0084ffec0085ffec0086ffec0087ffec0088ffd7008effec008fffec0090ffec0091ffec009fffd700c2ffec00c4ffec00c6 ffec00ecffec00f0ffec00f2ffec0124ffc30126ffc30136ffec0138ffd7013affd7013bffec013dffec013fffec0143ffec019dffd701a4ffd701a6ffd701aaffec01aeffec01b0ffd701bcffc301bf ffec01c4ffd701faffec01fcffec01feffec0200ffd70228ffec0258ffec0272ffec0276ffd7029fffd702a9ffc302b5ffc302b7ffc302b9ffc302bbffd702bdffc302caffd702d9ffec02dbffec02dd ffec02e5ffd70305ffd70307ffd70317ffc3031dffec031fffec0321ffec0323ffec0325ffec0327ffec0329ffec032bffec032dffec032fffec0331ffec0333ffec0345ffec0347ffec036fffd70371 ffd70373ffd700450005003d000a003d000fff330011ff330024ffae0026ffec003bffec003cffec003dffd70082ffae0083ffae0084ffae0085ffae0086ffae0087ffae0088ff710089ffec009fffec 00c2ffae00c4ffae00c6ffae00c8ffec00ceffec0138ffec013affec013bffd7013dffd7013fffd70143ffae01a4ffae01aaffae01aeff9a01b5ff9a01bbffec01ceff9a01d5ffae01f2ffae0200ffec 0207003d020b003d0228ffae0258ffae0272ffae02ceff9a02cfffae02d9ffae02dbffae02ddffae0309ffae030bffae0311ff9a0312ffae031bff9a031cffae031dffae031fffae0321ffae0323ffae 0325ffae0327ffae0329ffae032bffae032dffae032fffae0331ffae0333ffae036fffec0371ffec0373ffec004200050029000a0029000c00290026ffd7002affd70032ffd70034ffd7004000290060 00290089ffd70094ffd70095ffd70096ffd70097ffd70098ffd7009affd700c8ffd700ceffd700deffd700e0ffd700e2ffd700e4ffd7010effd70112ffd7019fffd701b8ffd701bbffd701beffc301e1 ffc302070029020b0029025fffd7026cffd7027dffc3027effd70284ffd70286ffd70288ffd7028affd7028cffd702b1ffd702b3ffd702c0ffc302c2ffc302c6ffae02d5ffc302e1ffd702e3ffd702ef ffd702f1ffd702f3ffd702feffc30315ffd70319ffd70349ffd7034bffd7034dffd7034fffd70351ffd70353ffd70355ffd70357ffd70359ffd7035bffd7035dffd7035fffd7015200050052000a0052 000fff9a0010ff9a0011ff9a002200290024ff850026ffc3002affc30032ffc30034ffc30036ffec003700140044ff850046ff850047ff850048ff85004aff9a0050ffae0051ffae0052ff850053ffae 0054ff850055ffae0056ff850058ffae0059ffc3005affc3005bffc3005cffc3005dffc30082ff850083ff850084ff850085ff850086ff850087ff850088ff710089ffc30094ffc30095ffc30096ffc3 0097ffc30098ffc3009affc300a2ff8500a3ff8500a4ff8500a5ff8500a6ff8500a7ff8500a8ff8500a9ff8500aaff8500abff8500acff8500adff8500b3ffae00b4ff8500b5ff8500b6ff8500b7ff85 00b8ff8500baff8500bbffae00bcffae00bdffae00beffae00bfffc300c1ffc300c2ff8500c3ff8500c4ff8500c5ff8500c6ff8500c7ff8500c8ffc300c9ff8500cbff8500cdff8500ceffc300cfff85 00d5ff8500d7ff8500d9ff8500dbff8500ddff8500deffc300e0ffc300e2ffc300e4ffc30106ffae0108ffae010affae010effc3010fff850111ff850112ffc30113ff850114ffc30115ff85011cffec 011dff85011fff850120ffec0121ff850122ffec0123ff8501240014012600140137ffc30139ffc30140ffc30143ff850144ff85014aff85019fffc301a0ffec01a4ffae01aaff8501aeff9a01b5ff9a 01b8ffc301bbffc301bc001401beffc301c4001401caff8501ccffc301cdffc301ceff7101cfff8501d0ffc301d1ffc301d2ffc301d4ffc301d5ff7101d6ffc301d7ffc301d8ff8501d9ffc301daffc3 01dbff8501dcffc301ddffc301deff8501dfffc301e0ffc301e1ffc301e2ffc301e3ffc301e5ffc301e6ffc301e8ffc301e9ffc301eaff8501eb002901ecffc301edff8501eeff8501f0005201f2ff85 01f3ffc301f5ffc301f7ffc301f9ffc301fbffc301fdffc301ffffc30201ffc302070052020b00520228ff850258ff850259ff85025fffc30260ff85026aff85026bffc3026cffc3026dffc30272ff85 027dffc3027effc3027fff850281ffc30283ffc30284ffc30285ff850286ffc30287ff850288ffc30289ff85028affc3028bffc3028cffc3028dff850296ffc3029affc302a0ffc302a4ffc302a6ffc3 02a9001402aaffc302acffc302aeffc302b0ffc302b1ffc302b2ff8502b3ffc302b4ff8502b5001402b6ffc302b7001402b8ffc302b9001402baffc302bcffc302bd001402c0ffc302c2ffc302c4ffc3 02c5ffc302c6ff8502c7ffc302cbffc302ceff9a02cfff7102d1ffc302d3ffc302d5ffc302d7ffc302d9ff8502daff8502dbff8502dcff8502ddff8502e0ff8502e1ffc302e3ffc302e6ffc302ecffc3 02eeffc302efffc302f0ff8502f1ffc302f2ff8502f3ffc302f4ff8502f8ffc302faffc302fcffc302feffc30300ffc30306ffc30308ffc30309ff85030aff85030bff85030cff85030effc30310ffc3 0311ff9a0312ff710314ffc30315ffc30316ff85031700140318ffc30319ffc3031aff85031bff9a031cff71031dff85031eff85031fff850321ff850322ff850323ff850324ff850325ff850326ff85 0327ff850328ff850329ff85032aff85032bff85032cff85032dff85032eff85032fff850330ff850331ff850332ff850333ff850334ff850336ff850338ff85033aff85033cff85033eff850340ff85 0342ff850344ff850349ffc3034aff85034bffc3034cff85034dffc3034eff85034fffc30350ff850351ffc30352ff850353ffc30354ff850355ffc30356ff850357ffc30358ff850359ffc3035aff85 035bffc3035cff85035dffc3035eff85035fffc30360ff850362ffae0364ffae0366ffae0368ffae036affae036cffae036effae0370ffc30372ffc30374ffc300630005003d000a003d0010ffd7019f ffd701a4ffae01aaff9a01aeff8501b5ff9a01bbffd701beffec01c4002901caffae01ccffc301cdffc301ceff7101cfffc301d2ffc301d3ffc301d4ffc301d5ff7101d6ffc301d7ffc301d8ff9a01d9 ffc301daffc301dbffc301deffae01e0ffc301e1ffc301e2ffc301e3ffc301e5ffc301e6ffc301e8ffc301e9ffc301eaffc301ecffc301edffc301eeffc301f0003d01f2ff8501f3ffc301f5ffc301f7 ffc301f9ffc30207003d020b003d026aff9a026bffc30272ff9a027dffc3027fff9a0285ff9a0287ff9a0289ff9a028dff9a0296ffc3029affc302a4ffc302a6ffc302acffc302aeffc302b0ffc302b2 ff9a02b4ff9a02c0ffc302c2ffc302c4ffc302c6ffae02ceff9a02cfff7102d1ffc302d3ffc302d5ffc302d7ffc302d9ff9a02daffae02dbff9a02dcffae02ddff9a02e0ff9a02ecffc302eeffc302f0 ff9a02f2ff9a02f4ff9a02feffc30300ffc30309ff85030aff9a030bff85030cff9a0311ff9a0312ff710314ffc30316ff9a031aff9a031bff9a031cff71002a019dffd701a4ffd701a6ffc301a8ffec 01aaffd701aeffd701b0ffc301b5ffd701bcffc301bfffd701c4ffc301c7ffd701ceffc301d5ffc301f2ffc30272ffd70276ffc3029fffc302a1ffd702a9ffc302b5ffc302b7ffc302b9ffc302bbffc3 02bdffc302caffc302ceffd702cfffc302d9ffd702dbffd702ddffd702e5ffc302e7ffd702e9ffd702f5ffd70305ffc30307ffc30311ffd70312ffc30317ffc3031bffd7031cffc3002e00050029000a 0029019fffd701a4003d01ae002901b5002901b8ffec01bbffd701beffd701c1ffec01e1ffc302070029020b0029026cffec027cffec027dffc3027effec0280ffec0282ffec0284ffec0286ffec0288 ffec028affec028cffec02b1ffec02b3ffec02bfffec02c0ffc302c1ffec02c2ffc302ce002902d4ffec02d5ffc302e1ffec02e3ffec02efffec02f1ffec02f3ffec02fdffec02feffc3030dffec030f ffec031100290315ffec0319ffec031b0029003001a300f601a4002901aa001401ae002901b5002901bcffec01beffec01bf001401c1ffec01ce002901d5001401e1ffd701e7002901f1006601f20029 02720014027cffec027dffd70280ffec0282ffec02a9ffec02b5ffec02b7ffec02b9ffec02bdffec02bfffec02c0ffd702c1ffec02c2ffd702c5ffd702c6ffd702c7ffd702ce002902cf001402d4ffec 02d5ffd702d9001402db001402dd001402fdffec02feffd7030dffec030fffec03110029031200140317ffec031b0029031c0014003e019dffec01a300e101a4003d01aa002901ae002901b5002901bc ffec01bd002901beffec01bf001401c1ffec01c4ffec01c7001401ce003d01d1001401d5002901dcffec01e1ffd701e4ffec01e7002901f1006601f2002902720029027cffec027dffd70280ffec0282 ffec02a1001402a9ffec02aaffec02b5ffec02b6ffec02b7ffec02b9ffec02bdffec02bfffec02c0ffd702c1ffec02c2ffd702ce002902cf002902d4ffec02d5ffd702d9002902db002902dd002902e7 001402e9001402f5001402f7002902f9002902fb002902fdffec02feffd7030dffec030fffec03110029031200290317ffec0318ffec031b0029031c0029001e0005ffc3000affc3019dff8501a6ff71 01a8ffd701bcff8501c1ffc301c4ff8501dcffd701e4ffd70207ffc3020bffc3027cffc30280ffc30282ffc302a9ff8502aaffd702b5ff8502b6ffd702b7ff8502b9ff8502bdff8502bfffc302c1ffc3 02d4ffc302fdffc3030dffc3030fffc30317ff850318ffd700200005ff9a000aff9a019dff8501a6ff8501a8ffd701bcff8501c1ffc301c4ff8501dcffd701e4ffd70207ff9a020bff9a027cffc30280 ffc30282ffc302a9ff8502aaffd702b5ff8502b6ffd702b7ff8502b9ff8502bdff8502bfffc302c1ffc302c5ffc302c7ffc302d4ffc302fdffc3030dffc3030fffc30317ff850318ffd70023019dffd7 01a4ffd701a6ffd701a8ffd701aeffd701b0ffc301b1ffec01b5ffc301bcffd701bdffec01bfffd701d5ffd701f2ffd70276ffc3029fffc302a9ffd702b5ffd702b7ffd702b9ffd702bbffc302bdffd7 02caffc302ceffc302cfffd702e5ffc302f7ffec02f9ffec02fbffec0305ffc30307ffc30311ffc30312ffd70317ffd7031bffc3031cffd7001d019dffd701a4ffd701a6ffd701a8ffec01aeffd701b0 ffd701b1ffec01b5ffd701bdffec01bfffd701ceffd701d5ffd701f2ffd70276ffd7029fffd702bbffd702caffd702ceffd702cfffd702e5ffd702f7ffec02f9ffec02fbffec0305ffd70307ffd70311 ffd70312ffd7031bffd7031cffd70019000affd701dcffd701ddffec01e1ffec01e4ffd701f6ffd7026dffec027dffec0281ffec0283ffec028bffec02aaffd702b6ffd702b8ffec02baffec02c0ffec 02c2ffec02d5ffec02f8ffec02faffec02fcffec02feffec030effec0310ffec0318ffd7002101ceffd701d0ffd701dcffd701ddffd701dfffd701e1ffec01e4ffd701f6ffd7026dffd7027dffec0281 ffd70283ffd7028bffd702a0ffd702aaffd702b6ffd702b8ffd702baffd702bcffd702c0ffec02c2ffec02cbffd702d5ffec02e6ffd702f8ffd702faffd702fcffd702feffec0306ffd70308ffd7030e ffd70310ffd70318ffd700240005003d000a003d01d0ffec01dcffd701ddffd701dfffd701e1ffec01e4ffd701f6ffd70207003d020b003d026dffd7027dffec0281ffd70283ffd7028bffd702a0ffec 02aaffd702b6ffd702b8ffd702baffd702bcffec02c0ffec02c2ffec02cbffec02d5ffec02e6ffec02f8ffd702faffd702fcffd702feffec0306ffec0308ffec030effd70310ffd70318ffd7000701ce ff9a01d5ff9a01edffec01f2ff9a02cfff9a0312ff9a031cff9a001001ca001401ce002901dcffd701e1ffd701e4ffc301f1007b027dffd702aaffd702b6ffd702c0ffd702c2ffd702d5ffd702da0014 02dc001402feffd70318ffd7000d000affd701d0ffd701dcffec01dfffec02a0ffd702aaffec02b6ffec02bcffd702cbffd702e6ffd70306ffd70308ffd70318ffec002000050029000a002901cfffd7 01d8ffd701dbffec01deffd701e1ffd701eaffd701edffd702070029020b0029026affd7027dffd7027fffd70285ffd70287ffd70289ffd7028dffd702b2ffd702b4ffd702c0ffd702c2ffd702d5ffd7 02e0ffd702f0ffd702f2ffd702f4ffd702feffd7030affd7030cffd70316ffd7031affd7001d0005003d000a003d01d1ffec01dcffec01ddffec01dfffec01e1ffd701f6ffec0207003d020b003d026d ffec027dffd70281ffec0283ffec028bffec02aaffec02b6ffec02b8ffec02baffec02c0ffd702c2ffd702d5ffd702f8ffec02faffec02fcffec02feffd7030effec0310ffec0318ffec002100050029 000a002901cbffd701cfffd701d8ffd701dbffd701deffd701e1ffd701eaffd701edffd702070029020b0029026affd7027dffd7027fffd70285ffd70287ffd70289ffd7028dffd702b2ffd702b4ffd7 02c0ffd702c2ffd702d5ffd702e0ffd702f0ffd702f2ffd702f4ffd702feffd7030affd7030cffd70316ffd7031affd70022005bffd7005dffec0140ffec01d0ffd701d1ffec01d5ffec01dcffd701dd ffec01dfffd701f2ffec01f6ffec026dffec0281ffec0283ffec028bffec02a0ffd702aaffd702b6ffd702b8ffec02baffec02bcffd702cbffd702cfffec02e6ffd702f8ffec02faffec02fcffec0306 ffd70308ffd7030effec0310ffec0312ffec0318ffd7031cffec001301d0ffd701d1ffec01d5ffec01dcffec01dfffec01e4ffec01f2ffec02a0ffd702aaffec02b6ffec02bcffd702cbffd702cfffec 02e6ffd70306ffd70308ffd70312ffec0318ffec031cffec00170005003d000a003d01cfffec01d8ffec01edffec0207003d020b003d026affec027fffec0285ffec0287ffec0289ffec028dffec02b2 ffec02b4ffec02e0ffec02f0ffec02f2ffec02f4ffec030affec030cffec0316ffec031affec003000050052000a00520049001401caffd701ceff9a01cfffec01d5ffc301d8ffd701dbffd701dd0014 01deffd701edffd701f2ff9a01f6001402070052020b0052026affd7026d0014027fffd702810014028300140285ffd70287ffd70289ffd7028b0014028dffd702b2ffd702b4ffd702b8001402ba0014 02cfffc302daffd702dcffd702e0ffd702f0ffd702f2ffd702f4ffd702f8001402fa001402fc0014030affd7030cffd7030e0014031000140312ffc30316ffd7031affd7031cffc300240005003d000a 003d0049001401caffec01ceffc301d5ffc301d8ffec01dc001401deffec01f2ffc30207003d020b003d026affec027fffec0285ffec0287ffec0289ffec028dffec02aa001402b2ffec02b4ffec02b6 001402cfffc302daffec02dcffec02e0ffec02f0ffec02f2ffec02f4ffec030affec030cffec0312ffc30316ffec03180014031affec031cffc3001c005bffd7005dffec0140ffec01d0ffd701d1ffec 01d5ffec01dcffd701dfffec01e1ffec01e4ffd701f2ffd7027dffec02a0ffd702aaffd702b6ffd702bcffd702c0ffec02c2ffec02cbffd702cfffec02d5ffec02e6ffd702feffec0306ffd70308ffd7 0312ffec0318ffd7031cffec001d01cbffec01cfffec01d8ffec01dbffec01deffec01e1ffec01eaffec01edffec026affec027dffec027fffec0285ffec0287ffec0289ffec028dffec02b2ffec02b4 ffec02c0ffec02c2ffec02d5ffec02e0ffec02f0ffec02f2ffec02f4ffec02feffec030affec030cffec0316ffec031affec001501ce002901d5002901dcffec01e1ffec01e4ffd701e7002901e90014 01f1006601f2002901f60014027dffec02aaffec02b6ffec02c0ffec02c2ffec02cf002902d5ffec02feffec031200290318ffec031c0029001601ce003d01d5002901dcffec01e1ffec01e4ffec01e7 001401eaffec01edffec01f1006601f2002901f60014027dffec02aaffec02b6ffec02c0ffec02c2ffec02cf002902d5ffec02feffec031200290318ffec031c0029001901dcff9a01ddffd701dfffec 01e1ffd701e4ff7101f6ffc3026dffd7027dffd70281ffd70283ffd7028bffd702aaff9a02b6ff9a02b8ffd702baffd702c0ffd702c2ffd702d5ffd702f8ffd702faffd702fcffd702feffd7030effd7 0310ffd70318ff9a001c0005003d000a003d01dcff9a01ddffd701dfffec01e1ffd701e4ff710207003d020b003d026dffd7027dffd70281ffd70283ffd7028bffd702aaff9a02b6ff9a02b8ffd702ba ffd702c0ffd702c2ffd702d5ffd702f8ffd702faffd702fcffd702feffd7030effd70310ffd70318ff9a001101ceffd701d0ffd701d1ffec01d5ffec01dfffec01e4ffd701f2ffec01f6ffd702a0ffd7 02bcffd702cbffd702cfffec02e6ffd70306ffd70308ffd70312ffec031cffec001001ceffd701d0ffd701d1ffec01d5ffec01dfffec01e4ffd701f6ffec02a0ffd702bcffd702cbffd702cfffec02e6 ffd70306ffd70308ffd70312ffec031cffec00030005ff98000affd701dfffec001c01ceff9a01cfffd701d5ff9a01d8ffd701dbffec01deffd701eaffd701edffec01f2ff9a026affd7027fffd70285 ffd70287ffd70289ffd7028dffd702b2ffd702b4ffd702cfff9a02e0ffd702f0ffd702f2ffd702f4ffd7030affd7030cffd70312ff9a0316ffd7031affd7031cff9a000201eb003d01f4003d002101d0 ffd701dcff9a01ddffc301deffec01dfffec01e1ffd701e4ff9a01f6ffd7026dffc3027dffd70281ffc30283ffc3028bffc302a0ffd702aaff9a02b6ff9a02b8ffc302baffc302bcffd702c0ffd702c2 ffd702cbffd702d5ffd702e6ffd702f8ffc302faffc302fcffc302feffd70306ffd70308ffd7030effc30310ffc30318ff9a001f01d0ffd701dcff9a01ddffc301dfffec01e1ffd701e4ff9a026dffc3 027dffd70281ffc30283ffc3028bffc302a0ffd702aaff9a02b6ff9a02b8ffc302baffc302bcffd702c0ffd702c2ffd702cbffd702d5ffd702e6ffd702f8ffc302faffc302fcffc302feffd70306ffd7 0308ffd7030effc30310ffc30318ff9a000101f6ffd7001c00050029000a002901cbffec01cfffd701d8ffd701dbffec01deffd701eaffd701edffd701f6ffec02070029020b0029026affd7027fffd7 0285ffd70287ffd70289ffd7028dffd702b2ffd702b4ffd702e0ffd702f0ffd702f2ffd702f4ffd7030affd7030cffd70316ffd7031affd7001d01caffd701d5ffc301d8ffec01dc001401f2ffd7026a ffec027fffec0285ffec0287ffec0289ffec028dffec02aa001402b2ffec02b4ffec02b6001402cfffc302daffd702dcffd702e0ffec02f0ffec02f2ffec02f4ffec030affec030cffec0312ffc30316 ffec03180014031affec031cffc300da00050052000a00520010ff5c0026ffec002affec0032ffec0034ffec0037ff850038ffec0039ffae003affc3003cff9a0089ffec0094ffec0095ffec0096ffec 0097ffec0098ffec009affec009bffec009cffec009dffec009effec009fff9a00c8ffec00ceffec00deffec00e0ffec00e2ffec00e4ffec010effec0112ffec0114ffec0124ff850126ff85012cffec 0130ffec0132ffec0134ffec0136ffc30138ff9a013aff9a019fffec01a4ff9a01aaff8501aeff8501b5ff8501b8ffd701bbffec01bcff8501beffc301caff8501ccffc301cdffc301ceff5c01cfff85 01d0ffc301d1ffc301d2ffc301d3ffc301d4ffc301d5ff5c01d6ffc301d7ffc301d8ff8501d9ffc301daffc301dbff8501dcffc301ddffc301deff8501dfffc301e0ffc301e1ffc301e2ffc301e3ffc3 01e4ffc301e5ffc301e6ffc301e7ffc301e8ffc301e9ff9a01eaff8501ecffc301edff8501eeffae01f0003d01f2ff5c01f3ffc301f5ffc301f7ffc301f9ffc301faffc301fcffc301feffc30200ff9a 02070052020b0052025fffec0261ffec026aff85026bffc3026cffd7026dffc30272ff85027dffc3027effd7027fff850281ffc30283ffc30284ffd70285ff850286ffd70287ff850288ffd70289ff85 028affd7028bffc3028cffd7028dff850296ffc3029affc302a0ffc302a4ffc302a6ffc302a9ff8502aaffc302acffc302aeffc302b0ffc302b1ffd702b2ff8502b3ffd702b4ff8502b5ff8502b6ffc3 02b7ff8502b8ffc302b9ff8502baffc302bcffc302bdff8502c0ffc302c2ffc302c4ffc302c5ffae02c6ff7102c7ffae02cbffc302ceff8502cfff5c02d1ffc302d3ffc302d5ffc302d7ffc302d9ff85 02daff8502dbff8502dcff8502ddff8502e0ff8502e1ffd702e3ffd702e6ffc302ecffc302eeffc302efffd702f0ff8502f1ffd702f2ff8502f3ffd702f4ff8502f8ffc302faffc302fcffc302feffc3 0300ffc30306ffc30308ffc30309ff5c030aff85030bff5c030cff85030effc30310ffc30311ff850312ff5c0314ffc30315ffd70316ff850317ff850318ffc30319ffd7031aff85031bff85031cff5c 0349ffec034bffec034dffec034fffec0351ffec0353ffec0355ffec0357ffec0359ffec035bffec035dffec035fffec0361ffec0363ffec0365ffec0367ffec0369ffec036bffec036dffec036fff9a 0371ff9a0373ff9a00030037ff9a0171ff9a0172ffc300c30024ffae002c00290037005200390052003a0066003b0029003c0052003d00290046ffc30047ffc30048ffc3004affd70052ffc30054ffc3 0057002900590029005a00140082ffae0083ffae0084ffae0085ffae0086ffae0087ffae0088ff5c008e0029008f00290090002900910029009f005200a8ffc300a9ffc300aaffc300abffc300acffc3 00adffc300b4ffc300b5ffc300b6ffc300b7ffc300b8ffc300baffc300c2ffae00c4ffae00c6ffae00c9ffc300cbffc300cdffc300cfffc300d5ffc300d7ffc300d9ffc300dbffc300ddffc300ec0029 00f0002900f20029010fffc30111ffc30113ffc30115ffc30124005201260052013600660137001401380052013a0052013b0029013d0029013f00290143ffae015fffae0169ffae017100520179ffc3 017effc30182ffc3018a0029018cffc3018effc30190ffc3019100290193ffc3019400290196ffc30199ffc3019bffc3019d005201a4ff9a01a6005201a8003d01aaffae01aeff8501b0003d01b10014 01b5ff8501bc005201bd003d01bf002901c4005201cfffc301d8ffc301dbffc301dc002901deffc301eaffc301edffc301fa006601fb001401fc006601fd001401fe006601ff0014020000520228ffae 0258ffae0260ffc3026affc30272ffae0276003d027fffc30285ffc30287ffc30289ffc3028dffc3029f003d02a9005202aa002902b2ffc302b4ffc302b5005202b6002902b7005202b9005202bb003d 02bd005202ca003d02ceff8502d9ffae02dbffae02ddffae02e0ffc302e5003d02f0ffc302f2ffc302f4ffc302f7003d02f9003d02fb003d0305003d0307003d030affc3030cffc30311ff850316ffc3 0317005203180029031affc3031bff85031dffae031fffae0321ffae0323ffae0325ffae0327ffae0329ffae032bffae032dffae032fffae0331ffae0333ffae0336ffc30338ffc3033affc3033cffc3 033effc30340ffc30342ffc30344ffc30345002903470029034affc3034cffc3034effc30350ffc30352ffc30354ffc30356ffc30358ffc3035affc3035cffc3035effc30360ffc3036f005203710052 0373005200100045003d00490066004b003d004c003d004d003d004e003d004f003d0057006600590066005a0066005b0029005c0066005d002903700066037200660374006600100045003d00490066 004b003d004c003d004d003d004e003d004f003d0057006600590066005a0052005b0029005c0066005d001403700066037200660374006600020309ff85030bff8500020096000500050000000a000b 0001000f0011000300240027000600290029000a002c002c000b002e002f000c00320035000e0037003e001200440046001a0048004b001d004e004e00210050005200220055005700250059005e0028 006d006d002e007d007d002f008200870030008900920036009400980040009a009f004500a200ad004b00b300b8005700ba00bf005d00c100c9006300cb00cb006c00cd00cf006d00d100d1007000d5 00d5007100d700d7007200d900db007300dd00dd007600ec00ec007700f000f0007800f200f2007900f800f8007a00fa00fb007b00fd00fd007d00ff0101007e01030103008101060106008201080108 0083010a010a0084010e010f008501110113008701150115008a011d011d008b011f011f008c01210124008d012601270091012c012c00930130013000940132013200950134013400960136013b0097 013d013d009d013f0140009e0143014400a0014a014a00a20156015600a3015a016200a40164016400ad0166016900ae016c016d00b2016f017c00b4017e018400c20186018800c9018a018e00cc0190 019100d10193019700d30199019900d8019b01a200d901a401a800e101aa01ae00e601b001b100eb01b401b400ed01b801b800ee01ba01c000ef01c301c400f601c601c800f801ca01d100fb01d401d4 010301d801d8010401da01e0010501e301ea010c01ec01ee011401f001f0011701f201f6011801f80203011d020602060129020a020a012a02280228012b02580258012c02600260012d02620262012e 026a026a012f026c027201300274027401370276027c0138027e028c013f0295029d014e029f02a0015702a202af015902b102c0016702c302c3017702c502c5017802c702c7017902c902cc017a02ce 02cf017e02d202d3018002d602d9018202db02db018602de02de018702e002e9018802ef02fc019202ff030001a00303030801a2030b031d01a8031f031f01bb0321032101bc0323032301bd03250325 01be0327032701bf0329032901c0032b032b01c1032d032d01c2032f032f01c30331033101c40333033301c50336033601c60338033801c7033a033a01c8033c033c01c9033e033e01ca0340034001cb 0342034201cc0344034501cd0347034701cf0349035601d00358035801de035a035a01df035c035c01e0035e035e01e10360036101e20363036301e40366036601e50368036801e6036a036a01e7036c 036c01e8036e037401e9000000010000000a001c001e00016c61746e0008000400000000ffff000000000000 ]], ["fonts/Karla-Regular.ttf"] = [[ 0001000000110100000400104453494700000001000041c8000000084646544d5e5927d200003d280000001c47444546002800cc00003d440000002847504f5303802f7500003d6c0000040047535542 dc42ea3b0000416c0000005c4f532f3284373af00000019800000060636d61702dfec69900000494000001e2676173700000001000003d2000000008676c796674bfc695000007d000002e5068656164 f88661be0000011c000000366868656106c003300000015400000024686d74784b84229d000001f80000029c6c6f63618bbf97a400000680000001506d61787000ee004200000178000000206e616d65 eba6ecf300003620000004f2706f7374a6ad4d3e00003b14000002097072657068068c8500000678000000070001000000010000ff1f20465f0f3cf5000b03e800000000cabc7b1f00000000cb82a341 ffaaff0a037e036f000000080002000000000000000100000395ff04000003acffaaffd8037e0001000000000000000000000000000000a70001000000a7003f00050000000000020000000100010000 0040000000000000000301fd01900005000802bc028a0000008c02bc028a000001dd003200fa00000000000000000000000080000027080000421400000000000000707972730040002022120395ff04 0000039500fc000000010000000001de027500000020000202290000000000000229000000ee0000011600520132001c027300350278004502d6003d039400590088001b016400490164001c019c0038 020f001200d2001e015d002600b3001e01b0003902520033014b003102440040024f0034022f001a02350041023d003301d60018026700370245004200e700380106003901c6002801e8004f01c6002f 01f3001e03ac0043023f001a026e0065026500330295006402320064020c006502850033029d006501180065019400080261006501d400650350006502ad006302860033022a0063028c003302650065 025d004501f50006028e005702330012037f000e0282002f0225000a02500049013d006501b0002d011dfff201c0001502d60037013b00180230004602480065020300320252003c0203003201570031 0235001c025c0065012b005e013affaa023400650118006503a70064025b0064022200320252006502490033017d0064020e003c01780022025e005701f7001202d500120200001a01e4000501db0035 015d004b01180065015d0008020300350235001401430018013b0017023f001a023f001a023f001a023f001a023f001a0234006402340064023400690234006401180007011800060118ffd901180004 02ae00630286003302860033028600330286003302860033028e0057028e0057028e0057028e00570227003c0227003c0227003c0227003c0227003c02020033020200330202003602020033012b000c 012b000b012bffde012b0009025c00650223003302230033022300330223003302230033025e0057025e0057025e0057025e00570118006500b8002401970018016e001701da003702d6003700d60024 00d6000f0245005c01e8004f02130033014b0031023f00400232001c0230001802390041023d003301d60018026700370244004200000003000000030000001c00010000000000dc000300010000001c 000400c00000002c00200004000c007e00a000a300a800b400c400cf00d600dc00e400ef00f600fc013102bc02c602dc2014201920b92212ffff0000002000a000a300a800b400c000c800d100d900e0 00e800f100f9013102bc02c602dc2013201820b92212ffffffe3ff63ffbfffbbffb0ffa5ffa2ffa1ff9fff9cff99ff98ff96ff62fdd8fdcffdbae084e081dfe2de8a0001000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000010600000100000000000000010200000002000000000000000000000000000000010000030405060708090a0b0c 0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c 5d5e5f6061006900006b72777b7d7c7e807f00008281838486858788898b8a8c8e8d908f9192000000620000000000000064630000000000000000000000000000000000000000000000000000000000 03656876000097980000999a000000000000000000000000000000676c666d6a6f70716e74750073797a7893959600000000000000000000b801ff85b0048d0000000000000000000000001a002e0060 00a800f001480156016c018201a001b601ce01dc01ee01fc021c0230025e029202ae02d60308031c035e039803b603da03ee04020416044e04a604be04f005160536054e0564058e05a605b405cc05e8 05f80614062c0650067006a406ca06fe0710072e07420760077a079007a807ba07c807d807ea07f80806083a0862088608ae08d808fa09540972098c09b409cc09da0a080a260a480a6e0aa20abc0aee 0b100b2e0b420b600b780b9a0bb20bde0bec0c180c380c6e0c8e0c9c0cbc0cdc0cfe0d320d620d820da00dc20df20e060e1a0e320e580e8c0eb80ee40f120f520f8e0fb20fd810001036107010ac10ea 113c118811ba11e8121c125e12721286129e12c41300132a1354138213c213fe1424144a147214aa14b814d014e2150615141522153c15581584159215b015c415f0162616421668169a16ae16f01728 00020052fff700c902730003000b0000133303231626343632161406635309400621213323230273fe3db9212f21212f210000000002001c01cd011602a900030007000013072327330723276e0b3c0b fa0b3c0b02a9dcdcdcdc000000020035001f024a0251001b001f00002523072337233733372337333733073337330733072307330723072327333723017c9a0e4a0e630564136506640f4a0f9a0f490f 670666136706670e4a85991399aa8b8b36b2358a8a8a8a35b2368bc1b200000000030045ffa5023302c9001f0026002d0000011616140607152335262635331417352726263436373533151616172326 2715173427271536360206141617173501a1454d72663e5f794d8b20535565633e575e0b4e1161805c243f41f73a282d1e014a174d8565065152086757710deb0c1a488659074b4c075644500cd7ba4a 1d0cdc053e01b23649290e0bc70000000005003dfff5029b02800009001300170021002d0000121615140622263534361626220615141632363525330123013216140623222634361722061514163332 36353426f14c4b6c494a76243a24243a24011952fe595101aa364b4b36364949361d24241d1d242402804c44444b4c43434d612c2c2f2f2a2a2f85fd8b01144b894b4c874c352c2f2f2a2a2f2f2c0000 00030059fff50365027f0024002b00370000010607171616323637330606232226272706232226343637272635343632161406071736370406141632372737342622061416171736373602d52d462b14 1f3127034a0443402742271a6480698e5f5c0e4d69ad674e589e442cfe5a4953ac51ba9b3763371a1e1b681006015e8955251110252d484f2023165969944b0f0d43503f54547756268b527d66366045 42a3c824303740321a193034110000000001001b01c9006d02a500030000130723276d0b3c0b02a5dcdc000000010049ff8f014802d800090000121017072626343637179bad3962646462390200fe66 af2859d8e7d75a290001001cff8f011b02d80009000036102737161614060727c9ad39626464623966019aaf295ad7e7d8592800000100380184016602ac000e00001327371727330737170717072707 27ad75186a0a3e0a6a18745a2c50502d0204283636808036362859276868270000010012000001fd01eb000b0000011533152315233523353335012fcece4fcece01ebd443d4d443d40000000001001e ff9300b20061000b0000162634363216140607273637521e1f39262c2d3b3e0d031a2c1e2d4447161d1e2d00000100260101013601450003000013211521260110fef001454400000001001efff70094 00680007000016263436321614063f212133222209212f21212f210000010039ffb7018402db0003000001330323013450fc4f02dbfcdc0000020033fff5022002800007000f00000016100622261036 0426220614163236019c8484e48585011654a15454a1540280a8fec5a8a6013fa6cb8383f583830000010031000000e6027700080000133637331123110607314332404e32350244092afd8902192003 00010040000002010280001c000037211521353437363737363534262206072336363216140607070606158f016dfe44541b217c6042774b0657057abf784f457f302f49495d6f34110d322657303d32 32525868995a1b331433290000010034fff502110280002100000114071616151406222635331616323634262323353332363426220607233636321601f96e3c4a7ece9152025b8c4d4a534831485444 704b0d520b74b77d01d46427114e3d53656b61404443633f3f39603e27355351610000000002001a00000219027e000a000d0000011133152315233521350103331101ac6d6d4dfebb0149ebe9027efe 5e4498983d01a9fe57012c0000010041fff501fd0275001800002534232313211521073633321614062226353314171633323601ab9ba91b015dfeef11342f67767cc47c4f541a1f404ecc77013248b5 095bb879635752190751000000020033fff4020302800015001e00000126220615141736363216140623222610363332161704061416323635342601a911b4610506659e727660708a8c79546a08fef7 4b4a724b4b01d662948035235c536fad6bb40125b35e4ca1476e43423a3a420000010018000001c40275000600000115012301213501c4fee06a012efeb0027549fdd402294c000000030037fff50231 02800015001f002a000013263534363216151406071716161514062226353436170606141632363426272714161717363634262206c97d7ccd84454311454a87e58e518c3f4c609b5b302ae62c29493c 4e528254013e39624b5c624d34520a061a473d4c5c664d3e4e130741603c344a2d0fd81b27101c023b5f3b3900020042fff502120280001c002500000132161716151407062322263533161632373635 342706062226353436162206151416323634011a335c2148882f37677853024468205b050a619d727698724a4b714b02802c29588df54517705539441339c8292151506f56576a49423a3a42476e0000 00020038001700ae01ba0007000f00003626343632161406022634363216140659212133222233212133222217212f21212f210132212f21212f210000020039ff9300cd01ba000b0013000016263436 321614060727363702263436321614066d1e1f39262c2d3b3e0d112121332222031a2c1e2d4447161d1e2d014e212f21212f21000001002800280198023c00060000010505072535250198fee0012034 fec4013c0200cfcc3de745e80002004f00750199017900030007000025152135251521350199feb6014afeb6b94444c0454500000001002f0028019e023c000600001305150527252562013cfec43301 1efee2023ce845e73dcccf000002001efff501c502800019002300001322072336363216151406070606070615152335343e02342603321614062322263436f8751154076cc371343a19220a134e2a6e 263f571a22221a1a202002385c4a5a60453445200e160e192f272d3f433c2d4c33fe2e222f20202f2200000000020043ff4b037e0280000a003d00000134232206151416323637171433323637363534 2623220607061016331522272626343e02321e021514062322262727060623222635343633321615023f3b3b5e375234174227142f132ea28b52862f64d4b9d5863f444276a3b68e643881562b340503 123c284a5f845b3c45012154614a353a2f2d2d331b1a3d5f779a382f64fed6b940733695b2986f3e365d7e437a962422102630624b638748490000000002001a0000022502750007000a000013331323 27230723373303f260d35236fa36539ed1680275fd8ba0a0de01360000030065000002290275000f00180020000013333216151406071616151407062323373236353426232315113332363426232365 eb636b3b3c3b47712a3decea483e44429b9a3a45433c9a02755e4736500e0a523474290f453a303039d301173964380000010033fff50236028000160000013216170726262322061416333236353314 0622261036013f657b17551455394f685d5a4b575587eb919602806551113b4584eb8e4f416374b4012ea900000200640000025602750007001000000132161006232311133332363534262323011d8e abab8eb94f6a697c7d686a0275abfee1ab0275fdd08b6b6b8900000000010064000001e70275000b0000132115211521152115211521640183fecc0122fede0134fe7d027544d343d645000000010065 000001e30275000900001321152115211521112365017efed1011afee64f027544d144fee400000000010033fff5023b027f001900002506222610363332161707262206141633323635352735331123 01ea2af29ba97e4a6f284c41ae79685848589eeb406c77b0012ab03c421a518ee38a605e020634fec900000000010065000002380275000b0000131121113311231121112311b401354f4ffecb4f0275 feeb0115fd8b011cfee4027500010065000000b402750003000013331123654f4f0275fd8b00000000010008fff501440275000b000024062227351632363511331101445d904f467b2c4f4f5a2a5230 3c3901bffe410000000100650000024c0275000b0000131101330101230307152311b501196dfeed012466f33e500275fedd0123fee5fea6012340e30275000000010065000001cc0275000500003721 15211133b40118fe994f45450275000000010065000002eb0275000c00001b0233112311032303112311d6d4d26f4fd835db4f0275fe5601aafd8b0205fe4a01bdfdf402750000000001006300000248 02750009000013011133112301112311c101384f58fec3500275fe0701f9fd8b0200fe000275000000020033fff502540280000a0014000001321610062322263534361722061416333236342601437a 97967b7b95957b586666585867670280a7fec1a5a79e9fa74784f88080f884000002006300000203027500090011000000161406232315231133113236342623231501966d6d687c4fcb414343417c02 7569b267f30275fec2427345fa00000000020033ff59025402800015001f000005062322272726261036333216151406071716173237012206141633323634260254282c553d2f7993957b7a976a5b1f 1d282b36feef586666585867679413594302a6013ca7a79f84a1172c270219027784f88080f88400000200650000022b0275000c00140000000607132303231123113332160732363426232315021b53 51b466a36e4fdb6a71e1474947438c0173600efefb0101feff027566d7457143f900000000010045fff502180280001f0000012623220614161717161614062226273314163236342627272626343632 161701b411763f442a2f83434f7cd085024d57895031306f4e5070ca6b0801dc5c374d280f2d17509163695f3e423d533010291a488b5d594b00000000010006000001ef027500070000132115231123 11230601e9cd4fcd027544fdcf02310000010057fff502350275001000001311141633323635113311140622263511a6584848584f82db810275fe6e584e4e580192fe6e767878760192000000010012 000002210275000600001b023303230365b4b553df52de0275fdef0211fd8b02750000000001000e000003700275000c00001b023313133303230303230366999b359ab057de53898e53c70275fdf501 cafe36020bfd8b0193fe6d02750000000001002f000002510275000b0000212327072313033313133303025162b6a960dedf5fb4a65fd9fbfb0138013dfeff0101fec4000001000a0000021b02750008 00001b0233031123110368a9ad5de250df0275fedf0121fe8dfefe010201730000010049000002170275000900003701253521150105152149016bfe9501cefe95016bfe324701e3034847fe1d034800 00010065ff9a012b02db00070000133315231133152365c67777c602db46fd4b460000000001002dffb7017802db00030000133313232d4ffc5002dbfcdc00000001fff2ff9a00b802db000700001723 353311233533b8c67777c6664602b5460001001500f501b2024a000600003713331323270715b03db0587775f50155feabf6f60000010037ff84029fffc80003000017211521370268fd983844000000 0001001802a50124035c000300001317072739eb17f5035c8532710000020046fff501db01ea00180021000001342622061523343736333216151123270623222634363217152622061514333236018d 36673f5776242a596444082c734d5d679a46476a42663a5301364138292c6e1a085a5cfecc505b5680481a321426295a5300000000020065fff5021602a9000d00170000133632161406232226270723 113312060715141632363426b430b87a7c59304d1612374f4e4c024f70525101975389e18b302f5402a9fefb49414e424f63a46200010032fff501cd01ea001500000016170726262322061416323635 33140623222634360159640f500d3a23404f4d7339516b565b7f7e01ea5741072a2f60a56435314d5f8ae5860002003cfff501ec02a9000d001700000111331123270606232226343632060614163236 37353426019e4e400a174c2d5b7b79b9924f50704f024e01970112fd57502d2e8ce1884662a4634b3f4e434e00020032fff501d701ea0010001800002532373306062322263436321607211416132623 2206073334010a630e510b694e607879c9630ffeb9487b17213d4706ff3557484f89e4889c704a5f016a0c533e640000000100310000015b02b100140000012623220615153315231123112335333534 363217014d2113232863634e4f4f4e662702660d222b4836fe5801a8364947430d0000000003001cff0a0225023b00280034003e00003726353436372635343632173636330722071615140623222706 06151433333216151406222635343617141632363534262323060600262206151416333236793c2f23366f983507473a075804236f53392c142058ba434e99ea86331b53a9712122c1333601263e6d3e 3f36363e0f1d3c1f2f08304e4e602435404e4a2b3c4d6317041d193539334c7257422b365e263749311721022d01a4414134344344000000000100650000020702a90011000013363332161511231134 2622061515231133b4306f555f4e417a4a4f4f0186647061fee701194546675be202a9000002005e000000c602b20003000b00001333112312263436321614066a4f4f0f1b1b301d1d01dffe21024f1b 2d1b1b2d1b0000000002ffaaff0a00d502b2000900170000122634363332161406230332351133111407062322273716881b1b18181d1d187f584f5a1c223e48043f024f1b2d1b1b2d1bfd006e0223fd dd89200a25452500000100650000021402a9000b0000370715231133113733071323f4404f4fe76edce761fd34c902a9fe74c1b3fed5000000010065000000b402a90003000013331123654f4f02a9fd 57000000000100640000035201ea001e000013363332161736333216151123113426220615152311342622060715231133b12f723e54132d7a565e4e417a434e41784a024f440182683d36737061fee7 011945466458e8011945466257eb01de000100640000020601ea00110000133633321615112311342622060715231133b12f72555f4e41784a024f440182687061fee7011945466257eb01de00020032 fff501f001ea000b0013000001321615140623222635343616262206141632360111647b7b64647b7bf3488b4a468b4c01ea8279788282787982a56161ab616100020065ff15021601ea000b00150000 13363216140622271123113312363426220607151416af2fbb7d7eb82c4f41ca5551744a024c0195558ae28945fedb02c9fe5d60a762493e5b3f480000020033ff0a022c01ea0013001f000001321737 331114161617072626353506222634361606141633323736373534260108662e1136171d151a443929bb7e7d2551563952230c014c01ea5a4efdd131210f073d124e4a985789e28a4662a7604917205b 424c0000000100640000016901e7000d00000122071523113315363332170726012871044f4f245b1d1a041e019bb2e901df5c64094d0a000001003cfff501d101ea001f000012363216172326232206 141617171616140622262733161632363426272726354c65ac61024d09653135282c603d416abe6a034c02456844282d5d7d01a4464837412c33230d20133b675355432d2d2c3d200c1f255d00010022 ffe6015f02630015000025062726272635112335333533153315231114333237015f564733150b4d4d4e969644252e0e28171033192301263c85853cfedb491200010057fff701f901df001100002506 2322263511331114333236373533112301aa316e51634f704151024f4f5f685a5e0130fed679644ef1fe210000010012000001e501de000600001b02330323036b909159be57be01defe75018bfe2201 de00000000010012000002c001de000c00001b02331313330323030323036474724271754e9c4d6e6c4c9f01defe830166fe960181fe22014ffeb101de0000000001001a000001e601df000b00002123 2707233727331737330701e560898260b5b560898360b7b5b5eff0b4b4f0000000010005ff0a01cb01de00110000171633323736373703331313330306062227053136281d15110ec458917150b3174b 733e8b26281d3b3101defe83017dfdc3494e230000010035000001a701de0009000037012135211501211521350119fee70172feeb0115fe8e40015e4040fea2400000000001004bff76015502ec001f 000013161515141633152235353426232335333236353534373633152206151514079a343d4ad511131111131172283b4a3d34012f19585d515545ea5c2b244c232c5ba831124555525c561b00010065 ff8600b402ee0003000013331123654f4f02eefc9800000000010008ff76011202ec001f00001326353534262335321515141633331523220615151407062335323635353437c3343d4ad51113111113 1172293a4a3d3401331b565c525545eb5b2c234c242b5ca830124555515d58190001003500df01ce0167001100001322072736333216333237170623222627269e25182c214a22861a28192b234e1760 0e27011a3b176f37391b6a24060e000000010014000002110280002500000126232206151533152315140733323637330606232135333236353523353335343633321617019010562a39b6b625b7312d 065406545efebb1c26235b5b5d5b475a0b01ea4e40486d3868441a292c4d4d452c2e6c386d636d4c4a00000000020018030b012a036f000900110000122634363332161406233226343632161406351d 1d17171f1f17921e1e2d1f1f030b1d2a1d1d2a1d1d2a1d1d2a1d00000001001702a50122035c00030000010727370122f417eb03167132850003001a00000225035c0007000a000e0000133313232723 072337330303170727f260d35236fa36539ed16863eb17f50275fd8ba0a0de0136014885327100000003001a00000225035c0007000a000e0000133313232723072337330313072737f260d35236fa36 539ed16886f417eb0275fd8ba0a0de0136010271328500000003001a0000022503680007000a001000001333132327230723373303370727072737f260d35236fa36539ed168b432818232b40275fd8b a0a0de0136b8276c6c279c000003001a00000225034a0007000a001e0000133313232723072337330327220727363632171616323637170606222e02f260d35236fa36539ed168442019200c2e34222e 1b1a1c0a230b3129223c150275fd8ba0a0de0136ee3313333511170c191b1730340c1f080004001a0000022503430007000a0014001c0000133313232723072337330326263436333216140623322634 3632161406f260d35236fa36539ed168561d1d17171f1f17921e1e2d1f1f0275fd8ba0a0de0136cb1d2a1d1d2a1d1d2a1d1d2a1d00020064000001e7035c000b000f0000132115211521152115211521 13170727640183fecc0122fede0134fe7d5eeb17f5027544d343d645035c85327100000000020064000001e7035c000b000f000033213521352135213521352125072737640183fecc0122fede0134fe 7d0147f417eb45d643d344a17132850000020069000001ec0368000b00110000132115211521152115211521010727072737690183fecc0122fede0134fe7d017632818232b4027544d343d64502cc27 6c6c279c00030064000001e70343000b0015001d0000132115211521152115211521122634363332161406233226343632161406640183fecc0122fede0134fe7d571d1d17171f1f17921e1e2d1f1f02 7544d343d64502df1d2a1d1d2a1d1d2a1d1d2a1d0002000700000113035c0003000700001333112303170727654f4f3deb17f50275fd8b035c8532710002000600000111035c00030007000033331123 37072737654f4facf417eb0275a17132850000000002ffd900000140036800030009000013331123130727072737654f4fdb32818232b40275fd8b02cc276c6c279c0000000300040000011603430003 000d0015000013331123022634363332161406233226343632161406654f4f441d1d17171f1f17921e1e2d1f1f0275fd8b02df1d2a1d1d2a1d1d2a1d1d2a1d000002006300000248034a0009001d0000 1311331101331123110137220727363632171616323637170606222e026350013d584ffec8512019200c2e34212f1b1a1c0a230b3129223c150275fd8b0200fe000275fe0701f98d3313333511170c19 1b1730340c1f080000030033fff50254035c000a0014001800000132161006232226353436172206141633323634260317072701437a97967b7b95957b58666658586767bceb17f50280a7fec1a5a79e 9fa74784f88080f8840123853271000000030033fff50254035c000a0014001800000122061514163332361026073216140623222634363707273701437b95957b7b96977a58676758586666ddf417eb 0280a79f9ea7a5013fa74784f88080f884dd71328500000000030033fff502540368000a0014001a000001321610062322263534361722061416333236342637072707273701437a97967b7b95957b58 6666585867675b32818232b40280a7fec1a5a79e9fa74784f88080f88493276c6c279c0000030033fff50254034a000a0014002800000122061514163332361026073216140623222634363722072736 3632171616323637170606222e0201437b95957b7b96977a58676758586666132019200c2e34212f1b1a1c0a230b3129223c150280a79f9ea7a5013fa74784f88080f884c93313333511170c191b1730 340c1f0800040033fff502540343000a0014001e0026000001321610062322263534361722061416333236342e023436333216140623322634363216140601437a97967b7b95957b58666658586767c4 1d1d17171f1f17921e1e2d1f1f0280a7fec1a5a79e9fa74784f88080f884a61d2a1d1d2a1d1d2a1d1d2a1d0000020057fff50235035c0010001400001311141633323635113311140622263511371707 27a6584848584f82db818beb17f50275fe6e584e4e580192fe6e767878760192e785327100020057fff50235035c0010001400001311141632363511231114062322263511250727375781db824f5848 48580125f417eb0275fe6e767878760192fe6e584e4e580192a171328500000000020057fff5023503680010001600001311141633323635113311140622263511250727072737a6584848584f82db81 01a232818232b40275fe6e584e4e580192fe6e76787876019257276c6c279c0000030057fff5023503430010001a00220000131114163332363511331114062226351136263436333216140623322634 3632161406a6584848584f82db81831d1d17171f1f17921e1e2d1f1f0275fe6e584e4e580192fe6e7678787601926a1d2a1d1d2a1d1d2a1d1d2a1d000003003cfff501d102db00180021002500000134 262206152334373633321615112327062322263436321715262206151433323603170727018336673f5776242a596444082c734d5d679a46476a42663a53cdeb17f501364138292c6e1a085a5cfecc50 5b5680481a321426295a5302568532710003003cfff501d102db0018002200260000013426220615233437363332161511232706232226343632171526220615143332363713072737018336673f5776 242a596444082c734d5d679a46476a42663952021cf417eb01364138292c6e1a085a5cfecc505b5680481a321426295a503f01d4713285000003003cfff501d102e70018002100270000013426220615 23343736333216151123270623222634363217152622061514333236130727072737018336673f5776242a596444082c734d5d679a46476a42663a534a32818232b401364138292c6e1a085a5cfecc50 5b5680481a321426295a5301c6276c6c279c00000003003cfff501d102c90018002200360000013426220615233437363332161511232706232226343632171526220615143332363703220727363632 171616323637170606222e02018336673f5776242a596444082c734d5d679a46476a4266395202ae2019200c2e34222e1b1a1c0a230b3129223c1501364138292c6e1a085a5cfecc505b5680481a3214 26295a503f01c03313333511170c191b1730340c1f0800000004003cfff501d102c100180021002b00330000013426220615233437363332161511232706232226343632171526220615143332360226 34363332161406233226343632161406018336673f5776242a596444082c734d5d679a46476a42663a53d51d1d17171f1f17921e1e2d1f1f01364138292c6e1a085a5cfecc505b5680481a321426295a 5301d81d2a1d1d2a1d1d2a1d1d2a1d0000030033fff501d802e000100018001c00002532373306062322263436321607211416132623220607333403170727010b630e510b694e607879c9630ffeb948 7a16203e4706ffe3eb17f53557484f89e4889c704a5f016a0c533e64016285327100000000030033fff501d802e000100016001a00002506232226352136262206141633323637021615233636370727 37017c0e63414801470f63c97978604e690b8237ff0647b8f417eb8c575f4a709c88e4894f48011f533e3e53ef71328500030036fff501db02ec00100018001e00002532373306062322263436321607 2114161326232206073334370727072737010e630e510b694e607879c9630ffeb9487b17213d4706ff3532818232b43557484f89e4889c704a5f016a0c533e64d2276c6c279c000000040033fff501d8 02c1001000180022002a000025323733060623222634363216072114161326232206073334262634363332161406233226343632161406010b630e510b694e607879c9630ffeb9487a16203e4706ffea 1d1d17171f1f17921e1e2d1f1f3557484f89e4889c704a5f016a0c533e64df1d2a1d1d2a1d1d2a1d1d2a1d000002000c0000011802db00030007000013331123031707276a4f4f3deb17f501dffe2102 db8532710002000b0000011602db00030007000033331123370727376a4f4facf417eb01dfb67132850000000002ffde0000014502e7000300090000133311231307270727376a4f4fdb32818232b401 dffe21024b276c6c279c0000000300090000011b02c10003000d00150000133311230226343633321614062332263436321614066a4f4f441d1d17171f1f17921e1e2d1f1f01dffe21025d1d2a1d1d2a 1d1d2a1d1d2a1d00000200650000020702c900110025000001220727231133353636321615113311342627220727363632171616323637170606222e020153722f09444f024a78414e5fbb2019200c2e 34222e1b1a1c0a230b3129223c1501ea685cfe22eb57624645fee701196170973313333511170c191b1730340c1f080000030033fff501f102db000b0013001700000132161514062322263534361626 220614163236031707270112647b7b64647b7bf3488b4a468b4cf3eb17f501ea8279788282787982a56161ab616102418532710000030033fff501f102db000b00130017000001220615141633323635 34260636321614062226010727370112647b7b64647b7bf24a8b484c8b460113f417eb01ea8279788282787982a56161ab616101fb71328500030033fff501f102e7000b001300190000013216151406 23222635343616262206141632361307270727370112647b7b64647b7bf3488b4a468b4c2432818232b401ea8279788282787982a56161ab616101b1276c6c279c00000000030033fff501f102c9000b 001300270000012206151416333236353426063632161406222613220727363632171616323637170606222e020112647b7b64647b7bf24a8b484c8b464a2019200c2e34212f1b1a1c0a230b3129223c 1501ea8279788282787982a56161ab616101e73313333511170c191b1730340c1f08000000040033fff501f102c1000b0013001d00250000013216151406232226353436162622061416323602263436 33321614062332263436321614060112647b7b64647b7bf3488b4a468b4cfa1d1d17171f1f17921e1e2d1f1f01ea8279788282787982a56161ab616101c31d2a1d1d2a1d1d2a1d1d2a1d000000020057 fff701f903010011001500002506232226351133111433323637353311230317072701aa316e51634f704151024f4fe2eb17f55f685a5e0130fed679644ef1fe210301853271000000020057fff701f9 030100110015000005323715331123151406232235112311141613072737010b6e314f4f5242704f63f7f417eb09685f01dfe9536779012afed05e5a02c471328500000000020057fff701f9030d0011 0017000025062322263511331114333236373533112313072707273701aa316e51634f704151024f4f3632818232b45f685a5e0130fed679644ef1fe210271276c6c279c00030057fff701f902c10011 001b0023000025062322263511331114333236373533112302263436333216140623322634363216140601aa316e51634f704151024f4fe91d1d17171f1f17921e1e2d1f1f5f685a5e0130fed679644e f1fe21025d1d2a1d1d2a1d1d2a1d1d2a1d00000000010065000000b401df0003000013331123654f4f01dffe210000000001002401a300b80271000b0000122634363216140607273637581e1f39262c 2d3b3e0d020d1a2c1e2d4447161d1e2d0001001802a5017f036800050000010727072737017f32818232b402cc276c6c279c00000001001702cf0153034a001300001322072736363217161632363717 0606222e02702019200c2e34212f1b1a1c0a230b3129223c1503023313333511170c191b1730340c1f08000000010037010101a30145000300001321152137016cfe940145440000000100370101029f 01450003000013211521370268fd9801454400000001002401a200b80272000c000012062226343637170607161615a21f38272f2d383e0d171e01c11f2e4547161d202c021a16000001000f01a200a2 0272000d00001236321615140607273637262635242039252f2c383e0d171f02541e2c232347171e202c021a160000000001005c000001fc0275001b0000132115231617331523060706070523253533 323637233533262623235c01a0b7450f635e07702837011270fef23d575403ebe70b534c3d027531244330732c0f05faf8304c39302e39000001004f01020199014500030000011521350199feb60145 4343000000020033fff501e10227000900110000123216151406222635340534232215143332a7c57575c574015d8686868602279287879291888888d4d4d30000010031000000e6021d000800001336 37331123110607314530404e333401e90b29fde301be200200010040000001f50227001a00003721152135343637373636342622060723363632161406070706158f0165fe4c4a4c6735334074490657 0574bd744a4c6f61494954505311190c304e362e2f4e55618449121b164d00000001001cff8e01ed02270024000001220723363332161514060716161514062226353316163236353427262323353332 36342601046e155316bf5d7439333d4881cc845002538358591e2a3d2b48534401e35da15d4a333e13145f3f526a68624541473658210b3f34623b0000020018ff9702180222000a000d000001113315 2315233521350103331101ab6d6d4efebb0149f1ef0222fe57439f9f3d01affe5101330000010041ff8e01fa0221001600001336333216140622263533141632363426232313211521bb2e30697886be 754d467e58514fa21c0159fef001280a6abc7e6459393c547f4801304700000000020033fff4020302800015001e00000126220615141736363216140623222610363332161704061416323635342601 a911b4610506659e727660708a8c79546a08fef74b4a724b4b01d662948035235c536fad6bb40125b35e4ca1476e43423a3a420000010018ff9e01c40227000600000115012301213501c4fed461013a fea7022743fdba024346000000030037fff5023102800015001f002a000013263534363216151406071716161514062226353436170606141632363426272714161717363634262206c97d7ccd844543 11454a87e58e518c3f4c609b5b302ae62c29493c4e528254013e39624b5c624d34520a061a473d4c5c664d3e4e130741603c344a2d0fd81b27101c023b5f3b3900020042ff8e02120227001a00230000 013216171610062322263533161632373635342706062226353436172206141632363426011e355d204282775d76530241691f5d05085e9d77765f3c4748754a480227332c59fed4b56f5639441439cb 2d234d557056576e464575454a70450000000016010e00010000000000000078000000010000000000010005007800010000000000020007007d0001000000000003002a008400010000000000040005 00780001000000000005000d00ae0001000000000006000d00bb0001000000000009001000c8000100000000000c000e00d8000100000000000d004c00e6000100000000000e001a0132000300010409 000000f0014c0003000104090001000a023c0003000104090002000e02460003000104090003005402540003000104090004000a023c0003000104090005001a02a80003000104090006001a02c20003 000104090009002002dc000300010409000c001c02fc000300010409000d00980318000300010409000e003403b0436f707972696768742028632920323031312c204a6f6e617468616e2050696e686f 726e202870696e686f726e2e7479706564657369676e40676d61696c2e636f6d292c207769746820526573657276656420466f6e74204e616d657320224b61726c612220616e6420224b61726c612054 616d696c222e4b61726c61526567756c6172466f6e74466f72676520322e30203a204b61726c6120526567756c6172203a2031332d31302d3230313156657273696f6e20312e3030304b61726c612d52 6567756c61724a6f6e617468616e2050696e686f726e6a6f6e70696e686f726e2e636f6d5468697320466f6e7420536f667477617265206973206c6963656e73656420756e646572207468652053494c 204f70656e20466f6e74204c6963656e73652c2056657273696f6e20312e312e687474703a2f2f736372697074732e73696c2e6f72672f4f464c0043006f007000790072006900670068007400200028 0063002900200032003000310031002c0020004a006f006e0061007400680061006e002000500069006e0068006f0072006e0020002800700069006e0068006f0072006e002e00740079007000650064 0065007300690067006e00400067006d00610069006c002e0063006f006d0029002c0020007700690074006800200052006500730065007200760065006400200046006f006e00740020004e0061006d 0065007300200022004b00610072006c0061002200200061006e006400200022004b00610072006c0061002000540061006d0069006c0022002e004b00610072006c00610052006500670075006c0061 00720046006f006e00740046006f00720067006500200032002e00300020003a0020004b00610072006c006100200052006500670075006c006100720020003a002000310033002d00310030002d0032 00300031003100560065007200730069006f006e00200031002e003000300030004b00610072006c0061002d0052006500670075006c00610072004a006f006e0061007400680061006e002000500069 006e0068006f0072006e006a006f006e00700069006e0068006f0072006e002e0063006f006d005400680069007300200046006f006e007400200053006f006600740077006100720065002000690073 0020006c006900630065006e00730065006400200075006e0064006500720020007400680065002000530049004c0020004f00700065006e00200046006f006e00740020004c006900630065006e0073 0065002c002000560065007200730069006f006e00200031002e0031002e0068007400740070003a002f002f0073006300720069007000740073002e00730069006c002e006f00720067002f004f0046 004c00000002000000000000ffb50032000000000000000000000000000000000000000000a70000000100020003000400050006000700080009000a000b000c000d000e000f00100011001200130014 00150016001700180019001a001b001c001d001e001f0020002100220023002400250026002700280029002a002b002c002d002e002f0030003100320033003400350036003700380039003a003b003c 003d003e003f0040004100420043004400450046004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d005e005f006000610085008e008d 00ad00c900c700ae006200cb006500c800ca00cf00cc00cd00ce006600d300d000d100af006700d600d400d50068006a0069006b006d006c007100700072007300750074007600770078007a0079007b 007d007c007f007e0080008100d7010200d800d900b200b300b600b7010300ef010401050106010701080109010a010b010c010d0a61706f7374726f7068650b727570656573796d626f6c0c7a65726f 2e70726f706f6c640b6f6e652e70726f706f6c640b74776f2e70726f706f6c640d74687265652e70726f706f6c640c666f75722e70726f706f6c640c666976652e70726f706f6c640b7369782e70726f 706f6c640d736576656e2e70726f706f6c640d65696768742e70726f706f6c640c6e696e652e70726f706f6c6400000000010001ffff000f0000000100000000c9896f3100000000ca151d3000000000 caba9b7000010000000c00000016001e00020001000100a6000100040000000100000002000100000000000000010000000a001e002c00016c61746e0008000400000000ffff0001000000016b65726e 000800000001000000010004000200000001000800010052000400000024009800ba00c0010601280136013c01420148019e01d8020e02140282029402a202b002be02d802e202ec02f20300030a0314 03260330033e034c0366036c0376038c039e03a803be0002000b002400240000002700270001002900290002002f002f00030032003400040036003700070039003c000900440046000d0048004b0010 004d004e00140050005d001600080037ffd80039ffe4003affe4003cffe60049fff40059ffea005affe8005cffe40001003cffe700110024ffc7003afff8003bfff0003cfff80044ffe80046ffe40047 ffe80048ffe4004affd30052ffe40054ffe40058ffe80059ffe0005affdc005bffe4005cffe4005dffe80008002d00100037ffcf0039ffd3003affd7003cffbb0059ffe8005affe8005cffec00030039 fff8003bfff4003cfff000010024ffda0001003cfff00001003cffe600150024ffd8002dffbb0044ffa90046ffb50047ffab0048ffb50049ffcb004affa90050ffbb0051ffbb0052ffb10053ffbb0054 ffb50055ffb70056ff9f0058ffbb0059ffb7005affd8005bffc7005cffce005dffcb000e0024ffdf0026fff8002dffbb0032fff80044ffdf0046ffdf0047ffdf0048ffdf0049ffd8004affcf0052ffdf 0054ffe30055ffef0056ffdf000d0024ffdf002dffbb0044ffdf0046ffdf0047ffdf0048ffdf0049ffd8004affcf0052ffdf0054ffdf0055ffdf0056ffd80058ffe400010032fff4001b0024ffbb0026 ffef002bfff8002dffae0032fff00034fff00036ffe40044ffc30046ffbf0047ffbf0048ffbf0049ffbf004affb30050ffbf0051ffbf0052ffbf0053ffbf0054ffbf0055ffbf0056ffbf0057ffdb0058 ffbd0059ffd3005affd3005bffcb005cffc7005dffbf00040037ffa70039ffdb003affe4003cffcb00030037ffec0039ffe3003cffef00030037ffc30039ffe4003cffdf00030037ffc30039ffe8003c ffd700060024fff0002dffcb0046fff0004affe6004dfff00056ffe80002004d0049005c001000020037fff8003cffd300010049ffea00030049fff0004dfff8005cfff000020037ffdc003cffd70002 0037ffd4003cffd700040037ffb90039ffdf003affdf003cffbf00020037ffcb003cffdc00030037ffb7003cffd1004d00510003002dffd80037ffd0004affec00060037ffa70039ffe4003affdc003c ffc70049ffe4005cffec0001003cffdb00020037ffc7003cffcf00050024ffe8002dffcb0037ffc4003cffd3004afff800040024ffe4002dffd70037ffe0003cffe000020037ffd7003cffcf00050024 fff4002dffe80037ffc8003cffe4004afff800020037ffe8003cffd700010000000a001e002c00016c61746e0008000400000000ffff0001000000016f6e756d00080000000100000001000400010000 000100080002001a000a0000000000000000000000000000000000000000000200010013001c00000000000100000000 ]], ["fonts/ProggyTiny.ttf"] = [[ 00010000000c0080000300404f532f3287eb7310000001480000004e636d617002122375000003a0000001526376742000000000000004fc00000002676c7966d3ee60d00000070400007cd468656164 d71168b2000000cc000000366868656106c201c30000010400000024686d747858804c8000000198000002066c6f636145f364f400000500000002046d61787001a600ba00000128000000206e616d65 01fc6ebc000083d80000019b706f7374a6ac83ef00008574000005d27072657069020112000004f4000000080001000000010000f6a410ea5f0f3cf50003080000000000b767778400000000bd92a933 0000ff00030004000000000600020000000000000001000003c0fec0000003000000000003000001000000000000000000000000000000020001000001010070001c00000000000200080040000a0000 00760008000000000000030001900005000002bc028a0000008f02bc028a000001c50032018000000000040900000000000000000000000000000000000000000000416c74730040000020ac08000000 0000040001000000030000000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300030003000300 0100008000000000000000000100008000800000000000800000010000000000008000000000000000000000000000000000010000800000000000000000000000000000000000000000000000000000 0080000000000000000000000000000000000000000000000000000000000000000000000080000000800000000001000000000000000000000000000000000000800000008000800000000000000000 0000000000000080000000000000000000000000008001000080000003000000030001000080008000000000000000800000000000800000030000000300030001000100008000800100000000000080 0000000001000000030000000000030001000080000000000000010000000080000000800000008003000000000000800000008000800100000000000100010000800080000000000000000000000000 0000000000000000000000000000000000000000000000800080008000800000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000 00000000000000800080008000800000000000000000000000000000000000000000000000000000000000000000000000000003000000000000001c000100000000004c000300010000001c00040030 00000008000800020000007f00ff20acffff00000000008120acffff00010001dfd500010000000000000000000001060000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000810000000000000000000000000000000000000000000000000000000000000000000000000000b100018db801ff8500000000 0000009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c009c00c600ee015001b00204 0266027e02b802f003320368037a039803a403e00442047e04d20522057405d00626066606c8071e0732074c077c07b207e2081a089e08ec095a09a60a040a640ab20b140b780bb80bfe0c520c920d02 0d780dd60e2c0e940efa0f4e0f8e0fe81032109410e4112c118011cc1202124e1272129412a612f41354139213f41446149214f2154a157815ba16081640169616de1726178217de1814185a189a18e2 191c1964199e19fa1a421a7c1ab61aee1b141b141b7e1b7e1b901bde1bfa1c101c5c1cbc1cd41d181d7a1d9e1e0a1e0a1e641e641e641e7c1e941ebc1ee41f001f1e1f401f5e1fb4200c203020862086 20e021302130215a21a221fc225822ae22e2234a235c23da240c244c2476247624ec250a2528257625a625d625ea263e26cc26da26f62728275227922802286e28ec2924296c29b62a062a5a2aa42af8 2b682bc02c202c822cea2d4a2d8c2dce2e162e582ec42f322f842fd83032309030e2311c317831c83218326e32be330e336033c83420347a34da353e359635fa364e369836f6375437b838163848387c 38b638e8394239a239f43a483aa23b003b523b7e3bda3c2e3c843cde3d323d9c3e023e6a001c0000ff000300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f00530057005b005f00630067006b006f00001135331531353315313533153135331531353315313533150535331521353315053533152135331505353315213533150535331521353315 0535331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533153135331531353315808080808080fd0080020080fd0080020080fd0080020080 fd0080020080fd0080020080fd0080020080fd0080020080fd0080020080fd00808080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080 808080808080808080808080808080808080808080808080800000000006010000000180038000030007000b000f00130017000001353315073533150735331507353315073533150335331501008080 80808080808080808003008080808080808080808080808080ff0080800000000006008002800200040000030007000b000f001300170000133533153335331505353315333533150535331533353315 80808080fe80808080fe808080800380808080808080808080808080808000000012000000000280030000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000 13353315333533150535331531353315313533153135331531353315053533153335331505353315333533150535331531353315313533153135331531353315053533153335331580808080fe008080 808080fe00808080fe80808080fe008080808080fe0080808002808080808080808080808080808080808080808080808080808080808080808080808080808080808080001100000000028003800003 0007000b000f00130017001b001f00230027002b002f00330037003b003f0043000001353315053533153135331531353315313533150535331533353315053533153135331531353315053533153335 33150535331531353315313533153135331505353315010080ff0080808080fd80808080ff00808080ff00808080fd8080808080ff008003008080808080808080808080808080808080808080808080 8080808080808080808080808080808080000000000e000000000300030000030007000b000f00130017001b001f00230027002b002f0033003700001335331521353315053533153335331533353315 0535331533353315053533153335331505353315333533153335331505353315213533158080018080fd008080808080fe00808080ff00808080fe008080808080fd0080018080028080808080808080 808080808080808080808080808080808080808080808080808000000011000000000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000133533153135 3315053533152135331505353315213533150535331531353315053533152135331533353315053533152135331505353315313533153135331533353315808080fe8080010080fe0080010080fe8080 80fe80800100808080fd0080018080fe0080808080800300808080808080808080808080808080808080808080808080808080808080808080808080808080800003010002800180040000030007000b 000001353315073533150735331501008080808080038080808080808080800000090080ff800200040000030007000b000f00130017001b001f00230000013533150535331505353315073533150735 3315073533150735331d0135331d01353315018080ff0080ff0080808080808080808080800380808080808080808080808080808080808080808080808080808000000000090080ff80020004000003 0007000b000f00130017001b001f002300001335331d0135331d01353315073533150735331507353315073533150535331505353315808080808080808080808080ff0080ff00800380808080808080 8080808080808080808080808080808080808080000b000000800280030000030007000b000f00130017001b001f00230027002b00000135331505353315333533153335331505353315313533153135 331505353315333533153335331505353315010080fe808080808080fe00808080fe008080808080fe808002808080808080808080808080808080808080808080808080808080000009000000800280 030000030007000b000f00130017001b001f002300000135331507353315053533153135331531353315313533153135331505353315073533150100808080fe808080808080fe808080800280808080 808080808080808080808080808080808080800000020080ff80018000800003000700002135331505353315010080ff00808080808080000005000001800280020000030007000b000f001300001135 33153135331531353315313533153135331580808080800180808080808080808080800000010100000001800080000300002135331501008080800000090000ff800280040000030007000b000f0013 0017001b001f002300000135331507353315053533150735331505353315073533150535331507353315053533150200808080ff00808080ff00808080ff00808080ff00800380808080808080808080 80808080808080808080808080808080800000000011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300001335331531353315313533150535 33152135331505353315213533150535331533353315333533150535331521353315053533152135331505353315313533153135331580808080fe0080018080fd8080018080fd808080808080fd8080 018080fd8080018080fe00808080030080808080808080808080808080808080808080808080808080808080808080808080808080808080000a008000000200038000030007000b000f00130017001b 001f00230027000001353315053533153135331507353315073533150735331507353315053533153135331531353315010080ff0080808080808080808080ff00808080030080808080808080808080 80808080808080808080808080808080000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b000013353315313533153135331505353315213533150735 331505353315313533150535331505353315073533153135331531353315313533153135331580808080fe00800180808080fe808080fe8080ff00808080808080800300808080808080808080808080 808080808080808080808080808080808080808080808080000e000000000280038000030007000b000f00130017001b001f00230027002b002f00330037000013353315313533153135331505353315 2135331507353315053533153135331d01353315053533152135331505353315313533153135331580808080fe00800180808080fe80808080fd8080018080fe00808080030080808080808080808080 808080808080808080808080808080808080808080808080000e000000000280038000030007000b000f00130017001b001f00230027002b002f00330037000001353315053533153135331505353315 33353315053533152135331505353315313533153135331531353315313533150535331507353315018080ff008080fe80808080fe0080010080fe008080808080ff0080808003008080808080808080 808080808080808080808080808080808080808080808080808000000011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000113533153135 331531353315313533153135331505353315073533150735331531353315313533153135331d0135331505353315213533150535331531353315313533158080808080fd80808080808080808080fd80 80018080fe0080808003008080808080808080808080808080808080808080808080808080808080808080808080808080808000000f000000000280038000030007000b000f00130017001b001f0023 0027002b002f00330037003b000001353315313533150535331505353315073533153135331531353315313533150535331521353315053533152135331505353315313533153135331501008080fe80 80ff00808080808080fe0080018080fd8080018080fe008080800300808080808080808080808080808080808080808080808080808080808080808080808080000b000000000280038000030007000b 000f00130017001b001f00230027002b0000113533153135331531353315313533153135331507353315053533150735331505353315073533150535331580808080808080ff00808080ff00808080ff 00800300808080808080808080808080808080808080808080808080808080800011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300001335 33153135331531353315053533152135331505353315213533150535331531353315313533150535331521353315053533152135331505353315313533153135331580808080fe0080018080fd808001 8080fe00808080fe0080018080fd8080018080fe008080800300808080808080808080808080808080808080808080808080808080808080808080808080808080800000000f00000000028003800003 0007000b000f00130017001b001f00230027002b002f00330037003b00001335331531353315313533150535331521353315053533152135331505353315313533153135331531353315073533150535 3315053533153135331580808080fe0080018080fd8080018080fe00808080808080ff0080fe808080030080808080808080808080808080808080808080808080808080808080808080808080808000 000201000080018002800003000700000135331503353315010080808002008080fe8080800000000003008000000180028000030007000b00000135331503353315053533150100808080ff00800200 8080fe8080808080800000000008000000800280030000030007000b000f00130017001b001f0000013533150535331531353315053533153135331d013533153135331d01353315020080fe808080fe 00808080808002808080808080808080808080808080808080808080000a000001000280028000030007000b000f00130017001b001f0023002700001135331531353315313533153135331531353315 01353315313533153135331531353315313533158080808080fd808080808080020080808080808080808080ff00808080808080808080800008000000800280030000030007000b000f00130017001b 001f00001135331d013533153135331d01353315313533150535331531353315053533158080808080fe008080fe80800280808080808080808080808080808080808080808000000009000000000280 038000030007000b000f00130017001b001f0023000013353315313533153135331505353315213533150735331505353315053533150335331580808080fe00800180808080ff0080ff008080800300 8080808080808080808080808080808080808080ff0080800019000000000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b 005f006300001335331531353315313533153135331505353315213533150535331533353315313533153335331505353315333533153135331533353315053533153335331531353315313533153135 33150535331d01353315313533153135331531353315313533158080808080fd8080020080fd00808080808080fd00808080808080fd00808080808080fd008080808080800300808080808080808080 808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808000000d000000000280038000030007000b000f00130017001b001f00230027002b 002f00330000013533150735331505353315333533150535331533353315053533153135331531353315053533152135331505353315213533150100808080ff00808080fe80808080fe80808080fe00 80018080fd8080018080030080808080808080808080808080808080808080808080808080808080808080800014000000000280038000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f00430047004b004f000011353315313533153135331531353315053533152135331505353315213533150535331531353315313533153135331505353315213533150535331521353315 0535331531353315313533153135331580808080fe0080018080fd8080018080fd8080808080fe0080018080fd8080018080fd8080808080030080808080808080808080808080808080808080808080 808080808080808080808080808080808080808080808080000d000000000280038000030007000b000f00130017001b001f00230027002b002f00330000133533153135331531353315053533152135 3315053533150735331507353315073533152135331505353315313533153135331580808080fe0080018080fd8080808080808080018080fe0080808003008080808080808080808080808080808080 808080808080808080808080808080000010000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001135331531353315313533150535331521353315 0535331521353315053533152135331505353315213533150535331521353315053533153135331531353315808080fe8080010080fe0080018080fd8080018080fd8080018080fd8080010080fe0080 80800300808080808080808080808080808080808080808080808080808080808080808080808080808000000012000000000280038000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f0043004700001135331531353315313533153135331531353315053533150735331507353315313533153135331531353315053533150735331507353315313533153135331531353315 313533158080808080fd808080808080808080fe0080808080808080808003008080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000e0000 00000280038000030007000b000f00130017001b001f00230027002b002f0033003700001135331531353315313533153135331531353315053533150735331507353315313533153135331531353315 0535331507353315073533158080808080fd808080808080808080fe00808080808003008080808080808080808080808080808080808080808080808080808080808080808000000011000000000280 038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000133533153135331531353315053533152135331505353315073533152135331531353315053533152135 331505353315213533150535331531353315313533153135331580808080fe0080018080fd8080808001008080fd8080018080fd8080018080fe00808080800300808080808080808080808080808080 808080808080808080808080808080808080808080808080800000000011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000113533152135 331505353315213533150535331521353315053533153135331531353315313533153135331505353315213533150535331521353315053533152135331580018080fd8080018080fd8080018080fd80 8080808080fd8080018080fd8080018080fd8080018080030080808080808080808080808080808080808080808080808080808080808080808080808080808080000000000b00800000020003800003 0007000b000f00130017001b001f00230027002b0000133533153135331531353315053533150735331507353315073533150735331505353315313533153135331580808080ff008080808080808080 80ff00808080030080808080808080808080808080808080808080808080808080808080000c000000000280038000030007000b000f00130017001b001f00230027002b002f00000135331531353315 31353315073533150735331507353315073533150735331505353315313533153135331531353315010080808080808080808080808080fd808080808003008080808080808080808080808080808080 80808080808080808080808080000000000e000000000280038000030007000b000f00130017001b001f00230027002b002f003300370000113533152135331505353315213533150535331533353315 053533153135331505353315333533150535331521353315053533152135331580018080fd8080010080fe00808080fe808080ff00808080fe8080010080fe0080018080030080808080808080808080 808080808080808080808080808080808080808080808080000b000000000280038000030007000b000f00130017001b001f00230027002b000011353315073533150735331507353315073533150735 3315073533153135331531353315313533153135331580808080808080808080808080808080800300808080808080808080808080808080808080808080808080808080800000000014000000000280 038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0000113533152135331505353315213533150535331531353315333533153135331505353315 313533153335331531353315053533153335331533353315053533153335331533353315053533152135331580018080fd8080018080fd808080808080fd808080808080fd808080808080fd80808080 8080fd80800180800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800015000000000280038000030007000b000f00130017001b 001f00230027002b002f00330037003b003f00430047004b004f005300001135331531353315213533150535331531353315213533150535331533353315333533150535331533353315333533150535 331533353315333533150535331521353315313533150535331521353315313533158080010080fd808080010080fd808080808080fd808080808080fd808080808080fd808001008080fd8080010080 800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000010000000000280038000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f000013353315313533153135331505353315213533150535331521353315053533152135331505353315213533150535331521353315053533153135331531353315 80808080fe0080018080fd8080018080fd8080018080fd8080018080fd8080018080fe008080800300808080808080808080808080808080808080808080808080808080808080808080808080808000 000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b00001135331531353315313533153135331505353315213533150535331521353315053533153135 3315313533153135331505353315073533150735331580808080fe0080018080fd8080018080fd8080808080fe0080808080800300808080808080808080808080808080808080808080808080808080 8080808080808080800000000012000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700001335331531353315313533150535331521353315 0535331521353315053533152135331505353315213533150535331521353315313533150535331531353315313533153135331580808080fe0080018080fd8080018080fd8080018080fd8080018080 fd808001008080fe008080808003008080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000012000000000280038000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047000011353315313533153135331531353315053533152135331505353315213533150535331531353315313533153135331505353315 213533150535331521353315053533152135331580808080fe0080018080fd8080018080fd8080808080fe0080018080fd8080018080fd80800180800300808080808080808080808080808080808080 808080808080808080808080808080808080808080808080000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b00001335331531353315313533150535 3315213533150535331d01353315313533153135331d01353315053533152135331505353315313533153135331580808080fe0080018080fd808080808080fd8080018080fe00808080030080808080 8080808080808080808080808080808080808080808080808080808080808080000b000000000280038000030007000b000f00130017001b001f00230027002b00001135331531353315313533153135 3315313533150535331507353315073533150735331507353315073533158080808080fe8080808080808080808080800300808080808080808080808080808080808080808080808080808080800000 000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b00001135331521353315053533152135331505353315213533150535331521353315053533152135 3315053533152135331505353315313533153135331580018080fd8080018080fd8080018080fd8080018080fd8080018080fd8080018080fe0080808003008080808080808080808080808080808080 8080808080808080808080808080808080808000000c000000000280038000030007000b000f00130017001b001f00230027002b002f0000113533152135331505353315213533150535331521353315 05353315333533150535331533353315053533150735331580018080fd8080018080fd8080018080fe00808080fe80808080ff0080808003008080808080808080808080808080808080808080808080 80808080808080000011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300001135331521353315053533153335331533353315053533153335 33153335331505353315333533153335331505353315333533150535331533353315053533153335331580018080fd808080808080fd808080808080fd808080808080fe00808080fe80808080fe8080 8080030080808080808080808080808080808080808080808080808080808080808080808080808080808080000d000000000280038000030007000b000f00130017001b001f00230027002b002f0033 00001135331521353315053533152135331505353315333533150535331505353315333533150535331521353315053533152135331580018080fd8080018080fe00808080ff0080ff00808080fe0080 018080fd80800180800300808080808080808080808080808080808080808080808080808080808080808000000c000000000280038000030007000b000f00130017001b001f00230027002b002f0000 11353315213533150535331521353315053533152135331505353315313533153135331505353315073533150735331580018080fd8080018080fd8080018080fe00808080ff00808080808003008080 80808080808080808080808080808080808080808080808080808080000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b000011353315313533153135 331531353315313533150735331505353315053533150535331505353315073533153135331531353315313533153135331580808080808080ff0080ff0080ff0080ff00808080808080800300808080 808080808080808080808080808080808080808080808080808080808080808080000000000d0080ff800200040000030007000b000f00130017001b001f00230027002b002f00330000133533153135 3315313533150535331507353315073533150735331507353315073533150735331507353315313533153135331580808080fe8080808080808080808080808080808080800380808080808080808080 8080808080808080808080808080808080808080808080808000000000090000ff800280040000030007000b000f00130017001b001f00230000113533150735331d013533150735331d013533150735 331d013533150735331d01353315808080808080808080808080800380808080808080808080808080808080808080808080808080808000000d0080ff800200040000030007000b000f00130017001b 001f00230027002b002f00330000133533153135331531353315073533150735331507353315073533150735331507353315073533150535331531353315313533158080808080808080808080808080 80808080fe808080800380808080808080808080808080808080808080808080808080808080808080808080800000000005000002000280038000030007000b000f0013000001353315053533153335 33150535331521353315010080ff00808080fe00800180800300808080808080808080808080000000060000ff800300000000030007000b000f00130017000015353315313533153135331531353315 31353315313533158080808080808080808080808080808080808000000201000280020003800003000700000135331d01353315010080800300808080808000000e000000000280028000030007000b 000f00130017001b001f00230027002b002f00330037000013353315313533153135331d0135331505353315313533153135331531353315053533152135331505353315313533153135331531353315 8080808080fe0080808080fd8080018080fe0080808080020080808080808080808080808080808080808080808080808080808080808080800000000011000000000280040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430000113533150735331507353315073533153135331531353315313533150535331521353315053533152135331505353315213533150535 331531353315313533153135331580808080808080808080fe0080018080fd8080018080fd8080018080fd80808080800380808080808080808080808080808080808080808080808080808080808080 808080808080808080808000000b000000000280028000030007000b000f00130017001b001f00230027002b00001335331531353315313533153135331505353315073533150735331d013533153135 331531353315313533158080808080fd808080808080808080800200808080808080808080808080808080808080808080808080808000000011000000000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043000001353315073533150735331505353315313533153135331531353315053533152135331505353315213533150535331521353315053533153135 3315313533153135331502008080808080fe0080808080fd8080018080fd8080018080fd8080018080fe0080808080038080808080808080808080808080808080808080808080808080808080808080 808080808080808080800000000f000000000280028000030007000b000f00130017001b001f00230027002b002f00330037003b00001335331531353315313533150535331521353315053533153135 33153135331531353315313533150535331d0135331531353315313533153135331580808080fe0080018080fd808080808080fd80808080808002008080808080808080808080808080808080808080 80808080808080808080808080800000000d000000000280040000030007000b000f00130017001b001f00230027002b002f003300000135331531353315313533150535331507353315053533153135 33153135331531353315053533150735331507353315073533150100808080fe00808080ff0080808080fe80808080808080800380808080808080808080808080808080808080808080808080808080 808080808080000000110000ff000280028000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300001335331531353315313533150535331521353315053533152135 33150535331521353315053533153135331531353315313533150735331505353315313533153135331580808080fe0080018080fd8080018080fd8080018080fe00808080808080fe00808080020080 80808080808080808080808080808080808080808080808080808080808080808080808080808000000f000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b 000011353315073533150735331507353315313533153135331531353315053533152135331505353315213533150535331521353315053533152135331580808080808080808080fe0080018080fd80 80018080fd8080018080fd8080018080038080808080808080808080808080808080808080808080808080808080808080808080808080000007008000000180038000030007000b000f00130017001b 000001353315013533153135331507353315073533150735331507353315010080ff008080808080808080808003008080ff008080808080808080808080808080808000000b0000ff00020003800003 0007000b000f00130017001b001f00230027002b00000135331501353315313533150735331507353315073533150735331507353315053533153135331531353315018080ff00808080808080808080 808080fe0080808003008080ff008080808080808080808080808080808080808080808080808080000d008000000280040000030007000b000f00130017001b001f00230027002b002f003300001335 33150735331507353315073533152135331505353315333533150535331531353315053533153335331505353315213533158080808080808080010080fe00808080fe808080ff00808080fe80800100 8003808080808080808080808080808080808080808080808080808080808080808080800009008000000180040000030007000b000f00130017001b001f002300001335331531353315073533150735 3315073533150735331507353315073533150735331580808080808080808080808080808080800380808080808080808080808080808080808080808080808080800000000f00000000028002800003 0007000b000f00130017001b001f00230027002b002f00330037003b00001135331531353315333533150535331533353315333533150535331533353315333533150535331533353315333533150535 3315333533153335331580808080fe008080808080fd808080808080fd808080808080fd8080808080800200808080808080808080808080808080808080808080808080808080808080808080800000 000c000000000280028000030007000b000f00130017001b001f00230027002b002f00001135331531353315313533153135331505353315213533150535331521353315053533152135331505353315 2135331580808080fe0080018080fd8080018080fd8080018080fd80800180800200808080808080808080808080808080808080808080808080808080800000000c000000000280028000030007000b 000f00130017001b001f00230027002b002f000013353315313533153135331505353315213533150535331521353315053533152135331505353315313533153135331580808080fe0080018080fd80 80018080fd8080018080fe0080808002008080808080808080808080808080808080808080808080808080808000000000100000ff000280028000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00001135331531353315313533153135331505353315213533150535331521353315053533152135331505353315313533153135331531353315053533150735331580808080 fe0080018080fd8080018080fd8080018080fd8080808080fe008080800200808080808080808080808080808080808080808080808080808080808080808080808080808000000000100000ff000280 028000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001335331531353315313533153135331505353315213533150535331521353315053533152135331505353315 31353315313533153135331507353315073533158080808080fd8080018080fd8080018080fd8080018080fe008080808080808080020080808080808080808080808080808080808080808080808080 808080808080808080808080800000000009000000000280028000030007000b000f00130017001b001f0023000011353315333533153135331505353315313533152135331505353315073533150735 331580808080fe008080010080fd808080808080020080808080808080808080808080808080808080808080000d000000000280028000030007000b000f00130017001b001f00230027002b002f0033 0000133533153135331531353315313533150535331d01353315313533153135331d01353315053533153135331531353315313533158080808080fd808080808080fd80808080800200808080808080 808080808080808080808080808080808080808080808080000b008000000280038000030007000b000f00130017001b001f00230027002b000013353315073533150735331531353315313533150535 3315073533150735331d0135331531353315313533158080808080808080fe8080808080808080800300808080808080808080808080808080808080808080808080808080800000000c000000000280 028000030007000b000f00130017001b001f00230027002b002f000011353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135331580018080 fd8080018080fd8080018080fd8080018080fe008080808002008080808080808080808080808080808080808080808080808080808000000009000000000280028000030007000b000f00130017001b 001f0023000011353315213533150535331521353315053533153335331505353315333533150535331580018080fd8080018080fe00808080fe80808080ff0080020080808080808080808080808080 808080808080808080000000000c000000000280028000030007000b000f00130017001b001f00230027002b002f00001135331521353315053533153335331533353315053533153335331533353315 0535331533353315053533153335331580018080fd808080808080fd808080808080fe00808080fe80808080020080808080808080808080808080808080808080808080808080808080000000090000 00000280028000030007000b000f00130017001b001f0023000011353315213533150535331533353315053533150535331533353315053533152135331580018080fe00808080ff0080ff00808080fe 008001808002008080808080808080808080808080808080808080808000000000100000ff000280028000030007000b000f00130017001b001f00230027002b002f00330037003b003f000011353315 21353315053533152135331505353315213533150535331521353315053533153135331531353315313533150735331505353315313533153135331580018080fd8080018080fd8080018080fd808001 8080fe00808080808080fe008080800200808080808080808080808080808080808080808080808080808080808080808080808080808000000d000000000280028000030007000b000f00130017001b 001f00230027002b002f00330000113533153135331531353315313533153135331505353315053533150535331505353315313533153135331531353315313533158080808080ff0080ff0080ff0080 ff00808080808002008080808080808080808080808080808080808080808080808080808080800000090080ff800200040000030007000b000f00130017001b001f0023000001353315053533150735 3315073533150535331d01353315073533150735331d01353315018080ff008080808080ff00808080808080800380808080808080808080808080808080808080808080808080808000000000090100 ff800180040000030007000b000f00130017001b001f00230000013533150735331507353315073533150735331507353315073533150735331507353315010080808080808080808080808080808080 800380808080808080808080808080808080808080808080808080808000000000090080ff800200040000030007000b000f00130017001b001f002300001335331d01353315073533150735331d0135 3315053533150735331507353315053533158080808080808080ff008080808080ff0080038080808080808080808080808080808080808080808080808080800006000001000300020000030007000b 000f001300170000133533153135331521353315053533152135331531353315808080010080fd0080010080800180808080808080808080808080800013000000000300038000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b00000135331531353315313533150535331521353315053533153135331531353315313533150535331505353315313533153135 33153135331505353315213533150535331531353315313533150100808080fe0080018080fd0080808080fe8080ff0080808080fe8080018080fe008080800300808080808080808080808080808080 808080808080808080808080808080808080808080808080808080808000000000020100ff80020000800003000700002135331505353315018080ff0080808080808000000d0080ff00028004000003 0007000b000f00130017001b001f00230027002b002f00330000013533153135331505353315073533150535331531353315313533150535331507353315073533150735331507353315053533150180 8080fe80808080ff00808080ff00808080808080808080ff0080038080808080808080808080808080808080808080808080808080808080808080808080800000040080ff800200008000030007000b 000f00003335331533353315053533153335331580808080fe8080808080808080808080808000000003000000000280008000030007000b000031353315333533153335331580808080808080808080 80000000000d0000ff800280040000030007000b000f00130017001b001f00230027002b002f003300000135331507353315053533153135331531353315313533153135331505353315073533150735 33150735331507353315073533150100808080fe808080808080fe8080808080808080808080800380808080808080808080808080808080808080808080808080808080808080808080800000110000 ff800280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300000135331507353315053533153135331531353315313533153135331505353315053533153135 3315313533153135331531353315053533150735331507353315073533150100808080fe808080808080fe8080fe808080808080fe808080808080808003808080808080808080808080808080808080 808080808080808080808080808080808080808080808080800000000003008003000200040000030007000b0000013533150535331533353315010080ff0080808003808080808080808000000b0000 00800300030000030007000b000f00130017001b001f00230027002b000013353315213533150535331533353315053533150535331533353315333533150535331521353315333533158080010080fe 00808080ff0080ff008080808080fd008001008080800280808080808080808080808080808080808080808080808080808000000012000000000280040000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f004300470000133533153335331505353315013533153135331531353315313533150535331507353315313533153135331531353315313533150735331505353315 31353315313533153135331580808080ff0080ff0080808080fd80808080808080808080fd8080808080038080808080808080ff00808080808080808080808080808080808080808080808080808080 80808080808080000005008000000200028000030007000b000f0013000001353315053533150535331d0135331d01353315018080ff0080ff0080808002008080808080808080808080808080000000 0013000000000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000133533153135331533353315313533150535331521353315053533152135 33150535331521353315313533150535331521353315053533152135331505353315313533153335331531353315808080808080fd0080010080fe0080010080fe008001008080fd8080010080fe0080 010080fe808080808080030080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800010000000000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000133533153335331505353315013533153135331531353315313533153135331505353315053533150535331505353315313533153135331531353315 3135331580808080ff0080fe808080808080ff0080ff0080ff0080ff008080808080038080808080808080ff008080808080808080808080808080808080808080808080808080808080800000030100 02800200040000030007000b0000013533150735331d013533150100808080800380808080808080808000000003010002800200040000030007000b00000135331507353315053533150180808080ff 0080038080808080808080800006008002800280040000030007000b000f00130017000013353315333533150535331533353315053533153335331580808080fe80808080ff00808080038080808080 8080808080808080808000000006008002800280040000030007000b000f0013001700000135331533353315053533153335331505353315333533150100808080fe80808080fe008080800380808080 8080808080808080808080000004010001000200020000030007000b000f00000135331531353315053533153135331501008080ff008080018080808080808080808000000500000100028001800003 0007000b000f0013000011353315313533153135331531353315313533158080808080010080808080808080808080000006000001000300018000030007000b000f0013001700001135331531353315 3135331531353315313533153135331580808080808001008080808080808080808080800004008001000280020000030007000b000f0000013533153335331505353315333533150100808080fe0080 808001808080808080808080800000000010000000800300028000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001135331531353315313533153135331531353315 3135331505353315333533153135331531353315053533153335331533353315053533153335331533353315808080808080fd808080808080fd808080808080fd808080808080020080808080808080 808080808080808080808080808080808080808080808080808080800010000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00001335331533353315 05353315013533153135331531353315313533150535331d01353315313533153135331d013533150535331531353315313533153135331580808080ff0080ff0080808080fd808080808080fd808080 8080038080808080808080ff00808080808080808080808080808080808080808080808080808080808080000005010000000280028000030007000b000f001300000135331d0135331d013533150535 3315053533150100808080ff0080ff008002008080808080808080808080808080000000000f000000000300028000030007000b000f00130017001b001f00230027002b002f00330037003b00001335 33153135331533353315313533150535331521353315053533152135331531353315053533152135331505353315313533153335331531353315808080808080fd0080010080fe008001008080fd8080 010080fe80808080808002008080808080808080808080808080808080808080808080808080808080808080808000000010000000000280040000030007000b000f00130017001b001f00230027002b 002f00330037003b003f00001335331533353315053533150135331531353315313533153135331531353315053533150535331505353315053533153135331531353315313533153135331580808080 ff0080fe808080808080ff0080ff0080ff0080ff008080808080038080808080808080ff0080808080808080808080808080808080808080808080808080808080808000000d00000000028004000003 0007000b000f00130017001b001f00230027002b002f00330000133533153335331501353315213533150535331521353315053533152135331505353315313533153135331505353315073533158080 8080fe0080018080fd8080018080fd8080018080fe00808080ff00808080038080808080ff00808080808080808080808080808080808080808080808080808080000000000601000000018003800003 0007000b000f0013001700000135331503353315073533150735331507353315073533150100808080808080808080808003008080ff008080808080808080808080808080000000000c008000000280 030000030007000b000f00130017001b001f00230027002b002f0000013533150535331531353315313533150535331533353315053533153335331505353315313533153135331505353315018080ff 00808080fe00808080fe80808080ff00808080ff0080028080808080808080808080808080808080808080808080808080808080800000000010000000000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000013533153135331505353315073533150535331531353315313533153135331505353315053533150535331507353315313533153135331531353315 3135331501808080fe80808080ff0080808080fe8080ff0080ff008080808080808003808080808080808080808080808080808080808080808080808080808080808080808080808080800000100000 00000300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f000011353315213533150535331531353315313533153135331505353315213533150535331521353315 05353315313533153135331531353315053533152135331580020080fd8080808080fe0080010080fe0080010080fe0080808080fd808002008002808080808080808080808080808080808080808080 8080808080808080808080808080808080000000000f000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b0000113533152135331505353315213533150535 33153135331531353315053533150535331531353315313533153135331531353315053533150735331580018080fd8080018080fe00808080ff0080fe808080808080fe808080800300808080808080 808080808080808080808080808080808080808080808080808080808080000000080100ff800180040000030007000b000f00130017001b001f00000135331507353315073533150735331503353315 073533150735331507353315010080808080808080808080808080808003808080808080808080808080ff0080808080808080808080800000120000ff000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043004700000135331531353315053533150735331505353315313533153135331505353315213533150535331521353315053533153135331531353315 0535331507353315053533153135331501808080fe80808080ff00808080fe0080018080fd8080018080fe00808080ff00808080fe808080038080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080000002008003000200038000030007000013353315333533158080808003008080808000000017000000000300038000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b0000133533153135331531353315313533150535331521353315053533153335331531353315333533150535 33153335331521353315053533153335331531353315333533150535331521353315053533153135331531353315313533158080808080fd8080020080fd00808080808080fd00808080010080fd0080 8080808080fd0080020080fd8080808080030080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000008008001800200 040000030007000b000f00130017001b001f00000135331d0135331505353315313533150535331533353315053533153135331501008080ff008080fe80808080ff0080800380808080808080808080 808080808080808080808000000a000000000300028000030007000b000f00130017001b001f002300270000013533152135331505353315213533150535331521353315053533152135331505353315 21353315010080010080fd8080010080fd8080010080fe8080010080fe808001008002008080808080808080808080808080808080808080808080800007008000000280020000030007000b000f0013 0017001b0000133533153135331531353315313533150735331507353315073533158080808080808080808080018080808080808080808080808080808080800015000000000300038000030007000b 000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530000133533153135331531353315313533150535331521353315053533152135331533353315053533153335 3315213533150535331533353315213533150535331521353315053533153135331531353315313533158080808080fd8080020080fd00800100808080fd00808080010080fd00808080010080fd0080 020080fd80808080800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000005000003000280038000030007000b000f0013 000011353315313533153135331531353315313533158080808080030080808080808080808080000004008002000200038000030007000b000f000001353315053533153335331505353315010080ff 00808080ff008003008080808080808080808000000e000000000280030000030007000b000f00130017001b001f00230027002b002f0033003700000135331507353315053533153135331531353315 3135331531353315053533150735331505353315313533153135331531353315313533150100808080fe808080808080fe80808080fe8080808080800280808080808080808080808080808080808080 808080808080808080808080808080000008008001800200040000030007000b000f00130017001b001f0000133533153135331d01353315053533150535331507353315313533153135331580808080 ff0080ff008080808080038080808080808080808080808080808080808080800008008001800200040000030007000b000f00130017001b001f0000133533153135331d01353315053533153135331d 01353315053533153135331580808080fe80808080fe8080800380808080808080808080808080808080808080808000000201000300020004000003000700000135331505353315018080ff00800380 8080808080000000000e0000ff000300028000030007000b000f00130017001b001f00230027002b002f0033003700001335331521353315053533152135331505353315213533150535331521353315 0535331531353315313533153335331505353315053533158080010080fe0080010080fe0080010080fe0080010080fe008080808080fd8080ff00800200808080808080808080808080808080808080 80808080808080808080808080808080001a0000ff000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f00530057005b005f006300670000 1335331531353315313533153135331531353315053533153135331531353315333533150535331531353315313533153335331505353315313533153335331505353315333533150535331533353315 053533153335331505353315333533150535331533353315808080808080fd008080808080fd808080808080fe0080808080fe80808080fe80808080fe80808080fe80808080fe808080800300808080 8080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000001010001800180020000030000013533150100 800180808000000000040100ff000200008000030007000b000f000021353315313533150735331505353315010080808080ff008080808080808080808080000008008001800200040000030007000b 000f00130017001b001f00000135331505353315313533150735331507353315053533153135331531353315010080ff00808080808080ff008080800380808080808080808080808080808080808080 808000000006008002000200040000030007000b000f001300170000013533150535331533353315053533153335331505353315010080ff00808080fe80808080ff0080038080808080808080808080 8080808080000000000a000000000300028000030007000b000f00130017001b001f00230027000011353315213533150535331521353315053533152135331505353315213533150535331521353315 80010080fe8080010080fe8080010080fd8080010080fd80800100800200808080808080808080808080808080808080808080808080000000130000ff800300040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f00430047004b0000013533150535331521353315053533152135331505353315213533150535331521353315053533153335331531353315053533153335 33153135331531353315053533152135331505353315020080fd8080018080fd8080010080fe0080010080ff0080010080fe0080808080fd808080808080fd8080018080fd0080038080808080808080 8080808080808080808080808080808080808080808080808080808080808080808080808080800000120000ff800300040000030007000b000f00130017001b001f00230027002b002f00330037003b 003f004300470000013533150535331521353315053533152135331505353315213533150535331533353315313533150535331521353315053533152135331505353315213533153135331505353315 020080fd8080018080fd8080010080fe0080010080ff0080808080fe0080010080fd8080010080fe008001008080fd008003808080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080800000160000ff800300040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b004f0053005700001135331521353315 0535331521353315053533153135331533353315053533153335331505353315333533152135331505353315333533153135331505353315333533153135331531353315053533152135331505353315 80018080fe0080010080fd8080808080fe80808080fe00808080010080fe0080808080fd808080808080fd8080018080fd00800380808080808080808080808080808080808080808080808080808080 808080808080808080808080808080808080808080808080800000000009000000000280038000030007000b000f00130017001b001f00230000013533150335331d0135331d01353315053533152135 331505353315313533153135331501008080808080fd8080018080fe0080808003008080ff0080808080808080808080808080808080808080800000000c000000000280040000030007000b000f0013 0017001b001f00230027002b002f00001335331d01353315033533150535331533353315053533153135331531353315053533152135331505353315213533158080808080ff00808080fe80808080fe 0080018080fd808001808003808080808080ff00808080808080808080808080808080808080808080808080000c000000000280040000030007000b000f00130017001b001f00230027002b002f0000 013533150535331511353315053533153335331505353315313533153135331505353315213533150535331521353315010080ff008080ff00808080fe80808080fe0080018080fd8080018080038080 80808080ff008080808080808080808080808080808080808080808080800000000d000000000280040000030007000b000f00130017001b001f00230027002b002f0033000001353315053533153335 331501353315053533153335331505353315313533153135331505353315213533150535331521353315010080ff00808080ff0080ff00808080fe80808080fe0080018080fd80800180800380808080 80808080ff008080808080808080808080808080808080808080808080800000000e000000000280040000030007000b000f00130017001b001f00230027002b002f0033003700000135331533353315 0535331533353315013533150535331533353315053533153135331531353315053533152135331505353315213533150100808080fe00808080ff0080ff00808080fe80808080fe0080018080fd8080 0180800380808080808080808080ff00808080808080808080808080808080808080808080808080000c000000000280038000030007000b000f00130017001b001f00230027002b002f000013353315 333533150135331505353315333533150535331531353315313533150535331521353315053533152135331580808080ff0080ff00808080fe80808080fe0080018080fd8080018080030080808080ff 00808080808080808080808080808080808080808080808080000000000e000000000280040000030007000b000f00130017001b001f00230027002b002f003300370000013533150535331533353315 0535331507353315053533153335331505353315313533153135331505353315213533150535331521353315010080ff00808080ff00808080ff00808080fe80808080fe0080018080fd808001808003 8080808080808080808080808080808080808080808080808080808080808080808080800014000000000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 0047004b004f0000013533153135331531353315313533150535331533353315053533153335331505353315313533153135331531353315053533152135331505353315213533150535331521353315 3135331531353315010080808080fd80808080fe80808080fe8080808080fd8080010080fe0080010080fe00800100808080030080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080800000000f0000ff000280038000030007000b000f00130017001b001f00230027002b002f00330037003b0000133533153135331531353315053533152135 33150535331507353315073533150735331521353315053533153135331531353315053533150535331580808080fe0080018080fd8080808080808080018080fe00808080ff0080ff00800300808080 8080808080808080808080808080808080808080808080808080808080808080808080000012000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043 004700001335331d0135331501353315313533153135331531353315313533150535331507353315313533153135331531353315053533150735331531353315313533153135331531353315808080fe 808080808080fd80808080808080fe008080808080808003808080808080ff00808080808080808080808080808080808080808080808080808080808080808080808080001200000000028004000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700000135331505353315013533153135331531353315313533153135331505353315073533153135331531353315 31353315053533150735331531353315313533153135331531353315010080ff0080ff008080808080fd80808080808080fe008080808080808003808080808080ff0080808080808080808080808080 8080808080808080808080808080808080808080808080000013000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b0000013533150535 33153335331501353315313533153135331531353315313533150535331507353315313533153135331531353315053533150735331531353315313533153135331531353315010080ff00808080fe00 8080808080fd80808080808080fe0080808080808080038080808080808080ff008080808080808080808080808080808080808080808080808080808080808080808080800000000012000000000280 038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047000013353315333533150135331531353315313533153135331531353315053533150735331531353315 313533153135331505353315073533153135331531353315313533153135331580808080fe008080808080fd80808080808080fe0080808080808080030080808080ff00808080808080808080808080 808080808080808080808080808080808080808080808080000b008000000200040000030007000b000f00130017001b001f00230027002b00001335331d013533150135331531353315313533150535 33150735331507353315053533153135331531353315808080ff00808080ff008080808080ff0080808003808080808080ff0080808080808080808080808080808080808080808080000000000b0080 00000200040000030007000b000f00130017001b001f00230027002b00000135331505353315033533153135331531353315053533150735331507353315053533153135331531353315010080ff0080 80808080ff008080808080ff0080808003808080808080ff008080808080808080808080808080808080808080808000000c008000000200040000030007000b000f00130017001b001f00230027002b 002f0000013533150535331533353315013533153135331531353315053533150735331507353315053533153135331531353315010080ff00808080fe80808080ff008080808080ff00808080038080 808080808080ff00808080808080808080808080808080808080808080800000000b008000000200038000030007000b000f00130017001b001f00230027002b00001335331533353315013533153135 33153135331505353315073533150735331505353315313533153135331580808080fe80808080ff008080808080ff00808080030080808080ff00808080808080808080808080808080808080808080 800000000013000000000300038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430047004b00001335331531353315313533150535331521353315053533152135 331505353315313533153135331531353315333533150535331521353315053533152135331505353315313533153135331580808080fe8080010080fe0080018080fd00808080808080fd8080018080 fd8080010080fe00808080030080808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000000013000000000280040000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047004b00000135331533353315053533153335331501353315313533152135331505353315333533153335331505353315333533153335 33150535331521353315313533150535331521353315313533150100808080fe00808080fe008080010080fd808080808080fd808080808080fd808001008080fd808001008080038080808080808080 8080ff00808080808080808080808080808080808080808080808080808080808080808080800000000e000000000280040000030007000b000f00130017001b001f00230027002b002f003300370000 1335331d01353315013533153135331531353315053533152135331505353315213533150535331521353315053533153135331531353315808080ff00808080fe0080018080fd8080018080fd808001 8080fe0080808003808080808080ff0080808080808080808080808080808080808080808080808080808080000e000000000280040000030007000b000f00130017001b001f00230027002b002f0033 003700000135331505353315033533153135331531353315053533152135331505353315213533150535331521353315053533153135331531353315010080ff008080808080fe0080018080fd808001 8080fd8080018080fe0080808003808080808080ff00808080808080808080808080808080808080808080808080808080800000000f000000000280040000030007000b000f00130017001b001f0023 0027002b002f00330037003b0000013533150535331533353315013533153135331531353315053533152135331505353315213533150535331521353315053533153135331531353315010080ff0080 8080fe80808080fe0080018080fd8080018080fd8080018080fe00808080038080808080808080ff00808080808080808080808080808080808080808080808080808080800000000010000000000280 040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331533353315053533153335331501353315313533153135331505353315213533150535331521353315 05353315213533150535331531353315313533150100808080fe00808080fe80808080fe0080018080fd8080018080fd8080018080fe008080800380808080808080808080ff00808080808080808080 8080808080808080808080808080808080808000000e000000000280038000030007000b000f00130017001b001f00230027002b002f0033003700001335331533353315013533153135331531353315 05353315213533150535331521353315053533152135331505353315313533153135331580808080fe80808080fe0080018080fd8080018080fd8080018080fe00808080030080808080ff0080808080 8080808080808080808080808080808080808080808080800009000000800280030000030007000b000f00130017001b001f002300001135331521353315053533153335331505353315053533153335 3315053533152135331580018080fe00808080ff0080ff00808080fe00800180800280808080808080808080808080808080808080808080800000000010000000000300030000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00000135331531353315333533150535331521353315053533153335331531353315053533153135331533353315053533152135331505353315 3335331531353315010080808080fd8080010080fe0080808080fe0080808080fe0080010080fd8080808080028080808080808080808080808080808080808080808080808080808080808080808080 80808000000d000000000280040000030007000b000f00130017001b001f00230027002b002f003300001335331d01353315013533152135331505353315213533150535331521353315053533152135 3315053533153135331531353315808080fe8080018080fd8080018080fd8080018080fd8080018080fe0080808003808080808080ff0080808080808080808080808080808080808080808080808080 80000000000d000000000280040000030007000b000f00130017001b001f00230027002b002f003300000135331505353315013533152135331505353315213533150535331521353315053533152135 3315053533153135331531353315010080ff0080ff0080018080fd8080018080fd8080018080fd8080018080fe0080808003808080808080ff0080808080808080808080808080808080808080808080 80808080000e000000000280040000030007000b000f00130017001b001f00230027002b002f003300370000013533150535331533353315013533152135331505353315213533150535331521353315 0535331521353315053533153135331531353315010080ff00808080fe0080018080fd8080018080fd8080018080fd8080018080fe00808080038080808080808080ff00808080808080808080808080 80808080808080808080808080800000000d000000000280038000030007000b000f00130017001b001f00230027002b002f003300001335331533353315013533152135331505353315213533150535 331521353315053533152135331505353315313533153135331580808080fe0080018080fd8080018080fd8080018080fd8080018080fe00808080030080808080ff0080808080808080808080808080 80808080808080808080808080000000000d000000000280040000030007000b000f00130017001b001f00230027002b002f003300000135331505353315053533152135331505353315213533150535 3315213533150535331531353315313533150535331507353315018080ff0080fe8080018080fd8080018080fd8080018080fe00808080ff008080800380808080808080808080808080808080808080 80808080808080808080808080808000000e0080ff800280038000030007000b000f00130017001b001f00230027002b002f003300370000133533150735331507353315313533153135331505353315 21353315053533152135331505353315313533153135331505353315073533158080808080808080fe8080010080fe0080010080fe00808080fe80808080030080808080808080808080808080808080 808080808080808080808080808080808080800000120000ff800280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000133533153135331531353315 05353315213533150535331521353315053533153135331531353315053533152135331505353315213533150535331531353315313533150535331580808080fe8080010080fe0080010080fe008080 80fe8080010080fe0080010080fe00808080fe00800300808080808080808080808080808080808080808080808080808080808080808080808080808080808080800000001000000000028004000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f00001335331d0135331501353315313533153135331d01353315053533153135331531353315313533150535331521353315 05353315313533153135331531353315808080ff0080808080fe0080808080fd8080018080fe008080808003808080808080ff0080808080808080808080808080808080808080808080808080808080 808080800010000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0000013533150535331503353315313533153135331d013533150535331531353315 3135331531353315053533152135331505353315313533153135331531353315010080ff00808080808080fe0080808080fd8080018080fe008080808003808080808080ff0080808080808080808080 8080808080808080808080808080808080808080808000000011000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043000001353315053533153335 331501353315313533153135331d0135331505353315313533153135331531353315053533152135331505353315313533153135331531353315010080ff00808080fe8080808080fe0080808080fd80 80018080fe0080808080038080808080808080ff0080808080808080808080808080808080808080808080808080808080808080800000000012000000000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0043004700000135331533353315053533153335331501353315313533153135331d01353315053533153135331531353315313533150535331521353315 053533153135331531353315313533150100808080fe00808080fe8080808080fe0080808080fd8080018080fe00808080800380808080808080808080ff008080808080808080808080808080808080 808080808080808080808080808080000010000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f0000133533153335331501353315313533153135331d 013533150535331531353315313533153135331505353315213533150535331531353315313533153135331580808080fe8080808080fe0080808080fd8080018080fe0080808080030080808080ff00 80808080808080808080808080808080808080808080808080808080808080800012000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000 0135331505353315333533150535331505353315313533153135331d0135331505353315313533153135331531353315053533152135331505353315313533153135331531353315010080ff00808080 ff0080ff0080808080fe0080808080fd8080018080fe0080808080038080808080808080808080808080808080808080808080808080808080808080808080808080808080808080000f000000000300 028000030007000b000f00130017001b001f00230027002b002f00330037003b000013353315313533153335331505353315333533150535331531353315313533153135331505353315213533150535 33153135331533353315313533158080808080ff00808080fd8080808080fd8080010080fe80808080808002008080808080808080808080808080808080808080808080808080808080808080808000 000d0000ff000280028000030007000b000f00130017001b001f00230027002b002f003300001335331531353315313533153135331505353315073533150735331d0135331531353315313533153135 331505353315053533158080808080fd80808080808080808080fe8080ff0080020080808080808080808080808080808080808080808080808080808080808080800000001100000000028004000003 0007000b000f00130017001b001f00230027002b002f00330037003b003f004300001335331d013533150135331531353315313533150535331521353315053533153135331531353315313533153135 33150535331d01353315313533153135331531353315808080ff00808080fe0080018080fd808080808080fd80808080808003808080808080ff00808080808080808080808080808080808080808080 808080808080808080808080800000000011000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000013533150535331503353315313533153135 3315053533152135331505353315313533153135331531353315313533150535331d01353315313533153135331531353315010080ff008080808080fe0080018080fd808080808080fd808080808080 03808080808080ff0080808080808080808080808080808080808080808080808080808080808080808080000012000000000280040000030007000b000f00130017001b001f00230027002b002f0033 0037003b003f004300470000013533150535331533353315013533153135331531353315053533152135331505353315313533153135331531353315313533150535331d013533153135331531353315 31353315010080ff00808080fe80808080fe0080018080fd808080808080fd808080808080038080808080808080ff008080808080808080808080808080808080808080808080808080808080808080 808000000011000000000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f00430000133533153335331501353315313533153135331505353315213533150535 3315313533153135331531353315313533150535331d0135331531353315313533153135331580808080fe80808080fe0080018080fd808080808080fd808080808080030080808080ff008080808080 80808080808080808080808080808080808080808080808080808080800000000008008000000180040000030007000b000f00130017001b001f00001335331d01353315013533153135331507353315 073533150735331507353315808080ff008080808080808080808003808080808080ff00808080808080808080808080808080800008008000000180040000030007000b000f00130017001b001f0000 0135331505353315033533153135331507353315073533150735331507353315010080ff0080808080808080808080808003808080808080ff0080808080808080808080808080808080000000090080 00000200040000030007000b000f00130017001b001f00230000013533150535331533353315013533153135331507353315073533150735331507353315010080ff00808080fe808080808080808080 8080038080808080808080ff00808080808080808080808080808080800000000008008000000200038000030007000b000f00130017001b001f00001335331533353315013533153135331507353315 07353315073533150735331580808080fe8080808080808080808080030080808080ff00808080808080808080808080808080800010000000000280038000030007000b000f00130017001b001f0023 0027002b002f00330037003b003f00001335331531353315333533150535331d013533150535331531353315313533153135331505353315213533150535331521353315053533153135331531353315 8080808080ff008080fe0080808080fd8080018080fd8080018080fe00808080030080808080808080808080808080808080808080808080808080808080808080808080808080800010000000000280 040000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331533353315053533153335331501353315313533153135331531353315053533152135331505353315 21353315053533152135331505353315213533150100808080fe00808080fe0080808080fe0080018080fd8080018080fd8080018080fd80800180800380808080808080808080ff0080808080808080 808080808080808080808080808080808080808080000000000e000000000280040000030007000b000f00130017001b001f00230027002b002f0033003700001335331d013533150135331531353315 31353315053533152135331505353315213533150535331521353315053533153135331531353315808080ff00808080fe0080018080fd8080018080fd8080018080fe0080808003808080808080ff00 80808080808080808080808080808080808080808080808080808080000e000000000280040000030007000b000f00130017001b001f00230027002b002f003300370000013533150535331503353315 3135331531353315053533152135331505353315213533150535331521353315053533153135331531353315010080ff008080808080fe0080018080fd8080018080fd8080018080fe00808080038080 80808080ff00808080808080808080808080808080808080808080808080808080800000000f000000000280040000030007000b000f00130017001b001f00230027002b002f00330037003b00000135 33150535331533353315013533153135331531353315053533152135331505353315213533150535331521353315053533153135331531353315010080ff00808080fe80808080fe0080018080fd8080 018080fd8080018080fe00808080038080808080808080ff00808080808080808080808080808080808080808080808080808080800000000010000000000280040000030007000b000f00130017001b 001f00230027002b002f00330037003b003f0000133533153335331505353315333533150135331531353315313533150535331521353315053533152135331505353315213533150535331531353315 3135331580808080fe00808080ff00808080fe0080018080fd8080018080fd8080018080fe008080800380808080808080808080ff008080808080808080808080808080808080808080808080808080 80800000000e000000000280038000030007000b000f00130017001b001f00230027002b002f003300370000133533153335331501353315313533153135331505353315213533150535331521353315 053533152135331505353315313533153135331580808080fe80808080fe0080018080fd8080018080fd8080018080fe00808080030080808080ff008080808080808080808080808080808080808080 80808080808080800007000000800280030000030007000b000f00130017001b000001353315013533153135331531353315313533153135331501353315010080fe808080808080fe808002808080ff 0080808080808080808080ff008080000010000000000300030000030007000b000f00130017001b001f00230027002b002f00330037003b003f00000135331531353315333533150535331521353315 0535331533353315313533150535331531353315333533150535331521353315053533153335331531353315010080808080fd8080010080fe0080808080fe0080808080fe0080010080fd8080808080 02808080808080808080808080808080808080808080808080808080808080808080808080808000000e000000000280040000030007000b000f00130017001b001f00230027002b002f003300370000 1335331d01353315013533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315808080fe8080018080fd8080018080fd8080018080fd8080 018080fe008080808003808080808080ff00808080808080808080808080808080808080808080808080808080800000000e000000000280040000030007000b000f00130017001b001f00230027002b 002f0033003700000135331505353315013533152135331505353315213533150535331521353315053533152135331505353315313533153135331531353315010080ff0080ff0080018080fd808001 8080fd8080018080fd8080018080fe008080808003808080808080ff0080808080808080808080808080808080808080808080808080808080000000000f000000000280040000030007000b000f0013 0017001b001f00230027002b002f00330037003b000001353315053533153335331501353315213533150535331521353315053533152135331505353315213533150535331531353315313533153135 3315010080ff00808080fe0080018080fd8080018080fd8080018080fd8080018080fe0080808080038080808080808080ff008080808080808080808080808080808080808080808080808080808000 000e000000000280038000030007000b000f00130017001b001f00230027002b002f00330037000013353315333533150135331521353315053533152135331505353315213533150535331521353315 0535331531353315313533153135331580808080fe0080018080fd8080018080fd8080018080fd8080018080fe0080808080030080808080ff0080808080808080808080808080808080808080808080 808080808080000000120000ff000280040000030007000b000f00130017001b001f00230027002b002f00330037003b003f004300470000013533150535331501353315213533150535331521353315 053533152135331505353315213533150535331531353315313533153135331507353315053533153135331531353315010080ff0080ff0080018080fd8080018080fd8080018080fd8080018080fe00 808080808080fe0080808003808080808080ff008080808080808080808080808080808080808080808080808080808080808080808080808080000000120000ff000280038000030007000b000f0013 0017001b001f00230027002b002f00330037003b003f00430047000011353315073533150735331531353315313533153135331505353315213533150535331521353315053533152135331505353315 31353315313533153135331505353315073533158080808080808080fe0080018080fd8080018080fd8080018080fd8080808080fe008080800300808080808080808080808080808080808080808080 80808080808080808080808080808080808080808080800000120000ff000280038000030007000b000f00130017001b001f00230027002b002f00330037003b003f0043004700001335331533353315 0135331521353315053533152135331505353315213533150535331521353315053533153135331531353315313533150735331505353315313533153135331580808080fe0080018080fd8080018080 fd8080018080fd8080018080fe00808080808080fe00808080030080808080ff008080808080808080808080808080808080808080808080808080808080808080808080808080000000001501020000 000000000000002400470000000000000001001800810000000000000002000e006b00000000000000030018008100000000000000040018008100000000000000050014000000000000000000060018 00810001000000000000001200140001000000000001000c003100010000000000020007002600010000000000030010002d0001000000000004000c00310001000000000005000a003d000100000000 0006000c00310003000104090000002400470003000104090001001800810003000104090002000e006b0003000104090003002000790003000104090004001800810003000104090005001400000003 000104090006001800810032003000300034002f00300034002f003100356279205472697374616e204772696d6d6572526567756c61725454582050726f67677954696e795454323030342f30342f31 35006200790020005400720069007300740061006e0020004700720069006d006d006500720052006500670075006c00610072005400540058002000500072006f00670067007900540069006e007900 54005400000200000000000000000014000000010000000000000000000000000000000001010000000101020103010401050106010701080109010a010b010c010d010e010f01100111011201130114 01150116011701180119011a011b011c011d011e011f01200003000400050006000700080009000a000b000c000d000e000f0010001100120013001400150016001700180019001a001b001c001d001e 001f0020002100220023002400250026002700280029002a002b002c002d002e002f0030003100320033003400350036003700380039003a003b003c003d003e003f0040004100420043004400450046 004700480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d005e005f00600061012101220123012401250126012701280129012a012b012c012d 012e012f0130013101320133013401350136013701380139013a013b013c013d013e013f0140014100ac00a30084008500bd009600e80086008e008b009d00a900a400ef008a00da0083009300f200f3 008d0097008800c300de00f1009e00aa00f500f400f600a200ad00c900c700ae006200630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d5 006800eb00ed0089006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d007c00b800a1007f007e0080008100ec00ee00ba0e756e69636f6465 233078303030310e756e69636f6465233078303030320e756e69636f6465233078303030330e756e69636f6465233078303030340e756e69636f6465233078303030350e756e69636f64652330783030 30360e756e69636f6465233078303030370e756e69636f6465233078303030380e756e69636f6465233078303030390e756e69636f6465233078303030610e756e69636f6465233078303030620e756e 69636f6465233078303030630e756e69636f6465233078303030640e756e69636f6465233078303030650e756e69636f6465233078303030660e756e69636f6465233078303031300e756e69636f6465 233078303031310e756e69636f6465233078303031320e756e69636f6465233078303031330e756e69636f6465233078303031340e756e69636f6465233078303031350e756e69636f64652330783030 31360e756e69636f6465233078303031370e756e69636f6465233078303031380e756e69636f6465233078303031390e756e69636f6465233078303031610e756e69636f6465233078303031620e756e 69636f6465233078303031630e756e69636f6465233078303031640e756e69636f6465233078303031650e756e69636f6465233078303031660664656c657465044575726f0e756e69636f6465233078 303038310e756e69636f6465233078303038320e756e69636f6465233078303038330e756e69636f6465233078303038340e756e69636f6465233078303038350e756e69636f6465233078303038360e 756e69636f6465233078303038370e756e69636f6465233078303038380e756e69636f6465233078303038390e756e69636f6465233078303038610e756e69636f6465233078303038620e756e69636f 6465233078303038630e756e69636f6465233078303038640e756e69636f6465233078303038650e756e69636f6465233078303038660e756e69636f6465233078303039300e756e69636f6465233078 303039310e756e69636f6465233078303039320e756e69636f6465233078303039330e756e69636f6465233078303039340e756e69636f6465233078303039350e756e69636f6465233078303039360e 756e69636f6465233078303039370e756e69636f6465233078303039380e756e69636f6465233078303039390e756e69636f6465233078303039610e756e69636f6465233078303039620e756e69636f 6465233078303039630e756e69636f6465233078303039640e756e69636f6465233078303039650e756e69636f6465233078303039660000 ]], ["fonts/Roboto-Medium.ttf"] = [[ 00010000001101000004001047504f537daa718c000208a80000590c475355424c9c28e0000261b4000019684f532f32a10bb1b60000019800000060636d61704026487200001a6c000012c863767420 04972b4a00002fbc000000566670676d7bf961ab00002d34000001bc67617370000800130002089c0000000c676c7966ae9e62e9000039dc0001cbcc68646d783d3f3c2000001580000004ec68656164 f87bab080000011c00000036686865610aef0a9b0000015400000024686d747824f344f5000001f8000013886c6f6361ddde66ad00003014000009c66d617870071202f500000178000000206e616d65 3d636f4c000205a8000002d4706f7374ff6d00640002087c00000020707265701bb1f83600002ef0000000cc00010000000200001140a46d5f0f3cf5001b080000000000c4f0112e00000000d0db4e94 fa24fdd5095c087300000009000200000000000000010000076cfe0c0000096bfa24fe41095c0001000000000000000000000000000004e20001000004e2008f0016004e0005000100000000000e0000 02000216000600010003049501f400050000059a05330000011f059a0533000003d100660200000002000000000000000000e0000aff5000217f0000002100000000474f4f4700400000fffd0600fe00 0066079a02002000019f00000000043a05b0002000200002038c0064000000000000000001fe000001fe00000225008f0298006504e20060048c006405e00063051d0056015a005202ca008002d20028 0389001b0475004401c2001c02a00047023c0087032a0002048c0069048c00a8048c0051048c004f048c0034048c0081048c0075048c0045048c0068048c005d021f008201e7002e0411003f047a0091 042a008003e4003c0728005b05530012050c009405390066053a009404860094046500940572006a05af0094024200a30471002d050b0094045400940701009405ae009405860066051d009405860060 04fe009404d4004a04db002d0537007d052d0012070a00300510002904e0000704d1005002310084035800140231000c036b0035039c0003029400310454005a0481007c0430004f0484004f044b0053 02d6002d0489005204710079020b007d0201ffb5042d007d020b008c06f6007c04730079048e004f0481007c048b004f02d0007c0421004b02a900080472007703f5001605f200210406001f03e5000c 0406005202af0038020200ae02af001b05510075021e0086047d006404b5005e059d005d04e0001901fc008804f8005a0385005d064400570391008d03e20057046d007f0644005703db0087030a007f 044a005f02f6003c02f60037029b007004bb009203ed00450242008e0210006d02f6008003a7007703e2005d05d00059062b00500657006703e400420785fff60444004d0584006904ca009404e70088 06c1004804a70067049100430488004f0497008205b0001f021a008f0498008e04640022024f0021059300900488007e07b40064073a005b020c008b0588005102d0ffe4058a0058049e004f05a4007d 04f200770226ffb5043c005903e6009403b0007203dc0087037c0075020b008102b20078024d002903d8007a031f0049026c00820000fc8e0000fd5e0000fc730000fd3e0000fc0c0000fd1c025d00c6 043c00670242008e0475009b05bf0019057a005b053800200490006c05b1009b0490004705ef004a05aa0044055b006b0484005604c60096040e00200488005404600060041a00610488007e04a10073 02aa00a9046a00160413006404f3002d048800800437005204900052042d003f0460008005d0004405c9004f0694006604b30076047bffe10671003305fe0022055900680888002d088f009b065b0031 05aa0092050800900606002407a2001604d6004905a8009405a9002d050a0039065f004f05f900920589008e079b009807f90098061a001806f9009b050700900550006b075400a004f70020047d005b 048f008f035a008504f600270676001e0416004d04980086046e008f049a00210603008f049700860498008603f5002305d3005404d300860466005f068e008606ec007e0517001f066f008f0468008f 043c005106840091047000270471ffdb043c005406d1001e06e400860489ffee0498008607490088064f00700467ffe00728009806010086050c001c0460000a074200ac0636009d06ed008005e60082 093200a307f9008f0420002803f00033057a005f0488004f051a0010040e0020057a005f0488004f074500880644007407490088064f0070051a0066044a005c04ff006d0000fc660000fc730000fd7b 0000fda50000fa240000fa4d0467ffe0051300940486007c046a008f03a1007e04b7009b0420007e052c009004ab008e0695003405a4003d07d0009405aa007e0847009b06f5007e062a006704ff0061 0731002d057000260574008004730074058700850624001604c3ffcb052100900478008e05af009b0488007e0588005104a6005b04a6005d04c700340353002d0507005206f1006806dd005e0653003c 0528002f047b0048043e007407be0042069d004007fd0094069e00770504005d042c005505aa0021051d004405550081032c00670414000008290000041400000829000002b90000020a0000015c0000 047f00000230000001a2000000d100000000000002a1004702a100470529009d06300081039d000401c0006301bc003301ce003201a8004a0314006c031b004003080032045d00400499005c02cb0088 03fa008a05a6008a016c004707a7004a0272006c02690054039c002d02f60035035c006904b5005f0670002106b800980893009407880035068c007c048c005e05f500210434002804a20021055e004f 057d002805e4007003e2004c082e00900509006d051400960635005906dd005406d1005b06a2005804910062059600a604d900400483009e04b2003b0845005e022dffaf048e0065047a00910411003c 042a0080040c0024025b00a10298006301f10045051b002d04a8001804bc002d0723002d0723002d0511002d06b7004b00000000083000590835005c0433003a0493004f0210ffb001b3005c03a10075 03a1007503a10075040b0075040b0075040bff4c040b007a03a1007502050094049e0009046000760480004f047a007603e0007603c5007604a6005404de007601fc008503d50024045b007603b90076 0606007604dd007604c0004f046d007604c0004c045c00760434003e043b002404840067047b000906070028045e0015043c0005042a004102f6004b02f6008002f6003c02f6003702f6003502f6004f 02f6004d02f6003602f6004b02f6004603b9009002b20096043b000a04bb00560544009b0528009b043000810539009b042d00810434003e04660038044d000e03b90076047b000904c0004f047b0009 0398004204d8007604190044059d00500554005004e4005f059100240480004f07540024075700760597002404d700760471007605590027063a001a0446004204e40076045c007604cb00240446001f 055d0076048c004106840076070a0076055a000a06200076046700760480003c06920076048800430422000a0692001a049d0076051a0076056e002405f0004f045a000504c4001506950024048c0041 048c007605fe000a04d2004f0446004204c0004f0466003803f700460836007604eb00280488007c043d00500498004f03a4005b04a1004c0494007c049f004f044b005304890051057a006b05a2006b 0586009b05e0006b05e2006b041b00970482006e03b900760457000f04be003502f6004b02f6003502f6004f02f6004d02f6003602f6004b02f60046046b0066042e00430698004f04b4007304eb0062 0226ffb50226ffb5021b008f021bfffb021b008f0460007601fe000002a000470558fff70558fff7048fffd404db002d02a9ffe805530012055300120553001205530012055300120553001205530012 05390066048600940486009404860094048600940242ffc8024200a30242ffcb0242ffbf05ae009405860066058600660586006605860066058600660537007d0537007d0537007d0537007d04e00007 0454005a0454005a0454005a0454005a0454005a0454005a0454005a0430004f044b0053044b0053044b0053044b0053021affb4021a008f021affb7021affab04730079048e004f048e004f048e004f 048e004f048e004f0472007704720077047200770472007703e5000c03e5000c055300120454005a055300120454005a055300120454005a053900660430004f053900660430004f053900660430004f 053900660430004f053a0094051a004f04860094044b005304860094044b005304860094044b005304860094044b005304860094044b00530572006a048900520572006a048900520572006a04890052 0572006a0489005205af0094047100790242ffb3021aff9f0242ffb9021affa50242ffdf021affcb02420017020b00000242009d06b300a3040c007d0471002d0226ffb5050b0094042d007d04540094 020b008a04540094020b00550454009402a1008c0454009402e7008c05ae00940473007905ae00940473007905ae0094047300790473ffa505860066048e004f05860066048e004f05860066048e004f 04fe009402d0007c04fe009402d0004f04fe009402d0003804d4004a0421004b04d4004a0421004b04d4004a0421004b04d4004a0421004b04d4004a0421004b04db002d02a9000804db002d02a90008 04db002d02d100080537007d047200770537007d047200770537007d047200770537007d047200770537007d047200770537007d04720077070a003005f2002104e0000703e5000c04e0000704d10050 0406005204d100500406005204d10050040600520785fff606c10048058400690488004f047affa6047affa6043b0024049e0009049e0009049e0009049e0009049e0009049e0009049e00090480004f 03e0007603e0007603e0007603e0007601fcffa601fc008301fcffa901fcff9d04dd007604c0004f04c0004f04c0004f04c0004f04c0004f04840067048400670484006704840067043c0005049e0009 049e0009049e00090480004f0480004f0480004f0480004f047a006a03e0007603e0007603e0007603e0007603e0007604a6005404a6005404a6005404a6005404de007601fcff9101fcff9701fcffbd 01fc001501fc007c03d50024045b007603b9007603b9007603b9007603b9007604dd007604dd007604dd007604c0004f04c0004f04c0004f045c0076045c0076045c00760434003e0434003e0434003e 0434003e043b0024043b0024043b002404840067048400670484006704840067048400670484006706070028043c0005043c0005042a0041042a0041042a00410553001204eaff4a0613ff5302a6ff56 059affa70544fee1056fffb202aaff8705530012050c00940486009404d1005005af0094024200a3050b00940701009405ae009405860066051d009404db002d04e00007051000290242ffbf04e00007 04840056046000600488007e02aa00a9046000800498008e048e004f04bb009203f500160406001f02aaffcc04600080048e004f0460008006940066048600940475009b04d4004a024200a30242ffbf 0471002d0528009b050b0094050a003905530012050c00940475009b0486009405a800940701009405af00940586006605b1009b051d00940539006604db002d051000290454005a044b005304980086 048e004f0481007c0430004f03e5000c0406001f044b0053035a00850421004b020b007d021affab0201ffb5046e008f03e5000c070a003005f20021070a003005f20021070a003005f2002104e00007 03e5000c015a005202980065044a008f0226ffb101bc00330701009406f6007c055300120454005a0486009405a80094044b00530498008605aa004405c9004f051a0010040efff10873004f096b0066 04d600490416004d053900660430004f04e00007040e0020024200a307a200160676001e024200a3055300120454005a055300120454005a0785fff606c1004804860094044b005305880051043c0059 043c005907a200160676001e04d600490416004d05a800940498008605a800940498008605860066048e004f057a005f0488004f057a005f0488004f0550006b043c0051050a003903e5000c050a0039 03e5000c050a003903e5000c0589008e0466005f06f9009b066f008f051000290406001f0484004f05a9002d049a0021055300120454005a055300120454005a055300120454005a055300100454ff9a 055300120454005a055300120454005a055300120454005a055300120454005a055300120454005a055300120454005a055300120454005a055300120454005a04860094044b005304860094044b0053 04860094044b005304860094044b00530486ffd5044bff8e04860094044b005304860094044b005304860094044b0053024200a3021a008f02420094020b007805860066048e004f05860066048e004f 05860066048e004f05860027048effa305860066048e004f05860066048e004f05860066048e004f058a0058049e004f058a0058049e004f058a0058049e004f058a0058049e004f058a0058049e004f 0537007d047200770537007d0472007705a4007d04f2007705a4007d04f2007705a4007d04f2007705a4007d04f2007705a4007d04f2007704e0000703e5000c04e0000703e5000c04e0000703e5000c 04a2004f04a2004f0528009b046e008f05af00940497008604db002d03f50023051000290406001f0589008e0466005f0589008e0466005f0475009b035a008507a200160676001e0624001604c3ffcb 047100790507ffd00507ffd00475fff0035affe2053cffe30444ffae05a800940498008605af009404970086070100940603008f05a9002d049a002104e00007040e0020051000290406001f04600060 0465000206300081048c0051048c004f048c0034048c008104a0005d04b4007d0572006a0489005205ae009404730079055300120454000d04860048044b00010242fef6021afee205860066048e0016 04fe003202d0ff6e053700710472000f04dffeac050c00940481007c053a00940484004f053a00940484004f05af009404710079050b0094042d007d050b0094042d007d04540094020b007807010094 06f6007c05ae009404730079051d00940481007c04fe009402d0007204d4004a0421004b04db002d02a90008052d001203f50016052d001203f50016070a003005f2002104d100500406005205ccfe1c 049e0009041cff2a051aff370238ff3904caff930478fee804eeffa4049e00090460007603e00076042a004104de007601fc0085045b00760606007604c0004f046d0076043b0024043c0005045e0015 01fcff9d043c000503e0007603b900760434003e01fc008501fcff9d03d50024045b00760446001f049e00090460007603b9007603e0007604e400760606007604de007604c0004f04d80076046d0076 0480004f043b0024045e00150446004204de00760480004f043c000505fe000a04e400760446001f059d0050055300120454005a04860094044b0053021a007800000001000004e4090b040000020202 0306050706020303040502030304050505050505050505050202050505040806060606050506060305060508060606060605050606080605050204020404030505050505030505020205020805050505 0305030504070504050302030602050506050206040704040507040305030303050403020304040707070408050605060805050505060205050306050908020603060506060205040404040203030404 0300000000000003050305060606050605070606050505050505050503050506050505050507070705050707060a0a070606070905060606070706090907080606080605050406070505050507050504 070505070806070505070505050808050508070508070605080708070a090504060506050605080708070605060000000000000506050504050506050706090609080706080606050607050605060506 0505050406080807060505090709070605060606040509050903020205020201000303060704020202020304030505030406020903030403040507080a08070507050506060704090606070808070506 0505050902050505050503030206050508080608000909050502020404040505050504020505050504040505020405040705050505050505050507050505030303030303030303030403050506060506 0505050504050505040505060606060508080605050607050605050506050708060705050705050705060607050507050507050505050409060505050405050505050606060707050504050503030303 0303030505070506020202020205020306060505030606060606060606050505050303030306060606060606060606050505050505050505050505050202020205050505050505050505040406050605 0605060506050605060506060505050505050505050506050605060506050605030203020302030203080505020605050205020503050306050605060505060506050605060306030603050505050505 0505050505030503050306050605060506050605060508070504050505050505050808060505050505050505050505050404040402020202050505050505050505050505050505050505050404040404 0505050505020202020204050404040405050505050505050505050505050505050505050505070505050505060607030606060306060505060306080606060505060305050505030505050504050305 0505070505050303050606060606050506080606060606050605050505050504050504050202020504080708070807050402030502020808060505060505060706050a0b050506050505030907030605 0605080805050605050907050506050605060506050605060506040604060406050807060505060506050605060506050605060506050605060506050605060505050505050505050505050505050505 0302030206050605060506050605060506050605060506050605060506050605060606060606060606060504050405040505060506050504060506050605050409070705050606050406050605060508 0706050505060505050705050505050506050605060505050302060506030605050605060506050605060506050502080806050605060305050503060406040807050507050506030505060505040505 020507050505050502050404050202040505050504040607050505050505050505050507060506060505050200000003000000030000001c000300010000001c0003000a000006880004066c000000ea 00800006006a00000002000d007e00a000ac00ad00bf00c600cf00e600ef00fe010f01110125012701300153015f0167017e017f018f019201a101b001f001ff021b0237025902bc02c702c902dd02f3 030103030309030f0323038a038c039203a103b003b903c903ce03d203d60425042f0445044f0462046f0479048604ce04d704e104f50501051005131e011e3f1e851ef11ef31ef91f4d200b20112015 201e2022202720302033203a203c20442074207f20a420aa20ac20b120ba20bd21052113211621222126212e215e22022206220f2212221a221e222b22482260226525caee02f6c3fb04fefffffdffff 000000000002000d002000a000a100ad00ae00c000c700d000e700f000ff01100112012601280131015401600168017f018f019201a001af01f001fa02180237025902bc02c602c902d802f303000303 0309030f03230384038c038e039303a303b103ba03ca03d103d60400042604300446045004630470047a048804cf04d804e204f6050205111e001e3e1e801ea01ef21ef41f4d20002010201320172020 2025203020322039203c20442074207f20a320a620ab20b120b920bc21052113211621222126212e215b22022206220f2211221a221e222b22482260226425caee01f6c3fb01fefffffcffff00010000 fff6ffe401a4ffc20198ffc10000018b0000018600000182000001800000017e0000017600000178ff15ff06ff04fef7feea01ba00000000fe64fe4300effdd7fdd6fdc8fdb3fda7fda6fda1fd9cfd89 0000ffcaffc900000000fd090000ffaafcfdfcfa0000fcb90000fcb10000fca60000fca00000fef40000fef10000fc490000e5aee56ee51fe54ee4b3e54ce55ce15be1570000e154e153e151e149e375 e141e36de138e109e0ff0000e0da0000e0d5e0cee0cde086e079e077e06cdf93e061e035df92deabdf86df85df7edf7bdf6fdf53df3cdf39dbd5139f0adf06a302ab01af000100000000000000000000 00000000000000da000000e40000010e0000012800000128000001280000016a0000000000000000000000000000016a0174000000000000000000000000000000000000000000000000016200000000 016a01860000019e00000000000001b6000001fe000002260000024800000258000002e2000002f20000030600000000000000000000000000000000000002f800000000000000000000000000000000 0000000002e8000002e8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024b024c024d024e024f025000810247 025b025c025d025e025f02600082008302610262026302640265008400850266026702680269026a026b008600870276027702780279027a027b00880089027c027d027e027f0280008a02460446008b 0248008c02af02b002b102b202b302b4008d02b502b602b702b802b902ba02bb02bc008e008f02bd02be02bf02c002c102c202c30090009102c402c502c602c702c802c90092009302d802d902dc02dd 02de02df0249024a0251026c02f702f802f902fa02d602d702da02db00ad00ae035200af03530354035500b000b1035c035d035e00b2035f036000b30361036200b4036300b5036400b60365036600b7 036700b800b903680369036a036b036c036d036e036f00c30371037200c4037000c500c600c700c800c900ca00cb037300cc00cd03b0037900d1037a00d2037b037c037d037e00d300d400d5038003b1 038100d6038200d70383038400d8038500d900da00db0386037f00dc038703880389038a038b038c038d00dd00de038e038f00e900ea00eb00ec039000ed00ee00ef039100f000f100f200f3039200f4 0393039400f5039500f6039603b203970101039801020399039a039b039c010301040105039d03b3039e010601070108045c03b403b5011601170118011903b603b703b903b80127012804610462045b 0129012a012b012c012d045d045e012e012f0456045703ba03bb0448044901300131045f046001320133044a044b01340135013601370138013903bc03bd044c044d03be03bf0469046a044e044f013a 013b04500451013c013d013e045a013f01400458045903c003c103c2014101420467046801430144046304640452045304650466014503cd03cc03ce03cf03d003d103d2014601470454045503e703e8 0148014903e903ea046b046c014a03eb046d03ec03ed0169016a046f046e017f04470185000c000000000c4000000000000001040000000000000000000000010000000200000002000000020000000d 0000000d00000003000000200000007e00000004000000a0000000a000000244000000a1000000ac00000063000000ad000000ad00000245000000ae000000bf0000006f000000c0000000c50000024b 000000c6000000c600000081000000c7000000cf00000252000000d0000000d000000247000000d1000000d60000025b000000d7000000d800000082000000d9000000dd00000261000000de000000df 00000084000000e0000000e500000266000000e6000000e600000086000000e7000000ef0000026d000000f0000000f000000087000000f1000000f600000276000000f7000000f800000088000000f9 000000fd0000027c000000fe000000fe0000008a000000ff0000010f0000028100000110000001100000024600000111000001110000044600000112000001250000029200000126000001260000008b 0000012700000127000002480000012800000130000002a600000131000001310000008c0000013200000137000002af00000138000001380000008d0000013900000140000002b50000014100000142 0000008e0000014300000149000002bd0000014a0000014b000000900000014c00000151000002c4000001520000015300000092000001540000015f000002ca0000016000000161000002d800000162 00000165000002dc000001660000016700000249000001680000017e000002e00000017f0000017f000000940000018f0000018f00000095000001920000019200000096000001a0000001a100000097 000001af000001b000000099000001f0000001f0000003aa000001fa000001fa00000251000001fb000001fb0000026c000001fc000001ff000002f70000021800000219000002d60000021a0000021b 000002da00000237000002370000009b00000259000002590000009c000002bc000002bc000003ab000002c6000002c70000009d000002c9000002c90000009f000002d8000002dd000000a0000002f3 000002f3000000a60000030000000301000000a70000030300000303000000a90000030900000309000000aa0000030f0000030f000000ab0000032300000323000000ac0000038400000385000000ad 0000038600000386000003520000038700000387000000af000003880000038a000003530000038c0000038c000003560000038e00000392000003570000039300000394000000b00000039500000397 0000035c0000039800000398000000b2000003990000039a0000035f0000039b0000039b000000b30000039c0000039d000003610000039e0000039e000000b40000039f0000039f00000363000003a0 000003a0000000b5000003a1000003a100000364000003a3000003a3000000b6000003a4000003a500000365000003a6000003a6000000b7000003a7000003a700000367000003a8000003a9000000b8 000003aa000003b000000368000003b1000003b9000000ba000003ba000003ba0000036f000003bb000003bb000000c3000003bc000003bd00000371000003be000003be000000c4000003bf000003bf 00000370000003c0000003c6000000c5000003c7000003c700000373000003c8000003c9000000cc000003ca000003ce00000374000003d1000003d2000000ce000003d6000003d6000000d000000400 00000400000003b00000040100000401000003790000040200000402000000d100000403000004030000037a0000040400000404000000d200000405000004080000037b000004090000040b000000d3 0000040c0000040c000003800000040d0000040d000003b10000040e0000040e000003810000040f0000040f000000d60000041000000410000003820000041100000411000000d70000041200000413 000003830000041400000414000000d80000041500000415000003850000041600000418000000d90000041900000419000003860000041a0000041a0000037f0000041b0000041b000000dc0000041c 00000422000003870000042300000424000000dd00000425000004250000038e000004260000042f000000df00000430000004300000038f0000043100000434000000e9000004350000043500000390 0000043600000438000000ed0000043900000439000003910000043a0000043d000000f00000043e0000043e000003920000043f0000043f000000f40000044000000441000003930000044200000442 000000f50000044300000443000003950000044400000444000000f6000004450000044500000396000004460000044f000000f70000045000000450000003b200000451000004510000039700000452 0000045200000101000004530000045300000398000004540000045400000102000004550000045800000399000004590000045b000001030000045c0000045c0000039d0000045d0000045d000003b3 0000045e0000045e0000039e0000045f000004610000010600000462000004620000045c000004630000046f000001090000047000000471000003b40000047200000475000001160000047600000477 000003b60000047800000478000003b90000047900000479000003b80000047a000004860000011a0000048800000489000001270000048a0000048b000004610000048c0000048c0000045b0000048d 000004910000012900000492000004930000045d00000494000004950000012e0000049600000497000004560000049800000499000003ba0000049a0000049b000004480000049c0000049d00000130 0000049e0000049f0000045f000004a0000004a100000132000004a2000004a30000044a000004a4000004a900000134000004aa000004ab000003bc000004ac000004ad0000044c000004ae000004af 000003be000004b0000004b100000469000004b2000004b30000044e000004b4000004b50000013a000004b6000004b700000450000004b8000004ba0000013c000004bb000004bb0000045a000004bc 000004bd0000013f000004be000004bf00000458000004c0000004c2000003c0000004c3000004c400000141000004c5000004c600000467000004c7000004c800000143000004c9000004ca00000463 000004cb000004cc00000452000004cd000004ce00000465000004cf000004d7000003c3000004d8000004d800000145000004d9000004d9000003cd000004da000004da000003cc000004db000004df 000003ce000004e0000004e100000146000004e2000004f5000003d3000004f6000004f700000454000004f8000004f9000003e7000004fa000004fb00000148000004fc000004fd000003e9000004fe 000004ff0000046b00000500000005000000014a0000050100000501000003eb00000502000005100000014b00000511000005110000046d0000051200000513000003ec00001e0000001e01000003ae 00001e3e00001e3f000003ac00001e8000001e850000039f00001ea000001ef1000003ee00001ef200001ef3000003a500001ef400001ef90000044000001f4d00001f4d000004a9000020000000200b 0000015b00002010000020110000016700002013000020140000016900002015000020150000046f000020170000201e0000016b00002020000020220000017300002025000020270000017600002030 00002030000001790000203200002033000003a7000020390000203a0000017a0000203c0000203c000003a900002044000020440000017c00002074000020740000017d0000207f0000207f0000017e 000020a3000020a30000046e000020a4000020a40000017f000020a6000020aa00000180000020ab000020ab00000447000020ac000020ac00000185000020b1000020b100000186000020b9000020ba 00000187000020bc000020bd0000018900002105000021050000018b00002113000021130000018c00002116000021160000018d00002122000021220000018e0000212600002126000000b90000212e 0000212e0000018f0000215b0000215e000001900000220200002202000001940000220600002206000000b10000220f0000220f000001950000221100002212000001960000221a0000221a00000198 0000221e0000221e000001990000222b0000222b0000019a00002248000022480000019b00002260000022600000019c00002264000022650000019d000025ca000025ca0000019f0000ee010000ee02 000001a00000f6c30000f6c3000001a20000fb010000fb04000001a40000feff0000feff000001aa0000fffc0000fffd000001abb0002c4bb0095058b101018e59b801ff85b0841db109035f5e2db001 2c2020456944b001602db0022cb0012a212db0032c2046b003254652582359208a208a49648a204620686164b004254620686164525823658a592f20b00053586920b000545821b040591b6920b00054 5821b0406559593a2db0042c2046b00425465258238a592046206a6164b0042546206a61645258238a592ffd2db0052c4b20b0032650585158b080441bb04044591b21212045b0c05058b0c0441b2159 592db0062c2020456944b001602020457d691844b001602db0072cb0062a2db0082c4b20b003265358b0401bb000598a8a20b0032653582321b0808a8a1b8a235920b0032653582321b0c08a8a1b8a23 5920b0032653582321b801008a8a1b8a235920b0032653582321b801408a8a1b8a235920b003265358b0032545b8018050582321b8018023211bb003254523212321591b2159442db0092c4b53584544 1b2121592db00a2cb029452db00b2cb02a452db00c2cb1270188208a5358b94000040063b80800885458b9002903e870591bb0235358b02088b810005458b9002903e8705959592db00d2cb04088b820 005a58b12a00441bb9002a03e844592db00c2bb0002b00b2010d022b01b20e01022b01b70e3a30251b1000082b00b701382e241a1100082bb7024e4032231500082bb703483b2e211400082bb7044e40 32231500082bb70530281f160e00082bb70663513f2d1b00082bb7074034241a1100082bb7085b4a3a291900082bb70983644e3a2300082bb70a77624c362100082bb70b91775c3a2300082bb70c7660 4b361d00082bb70d2c241c140c00082b00b20f0d072bb00020457d691844b2b0130173b250130174b280130174b270130175b20f1f0173b26f1f0175002a00cc0091009e009100ec007200b2007d0056 005f004e0060010400c400000014fe600014029b0010ff39000dfe9700120321000b043a0014048d001005b000140618001506c00010025b001207040005000000000000000000600060006000600060 009a00c4014001bf025802f4030e033a0369039c03c103e303f904200437048b04b9050a057d05c10627068f06bc073a07a407b007bc07db0802082108870933097309dd0a300a790ab90aef0b4e0b8b 0ba60bd90c200c440c9d0cd90d330d7e0dde0e370ea50ecf0f0d0f3e0f8d0fd8100910411065107c10a110c810e31104118311e3123712941308135113cb140b1445149014d714f2155d15a615f41658 16b816f5176317ae17f41824187218bb18fc19341977198e19cf1a131a501ab21b151b761bd91bf81c931cc41d651de31def1e0c1ebc1ed21f111f541fa720192039208a20b620d6210b21392183218f 21a921c321dd224622aa22e8236323b4242024de255625ab261d267c26da26f52741278a27c7281e287928fd299929c92a2c2a922aff2b632bb72c112c422ca52cdc2d042d0c2d3b2d5e2d962dc22e05 2e3a2e7e2e9e2ebe2ec72ef52f272f432f5c2fa12fa92fcf2ffc307530a330e33111314d31c2321c328532f83368339b340f348d34e7353035a335d03628369836e93742379f37f53839387838e43936 39963a0e3a5e3ad33b343ba33c183c8c3cdd3d193d713dcd3e393eb83ef13f3a3f803fec4022406340a040e9414241a641f2426842e7434143a944134439448e44fb457945b24603464a469446ea4718 474447ce48044846488348c7491b497d49c74a384ab04b094b814bef4c634cd34d374d734dd24e314e984f1d4f9e4feb503950a55112518451f5527e530653a4543754a5550f555355995604566b572b 57e3585c58db5930598359b859d45a075a1d5a335b045b725bda5c315ca05ccc5cf55d4a5d955deb5e3d5e8d5ee25f415f8f5fed604360d2615c61a261e56237628662c9633863b76417646c64ca6525 658c65ee66486657666766b6671e67a56817688068e6694a69b56a1f6a836af06b4b6b9d6bef6c406cb66ce16ce16ce16ce16ce16ce16ce16ce16ce16ce16ce16ce16ce16ce96cf16cfb6d056d206d43 6d656d856da46db06dbc6dee6e2c6e8d6eb16ebd6ecd6ee66fb46fd06fec6fff7013705a70dc717e720a721672e6734b73c9747e74e4755e75b6762476c1772277b878167878789278ac78c678e0794b 797179a979bf79f37a857ac77b467b857b947ba37bdc7bef7c187c317c3d7ca07cf57d8e7e187e8f7f487f4880f88161818e820b823c825282c1831b836883d9842f847584bc850a852d856b85ef8644 868c86cc8702876087ba87d588008843886788b988f28946898f89ea8a428aab8ad58b0e8b3f8b898bd28c038c3b8c838cac8cfe8d718db38e128e6e8e9b8f1f8f7f8f958fe8909690ff916291ab91f1 9233927492ea935393c993f39428949b94ce9518954a958d95fb964c96af970c978597f8988898d89917996c99c29a3d9abb9af79b4f9b989bdb9c149c559c8d9ccb9d219d2d9d799def9e7e9ed19f13 9f949ff9a05fa0c1a150a15ca1ada1f9a247a288a2f7a35ca3baa430a4c2a547a5dea653a6b2a705a765a76da7b9a81ea881a8f2a96da9c0aa22aa6daac9ab2aab54abababd7ac2eac76ac8aac9eacb0 acc4acd6acedad01ad5fad85ae02ae66aeb8aec0aec8aed0aedbaee3af49af49af51afc1b031b092b0d4b137b14eb165b17cb18eb1a6b1b9b1c5b1d1b1e8b1ffb216b22eb245b25cb273b28bb29db2b4 b2cbb2e2b2f9b311b328b33ab351b369b380b397b3a9b3bfb3d5b3ecb404b410b41cb433b445b45bb472b488b49eb4b5b4cdb4deb4f5b507b51db52eb546b55db56fb585b59cb5aeb5c5b5dcb5edb604 b61bb685b727b739b74bb762b778b78fb7a6b7b8b7c9b7dbb7ebb802b813b82ab840b857b86eb8dbb972b989b99ab9b1b9c7b9deb9f4ba0bba22ba2eba40ba57ba69ba80ba92baa9bac0bad7baeebaf9 bb04bb1bbb27bb33bb4abb61bb6dbb79bb90bba7bbb3bbbfbbd4bbe9bbf5bc01bc18bc2abc36bc42bc59bc6abc7fbc96bca7bcbebcd5bcedbd05bd17bd29bd35bd41bd53bd64bd76bd88bd9fbdb5bdc1 bdcdbdd9bde5bdf7be08be14be20be2cbe38be4fbe5bbe72be88be9abeb0bec7bedebef1bf04bf1cbf2fbf8dbfefc006c01dc034c04ac062c079c090c0a7c0bec0d0c0e1c0f8c10ac121c138c168c198 c1a8c1bfc1d6c1ecc1fdc215c22dc239c245c25cc273c289c2a0c2b7c2cdc2e4c2fcc30ec325c337c34dc35ec376c38dc3a4c3bac3d2c3e9c3ffc416c47dc48fc4a5c4bcc4cdc4dec4f4c50ac521c58e c5a4c5bac5d1c5e8c5f4c60ac61cc633c64ac655c66bc682c68ec6a4c6b0c6c5c6d1c6e8c6f4c70bc71cc733c746c758c764c775c787c79dc7a9c7bac7c6c7dcc7e8c7fec80fc826c839c84cc8adc8c4 c8dac8f1c908c91fc935c940c94cc958c964c970c97cc988c9a3c9abc9b3c9bbc9c3c9cbc9d3c9dbc9e3c9ebc9f3c9fbca03ca0bca13ca2bca43ca55ca67ca79ca8acaa4caaccab4cabccac4cacccae4 cafbcb0dcb1fcb31cb49cb60cbcecbd6cbeecbf6cbfecc15cc2ccc34cc3ccc44cc4ccc63cc6bcc73cc7bcc83cc8bcc93cc9bcca3ccabccb3cccaccd2ccdacd2ecd36cd3ecd55cd6ccd74cd7ccd94cd9c cdb3cdc9cde0cdf7ce0ece25ce38ce4bce62ce73ce87cea6ceb2cec4cecccee3cef5cf01cf0dcf24cf3bcf52cf69cf71cf79cf91cfa9cfb5cfc1cfcdcfd9cfe5cff1cff9d001d009d020d037d03fd056 d06dd085d09cd0a4d0acd0c3d0d9d0f1d0f9d110d128d140d158d16fd186d19cd1b4d1ccd1e4d1fcd204d20cd224d23bd253d26ad27cd28dd2a5d2bcd2d4d2ecd304d31bd337d353d35fd36bd373d37f d38bd397d3a3d3b5d3c7d3e0d3f2d40bd41dd430d442d455d467d477d486d499d4abd4bed4d0d4e3d4f5d508d51ad52ad53ad546d552d564d576d588d599d5b2d5c4d5ddd5efd602d614d627d639d649 d658d66ad67cd688d694d6a0d6acd6bed6d0d6e3d6f5d708d71ad72dd73fd752d764d774d783d78fd7a1d7add7bfd7cbd7ddd7e9d7fad806d812d81ed82ad83cd84ed860d872d884d896d8a8d8bad8cc d8ddd8e9d8f5d901d90dd91fd931d943d954d9ced9e8d9f4da00da0cda18da24da30da3cda48da54da60da6cda78da84da90da9cdaa8dab4dac0dac8db2ddb92dbd0dc0fdc6ddcccdce7dd02dd0edd1a dd26dd32dd3edd4add95dde4de3ede96de9edeaadeb4debcdec4deccded4dedcdee4def6df08df1fdf36df4edf66df7edf96dfaedfc6dfdedff6e00ee026e03ee056e062e06ee07ae086e092e09ee0aa e0b6e0c2e0d4e0e6e0f2e0fee10ae116e122e12ee13ae146e158e16ae176e182e18ee19ae1a6e1b2e1c4e1d5e1e1e1ede1f9e205e211e21de229e235e241e24de259e265e271e27de285e28de295e29d e2a5e2ade2b5e2bde2c5e2cde2d5e2dde2e5e2fde314e32be33de345e34de365e36de37fe395e39de3a5e3ade3b5e3cce3d4e3dce3e4e3ece3f4e3fce404e40ce499e50ae56be573e57fe591e5a2e5aa e5b6e5c2e5cee5dae5e60000000500640000032805b0000300060009000c000f006fb20c1011111239b00c10b000d0b00c10b006d0b00c10b009d0b00c10b00dd000b0004558b0022f1bb1021f3e59b0 004558b0002f1bb1000f3e59b2040200111239b2050200111239b2070200111239b2080200111239b00adcb20c0200111239b20d0200111239b00210b00edc3031212111210311010111010321013501 210328fd3c02c436feeefeba010ce40203fefe0102fdfd05b0faa40507fd7d0277fb110278fd5e025e88025e0002008ffff201a305b00003000d003bb2060e0f111239b00610b001d000b0004558b002 2f1bb1021f3e59b0004558b00c2f1bb10c0f3e59b2060d0a2b5821d81bf459b001d0b0012f30310123032101343632161514062226017ed1170100fef94a804a48844801ad0403fac3394b4b39374a4a 0002006503f40240060000040009002500b0004558b0032f1bb103213e59b002d0b0022fb007d0b0072fb00310b008d0b0082f3031010323113305032311330113238bae012d238bae0577fe7d020c89 fe7d020c00020060000004bc05b0001b001f008d00b0004558b00c2f1bb10c1f3e59b0004558b0102f1bb1101f3e59b0004558b0022f1bb1020f3e59b0004558b01a2f1bb11a0f3e59b21d0c02111239 b01d2fb200030a2b5821d81bf459b004d0b01d10b006d0b01d10b00bd0b00b2fb208030a2b5821d81bf459b00b10b00ed0b00b10b012d0b00810b014d0b01d10b016d0b00010b018d0b00810b01ed030 31012303231323352113233521133303331333033315230333152303230333132302cfe04ca84ce701053af301114ea74ee14ea74ed0ee3addfb4ca776e03ae0019afe66019a9e01399f01a0fe6001a0 fe609ffec79efe660238013900010064ff2d0426069b002c007db22a2d2e11123900b0004558b00c2f1bb10c1f3e59b0004558b0092f1bb1091f3e59b0004558b0232f1bb1230f3e59b0004558b0202f 1bb1200f3e59b2190c20111239b01910b202010a2b5821d81bf459b20f0923111239b00c10b213010a2b5821d81bf459b2272309111239b02310b22a010a2b5821d81bf4593031013426262726353436 37353315161615233426232206151416041e021514060715233526263533141633323603336cfc46e9caada0aebef27161606c6b0100926436cfb99fc6d5f37f747277017c556f59267df5a6d614dadc 19f5c47e91686157695e5067865aa9d213c3c216f0c67e8a6e0000050063ffec058905c5000d001a0027003500390089b2053a3b111239b00510b013d0b00510b01bd0b00510b028d0b00510b036d000 b0362fb0382fb0004558b0032f1bb1031f3e59b0004558b0252f1bb1250f3e59b00310b00ad0b00a2fb211020a2b5821d81bf459b00310b218020a2b5821d81bf459b02510b01ed0b01e2fb02510b22b 020a2b5821d81bf459b01e10b232020a2b5821d81bf459303113343633321615151406232226351714163332363535342622061501343633321615151406202635171416333236353534262322061505 27011763aa8a8ca9a98a87afaa4d3f3e4c4d7e4b0212ae8788ada7fee8abaa4f3e40494e3d3e4dfe027d02c77d049884a9a9894883a8a58c06455555494945565747fcd086a6a68d4782a9a789054457 534b4b4654544af44804724800030056ffec051105c4001c002500310098b22e3233111239b02e10b010d0b02e10b01ed000b0004558b0092f1bb1091f3e59b0004558b01b2f1bb11b0f3e59b0004558 b0182f1bb1180f3e59b2201b09111239b228091b111239b2032028111239b2102820111239b2131b09111239b2111318111239b2191813111239b2161119111239b01b10b21d010a2b5821d81bf459b2 1f1d11111239b00910b22f010a2b5821d81bf45930311334363726263534363332161514060707013635331007172127062024053237010706151416031417373736353426232206566ea25543d0b09f cb5c696301193dd37ed6fee6529cfe50fefd01e27b6bfec21f788219676f1f3e56424754018965a9746b9646abc7bb8a5b994c48feb47893fef3acfd6175e523520177165b75657e03aa547f4c193756 395160000001005203fc010b06000004001600b0004558b0032f1bb103213e59b002d0b0022f30310103231133010b1a9fb90583fe79020400010080fe3102a2065f00100010b207111211123900b004 2fb00d2f30311334121237170602030710121707260202807cf086308daf0801ab9a3086f17b0250e7019f0147428e6bfe49fee556fed1fe257c87420149019d00010028fe310251065f00120010b207 131411123900b0042fb00e2f30310114020207273612113510022727371612121702517af8873096af988e1f3080f080080240defe63fead41877401dd013217011601c98a1c883efec4fe79d0000001 001b024d037405b0000e002000b0004558b0042f1bb1041f3e59b000d019b0002f18b009d019b0092f183031012537050333032517051307030327014cfecf37012e0fb30f012936fecac891b4b29203 cc58a9750158fea273ac58fef66a0120fee96600000100440092042a04b6000b001a00b0092fb000d0b00910b206010a2b5821d81bf459b003d0303101211521112311213521113302ae017cfe84ecfe 82017eec0321defe4f01b1de01950001001cfeb8015d00eb00090018b2090a0b11123900b00a2fb2050d0a2b5821d81bf4593031132736363735330706069f833a2b01db010169feb84e5b8746bdaf6a d500000100470209025402cd0003001100b0022fb201010a2b5821d81bf4593031012135210254fdf3020d0209c400010087fff501a20100000a0022b2000b0c11123900b0004558b0062f1bb1060f3e 59b2000d0a2b5821d81bf459303101321615140623222634360114444a4a44414c4a01004d3a394b4a744d0000010002ff8302fe05b00003001300b0002fb0004558b0022f1bb1021f3e593031172301 33c1bf023dbf7d062d0000020069ffec042205c4000d001b0046b2031c1d111239b00310b011d000b0004558b00a2f1bb10a1f3e59b0004558b0032f1bb1030f3e59b00a10b211010a2b5821d81bf459 b00310b218010a2b5821d81bf4593031011002232202033510123332121327342623220607111416333236370422ebf0ecef03ebf1efeb03f3707a777003727a7570030265fec6fec101370131fc013a 013afecefecf14cdbfb5c0feb6ccc8b9c500000100a8000002ff05b50006003900b0004558b0052f1bb1051f3e59b0004558b0002f1bb1000f3e59b2040005111239b0042fb203010a2b5821d81bf459 b202030511123930312123110535253302fff2fe9b02381f04917acdd100000100510000044005c40019004eb2111a1b11123900b0004558b0112f1bb1111f3e59b0004558b0002f1bb1000f3e59b203 1100111239b01110b209010a2b5821d81bf459b2161100111239b00010b218010a2b5821d81bf459303121213501363635342623220615233436363332161514060701210440fc2d01e5695975637682 f379e193d4f57b8cfe9c02a4a70211759d4f6880907d85d576d5bc6def98fe830001004fffec041505c40029006eb2072a2b11123900b0004558b00f2f1bb10f1f3e59b0004558b01b2f1bb11b0f3e59 b2010f1b111239b0012fb21f010171b29f01015db23f010171b00f10b207010a2b5821d81bf459b00110b228010a2b5821d81bf459b2152801111239b01b10b222010a2b5821d81bf459303101333636 353426232206152334363633321615140607161615140423222435331416333236353426232301869470836d70627ef377d584daf97d63787dfef3dbd2fef4f3816d718288868f034701726c6873715b 70b867dbc362ad2c29b07ac4e8e0ba60787872737c00000200340000045805b0000a000e004900b0004558b0092f1bb1091f3e59b0004558b0042f1bb1040f3e59b2010904111239b0012fb202010a2b 5821d81bf459b006d0b00110b00bd0b208060b111239b20d0904111239303101331523112311212701330121110703a3b5b5f3fd8b070274fbfd90017d120207c3febc01449403d8fc57026020000001 0081ffec043a05b0001d006ab21a1e1f11123900b0004558b0012f1bb1011f3e59b0004558b00d2f1bb10d0f3e59b00110b203010a2b5821d81bf459b207010d111239b0072fb21a010a2b5821d81bf4 59b205071a111239b00d10b214010a2b5821d81bf459b211141a111239b21d1a141112393031131321152103363332121514002322242733161633323635342623220607ae4f030efdbc28657fd0e7ff 00dfc8fef90beb0e7c64707d8a79425c3602d202ded2fea43afef6e1defef9e3ba6a71a08a859b23330000020075ffec043705b70014001f0062b2152021111239b01510b00dd000b0004558b0002f1b b1001f3e59b0004558b00d2f1bb10d0f3e59b00010b201010a2b5821d81bf459b207000d111239b0072fb205070d111239b215010a2b5821d81bf459b00d10b21b010a2b5821d81bf459303101152306 0607363332121514002322001135100021032206071514163236102603611eccf41775b6c1dffefbd4dafef10175015eec50851f88d87e8005b7c903dac87bfef0d7defeed0142010553017f01b2fd49 5a4b4aa2bfa20108a600000100450000043605b00006003200b0004558b0052f1bb1051f3e59b0004558b0012f1bb1010f3e59b00510b203010a2b5821d81bf459b20003051112393031010123012135 210436fdbaff0245fd0f03f10529fad704edc30000030068ffec042205c400170021002b0074b2092c2d111239b00910b01ad0b00910b024d000b0004558b0152f1bb1151f3e59b0004558b0092f1bb1 090f3e59b2290915111239b0292fb21f290171b21a010a2b5821d81bf459b2031a29111239b20f291a111239b00910b21f010a2b5821d81bf459b01510b225010a2b5821d81bf4593031011406071616 151404232224353436372626353436333216033426220615141632360334262206151416323604026e5f727bfefcd8d9fefb7c705e6df0cccdf0d381d47f7ddc7b1f6eba6c6dba6d04306ba73035b874 c0e1e2bf75ba3230a76bbadadafcaf6c85846d6b807c02fd5f7b7565647676000002005dfffa041205c4001500210064b2092223111239b00910b016d000b0004558b0092f1bb1091f3e59b0004558b0 112f1bb1110f3e59b21611091112397cb0162f18b202010a2b5821d81bf459b2000209111239b01110b212010a2b5821d81bf459b00910b21d010a2b5821d81bf4593031010623220235343636333200 11151000052335333636033236373534262206151416031e7aa3c0e474d68ddc0102fe9cfe9f1d23d7e6dc49802384d27d7e026181010ddb90ea82feb8feed44fe76fe6203c903c9010f544a5fa1c4ad 8489a800ffff0082fff5019d045100260012fb0000070012fffb0351ffff002efeb80188045100270012ffe603510006001012000001003f00a40384044e00060017b200070811123900b0004558b005 2f1bb1051b3e593031010515013501150136024efcbb03450277e0f30175c10174f300020091016403ef03d600030007002500b0072fb003d0b0032fb200010a2b5821d81bf459b00710b204010a2b58 21d81bf4593031012135211121352103effca2035efca2035e030ccafd8ec9000001008000a503e0044e00060017b200070811123900b0004558b0022f1bb1021b3e5930310125350115013502eafd96 0360fca0027ce3effe8cc1fe8cef0002003cfff4039805c400180023005eb2092425111239b00910b01cd000b0004558b0102f1bb1101f3e59b0004558b0222f1bb1220f3e59b21c0d0a2b5821d81bf4 59b000d0b0002fb2040010111239b01010b209010a2b5821d81bf459b20c1000111239b21500101112393031013436363736353426232206152336363332161514070706070334363332161514062226 015e42c31a285d5a5669f302edc3c9e1987b4202f44a3f404a48844701ac859ebd283d475e636153b1ceccb7a39e794b90fec93b494b39374a4a0002005bfe3b06d9059000360042007cb23b43441112 39b03b10b023d000b02a2fb0332fb0004558b0032f1bb1030f3e59b0004558b0082f1bb1080f3e59b2053308111239b20f3308111239b00f2fb00810b23a020a2b5821d81bf459b015d0b03310b21b02 0a2b5821d81bf459b02a10b223020a2b5821d81bf459b00f10b240020a2b5821d81bf4593031010602232227060623222637361236333216170306333236371200212204020706120433323637170606 2322242726131212243332041201061633323637132623220606cd0cdebeb53d33874a929712107fc36e54815734138566830611fec1fec0c4fed1b2090c8b011fcf54b740263dcf69fefe945b5e0b0c de0181f6f90167b2fc030d4a5136601e2d322f6f8c0206fafedf9a4c4cf0c9a301068f2a42fdcdc6dbae01710188c4fe8dedf1fea3b62822892831d7ccd30126011201b5f2dbfe65fe8c888d5f5301ed 13d1000200120000054205b00007000a004600b0004558b0042f1bb1041f3e59b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b2090402111239b0092fb200010a2b5821d81bf459b2 0a04021112393031012103210133012101210303c3fdcc76fef90226e30227fef8fd9c01a6d30153fead05b0fa50021f025c00030094000004a305b0000e0016001f006db2022021111239b00210b011 d0b00210b01ed000b0004558b0012f1bb1011f3e59b0004558b0002f1bb1000f3e59b2170001111239b0172fb21f170171b20f010a2b5821d81bf459b2080f17111239b00010b210010a2b5821d81bf4 59b00110b21e010a2b5821d81bf459303133112132041514060716161514042301112132363534272533323635342623239401f3f701026c687681fef9f5feea01197786e8fed2f876857b82f605b0c6 c464a02c20b17ccddc0291fe397669e305ba6b626c6000010066ffec04eb05c4001d0040b2031e1f11123900b0004558b00c2f1bb10c1f3e59b0004558b0032f1bb1030f3e59b00c10b213010a2b5821 d81bf459b00310b21a010a2b5821d81bf459303101060023222402273534122433320017232626232206071514163332363704eb16fed4f9aefef79003920111b3f1012618fc12938ea5b102a9a39596 1401dae9fefba50130c988ce013aaafefaef9d8bf1e981ecf8869c0000020094000004d205b0000b00150046b2021617111239b00210b015d000b0004558b0012f1bb1011f3e59b0004558b0002f1bb1 000f3e59b00110b20c010a2b5821d81bf459b00010b20d010a2b5821d81bf4593031331121320412151514020423031133323637353426239401aec1012ba4a5fecfc5a6a5c7d502cec405b0acfec4cc 49cffec6aa04e4fbe6f9e951edfa000100940000044c05b0000b004e00b0004558b0062f1bb1061f3e59b0004558b0042f1bb1040f3e59b20b0604111239b00b2fb200010a2b5821d81bf459b00410b2 02010a2b5821d81bf459b00610b208010a2b5821d81bf459303101211121152111211521112103e7fdaa02bbfc4803b1fd4c0256028afe40ca05b0ccfe6e000100940000043105b00009004000b00045 58b0042f1bb1041f3e59b0004558b0022f1bb1020f3e59b2090402111239b0092fb200010a2b5821d81bf459b00410b206010a2b5821d81bf45930310121112311211521112103dbfdb6fd039dfd6002 4a0269fd9705b0ccfe4f0001006affec04f005c4001e0055b20b1f2011123900b0004558b00b2f1bb10b1f3e59b0004558b0032f1bb1030f3e59b00b10b211010a2b5821d81bf459b00310b218010a2b 5821d81bf459b21e0b03111239b01e2fb21b010a2b5821d81bf45930312506042322240227351000213204172302212206071514123332371121352104f04ffee8b2b7fee69903013c011bf3011e1df8 2afef9aab103c7b1c252fed40228bd676aa60135ce72014a0173f0e20107f5ed70ecfefb58011dc0000100940000051805b0000b004c00b0004558b0062f1bb1061f3e59b0004558b00a2f1bb10a1f3e 59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b2090600111239b0092fb202010a2b5821d81bf45930312123112111231133112111330518fcfd75fdfd028bfc0287fd7905b0fda2 025e000100a30000019f05b00003001d00b0004558b0022f1bb1021f3e59b0004558b0002f1bb1000f3e59303121231133019ffcfc05b0000001002dffec03e405b0000f002fb205101111123900b000 4558b0002f1bb1001f3e59b0004558b0052f1bb1050f3e59b20c010a2b5821d81bf45930310133111404232226353314163332363502e8fcfefbd6e4f8fc736d667905b0fc03d1f6e6cd747587770001 00940000051805b0000c005300b0004558b0042f1bb1041f3e59b0004558b0082f1bb1081f3e59b0004558b0022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2000402111239b46a007a00025db2 060402111239b465067506025d3031010711231133113701210101210236a5fdfd8c01aa0132fde3023cfed40275affe3a05b0fd55ad01fefd7bfcd5000100940000042605b00005002800b0004558b0 042f1bb1041f3e59b0004558b0022f1bb1020f3e59b200010a2b5821d81bf459303125211521113301910295fc6efdcaca05b000000100940000066a05b0000e006e00b0004558b0002f1bb1001f3e59 b0004558b0022f1bb1021f3e59b0004558b0042f1bb1040f3e59b0004558b0082f1bb1080f3e59b0004558b00c2f1bb10c0f3e59b2010004111239b465017501025db2070004111239b46a077a07025d b20a0004111239b46a0a7a0a025d3031090221112311130123011311231101dc01a401a30147fc19fe52b5fe5319fc05b0fba4045cfa5001e00282fb9e0461fd7ffe2005b000000100940000051705b0 0009004cb2010a0b11123900b0004558b0052f1bb1051f3e59b0004558b0082f1bb1081f3e59b0004558b0002f1bb1000f3e59b0004558b0032f1bb1030f3e59b2020500111239b20705001112393031 212301112311330111330517fdfd77fdfd028bfb0409fbf705b0fbf3040d00020066ffec051e05c40010001e0046b2041f20111239b00410b014d000b0004558b00c2f1bb10c1f3e59b0004558b0042f 1bb1040f3e59b00c10b214010a2b5821d81bf459b00410b21b010a2b5821d81bf459303101140204232224022735341224200412170734022322020715141233321235051e94feedb3b1feeb97019701 13016401139601fdb7a8a4b902bba6a8b502b2d6febdadad0140d152d50146adabfebfd505f20102feffeb54f0fefa0100f600020094000004d405b0000a0013004db20a1415111239b00a10b00cd000 b0004558b0032f1bb1031f3e59b0004558b0012f1bb1010f3e59b20b0103111239b00b2fb200010a2b5821d81bf459b00310b213010a2b5821d81bf45930310111231121320415140423252132363534 2627210191fd022df4011ffee7fdfed30130878e907efec9021dfde305b0fed1d6eecb7f78768d0200020060ff04051a05c4001500230046b2082425111239b00810b020d000b0004558b0112f1bb111 1f3e59b0004558b0082f1bb1080f3e59b01110b219010a2b5821d81bf459b00810b220010a2b5821d81bf459303101140207170725062322240227353412243332041217073426232202071514123332 123505198376faa4feca3d46b0feeb9701970113b1b401139601feb8a8a3b902b9a7a9b502b2cffed159c394f50dad0140d152d50146adabfebfd505f6fefeffea55ecfef60100f600020094000004de 05b0000e0017005ab2051819111239b00510b010d000b0004558b0042f1bb1041f3e59b0004558b0022f1bb1020f3e59b20f0204111239b00f2fb201010a2b5821d81bf459b20b010f111239b00210b0 0ed0b00410b217010a2b5821d81bf459303101211123112132041514060701152101213236353426272102abfee6fd0200fc01128d7e0147fef1fdc2010480908584fef50231fdcf05b0e2d692c535fd a10d02fc8170758002000001004affec048a05c400270063b211282911123900b0004558b0092f1bb1091f3e59b0004558b01d2f1bb11d0f3e59b2021d09111239b20e091d111239b00910b211010a2b 5821d81bf459b00210b217010a2b5821d81bf459b2221d09111239b01d10b225010a2b5821d81bf459303101342624272635342433321616152334262322061514160416161514042322242635331416 333236038d87fea068c7011fe598ee88fc8f857c89940154ce60fee9ef9efef793fda4998485017760686a417dc9b0e470cf7e72816a5f506b6581a770b6d775ce897c886b000001002d000004b005b0 0007002e00b0004558b0062f1bb1061f3e59b0004558b0022f1bb1020f3e59b00610b200010a2b5821d81bf459b004d03031012111231121352104b0fe3afbfe3e048304e4fb1c04e4cc0001007dffec 04bd05b00010003cb204111211123900b0004558b0092f1bb1091f3e59b0004558b0102f1bb1101f3e59b0004558b0042f1bb1040f3e59b20d010a2b5821d81bf4593031011114002322003511331114 163320111104bdfed7f7fafedafc9490012405b0fc33e8fef1010bed03ccfc32929a013403c6000100120000051d05b000060038b200070811123900b0004558b0012f1bb1011f3e59b0004558b0052f 1bb1051f3e59b0004558b0032f1bb1030f3e59b2000103111239303101012101230121029501720116fdf4f5fdf60115013d0473fa5005b000010030000006e505b0000c0060b2050d0e11123900b000 4558b0012f1bb1011f3e59b0004558b0082f1bb1081f3e59b0004558b00b2f1bb10b1f3e59b0004558b0032f1bb1030f3e59b0004558b0062f1bb1060f3e59b2000103111239b2050103111239b20a01 03111239303101133301230101230133130133050ae0fbfeb0f2feebfee5f3feb0fbe20116d401680448fa500427fbd905b0fbba044600010029000004e905b0000b005300b0004558b0012f1bb1011f 3e59b0004558b00a2f1bb10a1f3e59b0004558b0042f1bb1040f3e59b0004558b0072f1bb1070f3e59b2000104111239b2060104111239b2030006111239b20906001112393031010121010121010121 010121028901320124fe4801c2fed9fec7fec6feda01c3fe47012403a2020efd2efd220216fdea02de02d20000010007000004d605b00008003100b0004558b0012f1bb1011f3e59b0004558b0072f1b b1071f3e59b0004558b0042f1bb1040f3e59b20001041112393031010121011123110121026f014f0118fe18fefe17011902fe02b2fc68fde80218039800000100500000048c05b00009004400b00045 58b0072f1bb1071f3e59b0004558b0022f1bb1020f3e59b200010a2b5821d81bf459b2040002111239b00710b205010a2b5821d81bf459b20905071112393031252115213501213521150182030afbc4 02f1fd14041fcacaa40440cca00000010084febc021c068e0007002200b0042fb0072fb200010a2b5821d81bf459b00410b203010a2b5821d81bf45930310123113315211121021ca5a5fe68019805d0 f9a9bd07d20000010014ff83036405b00003001300b0022fb0004558b0002f1bb1001f3e5930311333012314f00260f005b0f9d30001000cfebc01a6068e0007002500b0022fb0012fb00210b205010a 2b5821d81bf459b00110b206010a2b5821d81bf459303113211121353311230c019afe66a7a7068ef82ebd0657000001003502d9033505b000060027b200070811123900b0004558b0032f1bb1031f3e 59b000d0b2010703111239b0012fb005d030310103230133012301b5b2ce012bab012acd04a6fe3302d7fd2900010003ff41039800000003001b00b0004558b0032f1bb1030f3e59b200010a2b5821d8 1bf4593031052135210398fc6b0395bfbf000001003104d1020906000003002400b0012fb20f01015db003d0b0032fb40f031f03025db200010311123919b0002f183031012301210209cafef2011504 d1012f000002005affec03fb044e001e00290085b2172a2b111239b01710b020d000b0004558b0172f1bb1171b3e59b0004558b0042f1bb1040f3e59b0004558b0002f1bb1000f3e59b2021704111239 b20b1704111239b00b2fb01710b20f010a2b5821d81bf459b2120b0f11123940090c121c122c123c12045db00410b21f010a2b5821d81bf459b00b10b223070a2b5821d81bf459303121262706232226 35342433333534262322061523343636333216171114171525323637352322061514160303100c74a8a3ce0101ef955e60536af376cb7dbee20329fdfd487f208387885d1f4679ba89adb94754655340 599b58bfadfe18925711af463bcc5e5646530002007cffec04320600000f001b0064b2131c1d111239b01310b00cd000b0092fb0004558b00c2f1bb10c1b3e59b0004558b0032f1bb1030f3e59b00045 58b0062f1bb1060f3e59b2050c03111239b20a0c03111239b00c10b213010a2b5821d81bf459b00310b218010a2b5821d81bf45930310114022322270723113311363332121127342623220711163332 36370432e1c5be6a0cdcf369b2c6e2f37c769e40419f727c020212fcfed689750600fdd27cfedafef807b0b08afe428daaac0001004fffec03f5044e001c004bb2001d1e11123900b0004558b00f2f1b b10f1b3e59b0004558b0082f1bb1080f3e59b200010a2b5821d81bf459b203080f111239b2130f08111239b00f10b216010a2b5821d81bf459303125323637330e022322001135340033321617232626 2322060715141602395b7804e50476ca75e3fef60108e4c1f306e504775c7680017fae6a4e65af660126010319f70129e1b75d78abae27b0ad000002004fffec04030600000e00190064b2171a1b1112 39b01710b003d000b0062fb0004558b0032f1bb1031b3e59b0004558b00c2f1bb10c0f3e59b0004558b0082f1bb1080f3e59b205030c111239b20a030c111239b00c10b212010a2b5821d81bf459b003 10b217010a2b5821d81bf459303113341233321711331123270623220237141633323711262322064fe8c3ac6af3dc0c6db6beebf37f759545439576800225fa012f78022afa0070840132f2a5b98501 ce82bb0000020053ffec040b044e0015001d0083b2161e1f111239b01610b008d000b0004558b0082f1bb1081b3e59b0004558b0002f1bb1000f3e59b21a0008111239b01a2fb4bf1acf1a025db45f1a 6f1a0271b41f1a2f1a0271b4ef1aff1a0271b28c1a015db20c070a2b5821d81bf459b00010b210010a2b5821d81bf459b2120800111239b00810b216010a2b5821d81bf4593031052200353534363633 3212111521161633323717060603220607213526260259e7fee17de28bddf1fd3d0b9d77a7698341d9a4647b1101cf0872140123f21ea2ff8efee6fefe62869c877d616b039f8c7d127a7d000001002d 000002d6061500140053b207151611123900b0004558b0082f1bb108213e59b0004558b0042f1bb1041b3e59b0004558b0002f1bb1000f3e59b00410b010d0b213010a2b5821d81bf459b001d0b00810 b20d010a2b5821d81bf4593031331123353335343633321707262322151533152311d2a5a5c8b44048062835aedcdc0386b463b4c412be08b360b4fc7a0000020052fe56040c044e001900240083b222 2526111239b02210b00bd000b0004558b0032f1bb1031b3e59b0004558b0062f1bb1061b3e59b0004558b00b2f1bb10b113e59b0004558b0172f1bb1170f3e59b2050317111239b00b10b211010a2b58 21d81bf459b20f1117111239b2150317111239b01710b21d010a2b5821d81bf459b00310b222010a2b5821d81bf459303113341233321737331114042322262737163332363535062322023714163332 37112623220652edc4b96a0bdbfef7e177e33b7370a4798c69afbef1f285769347459378850225fc012d816dfbe7d5f663509285837f4975012ef6a3bb7e01dc7bbe00010079000003f8060000100042 b20a111211123900b0102fb0004558b0022f1bb1021b3e59b0004558b00d2f1bb10d0f3e59b0004558b0062f1bb1060f3e59b00210b20a010a2b5821d81bf45930310136332013112311342623220711 231133016c77b6015a05f3615e9248f3f303c48afe75fd3d02ba705d82fcfb0600000002007d0000019005d50003000d003eb2060e0f111239b00610b001d000b0004558b0022f1bb1021b3e59b00045 58b0012f1bb1010f3e59b00210b00cd0b00c2fb2060d0a2b5821d81bf45930312123113301343632161514062226017ff3f3fefe478448488447043a0119384a4a38374949000002ffb5fe4b018505d5 000c00160049b2031718111239b00310b010d000b0004558b00c2f1bb10c1b3e59b0004558b0042f1bb104113e59b209010a2b5821d81bf459b00c10b015d0b0152fb20f0d0a2b5821d81bf459303101 11140623222735163332371103343632161514062226017aa59f433e2630790315478448488447043afb66a6af11c0098404a30119384a4a383749490001007d000004360600000c005300b0004558b0 042f1bb104213e59b0004558b0082f1bb1081b3e59b0004558b0022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2000802111239b46a007a00025db2060802111239b465067506025d3031010711 2311331137012101012101dc6cf3f34c012b0124fe6e01bdfee701d06ffe9f0600fc8a5f0151fe3dfd890001008c0000017f06000003001d00b0004558b0022f1bb102213e59b0004558b0002f1bb100 0f3e59303121231133017ff3f30600000001007c00000679044e001d0077b2041e1f11123900b0004558b0032f1bb1031b3e59b0004558b0072f1bb1071b3e59b0004558b0002f1bb1001b3e59b00045 58b01b2f1bb11b0f3e59b0004558b0152f1bb1150f3e59b0004558b00c2f1bb10c0f3e59b201031b111239b2050715111239b00710b210010a2b5821d81bf459b018d030310117363332173633321617 1123113426232206071323112623220711231101610772c6d95076d6b3af02f35a6853691501f305be923df3043a7185a6a6c6c1fd3902c067605948fd1a02c8bf77fcf0043a00010079000003f8044e 00100053b20b111211123900b0004558b0032f1bb1031b3e59b0004558b0002f1bb1001b3e59b0004558b00e2f1bb10e0f3e59b0004558b0072f1bb1070f3e59b2010e03111239b00310b20b010a2b58 21d81bf45930310117363320131123113426232207112311015e0778c3015206f359659348f3043a7d91fe7dfd3502bd676385fcfe043a000002004fffec043d044e000f001a0043b20c1b1c111239b0 0c10b018d000b0004558b0042f1bb1041b3e59b0004558b00c2f1bb10c0f3e59b212010a2b5821d81bf459b00410b218010a2b5821d81bf4593031133436363332001717140606232200351714163236 3534262322064f7ee494db01110b017be596e5feedf38af6898d79778c02279fff89fee6e939a0fc8a0131fe09a7bdc0b9a4c0bd0002007cfe600430044e000f001a006eb2131b1c111239b01310b00c d000b0004558b00c2f1bb10c1b3e59b0004558b0092f1bb1091b3e59b0004558b0062f1bb106113e59b0004558b0032f1bb1030f3e59b2050c03111239b20a0c03111239b00c10b213010a2b5821d81b f459b00310b218010a2b5821d81bf45930310114022322271123113317363332121127342623220711163332360430e4c0b26bf3e00a6bb8c6e1f281789541429674830212fbfed575fdff05da6e82fe d9fefa06a2be7bfe207ebb000002004ffe600402044e000e0019006bb2171a1b111239b01710b003d000b0004558b0032f1bb1031b3e59b0004558b0062f1bb1061b3e59b0004558b0082f1bb108113e 59b0004558b00c2f1bb10c0f3e59b205030c111239b20a030c111239b212010a2b5821d81bf459b00310b217010a2b5821d81bf459303113341233321737331123110623220237141633323711262322 064fe8c6b56a0ed8f36aaac2eaf383749046468e74850226fe012a7f6bfa2601fc70012ff6a6bd7b01ec76ba0001007c000002b4044e000d0046b2090e0f11123900b0004558b0082f1bb1081b3e59b0 004558b00b2f1bb10b1b3e59b0004558b0052f1bb1050f3e59b00b10b202010a2b5821d81bf459b2090b051112393031012623220711231133173633321702b33033a73af3e806589c3422035c0880fd 1c043a798d0e0001004bffec03ca044e00260069b209272811123900b0004558b0092f1bb1091b3e59b0004558b01c2f1bb11c0f3e59b2021c09111239b00210b016d0b00910b210010a2b5821d81bf4 59b20d1610111239b40c0d1c0d025db01c10b224010a2b5821d81bf459b2212402111239b403211321025d30310134262627263534363332161523342623220615141604161615140623222626353316 1633323602db6bf853b6ecb6c2eff3685650655e011ea34ff2c485d074ec057863606401264144342858a78cbcc099465d4a3e383e3f577a5792b560a861565d490000010008ffec0272054100140052 b200151611123900b0004558b0132f1bb1131b3e59b0004558b00d2f1bb10d0f3e59b01310b001d0b000d0b0002fb00110b204010a2b5821d81bf459b00d10b208010a2b5821d81bf459b00410b010d0 303101113315231114163332371506232011112335331101adbfbf313f2a2b534dfee8b2b20541fef9b4fda43e370abc1701350265b4010700010077ffec03f7043a00100053b20a111211123900b000 4558b0072f1bb1071b3e59b0004558b00d2f1bb10d1b3e59b0004558b0022f1bb1020f3e59b0004558b00f2f1bb10f0f3e59b200020d111239b00210b20a010a2b5821d81bf459303125062322263511 33111433323711331123030c6bc5b0b5f3abb13ef3e56a7ecec302bdfd46ce7f0309fbc600010016000003da043a00060038b200070811123900b0004558b0012f1bb1011b3e59b0004558b0052f1bb1 051b3e59b0004558b0032f1bb1030f3e59b200050311123930310113330123013301fae5fbfe89d3fe86fc01340306fbc6043a0000010021000005cc043a000c0060b2050d0e11123900b0004558b001 2f1bb1011b3e59b0004558b0082f1bb1081b3e59b0004558b00b2f1bb10b1b3e59b0004558b0032f1bb1030f3e59b0004558b0062f1bb1060f3e59b2000b03111239b2050b03111239b20a0b03111239 3031011333012303032301331313330433acedfed9c8e8e4c8fed8edafdeb7014f02ebfbc602e7fd19043afd1d02e3000001001f000003e8043a000b005300b0004558b0012f1bb1011b3e59b0004558 b00a2f1bb10a1b3e59b0004558b0042f1bb1040f3e59b0004558b0072f1bb1070f3e59b2000a04111239b2060a04111239b2030006111239b209060011123930310113210101210303210101210201ce 010efeb50156fef4d8d7fef20156feb6010c02d60164fdebfddb0172fe8e022502150001000cfe4b03d6043a000f003fb200101111123900b0004558b00f2f1bb10f1b3e59b0004558b0052f1bb10511 3e59b200050f111239b00f10b001d0b00510b209010a2b5821d81bf45930310113210102232227351732363737012101f7dc0103fe5263ed35402e5c5d1b23fe840106015c02defb22feef12bc03434f 5d04350000010052000003c0043a0009004400b0004558b0072f1bb1071b3e59b0004558b0022f1bb1020f3e59b200010a2b5821d81bf459b2040002111239b00710b205010a2b5821d81bf459b20905 0711123930312521152135012135211501800240fc920225fde5034fc2c29f02d7c49a0000010038fe980291063d00170036b212181911123900b00c2fb0004558b0002f1bb100173e59b206000c1112 39b0062fb205070a2b5821d81bf459b212050611123930310124033534233532353536363717060715140716151516170261fe9f07c1c103b5b030ad06adad06adfe98630160d5e1b2e2d4b4de328c38 fad8e15b5ce3d5fa3800000100aefef2015505b00003001300b0002fb0004558b0022f1bb1021f3e593031012311330155a7a7fef206be000001001bfe980275063d00180036b205191a11123900b00b 2fb0004558b0182f1bb118173e59b211180b111239b0112fb212070a2b5821d81bf459b20512111112393031173637353437263535262737161615151433152215151406071bb004b6b604b030b6b2c2 c2b3b5db39ffd0e75656eacfff398c33e5b9c8e1b2e1c5bbe53300010075018304dc032f0017003fb211181911123900b00f2fb203180f111239b0032fb00f10b208010a2b5821d81bf459b00310b00b d0b00310b214010a2b5821d81bf459b00f10b017d0303101140623222e022322061523343633321e023332363504dcbe8e4a7d9a4326434dc1b6944a8591432743540312b0df3889216854abdb3b8422 705400020086fe940199044d0003000f003eb2071011111239b00710b000d000b0004558b00d2f1bb10d1b3e59b0004558b0032f1bb103173e59b00d10b2070d0a2b5821d81bf459b000d0b0002f3031 13331321011406232226353436333216aad118feff010748414248484241480296fbfe0537384b4b38374b4b00010064ff0b040a05260020005db21b212211123900b0004558b0112f1bb1111b3e59b0 004558b00a2f1bb10a0f3e59b200010a2b5821d81bf459b2030a11111239b00a10b007d0b0072fb01110b014d0b0142fb218110a111239b01110b21b010a2b5821d81bf4593031253236373306060715 233526023535341237353315161617232626232203071416024f597806e404c592c8b7ccccb7c89eb904e407765be610017fae685088cd1ceaea22011fdc1cd5012022e1e01cd89c6075fec848b0ad00 0001005e0000047c05c3001f0065b21a202111123900b0004558b0122f1bb1121f3e59b0004558b0052f1bb1050f3e59b204010a2b5821d81bf459b008d0b21e0512111239b01e2fb21f010a2b5821d8 1bf459b00cd0b01e10b00fd0b2160512111239b01210b219010a2b5821d81bf4593031011714072107213533363635272335332734362016152334262322061517211501fd074002b801fbe752272b07 a19b08fa0196e8f5695e59670901370256b08755caca096f5bb9c7f2caeadab85f698268f2c70002005dffe5054f04f1001b0028003fb202292a111239b00210b01fd000b0004558b0022f1bb1020f3e 59b010d0b0102fb00210b220070a2b5821d81bf459b01010b226070a2b5821d81bf45930312506232227072737263534372737173633321737170716151407170701141616323636342626220606043d 9fcbca9e818d87646d908d8e9bc0c29b918e946b628b8efc786ebedcbe6d6dbddebe6d6b7f7e8490899cc5c8a593909173759491979fcac19c8d91027b78ce7576ceeecc7575cc0000010019000004c0 05b00016007200b0004558b0162f1bb1161f3e59b0004558b00c2f1bb10c0f3e59b2000c16111239b01610b001d0b20f0c16111239b00f2fb013d0b0132fb40f131f13025db004d0b0042fb01310b212 040a2b5821d81bf459b006d0b00f10b007d0b0072fb00f10b20e040a2b5821d81bf459b00ad030310101210121152115211521112311213521352135210121026d013b0118fe77010dfea3015dfea3fc fe9e0162fe9e0119fe7701190334027cfd36988a97fed3012d978a9802ca00020088fef2016d05b000030007001800b0002fb0004558b0062f1bb1061f3e59b20501032b3031131133111123113388e5 e5e5fef2031bfce503c802f60002005afe26048c05c4002f003d0082b2203e3f111239b02010b030d000b0072fb0004558b0202f1bb1201f3e59b2392007111239b03910b213010a2b5821d81bf459b2 023913111239b00710b20e010a2b5821d81bf459b20b0e13111239b2322007111239b03210b22c010a2b5821d81bf459b21a322c111239b02010b227010a2b5821d81bf459b2242c2711123930310114 071615140423222435371416333236353426272e02353437262635342433320415233426232206151416041616252627061514161f0236353426048cab87fef2eaf6fee0f29c88798d86bbbcbe5da941 440113e6f0010cf391787b8b780183c25afdcd514c6c6395b32e738801c7b85964b9adc6d9cf016e785f4f4d5b37336e9a6db85a328864aacce1cc6a805f5254576871996e151c287c51562f35102f75 51610002005d04df032305cc00080011002200b0072fb20f07015db202050a2b5821d81bf459b00bd0b00710b010d0b0102f30311334363216140622262534363216140622265d43764444764301c844 764444764405563244446444443132444464444400030057ffec05e205c4001a00280036008eb21f3738111239b01f10b009d0b01f10b033d000b0004558b0332f1bb1330f3e59b02dd0b02d2fb20233 2d111239b0022fb40f021f02025db2092d33111239b0092fb400091009025db20d0902111239b210020a2b5821d81bf459b00210b217020a2b5821d81bf459b21a0209111239b02d10b21f080a2b5821 d81bf459b03310b225080a2b5821d81bf459303101140620263535343633321615233426232206151514163332363525340224232204021012042024122534122420041210020423222402045eaffec0 bdbf9ea3ad9c5c585c67685b595a01a696feeea39ffeef9c9b01110140011398faefbb014b0180014abbbbfeb8c2c1feb7bc025498a2d5b471aed5a59560538876757686516285a6011daba4fee0feac fee0a7aa0120a7ca015ac7c7fea6fe6cfea6c9c8015a0002008d02b3031105c4001a0024008fb20d2526111239b00d10b01cd000b0004558b0142f1bb1141f3e59b2032514111239b0032fb000d0b000 2fb2010314111239b20a0314111239b00a2fb01410b20d020a2b5821d81bf459b2100a0d111239b2cc10015d40130c101c102c103c104c105c106c107c108c10095db2ba100171b00310b21b020a2b58 21d81bf459b00a10b21f020a2b5821d81bf4593031012706232226353436333335342322061527343633321615111417253236373523060615140260114d7c7683a8ad66744149adaf88899a1afea028 541b6a4c5602c144527b696e79337f33300e68819184fec4615182241989013c3158ffff0057008a038503a90026017aeb000007017a015200000001007f017603c203250005001a00b0042fb001d0b0 012fb00410b202010a2b5821d81bf459303101231121352103c2c8fd85034301760104ab00040057ffec05e205c4000d001b0031003a009db20a3b3c111239b00a10b012d0b00a10b031d0b00a10b033 d000b0004558b0032f1bb1031f3e59b0004558b00a2f1bb10a0f3e59b00310b212080a2b5821d81bf459b00a10b218080a2b5821d81bf459b21d0a03111239b01d2fb21f030a111239b01f2fb4001f10 1f025db2321d1f111239b0322fb21c080a2b5821d81bf459b2251c32111239b01d10b02cd0b01f10b23a080a2b5821d81bf4593031133412242004121002042322240225340224232204021012042024 122511231121321615140716161416171523263534262327333236353426272357bb014b0180014abbbbfeb8c2c1feb7bc051196feeea39ffeef9c9b01110140011398fd2597011999ac784134070a9b 0d424d9e8f455d475d8d02d9ca015ac7c7fea6fe6cfea6c9c8015acba6011daba4fee0feacfee0a7aa01205bfeaf0352877d753f1d6fa344171022a04c43863e36463b01000100870512035e05b00003 001100b0012fb202030a2b5821d81bf459303101213521035efd2902d705129e0002007f03af028b05c4000900130039b2001415111239b00ad000b0004558b0002f1bb1001f3e59b00ad0b00a2fb205 020a2b5821d81bf459b00010b210020a2b5821d81bf4593031013216140623222634361332363534262206141601876a9a986c6d9b9d6b3545456a484905c49edc9b9bdc9efe784735344c4c68480002 005f000103f304fc000b000f004600b0092fb0004558b00d2f1bb10d0f3e59b00910b000d0b00910b206010a2b5821d81bf459b003d0b00d10b20e010a2b5821d81bf459b2050e06111239b40b051b05 025d303101211521112311213521113301213521029c0157fea9d8fe9b0165d80132fcaf03510383c7fe7c0184c70179fb05c4000001003c029b02b205bb00170059b208181911123900b0004558b00f 2f1bb10f1f3e59b0004558b0002f1bb100133e59b216020a2b5821d81bf459b2020016111239b2030f00111239b00f10b208020a2b5821d81bf459b20c0f00111239b2130f0011123930310121350136 3534262322061523343633321615140f022102b2fd9c011d7136343a42baa9878f9c6a628c0173029b7d010567432a354236749980736b66577100010037028f02a905ba0024007db21e252611123900 b0004558b00d2f1bb10d1f3e59b0004558b0172f1bb117133e59b201170d1112397cb0012f18b64001500160010371b29001015db00d10b206020a2b5821d81bf459b209010d111239b00110b223020a 2b5821d81bf459b2122301111239b21b170d111239b01710b21e020a2b5821d81bf459303101333235342623220615233436333216151407161514062322263533141633323635342723010c5184363e 3041baa5828fa38795b18f87abba453c3f3d865c046c6123352723637c79697733298e6a7e7f712635372a6501000001007004d1024806000003002300b0022fb20f02015db000d0b0002fb40f001f00 025db00210b003d019b0032f1830310121012301330115feebc30600fed100010092fe60041f043a00120060b20d131411123900b0004558b0002f1bb1001b3e59b0004558b0072f1bb1071b3e59b000 4558b0102f1bb110113e59b0004558b00d2f1bb10d0f3e59b0004558b00a2f1bb10a0f3e59b00d10b204010a2b5821d81bf459b20b0d0711123930310111161633323711331123270623222711231101 8402596aa83bf3df075c93794df2043afd848d82790312fbc6566b37fe3e05da000100450000035605b0000a002bb2020b0c11123900b0004558b0082f1bb1081f3e59b0004558b0002f1bb1000f3e59 b201000811123930312111232224353424332111028450e6fef7010ae601210208fed6d5fffa50000001008e024501a90352000a0016b2080b0c11123900b0022fb1080a2b58d81bdc59303113343632 161514062322268e4a864b4e40414c02ca3a4e4e3a3b4a4a0001006dfe4101c90003000e0034b2090f1011123900b0062fb0004558b00e2f1bb10e0f3e59b00610b1070a2b58d81bdc59b20d070e1112 39b2010d0e1112393031250716151406232732363534262737013e0b96ac9b07424747502003361b926976892f2a2d23058b0001008002a0020205b300060039b201070811123900b0004558b0052f1b b1051f3e59b0004558b0002f1bb100133e59b2040500111239b00410b203020a2b5821d81bf4593031012311073525330202b9c9016f1302a0023a3092770002007702b2032c05c4000c001a0040b209 1b1c111239b00910b010d000b0004558b0022f1bb1021f3e59b2091b02111239b0092fb210020a2b5821d81bf459b00210b217020a2b5821d81bf4593031133436201615151406232226351714163332 36373534262322061577bf0136c0bc9d9ebeaf5d504e5b015d4f4e5d0461a0c3c2a6489fc3c4a305626e6c6150616e6d6600ffff005d008a039903a90026017b09000007017b017e0000ffff00590000 058305ab002701d5ffd902980027017c011b0008010701d802c50000001000b0004558b0052f1bb1051f3e593031ffff0050000005cc05ae0027017c00f00008002701d5ffd0029b010701d6031a0000 001000b0004558b0092f1bb1091f3e593031ffff0067000005fc05bb0027017c01a80008002701d8033e0000010701d70030029b001000b0004558b0202f1bb1201f3e59303100020042fe7f03a5044e 001900230061b2102425111239b01010b01dd000b0004558b0212f1bb1211b3e59b0004558b0102f1bb110173e59b02110b21d0d0a2b5821d81bf459b000d0b0002fb2030010111239b01010b209010a 2b5821d81bf459b20c1000111239b216100011123930310106060707061514163332363533060623222635343737363737131406222635343632160276023549675a6259586af302efc2cee29b5c4e0a 02f747844848844702957c914f6a616a5e5d6453b1d0c9b8a5a35d4873350137384b4b38374b4b000002fff60000075705b0000f0012007700b0004558b0062f1bb1061f3e59b0004558b0002f1bb100 0f3e59b0004558b0042f1bb1040f3e59b2110600111239b0112fb202010a2b5821d81bf459b00610b208010a2b5821d81bf459b20b0600111239b00b2fb20c010a2b5821d81bf459b00010b20e010a2b 5821d81bf459b21206001112393031212103210321012115211321152113210121030757fc7e0ffe0ab8fede034303e0fd7a110224fde4140297faed01791b0154feac05b0c5fe68c5fe360167028800 0001004d00d603ec0486000b003800b0032fb2090c03111239b0092fb20a0903111239b2040309111239b2010a04111239b00310b005d0b207040a111239b00910b00bd0303113010137010117010107 01014d013cfec494013b013c94fec4013c94fec4fec5016c0142014296febe014296febefebe960141febf0000030069ffa1052205ee0017002000290066b2102a2b111239b01010b01dd0b01010b026 d000b0004558b0102f1bb1101f3e59b0004558b0042f1bb1040f3e59b21a1004111239b2231004111239b02310b01bd0b01010b21d010a2b5821d81bf459b01a10b024d0b00410b226010a2b5821d81b f4593031011402042322270723372611353412243332173733071613051417012623220207053427011633321235052294feedb4a4845ba991c3960114b2c58f57a7939d01fc444701f65787a4b90202 bf2cfe174e69a9b502b2d6febdad4b96eec3016743d50144af658ff3c1fec34bcf80033a55feffeb08a672fcdc360100f600000200940000047e05b0000c00140057b2021516111239b00210b00fd000 b0004558b0002f1bb1001f3e59b0004558b00a2f1bb10a0f3e59b2010a00111239b0012fb20e0a00111239b00e2fb209010a2b5821d81bf459b00110b20d010a2b5821d81bf459303101113332041514 04232311231113113332363426270187f1f40112feeef3f2f3f3f67d918c7a05b0fee8eec8c7effed405b0fe25fe1a82de84020000010088ffec049b0615002c005bb2232d2e11123900b0004558b005 2f1bb105213e59b0004558b0152f1bb1150f3e59b0004558b0002f1bb1000f3e59b20e0515111239b01510b21c010a2b5821d81bf459b2221505111239b00510b22a010a2b5821d81bf4593031212311 343633321615140e0215141e021514062322262737161633323635342e02353436353426232207017af2e5cebbd71b451641b251d9c650ab26312d7f36615a46ae517e5c50b8040451d6eebba93e6271 41272c5494894babb92719c31c255643315b88885058c94d5161f70000030048ffec0684045000290034003c00cab2023d3e111239b00210b02dd0b00210b038d000b0004558b0172f1bb1171b3e59b0 004558b0052f1bb1050f3e59b000d0b0002fb20c0517111239b00c2fb28f0c015db01710b210010a2b5821d81bf459b01710b01bd0b01b2fb238001b111239b0382fb41f382f380271b4ef38ff380271 b45f386f380271b4bf38cf38025db28c38015db220070a2b5821d81bf459b00010b223010a2b5821d81bf459b00510b22a010a2b5821d81bf459b00c10b22f070a2b5821d81bf459b01b10b235010a2b 5821d81bf45930310522270606232226353436333335342623220615273436333217361732121515211616333237371706062532363735230606151416012206072135342604e6fd8c41d686b0c8eee9 bf5f585b73f2fdc5df6f83c8d4eefd49099886896b3d4946d1fc983a882dc468785d032b637f1001c46d14a14d54b09c9eac475b6759421392b9858702fefdeb898b9e3a22a63840b83b2bd1025f4641 4f02e78a7f1e717a00020067ffec0440062c001d002b0065b2072c2d111239b00710b028d000b0004558b0192f1bb119213e59b0004558b0072f1bb1070f3e59b20f0719111239b00f2fb2110f071112 39b01910b218010a2b5821d81bf459b00f10b222010a2b5821d81bf459b00710b228010a2b5821d81bf45930310112111514020623222626353436363332172627072737262737161737170327262623 2206151416333236350342fe7ee58c8ae27e71ce849271317ecc4eac7ea24beeb1b44e8f01207b4e7e8b8d6e6f890517fef7fe6f52a6fef9927ee28895e77d5ba97a876d72522ac33287786dfd191230 38a8957ea8c8ad00000300430093043704cc0003000d00190052b2041a1b111239b00410b000d0b00410b011d000b0032fb200010a2b5821d81bf459b00310b1090a2b58d81bdc59b2040d0a2b5821d8 1bf459b00010b1110a2b58d81bdc59b2170d0a2b5821d81bf459303101213521013216140623222634360334363332161514062322260437fc0c03f4fe09444a4a44434a4a4a4a43444a4a44434a0246 d401b24c724b4b724cfc4a3a4c4c3a394a4a0003004fff77043d04bb0015001d00250066b2042627111239b00410b01bd0b00410b023d000b0004558b0042f1bb1041b3e59b0004558b00f2f1bb10f0f 3e59b218040f111239b220040f111239b02010b019d0b00410b21b010a2b5821d81bf459b01810b021d0b00f10b223010a2b5821d81bf459303113343636333217373307161114060623222707233726 131417012623220605342701163332364f7ee4946a58479166c47be5965d5a489166cef340012b2f39778c02093afed82b337b8902279fff89228fd099fec0a0fc8a1e93cf9601369c62026116bda794 5dfda711c00000020082fe6004370600000f001a0064b2131b1c111239b01310b00cd000b0092fb0004558b00c2f1bb10c1b3e59b0004558b0062f1bb106113e59b0004558b0032f1bb1030f3e59b205 0c03111239b20a0c03111239b00c10b213010a2b5821d81bf459b00310b218010a2b5821d81bf45930310114022322271123113311363332121127342623220711163332360437e3c2b26bf3f36ab0c5 e3f383769541429674830212f7fed175fdff07a0fdd777fedafefa05a6ba7bfe207ebb000002001f0000059d05b000130017006b00b0004558b00f2f1bb10f1f3e59b0004558b0082f1bb1080f3e59b2 14080f111239b0142fb210140f111239b0102fb000d0b01010b217070a2b5821d81bf459b003d0b00810b005d0b01410b207010a2b5821d81bf459b01710b00ad0b01010b00dd0b00f10b012d0303101 3315231123112111231123353311331121113301213521051e7f7ffcfd75fc7c7cfc028bfcfc79028bfd7504aea2fbf40287fd79040ca20102fefe0102fda2ba0001008f00000182043a0003001d00b0 004558b0022f1bb1021b3e59b0004558b0002f1bb1000f3e593031212311330182f3f3043a000001008e0000046b043a000c005f00b0004558b0042f1bb1041b3e59b0004558b0082f1bb1081b3e59b0 004558b0022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2060204111239b0062fb41f062f060271b28f06015db201010a2b5821d81bf459b20a0106111239303101231123113311330121010121 01ef6ff2f2550150012cfe6101b9fecb01acfe54043afe5001b0fdf3fdd3000100220000043605b0000d005b00b0004558b00c2f1bb10c1f3e59b0004558b0062f1bb1060f3e59b2010c06111239b001 2fb000d0b00110b202070a2b5821d81bf459b003d0b00610b204010a2b5821d81bf459b00310b008d0b009d0b00010b00bd0b00ad03031013715071121152111073537113301a1eaea0295fc6e8282fd 0367479347fdf6ca0287279327029600000100210000022e0600000b004a00b0004558b00a2f1bb10a213e59b0004558b0042f1bb1040f3e59b201040a111239b0012fb000d0b00110b202070a2b5821 d81bf459b003d0b006d0b007d0b00010b009d0b008d03031013715071123110735371133019a9494f38686f30379359235fd1902902f922f02de00010090fe4b050905b000130067b206141511123900 b0004558b0002f1bb1001f3e59b0004558b0102f1bb1101f3e59b0004558b0042f1bb104113e59b0004558b00c2f1bb10c0f3e59b0004558b00e2f1bb10e0f3e59b00410b209010a2b5821d81bf459b2 0d000c111239b2120e00111239303101111406232227371633323535011123113301110509bea9463c0e283a7bfd81fcfc027f05b0fa18b7c611c70cb8310415fbeb05b0fbec04140001007efe4b0406 044e001a0061b2151b1c11123900b0004558b0032f1bb1031b3e59b0004558b0002f1bb1001b3e59b0004558b00a2f1bb10a113e59b0004558b0182f1bb1180f3e59b2011803111239b00a10b20f010a 2b5821d81bf459b00310b215010a2b5821d81bf4593031011736333216171114062322273716333235113426232207112311015c0d73c4b0b501bba6453a0e283b7c5d69914bf3043a96aad6d2fd1bb4 c211c60cb002d9787067fce0043a00020064ffec072d05c4001700230091b2012425111239b00110b01ad000b0004558b00c2f1bb10c1f3e59b0004558b00e2f1bb10e1f3e59b0004558b0032f1bb103 0f3e59b0004558b0002f1bb1000f3e59b00e10b210010a2b5821d81bf459b212000e111239b0122fb215010a2b5821d81bf459b00010b217010a2b5821d81bf459b00310b218010a2b5821d81bf459b0 0c10b21d010a2b5821d81bf4593031212106232224022711341224333217211521112115211121053237112623220607111416072dfc9da779a7fef7940291010ba87ba7035cfd4c0256fdaa02bbfb7d 6368725ba1af01b21493010daa013aac01129614ccfe6ec8fe401c0d04380ecfbcfecac1d1000003005bffec06f2044f001e002a0032009bb2193334111239b01910b024d0b01910b02ed000b0004558 b0032f1bb1031b3e59b0004558b0082f1bb1081b3e59b0004558b0172f1bb1170f3e59b0004558b01b2f1bb11b0f3e59b2050817111239b22f1708111239b02f2fb41f2f2f2f0271b28c2f015db20c07 0a2b5821d81bf459b01710b210010a2b5821d81bf459b2190817111239b022d0b00310b228010a2b5821d81bf459b02bd030311334003332173636173212151521161633323637170606232227062322 001117141633323635342623220625220607213534265b010fe0f98641b76dd6eefd560b9175598f474f47cd78f78c86f6e3fef2f2867977868778758803e155781401b5710227f8012fb1545e01fefd ec888b9e2a329e3f41aeae012d010209aabab9c0a6bebaba8979196f7a000001008b000002950615000c0032b2030d0e11123900b0004558b0042f1bb104213e59b0004558b0002f1bb1000f3e59b004 10b209010a2b5821d81bf4593031331134363332170726232215118bc2b03f59192a32a3049cb6c315b90bbafb6800020051ffec051e05c40016001e005bb2001f20111239b017d000b0004558b00f2f 1bb10f1f3e59b0004558b0002f1bb1000f3e59b2050f00111239b0052fb00f10b208010a2b5821d81bf459b00010b217010a2b5821d81bf459b00510b21a010a2b5821d81bf459303105200011352126 26232207072737363320001115140204273236372115141602b8fedcfebd03d005dfcca797343121b0da013a016ba2fee5a996be12fd2fba140160014989e0f03413c60f48fe8bfeb76bc3fec3afd4da bd1fb9bf0001ffe4fe4b02d30615001e0071b2141f2011123900b0004558b0152f1bb115213e59b0004558b0102f1bb1101b3e59b0004558b01d2f1bb11d1b3e59b0004558b0052f1bb105113e59b01d 10b200010a2b5821d81bf459b00510b20b010a2b5821d81bf459b00010b00ed0b00fd0b01510b21a010a2b5821d81bf45930310123111406232227371616333235112335333534363332170726232207 15330284c9b5a448360f07441278a5a5c2b13d5b19263b9d01c90386fc35b0c011bf030aae03cab462b6c315bc0aad6700020058ffec05aa062e00180026005bb2042728111239b00410b023d000b000 4558b00d2f1bb10d1f3e59b0004558b0042f1bb1040f3e59b20f0d04111239b00f2fb216080a2b5821d81bf459b00d10b21c010a2b5821d81bf459b00410b223010a2b5821d81bf45930310114020423 22240227353412243332173636353314060716170734262322020715141233321235051094feedb4b0feeb9701970113b1ffa24f4cbb797c5704fdb8a8a4b902b9a8a9b502b2d6febdadad0140d152d5 0146ada80d8382a4d123a7df12f6fefeffeb54ecfef60100f6000002004fffec04bb04a800170022005bb2142324111239b01410b020d000b0004558b0042f1bb1041b3e59b0004558b0142f1bb1140f 3e59b2060414111239b0062fb20d080a2b5821d81bf459b01410b21a010a2b5821d81bf459b00410b220010a2b5821d81bf4593031133436363332173636353314060716171514060623220011171416 32363534262322064f7de494e18a3530a758673f027be795e3feecf28af6898d79778c0227a1fd8995136a7286b3257d9e1da0fc8a012e010109a7bdc0b9a7bdbd000001007dffec063d060100180054 b20c191a11123900b0004558b0182f1bb1181f3e59b0004558b0112f1bb1111f3e59b0004558b00c2f1bb10c0f3e59b2010c18111239b0012fb208080a2b5821d81bf459b00c10b215010a2b5821d81b f45930310115363635331406071114002322003511331114163320111104bd6d5eb5bbc5fed7f7fafedafc9490012405b0dc0a82a1e4d609fda5e8fef1010bed03ccfc32929a013403c600010077ffec 0528049300190061b2071a1b11123900b0004558b00d2f1bb10d1b3e59b0004558b0082f1bb1080f3e59b0004558b0042f1bb1040f3e59b00d10b013d0b2151308111239b0152fb203080a2b5821d81b f459b2061508111239b00810b210010a2b5821d81bf4593031011406071123270623222635113311143332371133153636373705288fa2e5066bc5b0b5f3abb13ef3484105020493b2a50bfccf6a7ece c302bdfd46ce7f03098807424c4c0001ffb5fe4b0193043a000c002fb2030d0e11123900b0004558b00c2f1bb10c1b3e59b0004558b0042f1bb104113e59b209010a2b5821d81bf45930310111060623 2227371633323511019301b8a746380f273a7c043afb85b2c211bf0dc0046c0000020059ffec03f8044f0016001e005eb2081f20111239b00810b017d000b0004558b0002f1bb1001b3e59b0004558b0 082f1bb1080f3e59b20c0008111239b00c2fb00010b210010a2b5821d81bf459b00810b217010a2b5821d81bf459b00c10b21a070a2b5821d81bf4593031013200151514060627220235352126262322 060727363613323637211514160200e401147bda86d5ef02aa0b8f77568b4e4f46d291567813fe4b71044ffed4f61f9afb8d010101ed8888a127359e3e43fc608e74196f7a000001009404e003430601 0008004500b0042fb20f04015db25004015db27004015db002d0b0022fb001d019b0012f18b00410b007d0b0072fb40f071f07025db2030704111239b00110b005d019b0052f18303101152327072335 01330343c39695c1010f8f04eb0b9c9c0d0114000001007204e0033406010008002500b0042fb20f04015db001d0b0012fb40f011f01025db2000401111239b008d0b0082f3031013733150123013533 01d292d0fee996feebce05669b0afee901180900ffff00870512035e05b00006007000000001007504cc02fb05e6000b002f00b0032fb20f03015db006d0b0062fb40f061f06025db00310b208020a2b 5821d81bf459b00610b00bd0b00b2f303101140620263533141632363502fbb0fedab0b64b844a05e67e9c9c7e42494942000001008104df018705d50009001db2030a0b11123900b0082fb20f08015d b202050a2b5821d81bf45930311334363216151406222681447e44447e440559354747353446460000020078048d0233062a00090014002a00b0052fb20f05015db013d0b0132fb2000a0a2b5821d81b f459b00510b20d0a0a2b5821d81bf459303101321614062322263436071416333236353426220601565d807d60617d7f11422e2f413f623f062a7baa7878aa7bd02f4140302e434300010029fe5201a1 003c000f0022b20f101111123900b0004558b00a2f1bb10a113e59b205030a2b5821d81bf459303121060615143332371706232226353437018c574a472c2e15495c5f74f4385e3144178e2c6e5bb56c 0001007a04db035705f50015004000b0032fb008d0b0082fb60f081f082f08035db00310b00bd0b00b2fb00810b20f030a2b5821d81bf459b00310b212030a2b5821d81bf459b00f10b015d030310114 0623222e02232206152734363332163332363503577f602739692b1a2635957f5f39a134263605e96e92113c0c392e086e965a392f000002004904d1035605ff00030007004000b0022fb20f02015db0 00d0b0002fb40f001f00025db00210b003d019b0032f18b00010b005d0b0052fb00210b006d0b0062fb00310b007d019b0072f18303101330123033303230268eefef6c590e9deb905fffed2012efed2 00020082fe6a01ecffbe000b0017003d00b0182fb003d0b0032f400f0003100320033003400350036003075db00fd0b00f2fb209090a2b5821d81bf459b00310b215090a2b5821d81bf4593031173436 33321615140623222637141633323635342623220682694e496a6a494e69653022212d2d212230ee4963614b4a5e6048212e2d22243030000001fc8e04d1fe6606000003002300b0012fb20f01015db0 00d019b0002f18b00110b002d0b0022fb40f021f02025d303101230121fe66cafef2011504d1012f0001fd5e04d1ff3606000003002300b0022fb20f02015db001d0b0012fb40f011f01025db00210b0 03d019b0032f18303101210123fe210115feebc30600fed1fffffc7304dbff5005f5000700a4fbf900000001fd3e04e6fe99067f000e002500b0002fb006d0b0062fb2010006111239b207080a2b5821 d81bf459b20d01001112393031012736363534233732161514060715fd510749419607a9ab4e4804e692051c23487b68583c4e0a45000002fc0c04e4ff3405ee00030007003700b0012fb000d019b000 2f18b00110b005d0b0052fb006d0b0062fb60f061f062f06035db003d0b0032fb00010b004d019b0042f1830310123012101230333fe07d0fed501060222c3f5fa04e4010afef6010a000001fd1cfe94 fe2fff8b0008001100b0022fb206050a2b5821d81bf4593031053436321614062226fd1c478448488447f13547476a464600000100c604e901e206410003001700b0022fb000d0b0002fb00210b003d0 19b0032f183031013303230103df8c900641fea80003006704df03ba06af0003000c0015003b00b0142fb002d0b0022fb001d0b0012fb40f011f01025db00210b003d019b0032f18b01410b00bd0b00b 2fb206050a2b5821d81bf459b00fd030310133032305343632161406222625343632161406222601eee58292fea8447643437644025643764444764306affed62f32444464444431324444644444ffff 008e024501a903520206007800000001009b0000043705b00005002b00b0004558b0042f1bb1041f3e59b0004558b0022f1bb1020f3e59b00410b200010a2b5821d81bf45930310121112311210437fd 60fc039c04e4fb1c05b000020019000005a005b000030006002f00b0004558b0002f1bb1001f3e59b0004558b0022f1bb1020f3e59b204010a2b5821d81bf459b2060200111239303101330121252101 026ff3023efa79015502e0fe9805b0fa50ca03bb0003005bffec051305c40003001400220076b2082324111239b00810b001d0b00810b01fd000b0004558b0102f1bb1101f3e59b0004558b0082f1bb1 080f3e59b20208101112397cb0022f18b460027002025db430024002025db200020171b201010a2b5821d81bf459b01010b218010a2b5821d81bf459b00810b21f010a2b5821d81bf459303101213521 0514020423222402273534122420041217073402232202071514123332123503a3fe4001c0017094feedb3b0feee9903960114016401139601fcb7a9a4b902bba6a9b50279c289d6febdadaa013ccd5d d50144afabfebfd505ef0105feffeb54f0fefa0100f6000100200000051205b00006003100b0004558b0032f1bb1031f3e59b0004558b0012f1bb1010f3e59b0004558b0052f1bb1050f3e59b2000301 1112393031010121013301210298fe97fef101fef501fffef00444fbbc05b0fa50000003006c0000042e05b000030007000b004b00b0004558b0082f1bb1081f3e59b0004558b0022f1bb1020f3e59b2 00010a2b5821d81bf459b2050802111239b0052fb206010a2b5821d81bf459b00810b20a010a2b5821d81bf45930313721152113211521032115216c03c2fc3e6402f6fd0a570399fc67caca034dc603 29cc0001009b0000051405b00007003800b0004558b0062f1bb1061f3e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b00610b202010a2b5821d81bf45930312123112111231121 0514fcfd7ffc047904e4fb1c05b0000100470000044d05b0000c003c00b0004558b0082f1bb1081f3e59b0004558b0032f1bb1030f3e59b201010a2b5821d81bf459b005d0b00810b20a010a2b5821d8 1bf459b007d0303101012115213501013521152101031cfe7502bcfbfa01c9fe3703e2fd6b018802d0fdfaca970242023f98ccfdff000003004a000005ae05b00015001c0023006cb20b2425111239b0 0b10b019d0b00b10b020d000b0004558b0142f1bb1141f3e59b0004558b00a2f1bb10a0f3e59b213140a111239b0132fb000d0b2090a14111239b0092fb00cd0b00910b221010a2b5821d81bf459b019 d0b01310b21a010a2b5821d81bf459b020d03031011604161514060706071523352624261036243735330114161711060605342627113636037ca101038e887c85a9fda2fefc8f8e0103a4fdfdc6aa93 96a70374a69491a904ff038ffe9e9af6484d03a9a9018cfa013eff8f03b1fd1fa0b00202ae04b79fa0b604fd5202b300000100440000055c05b00017005cb200181911123900b0004558b0112f1bb111 1f3e59b0004558b0162f1bb1161f3e59b0004558b0042f1bb1041f3e59b0004558b00b2f1bb10b0f3e59b2150b16111239b0152fb000d0b01510b20c010a2b5821d81bf459b009d03031013636351133 110600071123112600271133111616171133034c8390fd03fee9f6fcf0fee804fc018f80fc024317bea701f1fe06f6fecf19fe8a0175170130f501fffe0b9dc218036c000001006b000004dd05c30025 005cb207262711123900b0004558b01a2f1bb11a1f3e59b0004558b00f2f1bb10f0f3e59b0004558b0242f1bb1240f3e59b00f10b211010a2b5821d81bf459b00ed0b000d0b01a10b207010a2b5821d8 1bf459b01110b022d0b023d03031253612373534262322061515141217152135332602353534122433320412151514020733152102df747b019d908e9b7f77fe07d86b788e0105a4a5010690776bd4fe 10cf200110e76dcadad9cd64ebfeeb1ecfcb67011f9e62b6011d9f9efee2b56597fedc67cb0000020056ffeb0479044e001600210079b21f2223111239b01f10b013d000b0004558b0132f1bb1131b3e 59b0004558b0002f1bb1001b3e59b0004558b00c2f1bb10c0f3e59b0004558b0082f1bb1080f3e59b203010a2b5821d81bf459b20a130c111239b215130c111239b00c10b21a010a2b5821d81bf459b0 1310b21f010a2b5821d81bf45930310111163332371706232227062322023535101233321737011416333237112623220603fd0346110a18334ca23566c1c3e3e4c4b56713fe1c7a768c46468a737f04 3afcfa7b04b41ea3a2011df80d010a01369783fdbf9ead8801c78ec500020096fe77046a05c4001400280065b227292a111239b02710b000d000b00f2fb0004558b0002f1bb1001f3e59b0004558b00c 2f1bb10c0f3e59b227000c111239b0272fb224010a2b5821d81bf459b2062427111239b00010b218010a2b5821d81bf459b00c10b21e010a2b5821d81bf4593031013216151406071616151406232227 11231134363601342623220615111633323635342627233533320269cff263587982f2d1a57af27cd9014c715d6081589d71897a677b48d405c4d8b25f9b302cbd82cdec53fe3805a973c170fe6d5a76 7e68fce552896e6d9101b90000010020fe5f03f5043a00080038b200090a11123900b0004558b0012f1bb1011b3e59b0004558b0072f1bb1071b3e59b0004558b0042f1bb104113e59b2000704111239 3031011333011123110133020eecfbfe8ff3fe8ffb013b02fffbf0fe3501d0040b0000020054ffec04380620001f002b0062b2162c2d111239b01610b023d000b0004558b0032f1bb103213e59b00045 58b0162f1bb1160f3e59b00310b209010a2b5821d81bf459b20e1603111239b00e2fb229010a2b5821d81bf459b21d290e111239b01610b223010a2b5821d81bf4593031133436333216171526232206 1514171612171514060623220011343637272626131416333236353426272206d0d4b749714f97694e5abce0de027ae195e2feeeb889025b687689797787916d798904ea91a5161bc3353d345d424ffe eacc1c9bf68701230103a5ff22052889fd7da2bcbcb678cb17be00010060ffec040c044d0027008bb216282911123900b0004558b0092f1bb1091b3e59b0004558b0252f1bb1250f3e59b21709251112 397cb0172f18b440175017025db4d017e017025db218070a2b5821d81bf459b2031817111239b00910b210010a2b5821d81bf459b20d1710111239b21c0d015db20b0d015db02510b21e010a2b5821d8 1bf459b2211e18111239b404211421025d3031133436372626353436333216152334262322061514163333152306151416333236353314042322246069625761f8d2bffff27a595e726069c7d1d27d66 6282f2fefccbd5fef801325c7f2024794896a5b5913c4f4d3f3c4bad03933f5759429bbab20000010061fe7e03ca05b0001e004ab2081f2011123900b00f2fb0004558b0002f1bb1001f3e59b0004558 b0152f1bb1150f3e59b00010b21c010a2b5821d81bf459b2011c00111239b01510b208010a2b5821d81bf45930310115010606151416171716161514060727363536272726272635100137213503cafe 6056463d4bdd614f7a527d5d026e68c44a390125dcfdc405b091fe0a6dba6b545a18421f625147ba3e6567463d211b3269508b01200151fdc3000001007efe610406044e00110053b20c121311123900 b0004558b0032f1bb1031b3e59b0004558b0002f1bb1001b3e59b0004558b0072f1bb107113e59b0004558b00f2f1bb10f0f3e59b201030f111239b00310b20c010a2b5821d81bf45930310117363332 16171123113426232207112311015c0c77c1b6ad03f35e689646f3043a8397c4c5fb9c04536e697afcef043a00030073ffec042c05c4000d0016001e0079b2031f20111239b00310b013d0b00310b01b d000b0004558b00a2f1bb10a1f3e59b0004558b0032f1bb1030f3e59b20e030a1112397cb00e2f18b4600e700e025db4300e400e025db2000e0171b00a10b213010a2b5821d81bf459b00e10b218010a 2b5821d81bf459b00310b21b010a2b5821d81bf459303101100223220203351012333212130521353426232206150521151416323637042cf8e3dffa05f6e6e2f605fd3a01d47a716f7a01d4fe2c7be0 77020272fec4feb60141012de90135014cfec4fed32330cecbcbceef2ad0d1caca00000100a9fff40261043a000c002800b0004558b0002f1bb1001b3e59b0004558b0092f1bb1090f3e59b204010a2b 5821d81bf459303101111416333237150623201111019c323e2a2b4a56fee8043afcf63d360abc170135031100010016ffee044a05fb00190050b2031a1b11123900b0002fb0004558b00b2f1bb10b0f 3e59b0004558b0102f1bb1100f3e59b00b10b207010a2b5821d81bf459b20f000b111239b00f10b012d0b00010b215010a2b5821d81bf459303101321617011617173717062322262703032101272627 2307273601126c781f01ab24312011042a346d752bcaf6fef701815b2249221b033b05fb5550fbbf56070101c00a586f0214fd37040fda4b0302b61000010064fe7603d405c4002c0056b2032d2e1112 3900b0162fb0004558b02a2f1bb12a1f3e59b202010a2b5821d81bf459b2082d2a111239b0082fb209010a2b5821d81bf459b21d2d2a111239b01d10b20e010a2b5821d81bf459b22409081112393031 01262322061514213315232011141604161716150606072736363534262427262635343637262635342433321703838a577a88011c898cfe9e8101196f2351027b5083352e3ffefd4c7f76a3906e7c01 02e3997d04da24564bb8c6fee36288422518386d48bb3b64395029232d442035b79491c42d288e61a6c52c000001002dfff404cf043a0014005cb20b151611123900b0004558b0132f1bb1131b3e59b0 004558b00a2f1bb10a0f3e59b0004558b00f2f1bb10f0f3e59b01310b200070a2b5821d81bf459b00a10b205010a2b5821d81bf459b00010b00dd0b00ed0b011d0b012d0303101231114163332371506 232011112111231123352104a99f313f262f4a56fee8feb4f3ab047c037cfdb63e370abc1701350253fc84037cbe00020080fe600431044e000e001a0057b2111b1c111239b01110b000d000b0004558 b0002f1bb1001b3e59b0004558b00a2f1bb10a113e59b0004558b0072f1bb1070f3e59b2090007111239b211010a2b5821d81bf459b00010b217010a2b5821d81bf45930310132121115140223222711 231134000316333236353426232206150256e0fbe0c1b36af30103104395767d7c726677044efecbfeef0ff2fee577fdfd03dbf20121fcd575adb3b8c5c1a00000010052fe8a03e9044e0022004db21b 232411123900b0004558b0002f1bb1001b3e59b0004558b0142f1bb114173e59b00010b004d0b00010b207010a2b5821d81bf459b21c2300111239b01c10b20d010a2b5821d81bf45930310132161523 3426232206151514160416161714060727363635342627262627353436360238c4ede46d60718394012e6031017f4c7f332a3c41eeed0178dc044eddbb6174bcaa1a839b5639534248bf3865374e2c28 2a0f37fed1279dfa890000020052ffec047e043a000f001b004cb2071c1d111239b00710b013d000b0004558b00e2f1bb10e1b3e59b0004558b0072f1bb1070f3e59b00e10b200010a2b5821d81bf459 b00710b213010a2b5821d81bf459b00010b019d0303101211615140606232200113534003721011416333236353426232206047efef5ba7ade91e2fef0010cdf0241fcc7857a758183757687037692fb 8eec83012c01030cee012302fdd8a9bbbcbd9cb3b0000001003fffec03ec043a00100049b201111211123900b0004558b00f2f1bb10f1b3e59b0004558b00a2f1bb10a0f3e59b00f10b200010a2b5821 d81bf459b00a10b205010a2b5821d81bf459b00010b00dd0b00ed03031012111141633323717062320031121352103ecfe982b33273726506cfeec05feae03ad0379fdb03b3b16b12c01390254c10001 0080ffeb0408043a00120038b20e131411123900b0004558b0002f1bb1001b3e59b0004558b00e2f1bb10e0f3e59b203010a2b5821d81bf459b00010b008d0b0082f3031011110333236352603331611 100023222627110172a17191036ef173fefce7cbd101043afd76fefde9a0e7011de6fee2fef4fec1e2d8029500020044fe2205850441001a0023005fb2102425111239b01010b01bd000b0192fb00045 58b0112f1bb1111b3e59b0004558b0062f1bb1061b3e59b0004558b0002f1bb1000f3e59b20d010a2b5821d81bf459b00010b018d0b00d10b01bd0b01110b221010a2b5821d81bf45930310524003534 123717060607141617113436333216161514000511231336363526262322150265fefcfee37e7398484c029a949e7c93ec87fedefef5f3f395a5028d74370e1c0137ffa40105539246bc68a1cd1e0280 77928dfb92f3fed71afe31029419c19797bf3e000001004ffe22057e043a00180044b200191a11123900b00d2fb0004558b0142f1bb1141b3e59b0004558b00f2f1bb10f0f3e59b217010a2b5821d81b f459b001d0b01410b018d0b006d0b00f10b00cd0303101113636352603331611100005112311240003113311100511035293a70570ee79fee1fef3f3fefcfef501f3011d043afc7d1bcea4e20114e3fe edfefcfeca1afe3201d01e0133010a01edfe18fea23c038200010066ffec062d043a00200056b21a212211123900b0004558b0002f1bb1001b3e59b0004558b0182f1bb1180f3e59b0004558b01c2f1b b11c0f3e59b205010a2b5821d81bf459b209001c111239b00ed0b00010b013d0b0132fb21a0518111239303101020714163332363511331116163332363526033316100223222706232202103701e586 0761585b60fb025f5a58610785f18dd5cbe85c5ce6cbd68d043afee9edbdcb9d940146feaf8e98cbbdef0115e8fdc8fed2dede012e0238e800020076ffec049805c400200029006bb20f2a2b111239b0 0f10b021d000b0004558b01a2f1bb11a1f3e59b0004558b0062f1bb1060f3e59b2241a06111239b0242fb213010a2b5821d81bf459b002d0b20b1a06111239b00610b20f010a2b5821d81bf459b02410 b01ed0b01a10b227010a2b5821d81bf459303101060715140623220035113711141633323635352600273534363332161511363701141617112623220604983a44fad5d3fefeec826e626dd1ff0003c5 a5a7bc4b2afdaa7d6b046d34430257140b75dafd0105d4011d02fede7d8f86837c260113c01ba9ccd0bbfece0c0b01236ca22001459a49000001ffe10000049e05c3001a0042b2001b1c11123900b000 4558b0042f1bb1041f3e59b0004558b00d2f1bb10d0f3e59b200040d111239b00410b209010a2b5821d81bf459b012d0b00410b017d03031011336363332170726232207011123110126232207273633 321617023fd22b7a604642260d28411ffed9fcfedb21402b0a243c4a677d2c030701f864601ac20545fd6bfdee021002974505c11b646c0000020033ffec0654043a001200260070b2082728111239b0 0810b01ed000b0004558b0112f1bb1111b3e59b0004558b0062f1bb1060f3e59b0004558b00a2f1bb10a0f3e59b01110b200010a2b5821d81bf459b2081106111239b00fd0b010d0b015d0b016d0b00a 10b21b010a2b5821d81bf459b21f100a111239b024d0303101231615100223222706232202113437233521012627210607141633323637353315161633323606548037cabcee5c5ceebdc8366f0621fe c5043dfcc63c04534b5c6601fa02635d4b5303839eaffee2fed4e2e2012e011cb19cb7fdfca0adb19cbeca9795e8ee8f97ca00010022fff205bc05b00018006eb211191a11123900b0004558b0172f1b b1171f3e59b0004558b0092f1bb1090f3e59b0004558b0132f1bb1130f3e59b01710b200010a2b5821d81bf459b2041709111239b0042fb00910b20a010a2b5821d81bf459b00410b210010a2b5821d8 1bf459b00010b015d0b016d03031012111363332041004232732363526262322071123112135210490fe139472fb0118feeefe01898c018f8f8678fdfe7c046e04e4fe7426f0fe50ecbf7984778720fd 7404e4cc00010068ffec04ef05c4001f0071b203202111123900b0004558b00c2f1bb10c1f3e59b0004558b0032f1bb1030f3e59b00c10b213010a2b5821d81bf459b2170c031112397cb0172f18b430 174017025db460177017025db4d017e017025db200170171b218010a2b5821d81bf459b00310b21c010a2b5821d81bf45930310106002322240227353412243332001723262623220607211521161633 32363704ee16fed4f8affef59101920111b4f3012518fc12948ea1b00801fbfe0407ab9d93961401d9e8fefba50136cf7bcf013aaafef6ec9c8ee5d2cadde5879d000002002d0000084105b000190022 0074b2092324111239b00910b01ad000b0004558b0182f1bb1181f3e59b0004558b0082f1bb1080f3e59b0004558b0102f1bb1100f3e59b2001808111239b0002fb01810b20a010a2b5821d81bf459b0 1010b212010a2b5821d81bf459b00010b21a010a2b5821d81bf459b01210b01bd0b01cd0303101211e021514040721112103020206232335373e02371321111121323635342627050d013199eb7ffeeb e5fdcafe421a0f63bc9e4028575f310a1c03ab01297e918f7a03a10175d487cefd0504e4fdcdfef8fedd86ca03086ad7d102c9fd26fdf49375738f020002009b0000084705b00013001c0087b2011d1e 111239b00110b014d000b0004558b0022f1bb1021f3e59b0004558b0132f1bb1131f3e59b0004558b0102f1bb1100f3e59b0004558b00d2f1bb10d0f3e59b2001013111239b0002fb29f00015db2040d 02111239b0042fb00010b20f010a2b5821d81bf459b00410b214010a2b5821d81bf459b00d10b215010a2b5821d81bf45930310121113311213216161514042321112111231133011121323635342623 01970280fc012b9cee7ffee3f3fde0fd80fcfc037c01297e92947c0345026bfdd26ecb85cdf7027afd8605b0fd08fe1886706f8300010031000005c805b00015005600b0004558b0142f1bb1141f3e59 b0004558b0082f1bb1080f3e59b0004558b0102f1bb1100f3e59b01410b200010a2b5821d81bf459b2041014111239b0042fb20d010a2b5821d81bf459b00010b012d0b013d030310121113633200415 11231134262322071123112135210492fe11838f010c0107fc7d9a8c86fcfe8a046104e4fe9b1bece5fe3701ca8b7a1cfd4d04e4cc0000010092fe98050d05b0000b004800b0092fb0004558b0002f1b b1001f3e59b0004558b0042f1bb1041f3e59b0004558b0062f1bb1060f3e59b0004558b00a2f1bb10a0f3e59b202010a2b5821d81bf459b003d0303113331121113311211123112192fd0281fdfe4bfd fe3705b0fb1a04e6fa50fe98016800020090000004c105b0000d0016005bb2101718111239b01010b003d000b0004558b00c2f1bb10c1f3e59b0004558b00a2f1bb10a0f3e59b00c10b200010a2b5821 d81bf459b2020c0a111239b0022fb20e010a2b5821d81bf459b00a10b20f010a2b5821d81bf45930310121112132161615140407211121011121323635342627042cfd61012aa0ee7cfeebeffdd3039c fd610129808f8c7c04e4fe9f6eca85ccf80205b0fd08fe128b736e80020000020024fe9a05dc05b0000e00140065b2121516111239b01210b00bd000b0004558b00b2f1bb10b1f3e59b0004558b0042f 1bb104173e59b0004558b0022f1bb1020f3e59b00410b001d0b00210b206010a2b5821d81bf459b00dd0b00ed0b00fd0b010d0b00b10b211010a2b5821d81bf459303101231121112303333612371321 113321211121030205cff0fc41f4087557680f260396b9fbdb0270fe57181bfe9a0166fe9a0230540141cb0286fb1a041afe66fe6500000100160000079b05b00015007d00b0004558b0092f1bb1091f 3e59b0004558b00d2f1bb10d1f3e59b0004558b0112f1bb1111f3e59b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b0004558b0142f1bb1140f3e59b2100902111239b0102fb20001 0a2b5821d81bf459b004d0b2081000111239b01010b00bd0b213001011123930310123112311230121010121013311331133012101012104ffa3fcaafe9bfec501d5fe4a0132015c9dfc9601590131fe 4e01d1fec60274fd8c0274fd8c030702a9fda00260fda00260fd59fcf70000010049ffed047f05c300290086b2252a2b11123900b0004558b00b2f1bb10b1f3e59b0004558b0172f1bb1170f3e59b00b 10b203010a2b5821d81bf459b2280b171112397cb0282f18b21028015db430284028025db460287028025db4a028b028025db2062803111239b225010a2b5821d81bf459b2112528111239b01710b21f 010a2b5821d81bf459b21c251f1112393031013426232206152334363633320415140607161615140423222626353314163332363534262323353320036c947f6d92fc84ea8dfa0115786c7a81fed4fa 9af97dfc9c7886a38f8aaba2010c04236274735b77ba67dac463a6302aab7fc4e76ebe7b5e817e657b6fc800000100940000050d05b00009004500b0004558b0002f1bb1001f3e59b0004558b0072f1b b1071f3e59b0004558b0022f1bb1020f3e59b0004558b0052f1bb1050f3e59b2040002111239b20900021112393031013311231101231133110410fdfdfd81fdfd05b0fa50040dfbf305b0fbf2000001 002d0000050d05b00011004db204121311123900b0004558b0002f1bb1001f3e59b0004558b0012f1bb1010f3e59b0004558b0092f1bb1090f3e59b00010b203010a2b5821d81bf459b00910b20b010a 2b5821d81bf4593031011123112103020206232335373e023713050dfcfe421a0f63bc9e4028575f310a1c05b0fa5004e4fdcdfef8fedd86ca03086ad7d102c900010039ffeb04dd05b0000f0049b200 101111123900b0004558b00f2f1bb10f1f3e59b0004558b0062f1bb1060f3e59b2000f06111239b00f10b001d0b0012fb00610b20a010a2b5821d81bf459b20d060f1112393031010121010706232737 1633323737012102a001240119fe052e64e06802183d6c2c34fe0e011402b702f9fb485bb206c8045c7b04240003004fffc4061805ec0016001f00280055b20a292a111239b00a10b01ed0b00a10b020 d000b00a2fb0152fb214150a111239b0142fb000d0b20b0a15111239b00b2fb008d0b221010a2b5821d81bf459b01ed0b01410b21f010a2b5821d81bf459b020d0303101320412151402042315233523 2624023534122433353301220615141617331133113332363534262303aebb01169999feebbcf317a9feec989a0114bef3fefbaac1bbab17f311abbfbfad052698fef0acaafef197bebe0196010daaad 011297c6fe6fcfbcb4cd02030efcf2cfb6b9d00000010092fea105bd05b0000b003b00b0092fb0004558b0002f1bb1001f3e59b0004558b0042f1bb1041f3e59b0004558b00a2f1bb10a0f3e59b20201 0a2b5821d81bf459b006d0303113331121113311330323112192fd0281fdb014e8fbd105b0fb1a04e6fb1cfdd5015f000001008e000004ee05b00011003f00b0004558b0002f1bb1001f3e59b0004558 b0092f1bb1091f3e59b0004558b0012f1bb1010f3e59b20e0109111239b00e2fb205010a2b5821d81bf459303101112311062320242711331116163332371104eefca2b0fefbfef401fc017e97aea405 b0fa50023d29e6e801cefe308b762a02a700000100980000070305b0000b004800b0004558b0002f1bb1001f3e59b0004558b0032f1bb1031f3e59b0004558b0072f1bb1071f3e59b0004558b0092f1b b1090f3e59b201010a2b5821d81bf459b005d0b006d03031011121113311211133112111019601bcfc01b9fcf99505b0fb1a04e6fb1a04e6fa5005b000010098fea207ad05b0000f005400b00b2fb000 4558b0002f1bb1001f3e59b0004558b0032f1bb1031f3e59b0004558b0072f1bb1071f3e59b0004558b00d2f1bb10d0f3e59b201010a2b5821d81bf459b005d0b006d0b009d0b00ad0b002d030310111 2111331121113311330323112111019601bcfc01b9fcaa14def9dd05b0fb1a04e6fb1a04e6fb12fde0015e05b00000020018000005d405b0000d0016005eb2011718111239b00110b00ed000b0004558 b0002f1bb1001f3e59b0004558b00a2f1bb10a0f3e59b202000a111239b0022fb00010b20c010a2b5821d81bf459b00210b20e010a2b5821d81bf459b00a10b20f010a2b5821d81bf459303113211121 32161615140407211121011121323635342627180287012aa0ee7dfee9eefdd4fe7502870129808f8c7c05b0fdd36ec986cdf70204edfdcbfe128b736e8002000003009b0000065805b0000b000f0018 006db202191a111239b00210b00dd0b00210b017d000b0004558b00b2f1bb10b1f3e59b0004558b00e2f1bb10e1f3e59b0004558b0082f1bb1080f3e59b0004558b00c2f1bb10c0f3e59b200080b1112 39b0002fb210010a2b5821d81bf459b00810b211010a2b5821d81bf4593031012132161615140407211133012311330111213236353426270198012aa0ee7cfeebeffdd3fd04c0fcfcfb400129808f8c 7c03836eca85ccf80205b0fa5005b0fd08fe128b736e800200020090000004c105b0000b0014004db20e1516111239b00e10b001d000b0004558b00b2f1bb10b1f3e59b0004558b0092f1bb1090f3e59 b200090b111239b0002fb20c010a2b5821d81bf459b00910b20d010a2b5821d81bf4593031012132161615140407211133111121323635342627018d012aa0ee7cfeebeffdd3fd0129808f8c7c03836e ca85ccf80205b0fd08fe128b736e80020001006bffec04f105c4001f007fb203202111123900b0004558b0132f1bb1131f3e59b0004558b01c2f1bb11c0f3e59b209131c1112397cb0092f18b4600970 09025db4d009e009025db430094009025db200090171b206010a2b5821d81bf459b01c10b203010a2b5821d81bf459b2000603111239b01310b20c010a2b5821d81bf459b20f090c1112393031011616 333236372135212626232206072336003332041217151402042322002701681497939cab06fdfe020208b1a08c9512fc180125f2b3011093018ffef4b0f8fed41601d99e86e4d7ccd8e48c9eee0108a8 fec8cd7bcffec7a80105e800000200a0ffec070705c400170025007eb2122627111239b01210b01dd000b0004558b0132f1bb1131f3e59b0004558b00d2f1bb10d1f3e59b0004558b0042f1bb1040f3e 59b0004558b00a2f1bb10a0f3e59b20e0a0d1112397cb00e2f18b4600e700e025db208010a2b5821d81bf459b01310b21b010a2b5821d81bf459b00410b222010a2b5821d81bf4593031011402042322 2402272311231133113336122433320412170734022322020715141233321235070794feedb3a7fef89e0eb6fcfcb3069a010fadb201139601fdb7a8a4b902bba6a8b502b2d6febdad98011cbdfda305 b0fd71c90135a5abfebfd505f20102feffeb54f0fefa0100f600000200200000045f05b0000c00150061b2101617111239b01010b00ad000b0004558b00a2f1bb10a1f3e59b0004558b0002f1bb1000f 3e59b0004558b0032f1bb1030f3e59b2110a00111239b0112fb201010a2b5821d81bf459b2050111111239b00a10b212010a2b5821d81bf4593031211121012101261134243721110114163333112322 060362fee6fee7fef10145fe0113f601effd048a8aebeb8c880220fde0026b780111d1e902fa5003e97b8a0200860002005bffeb043c0613001a00260054b20e2728111239b00e10b01bd000b0004558 b0112f1bb111213e59b0004558b0072f1bb1070f3e59b2001107111239b0002fb2190007111239b21b010a2b5821d81bf459b00710b221010a2b5821d81bf45930310132121515140023220011351012 37363635331406060706060736172206151416333236353426027accf6fef5e5dffeeef8f68a51c44288a6989f1b91937686847a79858503fefeefea0ceafede0128010046015e0198331c3f36657e4f 2320a49195c39fa59caeafb08ca30003008f0000043a043a000e0015001c0078b2021d1e111239b00210b015d0b00210b017d000b0004558b0012f1bb1011b3e59b0004558b0002f1bb1000f3e59b216 01001112397cb0162f18b440165016025db4d016e016025db20f070a2b5821d81bf459b2080f16111239b00010b210010a2b5821d81bf459b00110b21b010a2b5821d81bf45930313311213216151406 0716161514062301112132353423253332353427238f01b7dee85d5b6a7cdfd1fef8010abbbefef9c8cfc4d3043a9b914b772016865b979e01cdfef38687ae7a8004000100850000034d043a0005002b 00b0004558b0042f1bb1041b3e59b0004558b0022f1bb1020f3e59b00410b200010a2b5821d81bf4593031012111231121034dfe2af202c80376fc8a043a00020027febe04c5043a000e0014005bb212 1516111239b01210b004d000b00c2fb0004558b0042f1bb1041b3e59b0004558b00a2f1bb10a0f3e59b200010a2b5821d81bf459b006d0b007d0b00c10b009d0b00710b00fd0b010d0b00410b211010a 2b5821d81bf4593031373636371321113311231121112313212111210702816545070e02ef96f2fd4af6010176019ffeef070ec271cb9e019efc88fdfc0142febe020402a7cffed60001001e0000065c 043a0015008200b0004558b0092f1bb1091b3e59b0004558b00d2f1bb10d1b3e59b0004558b0112f1bb1111b3e59b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b0004558b0142f1b b1140f3e59b2101102111239b0102fb28f10015db200010a2b5821d81bf459b004d0b2081000111239b01010b00bd0b21300101112393031012311231123032101012113331133113313210101210435 81f380f9fed60167feac0129f572f373f60129fead0169fed201b3fe4d01b3fe4d02330207fe5701a9fe5701a9fdfcfdca000001004dffec03c4044d0027008db21e282911123900b0004558b0252f1b b1251b3e59b0004558b0082f1bb1080f3e59b21925081112397cb0192f18b440195019025db4d019e019025db216070a2b5821d81bf459b2031619111239b00810b210070a2b5821d81bf459b20d1610 111239b4030d130d025db02510b21e070a2b5821d81bf459b221191e11123940090b211b212b213b21045d30310114060716151406232226263533141633323635342623233533363534262322061523 343633321603b0574fbaf2cb7ccc72f2765a59695c60aeb4a35e52506ef2f0b9c9e0031248792441ba95b1539969425953434f46af0284424a4f3c8fb7a40001008600000412043a0009004500b00045 58b0002f1bb1001b3e59b0004558b0072f1bb1071b3e59b0004558b0022f1bb1020f3e59b0004558b0052f1bb1050f3e59b2040702111239b20907021112393031013311231101231133110320f2f2fe 58f2f2043afbc602d2fd2e043afd2e000001008f00000465043a000c006800b0004558b0042f1bb1041b3e59b0004558b0082f1bb1081b3e59b0004558b0022f1bb1020f3e59b0004558b00b2f1bb10b 0f3e59b20602041112397cb0062f18b4d306e306025db443065306025db213060171b201010a2b5821d81bf459b20a010611123930310123112311331133012101012101fd7bf3f36b012b012cfe7901 a8fec401acfe54043afe5001b0fdfafdcc000001002100000414043a000f004db204101111123900b0004558b0002f1bb1001b3e59b0004558b0012f1bb1010f3e59b0004558b0082f1bb1080f3e59b0 0010b203010a2b5821d81bf459b00810b20a010a2b5821d81bf4593031011123112103020623232737363637130414f3fece1413abb04b013250490a14043afbc60376fe87fef0edca050bade501ce00 0001008f0000056f043a000c005900b0004558b0012f1bb1011b3e59b0004558b00b2f1bb10b1b3e59b0004558b0032f1bb1030f3e59b0004558b0062f1bb1060f3e59b0004558b0092f1bb1090f3e59 b2000b03111239b2050b03111239b2080b0311123930310101211123110123011123112102ff01400130f3fed6a5fed5f30132012b030ffbc602ccfd3402d0fd30043a000001008600000411043a000b 007e00b0004558b0062f1bb1061b3e59b0004558b00a2f1bb10a1b3e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b2090a00111239b0092fb4bf09cf09025db2bf090171b42f09 3f090272b25f090172b4ef09ff090271b41f092f090271b28f09015db48f099f090272b202010a2b5821d81bf45930312123112111231133112111330411f3fe5bf3f301a5f301b5fe4b043afe3d01c3 0001008600000412043a0007003800b0004558b0062f1bb1061b3e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b00610b202010a2b5821d81bf459303121231121112311210412 f3fe5af3038c0376fc8a043a00010023000003d0043a0007003100b0004558b0062f1bb1061b3e59b0004558b0022f1bb1020f3e59b00610b200010a2b5821d81bf459b004d0b005d030310121112311 21352103d0fea1f3fea503ad0379fc870379c10000030054fe60057f0600001a0024002f007fb2073031111239b00710b020d0b00710b02ad000b0062fb0004558b0032f1bb1031b3e59b0004558b00a 2f1bb10a1b3e59b0004558b0132f1bb113113e59b0004558b0102f1bb1100f3e59b0004558b0172f1bb1170f3e59b00a10b21e010a2b5821d81bf459b01010b223010a2b5821d81bf459b028d0b01e10 b02dd0303113101233321711331136333212111402232227112311062322022725342623220711163332011416333237112623220654d1bb4c3ef24056bad3d4b75345f23d4fafd1090437746a2d2521 33dcfcba6c6a2d21222a6870020e010901371c01cefe2e20fecbfee0f3fee61efe5601a61a0103e33cb6c70dfd3a0a014ba2a90a02c90ac100010086febf04a5043a000b003b00b0082fb0004558b000 2f1bb1001b3e59b0004558b0042f1bb1041b3e59b0004558b00a2f1bb10a0f3e59b202010a2b5821d81bf459b006d0303113331121113311330323112186f301a6f39314ddfcd2043afc880378fc88fd fd0141000001005f000003e0043b00110048b204121311123900b0004558b0092f1bb1091b3e59b0004558b0102f1bb1101b3e59b0004558b0012f1bb1010f3e59b20d01091112397cb00d2f18b20401 0a2b5821d81bf459303121231106232226351133111416333237113303e0f35e68deeaf3696c6264f3016916d5c7014cfeb4766217020c000001008600000603043a000b004800b0004558b0002f1bb1 001b3e59b0004558b0032f1bb1031b3e59b0004558b0072f1bb1071b3e59b0004558b0092f1bb1090f3e59b201010a2b5821d81bf459b005d0b006d0303101112111331121113311211101790152f301 53f2fa83043afc880378fc880378fbc6043a0001007efebf06b4043a000f004b00b00c2fb0004558b0002f1bb1001b3e59b0004558b0032f1bb1031b3e59b0004558b0072f1bb1071b3e59b0004558b0 0d2f1bb10d0f3e59b201010a2b5821d81bf459b005d0b009d030310111211133112111331133032311211101710152f30153f2b914ddfabb043afc880378fc880378fc88fdfd0141043a0002001f0000 04ea043a000d0015005bb2001617111239b00ed000b0004558b00c2f1bb10c1b3e59b0004558b0082f1bb1080f3e59b2000c08111239b0002fb00c10b20a010a2b5821d81bf459b00010b20e010a2b58 21d81bf459b00810b20f010a2b5821d81bf459303101333216161514060721112135211111333236342627024aee85c667ecc4fe1dfec8022bed5967655602e25ca66ea7ca010376c4fde5fea359a45f 01000003008f000005c9043a000b000f0017006db2071819111239b00710b00dd0b00710b014d000b0004558b00a2f1bb10a1b3e59b0004558b00e2f1bb10e1b3e59b0004558b0082f1bb1080f3e59b0 004558b00c2f1bb10c0f3e59b2000e08111239b0002fb210010a2b5821d81bf459b00810b211010a2b5821d81bf45930310133321616151406072111330123113301113332363426270182ee85c667ec c4fe1df30447f3f3fbb9ed5967655602e25ca66ea7ca01043afbc6043afde5fea359a45f01000002008f00000422043a000b0013004db20e1415111239b00e10b001d000b0004558b00a2f1bb10a1b3e 59b0004558b0082f1bb1080f3e59b2000a08111239b0002fb20c010a2b5821d81bf459b00810b20d010a2b5821d81bf459303101333216161514060721113311113332363426270182ee85c667ecc4fe 1df3ed5967655602e25ca66ea7ca01043afde5fea359a45f010000010051ffec03e8044e0020007db210212211123900b0004558b0082f1bb1081b3e59b0004558b0102f1bb1100f3e59b00810b20001 0a2b5821d81bf459b21e08101112397cb01e2f18b4401e501e025db2031e00111239b21c03015db20b03015db21b070a2b5821d81bf459b01010b218010a2b5821d81bf459b2151b18111239b4041514 15025d303101220615233436363332001515140606232226263533141633323637213521262602015576e574ca72dc010b79dc917bc86ee57656667e0cfeac01530e7e038b694f64af68fed2fc199bfc 8867ba755d779989a8848f0000020091ffec0638044e0014001f0085b2152021111239b01510b00dd000b0004558b0042f1bb1041b3e59b0004558b0132f1bb1131b3e59b0004558b0112f1bb1110f3e 59b0004558b00c2f1bb10c0f3e59b20111131112397cb0012f18b4d001e001025db440015001025db20f010a2b5821d81bf459b00c10b217010a2b5821d81bf459b00410b21d010a2b5821d81bf45930 3101333624333200171714060623220027231123113301141632363534262322060184cc1b010acbdb01110b017be596d2fef315caf3f301b98af6888d78778c0287cff8fee6e939a0fc8a0104d4fe3c 043afdd8a7bdc0b9a7bdbd0000020027000003df043a000d00160061b2141718111239b01410b004d000b0004558b0002f1bb1001b3e59b0004558b0012f1bb1010f3e59b0004558b0052f1bb1050f3e 59b2120001111239b0122fb203010a2b5821d81bf459b2070312111239b00010b213010a2b5821d81bf4593031011123112303231326263534363703141633331123220603dff2e3e7fcff646be9c6bc 654fefe0596a043afbc6018dfe7301b52a9c6597c102fea0445501385a000001ffdbfe4b03f806000021008bb215222311123900b01e2fb0004558b0042f1bb1041b3e59b0004558b00a2f1bb10a113e 59b0004558b0182f1bb1180f3e59b69f1eaf1ebf1e035db22f1e015db20f1e015db221181e111239b0212fb200070a2b5821d81bf459b2021804111239b00a10b20f010a2b5821d81bf459b00410b215 010a2b5821d81bf459b00010b01ad0b02110b01cd03031012115363320131114062322273716333235113426232207112311233533353315210277fef577b6015a05b9a6463a0f273b7b615e9248f39e 9ef3010b04ade98afe75fcfeb2c411bf0dbf02ed705d82fcfb04adaba8a800010054ffec03f9044e001d007ab2161e1f11123900b0004558b00f2f1bb10f1b3e59b0004558b0082f1bb1080f3e59b200 010a2b5821d81bf459b2190f081112397cb0192f18b41f192f190271b21b070a2b5821d81bf459b203001b111239b404031403025db00f10b216010a2b5821d81bf459b2131916111239b21c13015db2 0b13015d303125323637330e0223220011353400333216172326262322060721152112023e597806e40378ca74e4fef80108e4c0f504e407765b6e7d0a015bfea619ae685066b0640127010219f70129 e2b66075948da8feec000002001e0000069a043a0016001f0079b2092021111239b00910b017d000b0004558b0002f1bb1001b3e59b0004558b0082f1bb1080f3e59b0004558b00f2f1bb10f0f3e59b2 010008111239b0012fb00010b20a010a2b5821d81bf459b00f10b211010a2b5821d81bf459b00110b217010a2b5821d81bf459b00810b218010a2b5821d81bf459303101113316161514060721112103 0206072327373636371301113332363534262703faf8c3e5e9c3fe19fee61513a8af4e023252470a1402f3ed58686456043afe8703bc9fa0c1020376fe87fef2ee01ca050bafe301cefdc5fec1584d48 510100020086000006b1043a0012001b0082b2011c1d111239b00110b013d000b0004558b0022f1bb1021b3e59b0004558b0112f1bb1111b3e59b0004558b00b2f1bb10b0f3e59b0004558b00f2f1bb1 0f0f3e59b201110b111239b0012fb204110b111239b0042fb00110b20d010a2b5821d81bf459b00410b213010a2b5821d81bf459b00b10b214010a2b5821d81bf4593031012111331133161615140607 21112111231133011133323635342623017901a5f3f8c3e5e9c3fe19fe5bf3f30298ed5a66645b029f019bfe8703bc9fa0c10201ddfe23043afdc5fec15a4b4654000001ffee000003f8060000180079 b20c191a11123900b0152fb0004558b0042f1bb1041b3e59b0004558b0072f1bb1070f3e59b0004558b00f2f1bb10f0f3e59b2bf15015db22f15015db20f15015db2180f15111239b0182fb200070a2b 5821d81bf459b2020407111239b00410b20c010a2b5821d81bf459b00010b011d0b01810b013d0303101211536332013112311342623220711231123353335331521028bfee177b6015a05f3615e9248 f38b8bf3011f04b5f18afe75fd3d02ba705d82fcfb04b5aaa1a100010086fe9a0412043a000b004500b0082fb0004558b0002f1bb1001b3e59b0004558b0032f1bb1031b3e59b0004558b0052f1bb105 0f3e59b0004558b0092f1bb1090f3e59b201010a2b5821d81bf4593031011121113311211123112111017901a6f3feb5f3feb2043afc880378fbc6fe9a0166043a0000010088ffeb06c105b0001e0060 b2061f2011123900b0004558b0002f1bb1001f3e59b0004558b00c2f1bb10c1f3e59b0004558b0152f1bb1151f3e59b0004558b0042f1bb1040f3e59b0004558b0082f1bb1080f3e59b2060004111239 b211010a2b5821d81bf459b01ad030310111140623222706232226351133111416333236351121111416333236351106c1f9d2e56d71e9cff3fd675e697201016d63616e05b0fbffd6eea5a5efd50401 fbfc758281770403fbfc74837f79040300010070ffeb05ed043a001e0060b2061f2011123900b0004558b0002f1bb1001b3e59b0004558b00c2f1bb10c1b3e59b0004558b0152f1bb1151b3e59b00045 58b0042f1bb1040f3e59b0004558b0082f1bb1080f3e59b2061504111239b211010a2b5821d81bf459b01ad030310111060623222706232226351133111416333236351133111416333236351105ed01 dabdc76066cbb8d5f354465366f45c4f4a5b043afd4ec1dc8e8eddc302affd51726c6c7202affd51726c6c7202af0002ffe00000042106180012001b0071b2151c1d111239b01510b003d000b0004558 b00f2f1bb10f213e59b0004558b0092f1bb1090f3e59b2120f09111239b0122fb200070a2b5821d81bf459b2020f09111239b0022fb00010b00bd0b01210b00dd0b00210b213010a2b5821d81bf459b0 0910b214010a2b5821d81bf45930310121113316161514060721112335331133112101113332363534262702a3fedef7c4e5e5c0fe12aeaef30122fedeed5b656357043afec903ceaeadd304043aab01 33fecdfd5bfe82655955690200010098ffed06cd05c50025008eb20e262711123900b0004558b0242f1bb1241f3e59b0004558b0052f1bb1051f3e59b0004558b01c2f1bb11c0f3e59b0004558b0222f 1bb1220f3e59b2002224111239b0002fb21f000171b208241c111239b00510b20c010a2b5821d81bf459b00010b00fd0b00010b221010a2b5821d81bf459b012d0b01c10b215010a2b5821d81bf459b2 18241c111239303101333612243332001723262623220607211521161633323637330600232224022723112311330194b50b960109abf1012618fc12938ea1ab0b01e9fe1602a8a2959614fc16fed3f8 acfef89303b4fcfc034fbe011d9bfefaef9d8bddccc3e1f2869ce9fefba10134cafd7405b00000010086ffec05ba044e00230092b20d242511123900b0004558b0042f1bb1041b3e59b0004558b0232f 1bb1231b3e59b0004558b01b2f1bb11b0f3e59b0004558b0202f1bb1200f3e59b20e041b1112397cb00e2f18b4400e500e025db000d0b00410b20b010a2b5821d81bf459b2080e0b111239b00e10b20f 070a2b5821d81bf459b01b10b213010a2b5821d81bf459b216130f111239b00f10b01ed030310133362433321617232626232203211521161633323637330e0223222427231123113301799d140104d2 c1f504e407765bdb1a017cfe850a7d6e597806e40378ca74d3fefd149ef3f30271deffe2b66075fee6ab8a8e685066b064fedcfe3a043a000002001c0000051705b0000b000e005600b0004558b0082f 1bb1081f3e59b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b0004558b00a2f1bb10a0f3e59b20d0802111239b00d2fb200010a2b5821d81bf459b004d0b20e080211123930310123 1123112303210133012101210303837ee1738ffefa0206f50200fefafde00153a801aafe5601aafe5605b0fa50026801f8000002000a00000445043a000b0010005600b0004558b0082f1bb1081b3e59 b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b0004558b00a2f1bb10a0f3e59b20d0208111239b00d2fb201010a2b5821d81bf459b004d0b20f080211123930310123112311230323 01330123013303270702e45dc35b68f701a9e701abf7fe5cf86419190117fee90117fee9043afbc601c401066464000200ac0000073005b000130016007c00b0004558b0022f1bb1021f3e59b0004558 b0122f1bb1121f3e59b0004558b0042f1bb1040f3e59b0004558b0082f1bb1080f3e59b0004558b00c2f1bb10c0f3e59b0004558b0102f1bb1100f3e59b2150204111239b0152fb000d0b01510b20601 0a2b5821d81bf459b00ad0b00610b00ed0b21602041112393031012101330121032311231123032113211123113301210301a80168012bf50200fefa8e7ee2728ffefa98fedbfcfc02620153a9026703 49fa5001aafe5601aafe5601abfe5505b0fcb801f9000002009d00000618043a00130018007f00b0004558b0022f1bb1021b3e59b0004558b0122f1bb1121b3e59b0004558b0042f1bb1040f3e59b000 4558b0082f1bb1080f3e59b0004558b00c2f1bb10c0f3e59b0004558b0102f1bb1100f3e59b2001012111239b0002fb001d0b20e010a2b5821d81bf459b00bd0b007d0b00110b014d0b015d0b2171204 1112393031013313330123032311231123032313231123113301330327070190fef8e701abf76a5dc35b68f76dbaf3f301edf864191901c40276fbc60117fee90117fee90117fee9043afd8a01066464 000200800000066e05b0001a001d007ab21b1e1f111239b01b10b00dd000b0004558b0192f1bb1191f3e59b0004558b0042f1bb1040f3e59b0004558b00c2f1bb10c0f3e59b0004558b0132f1bb1130f 3e59b2001904111239b0002fb209010a2b5821d81bf459b00ed0b00fd0b00010b018d0b21b1904111239b01910b21c010a2b5821d81bf459303101161617112311262623230711231123220607112311 3636210121011321047afef105fc02768f6806fc7e8f7503fc03fa010ffe8504e4fd8ee9fe2f032804d9d8fe8d016c816f0bfdaf025c6e7efe90016ce1db0288fd8a01a90002008200000564043a001a 001d007ab21b1e1f111239b01b10b014d000b0004558b0052f1bb1051b3e59b0004558b0002f1bb1000f3e59b0004558b00b2f1bb10b0f3e59b0004558b0132f1bb1130f3e59b2040500111239b0042f b007d0b00410b210070a2b5821d81bf459b015d0b016d0b21b0500111239b00510b21c010a2b5821d81bf45930313335363637012101161617152335262627230711231123220607150113218202c5cc feeb03f4feeac6be02f3015e722f01f22d796003018595fed6b2ced20d01dbfe2411d3c7b3b17f720203fe5f01a46e7cba0269012200000200a3000008b305b0002000230097b21c2425111239b01c10 b023d000b0004558b0072f1bb1071f3e59b0004558b00b2f1bb10b1f3e59b0004558b0002f1bb1000f3e59b0004558b0052f1bb1050f3e59b0004558b0112f1bb1110f3e59b0004558b0192f1bb1190f 3e59b2090700111239b0092fb203010a2b5821d81bf459b00910b00dd0b00310b01cd0b017d0b2210700111239b00b10b222010a2b5821d81bf459303121113437211123113311210121011616171123 112626232307112311232206071101132102c53bfe9ffcfc0330fe8704e5fe84fef105fc02768f6805fc7f9173030208e9fe2e0160a165fd9a05b0fd7b0285fd7804d9d8fe8d016c816f09fdad025c71 7cfe91033901aa000002008f00000776043a002000230097b21d2425111239b01d10b023d000b0004558b0072f1bb1071b3e59b0004558b00b2f1bb10b1b3e59b0004558b0002f1bb1000f3e59b00045 58b0052f1bb1050f3e59b0004558b0112f1bb1110f3e59b0004558b0192f1bb1190f3e59b2090b00111239b0092fb203070a2b5821d81bf459b00910b00dd0b00310b01cd0b017d0b2210b00111239b0 0b10b222010a2b5821d81bf459303121353637211123113311210121011616171523352626272307112311232206071501132102950135feb7f3f302a5feec03f4feeac5be02f2015e732e01f22d7960 03018595fed6b09464fe58043afe2701d9fe2411d4c6b3b17f720203fe5f01a46e7cba026901220000020028fe4003aa07880027003000a7b2023132111239b00210b028d000b02c2fb0004558b0052f 1bb1051f3e59b0004558b0172f1bb117113e59b0004558b0112f1bb1110f3e59b00510b203010a2b5821d81bf459b22605111112397cb0262f18b21026015db24026015db460267026025db223010a2b 5821d81bf459b20c2326111239b01110b21d010a2b5821d81bf459b20f2c015db02c10b029d0b0292fb40f291f29025db2282c29111239b030d0b0302f30310134262321352132041514060704151404 23230615141707262627343637333636353421233533200337331501230135330296857afee50115ed010b7d6e010cfef7e8357a985284a202b1a43f7289fecf898901109493cffeea97feebce04215e 6ac7cfb570a32c57fec5e803636b419928b77f868b02017d65f3c7039f9b0afee901180900020033fe480388061c002700300095b2023132111239b00210b028d000b02c2fb0004558b0052f1bb1051b 3e59b0004558b0172f1bb117113e59b0004558b0122f1bb1120f3e59b00510b204010a2b5821d81bf459b22512051112397cb0252f18b440255025025db224070a2b5821d81bf459b20c2425111239b0 1210b21d010a2b5821d81bf459b02c10b029d0b0292fb40f291f29025db228292c111239b030d03031013426232135213216151406071615140623230615141707262627343637333236353421233533 3203373315012301353302747369fee40117dcf86157d9f6d0367e9051829602a9a1356c77fef99195e2a092d0fee996feebcd02fe3c47b9a58d4f772442ac96af04626b419130b6707d8701503f94a9 03129b0bfeea01170a000003005fffec051705c400100017001e0066b2041f20111239b00410b011d0b00410b018d000b0004558b00c2f1bb10c1f3e59b0004558b0042f1bb1040f3e59b00c10b21101 0a2b5821d81bf459b214040c1112397cb0142f18b00410b218010a2b5821d81bf459b01410b21c070a2b5821d81bf4593031011402042322240227353412242004121701220607212626033236372116 16051794feedb3b0feee9903960114016401139601fda4a0b60802bc08b4a09fb30afd440ab802b2d6febdadaa013ccd5dd50144afabfebfd501eff0d9dbeefbcae5ded9ea000003004fffec043d044e 000f0016001d0067b2041e1f111239b00410b010d0b00410b017d000b0004558b0042f1bb1041b3e59b0004558b00c2f1bb10c0f3e59b210010a2b5821d81bf459b21b040c1112397cb01b2f18b4401b 501b025db213070a2b5821d81bf459b00410b217010a2b5821d81bf45930311334363633320017171406062322001101323637211616132206072126264f7de494da01130b017be795e3feec01f76b85 10fdff10846b6a8510020010850227a1fd89fee7ea39a0fc8a012e0101fe939289889302dd958282950000010010000004f305c2000f0046b202101111123900b0004558b0062f1bb1061f3e59b00045 58b00f2f1bb10f1f3e59b0004558b00c2f1bb10c0f3e59b2010c0f111239b00610b208010a2b5821d81bf45930310117371336363317072306070123012102611b1be4359c7a2d02185427fe98f4fe0e 010d018b726f02f7ac9701d7027cfb9405b00001002000000418044e00110046b202121311123900b0004558b0052f1bb1051b3e59b0004558b0112f1bb1111b3e59b0004558b00e2f1bb10e0f3e59b2 01050e111239b00510b20a010a2b5821d81bf459303101173713123332170726232206070123013301e314147a5acf4327170c20223b0dfef6d3fe92fb016e616101be012216c006362afce2043a0002 005fff760517062e001300270055b2052829111239b00510b021d000b0004558b00d2f1bb10d1f3e59b0004558b0032f1bb1030f3e59b006d0b00d10b010d0b00d10b21a010a2b5821d81bf459b017d0 b00310b224010a2b5821d81bf459b021d03031011000071523352600033510003735331516001127342627152335060615151416173533153636350517fef3e9c6e8feef030112e9c6ea010dfd8278c6 7985847bc6798002b2fedafe8b237e7e230173011d550124017a23717223fe86fed906cef523606123f5cf4cc7fd25605f23f6cf0002004fff88043d04b4001300250058b2032627111239b00310b014 d000b0004558b0032f1bb1031b3e59b0004558b0102f1bb1100f3e59b00310b006d0b01010b00dd0b01010b223010a2b5821d81bf459b014d0b00310b21d010a2b5821d81bf459b01ad0303113341237 353315161215151402071523352602350136363534262715233506061514161735334fddbdb8bfdddfbfb8bbdd0250525a5a50b84f58564fb80227da01261f6e6d1ffed8dd11dbfed91d6b6c1f0126dd fea71eb59782b21f606021b29583ae21680000030088ffeb06b5073f002a003d004600bab2304748111239b03010b009d0b03010b045d000b0004558b0002f1bb1001f3e59b0004558b0122f1bb1121f 3e59b0004558b0072f1bb1070f3e59b0004558b00b2f1bb10b0f3e59b2090007111239b01210b213010a2b5821d81bf459b00b10b21a010a2b5821d81bf459b21e0b12111239b023d0b01310b02ad0b0 1210b036d0b0362fb02cd0b02c2fb22b080a2b5821d81bf459b02c10b032d0b0322fb239080a2b5821d81bf459b02c10b042d0b0422fb046d0b0462f3031013216171114062322270623222627113436 33152206151114163332363511331116163332363511342623131523222e022322151523353433321e0201363735331514060704f4cef201f1d0e37272e3cef004f3cf5f66665f6972f50171685f6666 5f6a21538abf30146886eb2546c96ffe294103a9603b05b0faddfdeaddfb9e9ef6d50220ddfdcc8e80fded808e81770182fe7973808e800213808e01e386234b0a681022dc0f4f1afe87523c68673178 1f0000030074ffeb05d105e3002a003d004600afb2094748111239b00910b03ad0b00910b046d000b0004558b0122f1bb1121b3e59b0004558b00b2f1bb10b0f3e59b01210b000d0b0002fb00b10b007 d0b209120b111239b01210b213010a2b5821d81bf459b00b10b21a010a2b5821d81bf459b21e0b12111239b023d0b01310b02ad0b01210b036d0b0362fb02dd0b02d2fb22b080a2b5821d81bf459b02d 10b032d0b0322fb239080a2b5821d81bf459b03610b041d0b0412fb046d0b0462f3031013216171514062322270623222627113436331522061515141633323637353315161633323635353426231315 23222e022322151523353433321e02013637353315140607043abadc01d4b5c56163c2b2d304dcbb495b5343505e01ec015e5142545b49bd24538ac12c156887eb2546c570fe304103a9603b0447e5cc f8cce79191e0c50103cde7c3757cf57c75706acaca6a70757cf57c7501e786234c09681022dc0f4e1bfe85523c686731781f00020088ffeb06c10711001e0026007db2062728111239b00610b023d000 b0004558b00d2f1bb10d1f3e59b0004558b0082f1bb1080f3e59b004d0b206080d111239b00810b211010a2b5821d81bf459b00d10b015d0b0152fb01110b01ad0b01510b01ed0b01e2fb00d10b025d0 b0252fb026d0b0262fb220080a2b5821d81bf459b02610b023d0b0232f303101111406232227062322263511331114163332363511211114163332363511253521172115233506c1f9d2e56d71e9cff3 fd675e697201016d63616efc39035501fea6b505b0fbffd6eea5a5efd50401fbfc758281770403fbfc74837f790403e77a7a7f7f00020070ffeb05ed05b1001e00260089b2062728111239b00610b025 d000b0004558b00d2f1bb10d1b3e59b0004558b0152f1bb1151b3e59b0004558b01e2f1bb11e1b3e59b0004558b0042f1bb1040f3e59b0004558b0082f1bb1080f3e59b2060815111239b211010a2b58 21d81bf459b01ad0b00d10b025d0b0252fb01fd0b01f2fb220080a2b5821d81bf459b01f10b022d0b023d030310111060623222706232226351133111416333236351133111416333236351125352117 2115233505ed01dabdc76066cbb8d5f354465366f45c4f4a5bfc9d033804feb2b5043afd4ec1dc8e8eddc302affd51726c6c7202affd51726c6c7202affc7b7b7f7f00010066fe8c04b605c500180053 b217191a11123900b0004558b00a2f1bb10a1f3e59b0004558b0002f1bb100173e59b0004558b0022f1bb1020f3e59b00a10b00ed0b00a10b210010a2b5821d81bf459b00210b217010a2b5821d81bf4 593031012311260035113412243320001523102122061511141617330334fbd3ff008d0101a30100011ffcfedd8ca9a98a9ffe8c0166200147f90111af01189bfef7e90126dfbcfeedb6df010001005c fe8903f3044e001a0053b2191b1c11123900b0004558b00a2f1bb10a1b3e59b0004558b0002f1bb100173e59b0004558b0022f1bb1020f3e59b00a10b00fd0b00a10b212010a2b5821d81bf459b00210 b219010a2b5821d81bf459303101231126023535343636333216161523342623220615151416173302d5f3b3d379db927cc66fe5745871827e7098fe89016a200123dc1c9bfc8967bb765b7abda81ba1 bb020001006d00000493053e0013001300b00e2fb0004558b0042f1bb1040f3e5930310105072503231325370513253705133303050725025b012148feddb5afe1fedf470125cafede490123b9ace401 254cfee001c1ac80aafec1018eab80ab0168ab82ab0146fe6bab7faa0001fc6604a2ff3905fd0007001100b0002fb203060a2b5821d81bf45930310115273721271715fd17b101022201b105207e01ee 6c01dc000001fc730517ff6d0615000f002e00b00b2fb007d0b0072fb200080a2b5821d81bf459b00b10b004d0b0042fb00b10b20c080a2b5821d81bf459303101321515233534232204072335333624 fe7fee886a36fee28b29277901180615dc2210687701860177000001fd7b0516fe7206600005000c00b0012fb005d0b0052f3031013533071707fd7bbd013b5205dc849670440001fda50516fe9c0660 0005000c00b0032fb000d0b0002f3031012737273315fdf7523b01bd0516447096840008fa24fec401bf05af000c001a002700350042004f005c006a007a00b0452fb0532fb0602fb0382fb0004558b0 022f1bb1021f3e59b209090a2b5821d81bf459b04510b010d0b04510b24c090a2b5821d81bf459b017d0b05310b01ed0b05310b25a090a2b5821d81bf459b025d0b06010b02bd0b06010b267090a2b58 21d81bf459b032d0b03810b23f090a2b5821d81bf45930310134363216152334262322061501343633321615233426232206151334363332161523342622061501343633321615233426232206150134 363216152334262322061501343632161523342623220615013436333216152334262206151334363332161523342623220615fd1173be747033302e3301de745d5f7571352e2c3348755d5f7470355c 33fecb745d5f7470352e2d33fd4f73be747033302e33fd4d74be747033302e33fede755d5f7470355c3335755d5f7571352e2d3304f3546868542e373530feeb5468675531343530fe09556768543134 372efdf9546868543134372efee4546868542e37372e051a546868542e373530fe09556768543134372efdf955676755313435300008fa4dfe63018c05c600040009000e00130018001d00220027002f 00b0212fb0162fb0122fb00b2fb01b2fb0262fb0004558b0072f1bb1071f3e59b0004558b0022f1bb102113e593031051703231303271333030137051525050725350501372517050107052725032703 37130117130703fe500b7a60463a0c7a6046021d0d014dfea6fb750dfeb3015a039c02014044fedbfcf302fec04501262b119441c60360119442c43c0efead016104a20e0152fea0fe110c7c62473b0c 7c624701ae109944c8fc8e119945c802e402014645fed5fce302febb47012b000002ffe00000042106620012001b0074b2151c1d111239b01510b003d000b0004558b00d2f1bb10d1f3e59b0004558b0 112f1bb1111f3e59b0004558b0092f1bb1090f3e59b01110b200070a2b5821d81bf459b2020d09111239b0022fb00010b00bd0b00cd0b00210b213010a2b5821d81bf459b00910b214010a2b5821d81b f45930310121113316161514060721112335333533152101113332363534262702a3fedef7c4e5e5c0fe12aeaef30122fedeed5b6563570505fdfe03ceaeadd3040505abb2b2fc90fe82655955690200 00020094000004d905b0000e001b004db2041c1d111239b00410b017d000b0004558b0032f1bb1031f3e59b0004558b0012f1bb1010f3e59b2160301111239b0162fb200010a2b5821d81bf459b00310 b214010a2b5821d81bf4593031011123112132041514071707270623133635342627211121323727370191fd022df4011f757a6d8879aaf91c907efec901304f3a736e021dfde305b0fed1c177876496 370143354a768d02fe04168064000002007cfe600430044e00130022006eb2172324111239b01710b010d000b0004558b0102f1bb1101b3e59b0004558b00d2f1bb10d1b3e59b0004558b00a2f1bb10a 113e59b0004558b0072f1bb1070f3e59b2091007111239b20e1007111239b01010b217010a2b5821d81bf459b00710b21c010a2b5821d81bf45930310114071707270623222711231133173633321211 27342623220711163332372737173604306e6a6f685970b26bf3e00a6bb8c6e1f281789541429646326a6e59220212f4977a63783675fdff05da6e82fed9fefa06a2be7bfe207e217b6467580001008f 00000434071000070032b201080911123900b0004558b0042f1bb1041f3e59b0004558b0022f1bb1020f3e59b00410b200010a2b5821d81bf459303101211123112111330434fd58fd02b2f304e4fb1c 05b001600001007e0000035b05730007002b00b0004558b0042f1bb1041b3e59b0004558b0022f1bb1020f3e59b00410b200010a2b5821d81bf45930310121112311211133035bfe16f301ebf20376fc 8a043a0139000001009bfec6049d05b00014005bb20f151611123900b0092fb0004558b0132f1bb1131f3e59b0004558b0112f1bb1110f3e59b01310b200010a2b5821d81bf459b2031309111239b003 2fb00910b20a070a2b5821d81bf459b00310b20f010a2b5821d81bf45930310121113320001110002327323635022523112311210437fd60a80122013cfef6f301838802feabbcfc039c04e4fe5ffecd feecfef4fed6bab3c2017b09fd8705b00001007efee203db043a0015004ab20b161711123900b00a2fb0004558b0142f1bb1141b3e59b0004558b0122f1bb1120f3e59b01410b200010a2b5821d81bf4 59b203140a111239b0032fb210010a2b5821d81bf4593031012115332000151406060727363534262323112311210346fe2b49010101205eab7355de9b8e4ef302c80376e5fefadd60c28d1dae4ad481 97fe3a043a00000100900000053605b00014006100b0004558b0002f1bb1001f3e59b0004558b00c2f1bb10c1f3e59b0004558b0022f1bb1020f3e59b0004558b00a2f1bb10a0f3e59b20f0a0c111239 b00f2fb29f0f015db208010a2b5821d81bf459b201080f111239b005d0b00f10b012d030310902210123152335231123113311333533153301050dfe7c01adfec1fed341a359fdfd59a337011b05b0fd 5bfcf5026de9e9fd9305b0fd9afefe0266000001008e000004ae043a0014005c00b0004558b00d2f1bb10d1b3e59b0004558b0142f1bb1141b3e59b0004558b00a2f1bb10a0f3e59b0004558b0032f1b b1030f3e59b20e0a0d111239b00e2fb209010a2b5821d81bf459b201090e111239b005d0b00e10b012d0303109022103231523352311231133113335331533130494fec40156fecbd82f9b57f2f2579b 27cf043afdfefdc801acb2b2fe54043afe50c7c701b000010034000006a205b0000e006100b0004558b0062f1bb1061f3e59b0004558b00a2f1bb10a1f3e59b0004558b0022f1bb1020f3e59b0004558 b00d2f1bb10d0f3e59b2080602111239b0082fb201010a2b5821d81bf459b00610b204010a2b5821d81bf459b20c0108111239303101231123112135211133012101012103b6adfcfe2702d58b01ad01 36fe0c021ffed00270fd9004ecc4fd9c0264fd47fd090001003d000005a8043a000e006b00b0004558b0062f1bb1061b3e59b0004558b00a2f1bb10a1b3e59b0004558b0022f1bb1020f3e59b0004558 b00d2f1bb10d0f3e59b2090a02111239b0092fb22f090171b28c09015db200010a2b5821d81bf459b00610b204010a2b5821d81bf459b20c000911123930310123112311213521113301210101210340 7bf2fe6a02886c012a012dfe7801a8fec501acfe540376c4fe5001b0fdf9fdcd000100940000078305b0000d008700b0004558b0022f1bb1021f3e59b0004558b00c2f1bb10c1f3e59b0004558b0062f 1bb1060f3e59b0004558b00a2f1bb10a0f3e59b2010206111239b0012fb29f01015db26f010171b2df010171b20f010172b29f010171b23f010171b42f013f010272b27c01015db00210b204010a2b58 21d81bf459b00110b208010a2b5821d81bf459303101211121152111231121112311330191028b0367fd95fcfd75fdfd0352025ec3fb130287fd7905b0000001007e00000566043a000d006600b00045 58b0022f1bb1021b3e59b0004558b00c2f1bb10c1b3e59b0004558b0062f1bb1060f3e59b0004558b00a2f1bb10a0f3e59b2010c061112397cb0012f18b440015001025db00210b204010a2b5821d81b f459b00110b208010a2b5821d81bf45930310121112115211123112111231133017101a50250fea3f3fe5bf3f3027701c3c4fc8a01b5fe4b043a0001009bfec407ef05b000160068b210171811123900 b0072fb0004558b0152f1bb1151f3e59b0004558b0132f1bb1130f3e59b0004558b0102f1bb1100f3e59b2011507111239b0012fb00710b208070a2b5821d81bf459b00110b20d010a2b5821d81bf459 b01510b211010a2b5821d81bf4593031013320001110002327323635022523112311211123112105147d0122013cfef6f301838802feab91fcfd7ffc04790341fecdfeecfef4fed6bab3c2017b09fd89 04e4fb1c05b00001007efee606ba043a00180057b212191a11123900b0082fb0004558b0172f1bb1171b3e59b0004558b0152f1bb1150f3e59b0004558b0122f1bb1120f3e59b2011708111239b0012f b20f010a2b5821d81bf459b01710b213010a2b5821d81bf459303101332000151406060727363635342623231123112111231121040a7d0107012c5dab73557569a59a7ff3fe5af3038c0294fefbde61 bf8e1dad288f678297fe360376fc8a043a0000020067ffeb05d705c5002500320085b2163334111239b01610b026d000b0004558b00d2f1bb10d1f3e59b0004558b01d2f1bb11d1f3e59b0004558b004 2f1bb1040f3e59b000d0b0002fb202041d111239b0022fb00d10b20e010a2b5821d81bf459b00410b215010a2b5821d81bf459b00010b225010a2b5821d81bf459b00210b029d0b01d10b22f010a2b58 21d81bf459303105222706232224022735341236331522061515141233323726113534123332121115100716330114161736113534262322061505d7dfb394b7bbfed4a9037de18c667edbb23129e2ed b8c2f3bb5c6afd8e6563a26058545e154747ae0136bfc9af011ea1d4e1bdb8d7fef907cb0144cbf00135febffefac6fedaca14021984d5488f0109d5aeabafa100020061ffeb04c9044e0022002e008c b2042f30111239b00410b023d000b0004558b00b2f1bb10b1b3e59b0004558b01a2f1bb11a1b3e59b0004558b0042f1bb1040f3e59b0004558b0002f1bb1000f3e59b202041a111239b0022fb00b10b2 0c010a2b5821d81bf459b00410b213010a2b5821d81bf459b00010b222030a2b5821d81bf459b00210b025d0b01a10b22b010a2b5821d81bf45930310522270623220011353412331506061515141633 37263535343633321615151407163301141736353534262322061504c9ba937a90e5fed4dbaa404b9a7d258fb69496bd814d58fe0e78633d31323b1236390142010442cf010cca04947b49a6cc0295e2 7abbeaffcd77d39411018faa6c63a97b6b87786a0001002dfea106b705b0000f004f00b00d2fb0004558b0082f1bb1081f3e59b0004558b0022f1bb1021f3e59b0004558b00e2f1bb10e0f3e59b00210 b200010a2b5821d81bf459b005d0b00e10b206010a2b5821d81bf459b00ad0303101213521152111211133113303231121018dfea003befe9f0281fcb014e7fbd104ecc4c4fbde04e6fb1cfdd5015f00 00010026febf053a043a000f004b00b00d2fb0004558b0032f1bb1031b3e59b0004558b00f2f1bb10f0f3e59b00310b204010a2b5821d81bf459b000d0b00f10b206010a2b5821d81bf459b00310b008 d0b00610b00ad0303101233521152311211133113303231121011bf502c3db01a6f39314ddfcd20377c3c3fd4b0378fc88fdfd01410000010080000004e105b00018004fb205191a11123900b0004558 b0002f1bb1001f3e59b0004558b00b2f1bb10b1f3e59b0004558b00e2f1bb10e0f3e59b2050e00111239b0052fb008d0b00510b214010a2b5821d81bf459b011d0303101111617161711331136371133 112311060715233526262711017d024f356ea36c64fdfd6070a3f6fa0105b0fe2c98392705012bfedc0a1902a7fa50023c180aebe506eadf01cd00010074000003f5043b00160051b206171811123900 b0004558b0152f1bb1151b3e59b0004558b00c2f1bb10c1b3e59b0004558b0012f1bb1010f3e59b20f010c1112397cb00f2f18b207010a2b5821d81bf459b004d0b00f10b012d0303121231106071523 3526262711331116171133113637113303f5f34531a3b6be01f20182a33b3bf301690e058a8b13d0b10150feb0ac1f010bfeef060e020c0000010085000004e505b000110046b205121311123900b000 4558b0012f1bb1011f3e59b0004558b0002f1bb1000f3e59b0004558b0092f1bb1090f3e59b2050100111239b0052fb20e010a2b5821d81bf459303133113311363320041711231126262322071185fc a0b20105010c01fc017e97aea405b0fdc329e6e9fe3301d08b762afd590000020016ffe905bc05c4001c00240064b2162526111239b01610b023d000b0004558b00e2f1bb10e1f3e59b0004558b0002f 1bb1000f3e59b21e000e111239b01e2fb212010a2b5821d81bf459b004d0b01e10b00ad0b00010b217010a2b5821d81bf459b00e10b222010a2b5821d81bf45930310520001135262635331417341224 172000111521151416333237170606012135342623220603dcfed2feaa9ba7b58d9401089e01080122fc98cbbdb1ac3143d8fe05026c9a948eb0170154012b3c18d4aab62aae011ca001fe9cfeb98435 cad746c5282e036c1fb8c0dd0002ffcbffec048b044e001a0021008cb2202223111239b02010b014d000b0004558b00d2f1bb10d1b3e59b0004558b0002f1bb1000f3e59b21c000d111239b01c2fb4bf 1ccf1c025db45f1c6f1c0271b41f1c2f1c0271b28f1c015db4ef1cff1c0271b211070a2b5821d81bf459b004d0b01c10b00ad0b00010b215010a2b5821d81bf459b217000d111239b00d10b220010a2b 5821d81bf45930310522242727262635331417362433321211152116163332371706060121352626220602d8d4fee614038286a9681f0107bbddf1fd3d0b9d77a8678441dafe6d01cf0872ca7a14fbd1 321dc1939530c5f3fee6fefe62869c877d616b0296127a7d8c0000010090febf04ed05b000160066b215171811123900b0102fb0004558b0042f1bb1041f3e59b0004558b0082f1bb1081f3e59b00045 58b0022f1bb1020f3e59b20704021112397cb0072f18b400071007025db00ad0b01010b211010a2b5821d81bf459b00710b216010a2b5821d81bf4593031012311231133113301210116001510002327 2011022521019508fdfd7101b20132fe22e90100fef0f401010902feaefef80271fd8f05b0fda4025cfd8a1ffed7f9fef3fed3c2016f017a06000001008efeea0443043a00160059b20d171811123900 b0072fb0004558b0112f1bb1111b3e59b0004558b0152f1bb1151b3e59b0004558b00f2f1bb10f0f3e59b214150f1112397cb0142f18b440145014025db20e010a2b5821d81bf459b200140e11123930 31011616151406060727362734262723112311331133012102cdafbc5eaa7355e0028d8baef2f2550141012d026129e3ad60ba881cad47ca768509fe54043afe5001b0000001009bfe4b051305b00014 0074b20a151611123900b0004558b0002f1bb1001f3e59b0004558b0032f1bb1031f3e59b0004558b0122f1bb1120f3e59b0004558b0082f1bb108113e59b20200121112397cb0022f18b46002700202 5db430024002025db00810b20d010a2b5821d81bf459b00210b210010a2b5821d81bf45930310111211133111406232227371633323511211123110197027ffdbea9453c0e243e7bfd81fc05b0fd8302 7dfa18b7c611c70cba0298fd9705b0000001007efe4b0409043a0014006db20b151611123900b0004558b0002f1bb1001b3e59b0004558b0032f1bb1031b3e59b0004558b0122f1bb1120f3e59b00045 58b0082f1bb108113e59b20203121112397cb0022f18b440025002025db00810b20d010a2b5821d81bf459b00210b210010a2b5821d81bf4593031011121113311060623222737163332351121112311 017101a5f301baa6453a0f273b7cfe5bf3043afe3d01c3fb85b3c111bf0dc001e7fe4b043a0000020051ffeb051e05c40016001e005eb2081f20111239b00810b017d000b0004558b0002f1bb1001f3e 59b0004558b0082f1bb1080f3e59b20d0008111239b00d2fb00010b210010a2b5821d81bf459b00810b217010a2b5821d81bf459b00d10b21a010a2b5821d81bf4593031012000111514020427200011 3521262623220707273736013236372115141602710140016da0fee3a9fedcfebd03d005dfcca79734311ba6012996be12fd2fba05c4fe8cfeb66bc1fec2b1010160014989e0f03413c60d4afafcdabd 1fb9bf000001005bffeb044b05b0001b006bb20b1c1d11123900b0004558b0022f1bb1021f3e59b0004558b00b2f1bb10b0f3e59b00210b200010a2b5821d81bf459b2040200111239b21b0b02111239 7cb01b2f18b005d0b2100b02111239b00b10b213010a2b5821d81bf459b01b10b219070a2b5821d81bf45930310121352117011616151404232226263533141633323635342623233502fffd92039101 fe86c8dafee5ea8be27efc8768799099918c04e4cca3fe4f18eac2c5e867bf835f807f649485ac000001005dfe750446043a001b005cb20b1c1d11123900b00b2fb0004558b0022f1bb1021b3e59b200 010a2b5821d81bf459b2040002111239b21b0b02111239b01b2fb005d0b2100b02111239b00b10b213010a2b5821d81bf459b01b10b219070a2b5821d81bf45930310121352117011616151404232226 263533141633323635342623233502f4fd9b038c01fe88cbd7feeaeb89e47bf3896c7a949a938f0376c49bfe4319e9bfc2ea68bf81608580699683abffff0034fe4b048905b0002600b05200002601de a429000701af01350000ffff002dfe4903a2043a002600eb5500002701deff9dff7a000701af010bfffe000200520000048305b0000b00140050b2041516111239b00410b00ed000b0004558b0012f1b b1011f3e59b0004558b0032f1bb1030f3e59b2000103111239b0002fb00310b20c010a2b5821d81bf459b00010b20d010a2b5821d81bf459303101113311212226263534243701112122061514161703 86fdfdda9dee800115eb0134fed77c928b79039b0215fa5074d488ccfc03fd2f020689757491030000020068000006b005b0001800210060b2072223111239b00710b019d000b0004558b0082f1bb108 1f3e59b0004558b0002f1bb1000f3e59b2070800111239b0072fb00010b20a010a2b5821d81bf459b2110800111239b019d0b00710b21a010a2b5821d81bf459b01910b021d030312122243534243721 11331133363637362627331616070606072511212206151416170272ecfee20115eb0134fc4b5e6c0502211df51f260204f3ccfeb1fed67d908e7afdd3cefa030215fb1a028a7d4ad94c5ecc45d4fc03 ca02068a747592010002005effe7067f0618001f002b0083b2192c2d111239b01910b02ad000b0004558b0062f1bb106213e59b0004558b0032f1bb1031b3e59b0004558b0182f1bb1180f3e59b00045 58b01c2f1bb11c0f3e59b2050318111239b01810b20b010a2b5821d81bf459b2100318111239b21a0318111239b00310b222010a2b5821d81bf459b01c10b228010a2b5821d81bf45930311310123332 171133110616333636373627331716070e0223042706232202270126232206151416333237275ee4c3a365f3024e437482040440ec172f03027de28cfeff556bcbb9e00b02ae4783737f7a768d450602 0e010a0136780242fb4f4f6902b7a9bed559b783a8f98504b7b30105de015168c1cd9eaa72440001003cffe705e305b000290063b2232a2b11123900b0004558b0092f1bb1091f3e59b0004558b0222f 1bb1220f3e59b2012a09111239b0012fb200010a2b5821d81bf459b00910b207010a2b5821d81bf459b20f0001111239b02210b215010a2b5821d81bf459b21a22091112393031133533363635342121 352116041514071613150616333636373627331616070e022306262735342623e6a79384fef3fea50164fa0106fff605013c336572040440f51a2b02027ada8aa7b2087c670262cd016d75d1cd01d3cc e6643ffefe4d394902b6a3bed562ca67a9f88504a7aa3e6e7e000001002fffe204fe043a00240060b20f252611123900b0004558b01d2f1bb11d1b3e59b0004558b00e2f1bb10e0f3e59b202010a2b58 21d81bf459b2070e1d111239b216251d111239b0162fb214070a2b5821d81bf459b01d10b21b010a2b5821d81bf459b22214161112393031250633363637362733161607060623062627353423232733 363534232327211616100716170301024e5a60030441ec2d180104e9bc9ea008a2e602c2b9cbff060114cbe4b0b906eb58028f7f96a9868039ccf2037183487fbd048396c302a6feca4a30ac00010048 feba043705b00022005fb20b232411123900b0172fb0004558b0092f1bb1091f3e59b0004558b01b2f1bb11b0f3e59b201091b111239b0012fb200010a2b5821d81bf459b00910b207010a2b5821d81b f459b20f0001111239b01b10b212010a2b5821d81bf459303113273336363534212127211604151407161315331514060727363637232627353426239701ce9181feebfeea03012eef0103e4e303cd64 5a83243808a33c037e74025cc301736febc303dcc9df6647fef686ac63d84b4d39774931b184718500010074fea9041a043a0022005fb206232411123900b0182fb0004558b0092f1bb1091b3e59b000 4558b01c2f1bb11c0f3e59b201091c111239b0012fb200070a2b5821d81bf459b00910b207010a2b5821d81bf459b2100001111239b01c10b213010a2b5821d81bf45930311327333235342623212721 321716151407161715331514060727363637232627353423b301e1d26b63fee1040120e3786aadb102bb685583263806a62b01c3019bb38e4a53c16459929e4f3cc324ac65da474d3d7e4f1e8354a600 00010042ffeb077f05b000220062b200232411123900b0004558b00d2f1bb10d1f3e59b0004558b01f2f1bb11f0f3e59b0004558b0062f1bb1060f3e59b00d10b200010a2b5821d81bf459b00610b208 010a2b5821d81bf459b01f10b212010a2b5821d81bf459b2171f0d1112393031012103020206072335373636131321111416333236373627331616070e02232226350407fe61180e61b99c4a287a680f 1c038e4c3f6e7f040441f61c2902027fe08cc3c604e3fde0fef6fed38a02ca0309df011c02dffbbc5264b4a7bbd866c766a7fb84c1bd00010040ffeb065a043a00210062b220222311123900b0004558 b00c2f1bb10c1b3e59b0004558b01e2f1bb11e0f3e59b0004558b0052f1bb1050f3e59b00c10b200010a2b5821d81bf459b00510b207010a2b5821d81bf459b01e10b211010a2b5821d81bf459b2161e 0c11123930310121030206072327373636371321111616333236373627331716070e02232226270317fef71311a8ad53023250490a1402e10151455867040440ec1630030270c77dc2c7010374fe9afe e9f403ca050bade501cefd2b5264a099b5c850b17c9be67cbeb900010094ffe7078605b0001d0065b2141e1f11123900b0004558b0002f1bb1001f3e59b0004558b0192f1bb1191f3e59b0004558b017 2f1bb1170f3e59b0004558b0112f1bb1110f3e59b204010a2b5821d81bf459b2090017111239b21c0017111239b01c2fb215010a2b5821d81bf459303101111416333636373627331716070e02230626 27352111231133112111050a4d3e707e040441f6172f03027ce28ebbc309fd82fcfc027e05b0fbbc566002b3a6bbd859b783a8f78704c0c3fffd9705b0fd83027d0000010077ffe3065c043a001c0078 b21b1d1e11123900b0004558b0042f1bb1041b3e59b0004558b0082f1bb1081b3e59b0004558b0022f1bb1020f3e59b0004558b01a2f1bb11a0f3e59b20708021112397cb0072f18b4d007e007025db4 40075007025db200010a2b5821d81bf459b01a10b20d010a2b5821d81bf459b2120802111239303101211123113311211133110616333636373627331616070e02230403031afe50f3f301b0f3025246 5e64030440eb1a2b020270c77efe8a1301bafe46043afe4301bdfd2d526602a691afce5dbf619be67c0801840001005dffeb04bb05c500210047b200222311123900b0004558b0092f1bb1091f3e59b0 004558b0002f1bb1000f3e59b00910b20e010a2b5821d81bf459b00010b215010a2b5821d81bf459b21a0009111239303105222402271134122433321707262322061511141633363637362733171607 0e0202bbacfeeb9b029a0117addf883f86a29dc5c49e7d83030335f52713010281ea159c0118ad010faf011d9e59b844e7bcff00b6e902857495ccb158588bcd6e0000010055ffeb03e7044e001e0044 b2131f2011123900b0004558b0132f1bb1131b3e59b0004558b00b2f1bb10b0f3e59b200010a2b5821d81bf459b2050b13111239b01310b218010a2b5821d81bf4593031253636373427331607060623 22003535343636333217072623220615151416025a51450213eb1d0204d2b5e7fee27ce292bb602e638a728b94af02434777678c52a0b00131f81e97fa8b42bd3abda4209abf00010021ffe7055a05b0 0019004db2051a1b11123900b0004558b0022f1bb1021f3e59b0004558b0162f1bb1160f3e59b00210b200010a2b5821d81bf459b004d0b005d0b01610b209010a2b5821d81bf459b20e160211123930 31012135211521111416333636373627331616070e022306262701e3fe3e0480fe3e4d3e707e040441f51b2b03027de28cbbc30904e3cdcdfc87546002b6a3bbd862ca67a8f98504c0c300010044ffe3 04cb043a0017004db205181911123900b0004558b0022f1bb1021b3e59b0004558b0152f1bb1150f3e59b00210b200010a2b5821d81bf459b004d0b005d0b01510b209010a2b5821d81bf459b20e1502 11123930310121352115211114163336363736273316160706062304030189febb038bfead52455e63030440eb2c190104f1c2fe89130377c3c3fdf05464028474939e7c7e37ccf20801840000010081 ffeb04ff05c500280073b226292a11123900b0004558b0162f1bb1161f3e59b0004558b00b2f1bb10b0f3e59b203010a2b5821d81bf459b224160b1112397cb0242f18b27324015db26024015db22501 0a2b5821d81bf459b2060325111239b2102524111239b01610b21e010a2b5821d81bf459b21b241e11123930310114163332363533140604232024353425262635342421321616152334262322061514 213315232206017fb79986aefc8dfefda0fef3febf010e7682012f010997fa8bfda37c90aa0133b6bf9da30198657e815e82be69e9c4fd5731a662c5db69ba7759757363d9c8700000020067046f02d6 05d70005000d001b00b00b2fb007d0b0072fb001d0b0012fb00b10b004d0b0042f30310113331503230133151617072635019370d3e65dfed4b1034c50b00498013f15fec101545f7b46485abe00ffff 00470209025402cd000600110000ffff00470209025402cd000600110000ffff009d026d0499033100460197e0004ccd4000ffff0081026d05d1033100460197850066664000ffff0004fe3f03990000 002700430001fefe010600430100001c00b6000210022002035db4100220020271b680029002a002035d30310001006304200196061a0008001db208090a11123900b0004558b0002f1bb100213e59b0 04d0b0042f3031011706071523353636011a7c5b03d50167061a4d8590988a60d100000100330400016506000008001db208090a11123900b0004558b0042f1bb104213e59b000d0b0002f3031132736 373533151406af7c5a03d56904004d83929e8a67d10000010032fed6016400ca00080018b208090a11123900b0092fb2040d0a2b5821d81bf4593031132736373533150606ad7b5503da0166fed64e7f 9493855dd0000001004a0400017c06000008001600b0004558b0082f1bb108213e59b004d0b0042f3031011516170726263535011f035a7c4d6906009e8f864d3ed1678affff006c042002ef061a0026 016c09000007016c01590000ffff0040040002c006000026016d0d000007016d015b000000020032fec202aa00ff000900120021b20b1314111239b00b10b005d000b0132fb2040d0a2b5821d81bf459 b00ed0303113273637353315060706172736373533151406b17f5503da013731f87f5804da66fec24e899dc9ba6c7264414e8e96cbb663dd000100400000041e05b0000b004b00b0004558b0082f1bb1 081f3e59b0004558b0062f1bb1061b3e59b0004558b00a2f1bb10a1b3e59b0004558b0022f1bb1020f3e59b00a10b200010a2b5821d81bf459b004d0b005d03031012111231121352111331121041efe 88f3fe8d0173f301780372fc8e0372c80176fe8a0001005cfe60043905b00013007c00b0004558b00c2f1bb10c1f3e59b0004558b00a2f1bb10a1b3e59b0004558b00e2f1bb10e1b3e59b0004558b002 2f1bb102113e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b206010a2b5821d81bf459b00e10b208010a2b5821d81bf459b009d0b010d0b011d0b00610b012d0b013d030312121 1123112135211121352111331121152111210439fe88f3fe8e0172fe8e0172f30178fe880178fe6001a0c202b4c40176fe8ac4fd4c00000100880206024403db000d0016b2030e0f11123900b0032fb1 0a0a2b58d81bdc59303113343633321615151406232226278879646778776763790203035f797962255e77735d00ffff008afff5036f01000026001203000007001201cd0000ffff008afff505280100 0026001203000027001201cd00000007001203860000000100470209012102cd00030018b200040511123900b0032fb200010a2b5821d81bf4593031012335330121dada0209c4000006004affec075f 05c400150023002700340041004e00b8b2284f50111239b02810b002d0b02810b01bd0b02810b026d0b02810b035d0b02810b047d000b0242fb0262fb0004558b0192f1bb1191f3e59b0004558b0122f 1bb1120f3e59b003d0b0032fb2050312111239b007d0b0072fb01210b00ed0b00e2fb2101203111239b01910b020d0b0202fb01210b22b020a2b5821d81bf459b00310b232020a2b5821d81bf459b02b 10b038d0b03210b03fd0b02010b245020a2b5821d81bf459b01910b24c020a2b5821d81bf459303101343633321736333216151514062322270623222635013436333216151514062322263501270117 031416333236353534262206150514163332363535342622061501141633323635353426220615032fac88964e4e9586afa98a974e4e948aacfd1ba8858aabab8885aa01777d02c77db04f3e404a4e7c 4d01c74f3e404a4e7c4dfb4e4d3f3e4c4d7e4b016582aa6f6fa78c4781aa6e6eaa86037b83aaaa894682a9a989fc1b48047248fc384457524c4b4654544a4a4457524c4b4654544a02ea455555494846 565749000001006c008a023303a90006001000b0052fb2020705111239b0022f303101132301350133013cf7a7fee00120a70219fe7101861301860000010054008a021b03a90006001000b0002fb203 0700111239b0032f303113011501231303fb0120fee0a7f7f703a9fe7a13fe7a018f01900001002d006d037105270003000900b0002fb0022f303137270117aa7d02c77d6d4804724800ffff00350293 02be05a8030701d800000293001300b0004558b0092f1bb1091f3e59b00dd030310000010069028c02ff05ba000f0053b20a101111123900b0004558b0002f1bb1001f3e59b0004558b0032f1bb1031f 3e59b0004558b00d2f1bb10d133e59b0004558b0072f1bb107133e59b201030d111239b00310b20a030a2b5821d81bf4593031011736332011112311262322071123110101204b900103c5057d6327c5 05ac7987fec9fe0901daad59fdd203200001005f0000047c05c30027008eb21f282911123900b0004558b0172f1bb1171f3e59b0004558b0062f1bb1060f3e59b2270617111239b0272fb20d020a2b58 21d81bf459b001d0b00610b205010a2b5821d81bf459b009d0b02710b010d0b02710b023d0b0232fb60f231f232f23035db225020a2b5821d81bf459b011d0b02310b014d0b01710b21e010a2b5821d8 1bf459b21b231e1112393031012117140721072135333636352723353327233533273436201615233426232206151721152117210332fed0024002b801fbe752272b02a5a0049c9705fa0196e8f5695f 586706013ffec605013501d42e8755caca096f5b37917990a1caeadab85f698268a19079000500210000064f05b0001b001f00230026002900bdb20a2a2b111239b00a10b01fd0b00a10b021d0b00a10 b026d0b00a10b028d000b0004558b01a2f1bb11a1f3e59b0004558b0172f1bb1171f3e59b0004558b00c2f1bb10c0f3e59b0004558b0092f1bb1090f3e59b205091a111239b0052fb001d0b0012fb20f 01015db203030a2b5821d81bf459b00510b207030a2b5821d81bf459b025d0b00ad0b00ed0b00510b01dd0b021d0b011d0b00310b01ed0b022d0b012d0b00110b019d0b027d0b015d0b00910b024d0b0 1710b029d030310133152315331523112301211123112335333523353311330121113301333523053327230135230133270577d8d8d8d8fdfec9feadfcd3d3d3d3fc01350157fbfe7194f3fe67ee5f8f 028c2ffda32b2b03c5a097a0fe1201eefe1201eea097a001ebfe1501ebfcde979797fe7e4b01d74400020098ffec063a05b0001e002500a2b2212627111239b02110b010d000b0004558b0152f1bb115 1f3e59b0004558b0192f1bb1191b3e59b0004558b01d2f1bb11d1b3e59b0004558b00a2f1bb10a0f3e59b0004558b0132f1bb1130f3e59b01d10b200010a2b5821d81bf459b00a10b205010a2b5821d8 1bf459b00010b00dd0b00ed0b2201315111239b0202fb211010a2b5821d81bf459b01d10b01cd0b01c2fb01510b224010a2b5821d81bf459303101231114163332371506232011112306060723112311 213216173311331133013332113427230633bf323f262f534dfee8781cf4ca9efa018cd4fd1875f2bffb5f92f4e6a00386fda43d380abc1701350265adbb03fde505b0c3b30107fef9fead0100f70600 ffff0094ffec083c05b00026003600000007005704720000000700350000075305b0001f00230027002b002e0031003400ebb2323536111239b03210b01ed0b03210b022d0b03210b027d0b03210b02a d0b03210b02ed0b03210b030d000b0004558b0022f1bb1021f3e59b0004558b01f2f1bb11f1f3e59b0004558b01b2f1bb11b1f3e59b0004558b0102f1bb1100f3e59b0004558b00d2f1bb10d0f3e59b2 091002111239b0092fb005d0b0052fb20f05015db001d0b00510b207030a2b5821d81bf459b00910b20a030a2b5821d81bf459b02dd0b00ed0b030d0b012d0b00910b025d0b029d0b021d0b015d0b007 10b026d0b02ad0b022d0b016d0b00110b01dd0b019d0b01010b02fd0b02cd0b01f10b032d0b00110b034d030310121133303331523073315210323032103230321353327233533033313211333013337 2305333723053327230137230537230107330498013157fb629abf25e4fef77ef390fef292f27ffefdde25b99462fb5801346cd4fdce9f2aea030e9f21e9fea6ba2a6501b02656fd322f5501a7081004 0701a9fe57a0a2a0fddb0225fddb0225a0a2a001a9fe5701a9fd15a2a2a2a2a2fe00beb9b902011f0002007c00000610043a000d001b006bb2081c1d111239b00810b010d000b0004558b0002f1bb100 1b3e59b0004558b0162f1bb1161b3e59b0004558b00b2f1bb10b0f3e59b0004558b00e2f1bb10e0f3e59b211010a2b5821d81bf459b00010b209010a2b5821d81bf459b2051109111239b21009111112 39303101321617112311342623211123110111331121323637113311060623030cbbae02f35a69feaef30199f301506a5901f401efdc043ac0cbfeb501426d63fc8a043afbc602d6fded616802aefd57 bcd50001005effed043005c30023008ab215242511123900b0004558b0162f1bb1161f3e59b0004558b0092f1bb1090f3e59b2231609111239b0232fb200020a2b5821d81bf459b00910b204010a2b58 21d81bf459b00010b00cd0b02310b00ed0b02310b013d0b0132fb60f131f132f13035db210020a2b5821d81bf459b01610b21b010a2b5821d81bf459b01310b01ed0b01010b020d03031012116163332 371706232000032335333523353336003332170726232206072115211521036afe9c06a3986e5f1c7880ff00feda08acacacad0d012cfd6a851c666597a2090163fe9c0164020faeac21cc1d01200102 8d808dff011b1fcd22aca48d800000040021000005d405b0001a001f0024002900e3b20c2a2b111239b00c10b01cd0b00c10b023d0b00c10b028d000b0004558b00b2f1bb10b1f3e59b0004558b0012f 1bb1010f3e59b00b10b224010a2b5821d81bf459b020d0b0202f4013002010202020302040205020602070208020095db01ed0b01e2fb6b01ec01ed01e035d400b001e101e201e301e401e055db22603 0a2b5821d81bf459b027d0b0272f400f3027402750276027702780279027075db200010a2b5821d81bf459b02610b003d0b01e10b006d0b02010b00fd0b212030a2b5821d81bf459b01cd0b01dd0b007 d0b02010b00ad0b01e10b014d0b02610b017d0303101112311233533352335331121320417331523170733152306062301272115212521262721012115213201d6fdb8b8b8b8022dad01013ce4bd0201 bce136fabd011503fdbe0243fdbd01f04672fec801f4fe0c01317b021dfde3031fa048a001098881a02622a07d8501c22848e83b02fe3b37000100280000040c05b0001a006db2161b1c11123900b000 4558b0192f1bb1191f3e59b0004558b00c2f1bb10c0f3e59b01910b218010a2b5821d81bf459b001d0b01910b014d0b0142fb003d0b01410b213070a2b5821d81bf459b006d0b01410b00ed0b00e2fb2 09070a2b5821d81bf459b20d090e111239303101231617330723060607011521012733323637213721262321372103d9da330fca329716dcc901d2fee1fe0301fd708316fde63301e331d8fef33603ae 04f94b65b6a5af11fddf0d0251995d4cb69bcc0000010021ffec045105b0001e0091b21b1f2011123900b0004558b0112f1bb1111f3e59b0004558b0052f1bb1050f3e59b2131105111239b0132fb017 d0b0172fb20017015db218010a2b5821d81bf459b019d0b008d0b009d0b01710b016d0b00bd0b00ad0b01310b214010a2b5821d81bf459b015d0b00cd0b00dd0b01310b012d0b00fd0b00ed0b00510b2 1a010a2b5821d81bf459b21e051111123930310115060204232227110735373507353711331537150715371507113636353504510296feedb26b8cdcdcdcdcfce1e1e1e1aab202ff59d2fec3ab14025d 57c7578957c857013bd75ac85a895ac859fdfb02fcf84d000001004f0000050f043a0017005cb200181911123900b0004558b0172f1bb1171b3e59b0004558b0102f1bb1100f3e59b0004558b00b2f1b b10b0f3e59b0004558b0052f1bb1050f3e59b2150b17111239b0152fb000d0b01510b20c010a2b5821d81bf459b009d030310116001315233526262711231106061515233512003735330328e0010304 f3018172f37182f3030104dff3036a29fe92feecbfb8c5ef2afd6a02952af3c7b1ba011401702bd1000200280000053305b00016001f0078b2182021111239b01810b00dd000b0004558b00c2f1bb10c 1f3e59b0004558b0022f1bb1020f3e59b206020c111239b0062fb205010a2b5821d81bf459b001d0b00610b00ad0b00a2fb20f0a015db209010a2b5821d81bf459b014d0b00610b015d0b00a10b017d0 b00c10b21f010a2b5821d81bf459303125211523352335333523353311213204151404072115210121323635342627210333febefccdcdcdcd022df10120feeef4fec40142febe012d88908d7cfec4e7 e7e7cb6bcb02c8fbd0d4f1036b01367e7d708e0300040070ffec058905c500190026003400380094b21a393a111239b01a10b000d0b01a10b027d0b01a10b037d000b0352fb0372fb0004558b0092f1b b1091f3e59b0004558b0242f1bb1240f3e59b00910b003d0b0032fb20d0903111239b00910b210020a2b5821d81bf459b00310b216020a2b5821d81bf459b2190309111239b02410b01dd0b01d2fb024 10b22a020a2b5821d81bf459b01d10b231020a2b5821d81bf459303101140620263535343633321615233426232206151514163236350134363332161515140620263517141633323635353426232206 150527011702b19fff00a29e8280a1aa41363442436a400118ae8788ada7fee8abaa4f3e40494e3d3e4dfdfb7e02c77e04257392a78a4782ab94733540544a4a45554331fd4086a6a68d4782a9a78905 4457534b4b4654544af4480472480002004cffeb039005f900170021005ab2012223111239b00110b018d000b00c2fb0004558b0002f1bb1000f3e59b2060c00111239b0062fb205070a2b5821d81bf4 59b013d0b00010b217010a2b5821d81bf459b00610b018d0b00c10b21f010a2b5821d81bf45930310522263506233532371136363332161515140207151416330336363535342623220702dbe1ed6160 616003b29a88acd7b2686cd44d572b20560315ebe513bb1801e9bfd6b49b26adfea9674d8e7a02444bcc66293f40b20000040090000007c205c00003000f001d002700a6b21e2829111239b01e10b001 d0b01e10b004d0b01e10b010d000b0004558b0262f1bb1261f3e59b0004558b0242f1bb1241f3e59b0004558b0062f1bb1061f3e59b0004558b0212f1bb1210f3e59b0004558b01f2f1bb11f0f3e59b0 0610b00dd0b00d2fb002d0b0022fb20002015db201020a2b5821d81bf459b00d10b213020a2b5821d81bf459b00610b21a020a2b5821d81bf459b2202421111239b2251f261112393031012135210134 362016151514062026351714163332363535342623220615012101112311210111330797fd9f0261fd76be0138bfbafec2bdaf5c514f5b5c504f5cfec7fef4fe0df4010b01f6f2019c95022f9fc1c0a6 4e9cc2c2a206606c6c63515f6d6d62fba3040afbf605b0fbf3040d000002006d0394045705b0000c0014006d00b0004558b0062f1bb1061f3e59b0004558b0092f1bb1091f3e59b0004558b0132f1bb1 131f3e59b2011506111239b0012fb2000901111239b2030106111239b004d0b2080109111239b00110b00bd0b00610b10d0a2b58d81bdc59b00110b00fd0b00d10b011d0b012d0303101032303112311 331313331123012311231123352103e87c3e7c6f898185856ffe118a758d018c0509fe8b0174fe8c021cfe83017dfde401bdfe4501bb5f0000020096ffec0491044e0015001c0062b2021d1e111239b0 0210b016d000b0004558b00a2f1bb10a1b3e59b0004558b0022f1bb1020f3e59b2190a02111239b0192fb20f0a0a2b5821d81bf459b00210b2130c0a2b5821d81bf459b2150a02111239b00a10b2160a 0a2b5821d81bf459303125062322260235341236333216161715211116333237012207112111260414b7bb91f48790f88485e38403fd00779ac4acfe90977a021c735e729d0101938f01039f8bf3903e feb86e7a032a7afeeb011e71ffff0059fff505cb0599002701d5ffd902860027017c00fb0000010701dc03210000001000b0004558b0062f1bb1061f3e593031ffff0054fff5066805b4002701d7001d 02940027017c01a80000010701dc03be0000001000b0004558b00d2f1bb10d1f3e593031ffff005bfff5065c05a8002701d9000c02930027017c018c0000010701dc03b20000001000b0004558b0012f 1bb1011f3e593031ffff0058fff5061a05a3002701db0022028e0027017c01330000010701dc03700000001000b0004558b0052f1bb1051f3e59303100020062ffeb044305f500190026005bb2132728 111239b01310b020d000b00b2fb0004558b0132f1bb1130f3e59b2000b13111239b0002fb2020b13111239b00b10b205010a2b5821d81bf459b00010b21a010a2b5821d81bf459b01310b220010a2b58 21d81bf45930310132172626232207273736332000111514020623220035353412172206151416333236353526260238ae771ac5847c8b1d3c6e8f010d01277ae394e3fef3fef47b85847a7985168b04 047dc2e535b7192cfe4efe7235c1fed3a70124f70ddf0112c2a7a49ab0d0c5554c5f000100a6ff1b04f405b00007002700b0042fb0004558b0062f1bb1061f3e59b00410b001d0b00610b202010a2b58 21d81bf4593031052311211123112104f4f4fd99f3044ee505d4fa2c069500010040fef304c105b0000c003500b0032fb0004558b0082f1bb1081f3e59b00310b202010a2b5821d81bf459b005d0b008 10b20a010a2b5821d81bf459b007d0303101012115213501013521152101038ffdee0344fb7f024ffdb10447fcf602120243fd73c39702c802c698c3fd730001009e026d03ef03310003001100b0022f b201010a2b5821d81bf45930310121352103effcaf0351026dc40001003b0000049205b00008003cb200090a11123900b0072fb0004558b0012f1bb1011f3e59b0004558b0032f1bb1030f3e59b20001 03111239b00710b206010a2b5821d81bf459303101013301230323352102410178d9fe17c5d8d10167012b0485fa500241c50003005effec07df044e001a002a00390072b2073a3b111239b00710b022 d0b00710b032d000b0004558b0042f1bb1040f3e59b0004558b0092f1bb1090f3e59b00410b016d0b0162fb2071604111239b012d0b0122fb2141604111239b01610b21e010a2b5821d81bf459b00410 b227010a2b5821d81bf459b02ed0b01e10b037d0303101140606232226270221222626353534123633201312213216161707342623220706071516171633323635051416333236373735262726232206 07df80e6908de955aafedf8fe58181e48e0124a9a901248ee48101ef927aa46e280f0f2e6b9f7995fa5d927b69ac2b070f286ea47992021198fd90a3a7feb68eff99159801008ffeb901478ffd97049a c6c94a42244555c3c3a2059dc3b3901a24424ac9c3000001ffaffe4b02a806150015003db202161711123900b0004558b00e2f1bb10e213e59b0004558b0032f1bb103113e59b208010a2b5821d81bf4 59b00e10b213010a2b5821d81bf4593031051406232227371633323711343633321707262322150190b6aa423f122c258a02c0b23f59192a32a34fb0b613bd0d9d04f4b3c315b90bb800000200650101 041503fa0015002b0078b2102c2d111239b01010b01cd000b0192fb003d0b0032fb008d0b0082fb00310b00ad0b00810b20d010a2b5821d81bf459b00310b212010a2b5821d81bf459b00d10b015d0b0 1910b01ed0b01e2fb01910b020d0b01e10b223010a2b5821d81bf459b01910b228010a2b5821d81bf459b02310b02bd03031133636333617171633323715062322272726072206071536363336171716 333237150623222727260722060765308442524c9c46518465667f5146984f54428730308042544f9846518765668351469c4c52428430038e323802224e207ed96a204c2402423ccb323802244c207e d96a204e2202423c00010091008003ef04c30013003700b0132fb200010a2b5821d81bf459b004d0b01310b007d0b01310b00fd0b00f2fb210010a2b5821d81bf459b008d0b00f10b00bd03031012107 273723352137213521371707331521072103effde2806d5db001217efe610210866e63bdfed17d01ac0164e43ea6c9dfcaed3eafcadfffff003c0013038d046b006700200000008b4000399a00070197 ff9efda6ffff0080001303e0046b006700220000008b4000399a00070197ffe2fda600020024000003eb05b0000500090038b2060a0b111239b00610b004d000b0004558b0002f1bb1001f3e59b00045 58b0032f1bb1030f3e59b2060003111239b208000311123930310133010123010103131301a4c40183fe80c5fe7e01e1edf2ec05b0fd27fd2902d701d6fe2afe2901d700ffff00a100ab01bc05070027 0012001a00b601070012001a0407000900b0002fb011dc30310000020063027f023e043900030007002ab2000809111239b005d000b0022fb0004558b0062f1bb1061b3e59b2000802111239b0002fb0 04d03031012311330123113301009d9d013e9d9d027f01bafe4601ba00010045ff67015a01060008000c00b0042fb000d0b0002f3031172736373533150606c5804903c90153994d737b644f5dbaffff 002d0000051a06150026004a00000007004a02440000000200180000041706150017001b0073b2091c1d111239b00910b019d000b0004558b0092f1bb109213e59b0004558b0042f1bb1041b3e59b000 4558b01a2f1bb11a1b3e59b0004558b0172f1bb1170f3e59b0004558b0192f1bb1190f3e59b00410b013d0b216010a2b5821d81bf459b001d0b00910b20f010a2b5821d81bf45930313311233533353e 0233321617072623220615153315231121231133bda5a5016ac28850934f258a726f64d5d50267f3f30386b44a7fb65c221ac930616144b4fc7a043a0001002d0000042c061500160063b21217181112 3900b0004558b0122f1bb112213e59b0004558b00e2f1bb10e1b3e59b0004558b0092f1bb1090f3e59b0004558b0162f1bb1160f3e59b01210b202010a2b5821d81bf459b00e10b005d0b00e10b20b01 0a2b5821d81bf459b008d0303101262322151533152311231123353335363633320511230339664ac4dcdcf3a5a501d7c47a0144f3053f0eb85bb4fc7a0386b461b7c330fa1b0002002d000006930615 0028002c00b5b2142d2e111239b01410b02ad000b0004558b0082f1bb108213e59b0004558b0162f1bb116213e59b0004558b02b2f1bb12b1b3e59b0004558b0212f1bb1211b3e59b0004558b0112f1b b1111b3e59b0004558b0042f1bb1041b3e59b0004558b0282f1bb1280f3e59b0004558b0252f1bb1250f3e59b0004558b02a2f1bb12a0f3e59b02110b222010a2b5821d81bf459b026d0b001d0b00810 b20d010a2b5821d81bf459b01610b21c010a2b5821d81bf4593031331123353335343633321707262322151521353e023332161707262322061515331523112311211121231133d2a5a5c8b440480628 35ae0174016ac28850934f2688736f64d5d5f3fe8c04cef3f30386b463b4c412be08b3604a7fb65c221ac930616144b4fc7a0386fc7a043a0001002d000006930615002700a5b213282911123900b000 4558b0152f1bb115213e59b0004558b0082f1bb108213e59b0004558b0042f1bb1041b3e59b0004558b0102f1bb1101b3e59b0004558b01f2f1bb11f1b3e59b0004558b0272f1bb1270f3e59b0004558 b0242f1bb1240f3e59b0004558b0192f1bb1190f3e59b00410b201010a2b5821d81bf459b00810b20d010a2b5821d81bf459b01510b21c010a2b5821d81bf459b00110b026d0b022d030313311233533 3534363332170726232215152135363633320511231126232215153315231123112111d2a5a5c8b44048062835ae017401d7c47a0144f3664ac4dcdcf3fe8c0386b463b4c412be08b36061b7c330fa1b 053f0eb85bb4fc7a0386fc7a0001002dffec04d1061500240085b213252611123900b0004558b00f2f1bb10f1b3e59b0004558b01a2f1bb11a1b3e59b0004558b0232f1bb1231b3e59b0004558b00a2f 1bb10a0f3e59b02310b200070a2b5821d81bf459b00a10b205010a2b5821d81bf459b00010b00dd0b00ed0b02310b21f010a2b5821d81bf459b213010a2b5821d81bf459b00e10b018d0b019d0303101 23111416333237150623201111233533352623221511231123353335343633321617113304cbbf313f262f534dfee8b2b2456ca3f3a5a5c2b065f172bf0386fda43e370abc1701350265b4f820b9fb67 0386b462b6c33831fe8e0001004bffec06800618004c00a7b2464d4e11123900b0004558b0472f1bb147213e59b0004558b0402f1bb1401b3e59b0004558b00f2f1bb10f1b3e59b0004558b04b2f1bb1 4b1b3e59b0004558b0092f1bb1090f3e59b0004558b02c2f1bb12c0f3e59b04b10b200070a2b5821d81bf459b00910b204010a2b5821d81bf459b00010b00dd0b00ed0b04710b214070a2b5821d81bf4 59b04010b220070a2b5821d81bf459b02c10b234070a2b5821d81bf4593031012311143332371506232226271123353335342623220615141e0215233426232206151416041616151406232226263533 1616333236353426262726353436333217263534363332161515330679bf71262f534d879001acac60584f581d211cf4685650655e011ea34ff2c485d074ec05786360646bf853b6ecb65b4d2dd9aec9 debf0386fdb7880abc17aaa2024eb458626954453a6966794d465d4a3e383e3f577a5792b560a861565d493b4144342858a78cbc176c4f81a5cac54f00160059fe7207ec05ae000d001a00280037003d 00430049004f0056005a005e00620066006a006e0076007a007e00820086008a008e01c0b2108f90111239b01010b000d0b01010b01bd0b01010b030d0b01010b03cd0b01010b03ed0b01010b046d0b0 1010b04ad0b01010b050d0b01010b057d0b01010b05bd0b01010b061d0b01010b063d0b01010b067d0b01010b06dd0b01010b070d0b01010b077d0b01010b07bd0b01010b07fd0b01010b084d0b01010 b088d0b01010b08cd000b03d2fb0004558b0462f1bb1461f3e59b27d44032bb27c79032bb27881032bb28039032bb20a463d111239b00a2fb003d0b0032fb00ed0b00e2fb00a10b00fd0b00f2fb26f0e 0f1112397cb06f2f18b2500b0a2b5821d81bf459b215506f111239b00a10b21e0b0a2b5821d81bf459b00310b2250b0a2b5821d81bf459b00f10b029d0b0292fb00e10b02ed0b02e2fb2340b0a2b5821 d81bf459b03d10b06bd0b067d0b063d0b03ed0b23f0c0a2b5821d81bf459b065d0b069d0b06dd0b03cd0b03910b041d0b04610b2470c0a2b5821d81bf459b05bd0b057d0b04ad0b04610b060d0b05cd0 b058d0b04bd0b04410b04ed0b00e10b2510b0a2b5821d81bf459b04710b05fd0b00f10b2760b0a2b5821d81bf459b07810b084d0b07910b085d0b07c10b088d0b07d10b089d0b08010b08cd0b08110b0 8dd0303101140623222627353436333216171311333216151407161615142301342623220615151416333236350133111406232226353314333236350111331533152135333533110111211523152535 21112335011533323534271335211521352115213521150135211521352115213521151333323534262323012335333523353311233533252335333523353311233533033781646680027e6865800243 bc6272543234d0fe8f4a41404a4a42404903ba5c6952586d5d682936f9c471c40528c76ff86d0135c405ec01366ffc5c7e6762cb0116fd5b0115fd5c0114020a0116fd5b0115fd5c0114bc5d763a3c5d fcf171717171717107226f6f6f6f6f6f01d46279785e755f7c785efeb30225494d54200d462d9b0148454e4e4570454e4e45014ffe864e5d51535b362cfcc9013bca7171cafec5061f011d74a9a974fe e3a9fcb6a9535204034a747474747474f93871717171717103c450291efed3fc7efafc15f97efc7efafc15f90005005cfdd507d708730003001c002000240028004c00b0212fb0252fb000d0b0002fb0 2110b002d0b0022fb2200200111239b0202fb01dd0b01d2fb004d0b0042fb20d0002111239b00d2fb014d0b0142fb2070414111239b21914041112393031090305343637363635342623220607333636 333216151407060615172315330333152303331523041803bffc41fc44040f1e244a5ca79590a002cb023a2b39385d5b2fcacaca4b04040204040652fc31fc3103cff13a3a1827874a80978b7f333440 345f3c415c4c5baafd4c040a9e040001003a000003ea05b00006003200b0004558b0052f1bb1051f3e59b0004558b0012f1bb1010f3e59b00510b203010a2b5821d81bf459b200030511123930310101 230121352103eafdd4f4022cfd4403b00529fad704edc3000002004ffe560417044e001b00260083b21f2728111239b01f10b00cd000b0004558b0042f1bb1041b3e59b0004558b0072f1bb1071b3e59 b0004558b00c2f1bb10c113e59b0004558b0182f1bb1180f3e59b2060418111239b00c10b212010a2b5821d81bf459b2101218111239b2160418111239b01810b21f010a2b5821d81bf459b00410b224 010a2b5821d81bf45930311334363633321737331114002322262737163332363535062322262637141633323711262322064f6dcd85bf6910d1fefbef55b9493582908e836aae7fcc72f38f78954645 947c8d0226a0fb8d8672fc1cf6fef62f2db04c9c9b16778cfc9d9fc08101d97bc1000001ffb0fe4b018e00cd000d002eb2030e0f11123900b00e2fb0004558b0052f1bb105113e59b20a010a2b5821d8 1bf459b00e10b00dd0b00d2f30312511140706232227371633323511018e705b9546380e243d7ccdfef7c8624f11c60cb20105000001005cfe9a014f00b50003001200b0042fb002d0b0022fb001d0b0 012f303101231133014ff3f3fe9a021b0002007504d002f706dc000c0020007b00b0032fb006d0b0062f400b0f061f062f063f064f06055db00310b209060a2b5821d81bf459b00610b00cd0b00c2fb0 0610b010d0b0102fb013d0b0132f400d0f131f132f133f134f135f13065db01010b016d0b0162fb01310b21a080a2b5821d81bf459b01010b21d080a2b5821d81bf459b01a10b020d030310114062026 3533141633323635131406232226232206152734363332163332363502f7b0fedeb0af4c46484a905f4738812a1f2a6861452f882c1e2c05b0657b7b65353a3c33010f4b6b4732251b4d6c4732240002 007504d502f60708000d001c005900b0032fb007d0b0072f400b0f071f072f073f074f07055db00310b20a060a2b5821d81bf459b00710b00dd0b00d2fb00710b00ed0b00e2fb014d0b0142fb20f0e14 111239b2150c0a2b5821d81bf459b21b0e0f1112393031011406232226353314163332363527273636353423373216151406070702f6af9192afad5044454ddf08483f92079e9f4e440105b062797962 34393a33197602171a366050442f3a083a000002007504d30300067e000d0011005d00b0032fb006d0b0062f400b0f061f062f063f064f06055db00310b20a060a2b5821d81bf459b00610b00dd0b00d 2fb00610b010d0b0102fb00ed0b00e2f400f0f0e1f0e2f0e3f0e4f0e5f0e6f0e075db01010b011d019b0112f1830310114062322263533141633323635273307230300af9695b1b14c49474c65b6a980 05b0617c7a63343c3c34cec00002007504e7035c06d10006001a008d00b0012fb003d0b0032fb004d019b0042f18b000d019b0002f18b00310b005d0b0052f40090f051f052f053f05045db202050311 1239b00ad0b00a2f40093f0a4f0a5f0a6f0a045db00dd0b00d2f400f0f0d1f0d2f0d3f0d4f0d5f0d6f0d075db00a10b010d0b0102fb00d10b214060a2b5821d81bf459b00a10b217060a2b5821d81bf4 59b01410b01ad03031012327072325333714062322262322061527343633321633323635035cc1b3b2c1012a93ba593d317b241b295a593c2a7f261a2c04e78e8eeddf3e5f422c1b184060412d1c0002 007504e7040a06cb00060015006000b0012fb003d0b0032fb004d019b0042f18b000d019b0002f18b00310b005d0b0052f40090f051f052f053f05045db2020305111239b00110b007d0b0072fb00dd0 b00d2fb208070d111239b20e060a2b5821d81bf459b2140807111239303101232707232533172736363534233732161514060707035cc1b3b2c10116bbb9073f388107898c49380104e7a2a2fa747d05 181d3e69594b3741073b0002ff4c04da035c06830006000a005b00b0032fb004d019b0042f18b000d019b0002f18b00310b001d0b0012fb006d0b0062f40090f061f062f063f06045db2020306111239 b00310b008d0b0082fb007d019b0072f18b00810b00ad0b00a2fb60f0a1f0a2f0a035d30310123270723253305230333035cd59f9fd40123a1fe879dd7dd04da8e8efa5c010b0002007a04e7048b0690 0006000a005b00b0032fb005d0b0052fb000d0b0002f40090f001f002f003f00045db00310b002d019b0022f18b2040300111239b006d019b0062f18b00310b009d0b0092fb007d0b0072fb60f071f07 2f07035db00910b00ad019b00a2f1830310133052327072301330323019da10123d49f9fd50333ded89d05e1fa8e8e01a9fef5000002007504d40300067e000d0011005d00b0032fb006d0b0062f400b 0f061f062f063f064f06055db00310b20a060a2b5821d81bf459b00610b00dd0b00d2fb00610b011d0b0112fb00ed0b00e2f400f0f0e1f0e2f0e3f0e4f0e5f0e6f0e075db01110b010d019b0102f1830 310114062322263533141633323635253317230300af9695b1b14c49474cfe94b7728005b1617c7a63343c3c34cdc00000010094046901a9062b0008001db208090a11123900b0004558b0002f1bb100 213e59b004d0b0042f30310117060707233534360126833f0201d355062b536d7c868559b6000002000900000494048d0007000a004600b0004558b0042f1bb1041d3e59b0004558b0022f1bb1020f3e 59b0004558b0062f1bb1060f3e59b2090402111239b0092fb200010a2b5821d81bf459b20a040211123930312521072301330123012103033ffe1e5ff501d7df01d5f6fe060154aaf9f9048dfb7301b2 01ba000300760000040a048d000e0016001f00a4b21e2021111239b01e10b002d0b01e10b011d000b0004558b0012f1bb1011d3e59b0004558b0002f1bb1000f3e59b2170100111239b0172fb4af17bf 17025db46f177f170271b2ff170171b20f170172b48f179f170272b25f170172b2cf170171b23f170171b41f172f17025db4bf17cf170272b20f010a2b5821d81bf459b2080f17111239b00010b21001 0a2b5821d81bf459b00110b21e010a2b5821d81bf459303133112132161514060716161514062303113332363534272733363635342623237601afdeeb595b6070e2dde2e46664b4fad45b636765c604 8da59c4f8323178f63a3ab01fbfec755419e05aa0248454f46000001004ffff00443049d001b004eb2031c1d11123900b0004558b00b2f1bb10b1d3e59b0004558b0032f1bb1030f3e59b20f0b031112 39b00b10b212010a2b5821d81bf459b00310b218010a2b5821d81bf459b21b030b111239303101060423220011353436363332041723262623201115141633323637044211fef7d9ecfeec7eec9cd601 0414f30c7d72feed8687787c0d0184bfd5012c010b44a9ff8adac27069fe8e48b9b56270000200760000042a048d000b00130046b2131415111239b01310b002d000b0004558b0012f1bb1011d3e59b0 004558b0002f1bb1000f3e59b00110b20c010a2b5821d81bf459b00010b20d010a2b5821d81bf4593031331121320416171514060423031133201335102576017ba4010390028ffef9a88382014706fe c9048d8afb9f3da3fe8b03c9fcf9015c4301600800010076000003b5048d000b004e00b0004558b0062f1bb1061d3e59b0004558b0042f1bb1040f3e59b20b0604111239b00b2fb200010a2b5821d81b f459b00410b202010a2b5821d81bf459b00610b208010a2b5821d81bf4593031012111211521112115211121035ffe0a024cfcc1033cfdb701f601f8fecac2048dc4fef2000100760000039e048d0009 004000b0004558b0042f1bb1041d3e59b0004558b0022f1bb1020f3e59b2090402111239b0092fb200010a2b5821d81bf459b00410b206010a2b5821d81bf459303101211123112115211121035bfe0e f30328fdcb01f201dbfe25048dc4fed500010054fff00448049d001c005cb21a1d1e11123900b0004558b00a2f1bb10a1d3e59b0004558b0032f1bb1030f3e59b20e030a111239b00a10b211010a2b58 21d81bf459b00310b217010a2b5821d81bf459b21b030a111239b01b2fb219070a2b5821d81bf4593031250706212200113510003332161723262623201115141620373523352104481796fed5f8fedc 0116f4d7fa19ed12796cfee4a0012846f901eb93188b012e0109410109012cc3c0645cfe8940b7ba39c8b1000001007600000468048d000b008600b0004558b0062f1bb1061d3e59b0004558b00a2f1b b10a1d3e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b2090600111239b0092fb4af09bf09025db23f090171b2cf090171b23f090172b2ff090171b20f090172b46f097f090271 b4df09ef09025db25f090172b41c092c09025db202010a2b5821d81bf45930312123112111231133112111330468f3fdf4f3f3020cf301dbfe25048dfe1101ef0001008500000177048d0003001d00b0 004558b0022f1bb1021d3e59b0004558b0002f1bb1000f3e593031212311330177f2f2048d0000010024fff00364048d000e0022b2050f1011123900b0004558b0052f1bb1050f3e59b20b010a2b5821 d81bf45930310133111406232226353314333236350271f3e3b2cae1f4b74b57048dfce0aecfc0afad5e5d000001007600000468048d000c004b00b0004558b0042f1bb1041d3e59b0004558b0082f1b b1081d3e59b0004558b0022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2060204111239b00610b001d0b20a010611123930310107112311331137012101012101f087f3f36e014f012cfe4301d3 fede01db83fea8048dfdfd86017dfdf7fd7c0001007600000394048d0005002800b0004558b0042f1bb1041d3e59b0004558b0022f1bb1020f3e59b200010a2b5821d81bf45930312521152111330169 022bfce2f3c2c2048d00000100760000058f048d000e0060b2010f1011123900b0004558b0002f1bb1001d3e59b0004558b0022f1bb1021d3e59b0004558b0042f1bb1040f3e59b0004558b0082f1bb1 080f3e59b0004558b00c2f1bb10c0f3e59b2010004111239b2070004111239b20a00041112393031090221112311130123011311231101b20151014e013ef219fea0a8fea119f2048dfcb5034bfb7301 3b023afc8b0370fdcbfec5048d000001007600000467048d0009004500b0004558b0052f1bb1051d3e59b0004558b0082f1bb1081d3e59b0004558b0002f1bb1000f3e59b0004558b0032f1bb1030f3e 59b2020500111239b20705001112393031212301112311330111330467f2fdf4f3f3020cf2031bfce5048dfce4031c000002004ffff0046f049d000e001c0046b2031d1e111239b00310b012d000b000 4558b00b2f1bb10b1d3e59b0004558b0032f1bb1030f3e59b00b10b212010a2b5821d81bf459b00310b219010a2b5821d81bf45930310110002322001135341236333200112734262322061515141633 323635046ffedfedecfeda85f09bf00120f29688869899878894022cfef8fecc0135010c2eac01078bfec7fef508b7c0c0b735b2c7c3b600000200760000042c048d000a0013004db2041415111239b0 0410b00cd000b0004558b0032f1bb1031d3e59b0004558b0012f1bb1010f3e59b20b0103111239b00b2fb200010a2b5821d81bf459b00310b212010a2b5821d81bf45930310111231121321615140607 2733323635342623230169f301e5d4fdf1d4fef268777965f30199fe67048dd5ada9c603c458545769000002004cff30046c049d001400220046b2082324111239b00810b01fd000b0004558b0112f1b b1111d3e59b0004558b0082f1bb1080f3e59b01110b218010a2b5821d81bf459b00810b21f010a2b5821d81bf45930310114060717072506232226022735341236333200112734262322061515141633 323635046c6e63cf9dfef632349af2840182f19cef0122f19789869797888995022ca3f1489888c9098b0101aa39ab01058efec8fef408b7c0c3b633b0c9c3b60002007600000439048d000d00160061 b2051718111239b00510b00fd000b0004558b0042f1bb1041d3e59b0004558b0022f1bb1020f3e59b0004558b00d2f1bb10d0f3e59b20e0204111239b00e2fb200010a2b5821d81bf459b20a000e1112 39b00410b215010a2b5821d81bf459303101231123112132161514070115210133323635342623230248dff301c8daf0e10112fefcfe34d56c6c696fd501a9fe57048db7aaeb5bfe250b026b5f4e5160 0001003efff003ef049d00250063b209262711123900b0004558b0092f1bb1091d3e59b0004558b01c2f1bb11c0f3e59b2031c09111239b20d091c111239b00910b210010a2b5821d81bf459b00310b2 15010a2b5821d81bf459b2211c09111239b01c10b223010a2b5821d81bf45930310134262426263534363332161523342623220615141617161615140623222626353314213236030268fecfb053f6c3 d2fef378655f6e718fddc0f8cc8ae57ef40100616f0132424f4c62835c92bbc8a0515d4d403a4c2336b28e99ae5daa71c04a0001002400000416048d0007002e00b0004558b0062f1bb1061d3e59b000 4558b0022f1bb1020f3e59b00610b200010a2b5821d81bf459b004d0303101211123112135210416fe7ef3fe8303f203c9fc3703c9c400010067fff0041e048d000f0035b20c101111123900b0004558 b0082f1bb1081d3e59b0004558b0042f1bb1040f3e59b20c010a2b5821d81bf459b00810b00fd0303101111404202435113311141633323711041efefffe4aff00f17e6ce504048dfd01bee0ddc102ff fd007368d40307000001000900000472048d0008003100b0004558b0032f1bb1031d3e59b0004558b0072f1bb1071d3e59b0004558b0052f1bb1050f3e59b20103051112393031011737012101230121 022a131201220101fe46f6fe47010101384d4b0357fb73048d0000010028000005e5048d000c005900b0004558b0012f1bb1011d3e59b0004558b0082f1bb1081d3e59b0004558b00b2f1bb10b1d3e59 b0004558b0032f1bb1030f3e59b0004558b0062f1bb1060f3e59b2000103111239b2050103111239b20a0103111239303101133301230303230133131333044aafecfee6ebd8dbebfee6ecb1d8d6012b 0362fb730341fcbf048dfc9c0364000100150000044a048d000b005300b0004558b0012f1bb1011d3e59b0004558b00a2f1bb10a1d3e59b0004558b0042f1bb1040f3e59b0004558b0072f1bb1070f3e 59b2000104111239b2060104111239b2030006111239b209060011123930310113210101210303210101210227f2011cfe89018cfee0fffafee40181fe88011a02fa0193fdbefdb50199fe67024b0242 0001000500000436048d0008003100b0004558b0012f1bb1011d3e59b0004558b0072f1bb1071d3e59b0004558b0042f1bb1040f3e59b20001041112393031010121011123110121021d010e010bfe5d f2fe64010b027a0213fd07fe6c01a102ec0000010041000003f3048d0009004400b0004558b0072f1bb1071d3e59b0004558b0022f1bb1020f3e59b200010a2b5821d81bf459b2040002111239b00710 b205010a2b5821d81bf459b20905071112393031252115213501213521150178027bfc4e026cfd9503a0c2c28d033cc48a000002004bfff502aa0320000d00170046b2031819111239b00310b010d000 b0004558b00a2f1bb10a193e59b0004558b0032f1bb1030f3e59b00a10b210020a2b5821d81bf459b00310b215020a2b5821d81bf4593031011406232226353534363332161527342322071514333237 02aa9e90929f9e9190a0bb757203776f04013e9faaaa9e989daead9e0ca99fb8a99a000100800000020203130006003100b0004558b0052f1bb105193e59b0004558b0012f1bb1010f3e59b00510b004 d0b0042fb203020a2b5821d81bf4593031212311073525330202b9c9016f13023a3092770001003c000002b2032000170059b208181911123900b0004558b00f2f1bb10f193e59b0004558b0002f1bb1 000f3e59b216020a2b5821d81bf459b2021600111239b2030f00111239b00f10b208020a2b5821d81bf459b20c000f111239b215000f111239303121213501363534262322061523343633321615140f 022102b2fd9c011d7136343a42baa9878f9c6a628c01737d010567432a354236749980736b66577100010037fff502a903200024007fb21e252611123900b0004558b00d2f1bb10d193e59b0004558b0 172f1bb1170f3e59b200170d1112397cb0002f18b4500060000271b680009000a000035db00d10b206020a2b5821d81bf459b20a0006111239b00010b224020a2b5821d81bf459b2122400111239b017 10b21e020a2b5821d81bf459b21b241e111239303101333235342623220615233436333216151407161514062322263533141633323635342723010c5184363e3041baa5828fa38795b18f87abba453c 3f3d865c01d26123352723637c79697733298e6a7e7f712635372a65010000020035000002be0315000a000e004900b0004558b0092f1bb109193e59b0004558b0042f1bb1040f3e59b2010904111239 b0012fb202020a2b5821d81bf459b006d0b00110b00bd0b2080b06111239b20d09041112393031013315231523352127013301333507025f5f5fbbfe9a09016dbdfe8bba0e013a97a3a37901f9fe25f2 16000001004ffff502ae0315001a006ab20d1b1c11123900b0004558b0022f1bb102193e59b0004558b00d2f1bb10d0f3e59b00210b203020a2b5821d81bf459b207020d111239b0072fb218020a2b58 21d81bf459b2051807111239b00d10b213020a2b5821d81bf459b2111318111239b21a18131112393031131321152107363332161514062322262733163332353426232207623401ecfeac143e47838c a38c81ad02b905727543424335017f019696941b867a78998463527d384428000002004dfff502b903220013001e005bb2141f20111239b01410b00cd000b0004558b0002f1bb100193e59b0004558b0 0c2f1bb10c0f3e59b00010b201020a2b5821d81bf459b2060c00111239b0062fb214020a2b5821d81bf459b00c10b21a020a2b5821d81bf4593031011522060736333216151406232226353534363303 22060715143332363534023291890d476b7587a88693abf0de962d420f7f35440322995f62458e7a7799a79b31d2e8fe572417249146367400010036000002ae03150006003200b0004558b0052f1bb1 05193e59b0004558b0022f1bb1020f3e59b00510b204020a2b5821d81bf459b200040511123930310101230121352102aefeadc40153fe4c027802acfd54027f96000003004bfff502aa03200013001c 00240096b2072526111239b00710b014d0b00710b022d000b0004558b0112f1bb111193e59b0004558b0072f1bb1070f3e59b22207111112397cb0222f18b680229022a022035db4502260220271b400 2210220271b440225022025db4d022e0220271b219020a2b5821d81bf459b2022219111239b20c1922111239b00710b214020a2b5821d81bf459b01110b21f020a2b5821d81bf4593031011407161514 0623222635343726353436333216013236342622061416133422151416323602977184a18e8ca484719b81829bfee43540416a404097c4336031024174373d806a7a796b803d3774697676fde0335a30 305a3301ab565627303000020046fff702a303200013001f0060b2142021111239b01410b008d000b0004558b0082f1bb108193e59b0004558b0102f1bb1100f3e59b20210081112397cb0022f18b010 10b211020a2b5821d81bf459b00210b214020a2b5821d81bf459b00810b21a020a2b5821d81bf4593031010623222635343633321617151406072335323627323735342623220615141601e7425a7e87 aa848ba202dce0138f79634e23423433413c0136398a7d78a4a6973bd7d9019352ac344548414e393744000100900287032d03310003001100b0022fb201010a2b5821d81bf459303101213521032dfd 63029d0287aa00030096044802a206950003000f001b004e00b00d2fb019d0b0192fb207090a2b5821d81bf459b002d0b0022fb000d0b0002f400f0f001f002f003f004f005f006f00075db00210b003 d019b0032f18b00d10b213090a2b5821d81bf45930310133072307343633321615140623222637141633323635342623220601bce6f595826e4e4c6c694f516b6334252430302425340695c2de4e6465 4d4a63624b253131252733330003000afe4a041b044e002900360043009bb2084445111239b00810b030d0b00810b03ad000b0004558b0262f1bb1261b3e59b0004558b0162f1bb116113e59b02610b0 28d0b0282fb200030a2b5821d81bf459b2081626111239b0082fb20f1608111239b00f2fb235010a2b5821d81bf459b21b350f111239b21f0826111239b01610b230010a2b5821d81bf459b00810b23a 010a2b5821d81bf459b02610b241010a2b5821d81bf459303101231615151406062322270615141733161615140606232224353437263534372626353534363332172101060615141633323635342725 03141633323635353426220615041b8a3a73ce8051452573c2c3ca8ffa9ad9fef5b632755a64fcc7554b0171fd302431887286ac93feea407a59587775b87503a055691664a95f12232f4a03019a8e58 a6629b79a55932487751319e5f16a2ca14fbe5134830424d5e406b090202b34b66674e124a66664d00020056ffeb045f044e0010001d006eb21b1e1f111239b01b10b009d000b0004558b0092f1bb109 1b3e59b0004558b00c2f1bb10c1b3e59b0004558b0022f1bb1020f3e59b0004558b0102f1bb1100f3e59b2000902111239b20b0902111239b00210b214010a2b5821d81bf459b00910b21b010a2b5821 d81bf459303125062322023535101233321737330313230114163332363735262623220603636ef2c7e6e8c7e9711cdd6c73ddfdc77c74607c17117d63737fc4d90120f40f010a0136d7c3fde2fde401 f9a0acaba62fa5b9c5000002009b000004f205b00016001e0061b2181f20111239b01810b004d000b0004558b0032f1bb1031f3e59b0004558b0012f1bb1010f3e59b0004558b00f2f1bb10f0f3e59b2 170301111239b0172fb200010a2b5821d81bf459b2090017111239b00310b21d010a2b5821d81bf4593031011123112132161514071613151417152126273534262325213236353421210197fc0229f5 fff7e50547fefc3b047b70fed301149081fef8fee30256fdaa05b0d9cde36545fef673a93d1a31b8797480ca716de6000001009b0000053005b0000c005800b0004558b0042f1bb1041f3e59b0004558 b0082f1bb1081f3e59b0004558b0022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2060204111239b0062fb21f060171b201010a2b5821d81bf459b20a0106111239303101231123113311330121 0101210243acfcfc8b01ac0136fe0c0220fed00270fd9005b0fd9c0264fd47fd090000010081000004350600000c005300b0004558b0042f1bb104213e59b0004558b0082f1bb1081b3e59b0004558b0 022f1bb1020f3e59b0004558b00b2f1bb10b0f3e59b2070802111239b0072fb200010a2b5821d81bf459b20a000711123930310123112311331133012101012101e26ff2f269010f011cfe9f018ffee6 01d9fe270600fc9c019efe11fdb50001009b0000051205b0000b004c00b0004558b0032f1bb1031f3e59b0004558b0072f1bb1071f3e59b0004558b0012f1bb1010f3e59b0004558b00a2f1bb10a0f3e 59b2000301111239b2050301111239b209000511123930310111231133113301210101210197fcfc0602190138fda5027ffec8029afd6605b0fd7f0281fd35fd1b0000010081000004220618000a004c 00b0004558b0032f1bb103213e59b0004558b0062f1bb1061b3e59b0004558b0012f1bb1010f3e59b0004558b0092f1bb1090f3e59b2000601111239b2050601111239b2080005111239303101112311 331101210101210173f2f20159012afe5001dcfedb01ebfe150618fc84019efe0cfdba000001003eff1303ef0573002a006fb2132b2c11123900b0004558b0092f1bb1091d3e59b0004558b0222f1bb1 220f3e59b2032209111239b00910b00cd0b00310b218010a2b5821d81bf459b00910b213010a2b5821d81bf459b2101813111239b02210b01fd0b02210b228010a2b5821d81bf459b226032811123930 3101342624262635343637353315161615233426232206151416171616151406071523352626353314213236030268fecfb053cfa9a0a6cbf378655f6e718fddc0c3aea0bde3f40100616f0132424f4c 62835c86b410d9dc15c08d515d4d403a4c2336b28e86ac11e1e113c79ac04a00000100380000041a049d001f006eb21b202111123900b0004558b0132f1bb1131d3e59b0004558b0052f1bb1050f3e59 b21f1305111239b01f2fb200020a2b5821d81bf459b00510b203010a2b5821d81bf459b007d0b008d0b00010b00cd0b01f10b00ed0b01310b21a010a2b5821d81bf459b2171f1a111239303101211607 210721353336362727233533272636333216152334262322061717210347fe850650029801fc650a292b0301a09b0306d8bfc2d9f357504d570504018001e5b270c3c30b937d079369ceeed4bc616a7e 79690001000e0000043f048d00180095b200191a11123900b0004558b0012f1bb1011d3e59b0004558b0182f1bb1181d3e59b0004558b00c2f1bb10c0f3e59b2000c18111239b2090c01111239b0092f b004d0b0042f400d0f041f042f043f044f045f04065db6cf04df04ef04035db206020a2b5821d81bf459b00910b20a020a2b5821d81bf459b00ed0b00910b010d0b0102fb00610b013d0b00410b016d0 b0162f3031010121013315210715211521152335213521352721353301210225010f010bfebed5feda100136fecaf2feca013609fed3dcfebe010b027a0213fdb7931d2a91d9d9913611930249000001 007600000397048d00050032b201060711123900b0004558b0042f1bb1041d3e59b0004558b0032f1bb1030f3e59b00410b200010a2b5821d81bf45930310121112311210397fdd2f3032103c9fc3704 8d000002000900000472048d00030008003cb205090a111239b00510b002d000b0004558b0022f1bb1021d3e59b0004558b0002f1bb1000f3e59b2050002111239b207010a2b5821d81bf45930312121 013303270703210472fb9701b9f6691213de01e3048dfec94b4dfd6f0003004ffff0046f049d0003001200200076b2072122111239b00710b001d0b00710b016d000b0004558b00f2f1bb10f1d3e59b0 004558b0072f1bb1070f3e59b2030f071112397cb0032f18b460037003025db430034003025db200030171b200010a2b5821d81bf459b00f10b216010a2b5821d81bf459b00710b21d010a2b5821d81b f45930310121352105100023220011353412363332001127342623220615151416333236350338fe5a01a60137fedfedecfeda85f09bf00120f2968886989987889401dfc376fef8fecc0135010c2eac 01078bfec7fef508b7c0c0b735b2c7c3b6000001000900000472048d00080038b207090a11123900b0004558b0022f1bb1021d3e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b2 0702001112393031212101330121012707010afeff01b9f601bafefffede1213048dfb7303564b4d0003004200000355048d00030007000b005eb2040c0d111239b00410b000d0b00410b008d000b000 4558b00a2f1bb10a1d3e59b0004558b0002f1bb1000f3e59b202010a2b5821d81bf459b2070a00111239b0072fb204010a2b5821d81bf459b00a10b208010a2b5821d81bf45930312121352103213521 132135210355fced031349fd7e028249fced0313c30138c4010ac4000001007600000462048d0007003fb201080911123900b0004558b0062f1bb1061d3e59b0004558b0042f1bb1040f3e59b0004558 b0012f1bb1010f3e59b00610b202010a2b5821d81bf459303121231121112311210462f4fdfbf303ec03c9fc37048d0000010044000003e6048d000c004bb2000d0e11123900b0004558b0082f1bb108 1d3e59b0004558b0032f1bb1030f3e59b201010a2b5821d81bf459b2050103111239b00810b20a010a2b5821d81bf459b2070a081112393031010121152135010135211521010290fee60270fc5e013f fec1037cfdba01160245fe7fc49801b701a698c4fe8f000300500000054d048d00110016001c006fb2081d1e111239b00810b014d0b00810b01ad000b0004558b0102f1bb1101d3e59b0004558b0082f 1bb1080f3e59b20f1008111239b00f2fb000d0b2090810111239b0092fb006d0b00910b214010a2b5821d81bf459b00f10b215010a2b5821d81bf459b01ad0b01410b01bd03031011604151404071523 35262435342437353301020511040534262711240349f00114fee9edf3f0feea0117eff3fdf9040118feec03199082011204150ff6cad0fa0f6d6c0ff9d0cdf70d78fdb7fefd15022a15fb85810afdd6 15000001005000000503048d0018004bb200191a11123900b0004558b0122f1bb1121d3e59b0004558b00c2f1bb10c0f3e59b2160c12111239b0162fb000d0b01210b017d0b004d0b01610b20d010a2b 5821d81bf459b00ad030310136363511331106070607112311260203113311141617113303237f6ef301687dfaf3e3fb02f3707df301dd18c2a7012ffecde393af1dfee8011716012a01000136fed1a8 c01802af0001005f00000484049d0023005cb207242511123900b0004558b0192f1bb1191d3e59b0004558b00f2f1bb10f0f3e59b0004558b0222f1bb1220f3e59b00f10b211010a2b5821d81bf459b0 0ed0b000d0b01910b207010a2b5821d81bf459b01110b020d0b021d0303125363635353426232206151514161715213533261135343636333200151514060733152102ad786c948d8a947674fe30b0bd 83f29cea012a6359b6fe2fc822c9b02b9eaca9a428b1c723c8c49b01271691ec84fee3ed198ddf4ac40000010024ffec0552048d0019006bb2161a1b11123900b0004558b0022f1bb1021d3e59b00045 58b00e2f1bb10e0f3e59b0004558b0182f1bb1180f3e59b00210b200010a2b5821d81bf459b004d0b005d0b208020e111239b0082fb00e10b20f070a2b5821d81bf459b00810b215010a2b5821d81bf4 5930310121352115211536333216151406233532363534262322071123017efea603adfea08a8ddaf0f0eb737674758185f303c9c4c4ee27d4c6bcc0bd5469726726fde70001004ffff00443049d001d 008fb2031e1f11123900b0004558b00b2f1bb10b1d3e59b0004558b0032f1bb1030f3e59b20f0b03111239b00b10b212010a2b5821d81bf459b2150b03111239b0152fb2ff150171b20f150172b23f15 0171b2cf150171b46f157f150271b4af15bf15025db25f150172b28f150172b216010a2b5821d81bf459b00310b21a010a2b5821d81bf459b21d030b1112393031010604232200113534363633320417 232626232203211521161633323637044211fef7d9ecfeec7eec9cd6010414f30c7d72fb160180fe800a7e83787c0d0184bfd5012c010b44a9ff8adac27069fecfc4949f62700002002400000715048d 001700200076b2042122111239b00410b018d000b0004558b0122f1bb1121d3e59b0004558b0032f1bb1030f3e59b0004558b00b2f1bb10b0f3e59b01210b205010a2b5821d81bf459b00b10b20e010a 2b5821d81bf459b2141203111239b0142fb218010a2b5821d81bf459b00310b219010a2b5821d81bf45930310114060721112103060206232337373636371321113332162511333236353426230715f9 cffe15fea40e0b58ac91340126604e0c15033becdafafd40f167757666017fabd20203c9fe9ceffeff75cd02079fed022bfe6cd00cfe8e6b535163000002007600000718048d0013001c00c1b2011d1e 111239b00110b014d000b0004558b0132f1bb1131d3e59b0004558b0022f1bb1021d3e59b0004558b0102f1bb1100f3e59b0004558b00d2f1bb10d0f3e59b2001013111239b0002fb4af00bf00025db2 3f000171b2cf000171b23f000172b25f000172b2ff000171b20f000172b46f007f000271b4df00ef00025db41f002f00025db29f000172b2040d02111239b0042fb00010b20f010a2b5821d81bf459b0 0410b214010a2b5821d81bf459b00d10b215010a2b5821d81bf45930310121113311333216161514062321112111231133011133323635342623016901fdf3f28cd26fffd2fe1ffe03f3f302f0f16775 7666029e01effe6c5fab70afd001dbfe25048dfda8fe8e6b535163000001002400000552048d00150057b212161711123900b0004558b0032f1bb1031d3e59b0004558b0142f1bb1140f3e59b0004558 b00d2f1bb10d0f3e59b00310b204010a2b5821d81bf459b000d0b2081403111239b0082fb211010a2b5821d81bf459303101213521152115363332161711231134262322071123017efea603adfea086 8edeeb04f374748185f303c9c4c4ed26cfcbfe98015a7c6926fde70000010076fe9f0461048d000b004fb2030c0d11123900b0022fb0004558b0062f1bb1061d3e59b0004558b00a2f1bb10a1d3e59b0 004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b208010a2b5821d81bf459b009d030312121112311211133112111330461fe8af3fe7ef30205f3fe9f0161048dfc3603ca000200760000 0428048d000b0014005eb2081516111239b00810b00cd000b0004558b00a2f1bb10a1d3e59b0004558b0082f1bb1080f3e59b00a10b200010a2b5821d81bf459b2030a08111239b0032fb00810b20c01 0a2b5821d81bf459b00310b212010a2b5821d81bf459303101211533161610062321112101323635342627231103b2fdb7fccff4f8d9fe1f033cfea868737066f603cbe003c4fea8cc048dfc3663544f 5d01fe9c00020027feaf0515048d000f0015005bb2131617111239b01310b005d000b00d2fb0004558b0052f1bb1051d3e59b0004558b00b2f1bb10b0f3e59b200010a2b5821d81bf459b007d0b008d0 b00d10b00ad0b00810b010d0b011d0b00510b212010a2b5821d81bf4593031373e02371321113311231121112313212111210702824a4223050c033d96f2fcf7f301017401f0fea1070dc35186b47e01 c1fc36fdec0151feaf02140306fcfeae0001001a0000061f048d0015009eb201161711123900b0004558b0112f1bb1111d3e59b0004558b00e2f1bb10e1d3e59b0004558b00a2f1bb10a1d3e59b00045 58b0062f1bb1060f3e59b0004558b0032f1bb1030f3e59b0004558b0152f1bb1150f3e59b20c030e111239b00c2fb23f0c0171b25f0c0172b2cf0c0171b4af0cbf0c025db48f0c9f0c0272b00fd0b201 010a2b5821d81bf459b004d0b2080f04111239b213010f11123930310123112311230321010121133311331133132101012103f55ff360fcfed3015cfec4011ef754f354f7011efec2015efed301d5fe 2b01d5fe2b02540239fe2001e0fe2001e0fdd0fda30000010042fff003e7049d0027008ab226282911123900b0004558b00a2f1bb10a1d3e59b0004558b0162f1bb1160f3e59b00a10b203010a2b5821 d81bf459b2060a16111239b2260a16111239b0262fb2cf260171b23f260171b4af26bf26025db2ff260171b20f260172b25f260172b223010a2b5821d81bf459b2102326111239b21c160a111239b016 10b21e010a2b5821d81bf45930310134262322061523343633321615140607161615140423222627263533163332363534272335333602e2706b5b66f3f3c3d8f46e5d6f6efefedc5daf3f7cf30bca77 74e0949ac70343464f463c94b3a7965b8a2724915b9fb52d2f5b9f935748a603b004000100760000046e048d0009004cb2000a0b11123900b0004558b0002f1bb1001d3e59b0004558b0082f1bb1081d 3e59b0004558b0052f1bb1050f3e59b0004558b0032f1bb1030f3e59b2040300111239b2090508111239303101331123110123113311037bf3f3fdeef3f3048dfb730323fcdd048dfce0000100760000 0440048d000c0077b2000d0e11123900b0004558b0082f1bb1081d3e59b0004558b0052f1bb1051d3e59b0004558b0022f1bb1020f3e59b0004558b00c2f1bb10c0f3e59b2060205111239b0062fb23f 060171b25f060172b2cf060171b4af06bf06025db48f069f060272b201010a2b5821d81bf459b20a010611123930310123112311331133012101012101d36af3f3630138011dfe7201adfed101d5fe2b 048dfe2001e0fdc5fdae0001002400000455048d0010004db204111211123900b0004558b0002f1bb1001d3e59b0004558b0012f1bb1010f3e59b0004558b0092f1bb1090f3e59b00010b203010a2b58 21d81bf459b00910b20c010a2b5821d81bf459303101112311210306020607233737363637130455f3fea40f0c57aa8c3a0127624a0c16048dfb7303c9fe9fedfefe7801cd040ba0e6022b000001001f ffec0439048d000f0043b200101111123900b0004558b00f2f1bb10f1d3e59b0004558b0022f1bb1021d3e59b0004558b0082f1bb1080f3e59b201080f111239b20b010a2b5821d81bf4593031011713 21010e022327371732370121022913f3010afe70385a7e5a6601576033fe5b010e024b370279fc7e7e693805c00461037f0000010076feaf0524048d000b0042b2090c0d11123900b0032fb0004558b0 072f1bb1071d3e59b0004558b00a2f1bb10a1d3e59b0004558b0052f1bb1050f3e59b208010a2b5821d81bf459b000d030312533032311211133112111330462c214ddfc43f30205f4c3fdec0151048d fc3603ca0001004100000416048d00110046b204121311123900b0004558b0092f1bb1091d3e59b0004558b0102f1bb1101d3e59b0004558b0012f1bb1010f3e59b20d0109111239b00d2fb204010a2b 5821d81bf45930312123110623222627113311141633323711330416f38681eaf001f36f798285f301aa26d2d10166fe9e776c26021f000100760000060e048d000b0041b2070c0d11123900b0004558 b0032f1bb1031d3e59b0004558b0012f1bb1010f3e59b204010a2b5821d81bf459b00310b006d0b00410b008d0b00610b00ad03031212111331121113311211133060efa68f3015ff30160f3048dfc36 03cafc3603ca00010076feaf06d1048d000f0041b20b101111123900b0032fb0004558b0072f1bb1071d3e59b0004558b0042f1bb1040f3e59b200010a2b5821d81bf459b00dd0b009d0b00710b00ad0 b00ed0303125330323112111331121113311211133060fc214ddfa96f3015ff30160f4c3fdec0151048dfc3603cafc3603ca0002000a0000051b048d000c0015005eb2081617111239b00810b014d000 b0004558b0072f1bb1071d3e59b0004558b0032f1bb1030f3e59b00710b205010a2b5821d81bf459b20a0703111239b00a2fb00310b20d010a2b5821d81bf459b00a10b213010a2b5821d81bf4593031 01140607211121352111333216013236353426272311051bf9cffe15fea20252ebdbf9fe3266757162f9017fabd20203c9c4fe6cd0fe9a6b534f6302fe8effff0076000005a9048d0026020800000007 01c2043200000002007600000428048d000b0014004db2031516111239b00310b00cd000b0004558b0062f1bb1061d3e59b0004558b0042f1bb1040f3e59b2070406111239b0072fb213010a2b5821d8 1bf459b00410b214010a2b5821d81bf45930310114062321113311333216160132363534262723110428ffd2fe1ff3f28cd26ffe3266757162f9017fafd0048dfe6c5fabfed46b534f6302fe8e000001 003cfff00430049d001d0087b2031e1f11123900b0004558b0122f1bb1121d3e59b0004558b01a2f1bb11a0f3e59b2001a12111239b203010a2b5821d81bf459b209121a111239b0092fb2cf090171b2 3f090171b46f097f090271b4af09bf09025db2ff090171b20f090172b25f090172b206010a2b5821d81bf459b01210b20b010a2b5821d81bf459b20e121a111239303101161633323637213521022322 0607233624333200171714060623222427012f0d7c7882800afe7f018016fb727d0cf3140104d6e201170c017bea9bdcfef80f018470629f94c401316970c2dafee8f075a9ff88daba0000020076fff0 0641049d0013002100afb2042223111239b00410b019d000b0004558b0102f1bb1101d3e59b0004558b00b2f1bb10b1d3e59b0004558b0032f1bb1030f3e59b0004558b0082f1bb1080f3e59b20d080b 111239b00d2fb4af0dbf0d025db46f0d7f0d0271b2ff0d0171b20f0d0172b48f0d9f0d0272b25f0d0172b2cf0d0171b23f0d0171b41f0d2f0d025db2cf0d0172b206010a2b5821d81bf459b01010b217 010a2b5821d81bf459b00310b21e010a2b5821d81bf4593031011000232200272311231133113336003332001127342623220615151416333236350641fedfeddefee213bcf2f2bc14011ddcf00120f2 9688869899878894022cfef8fecc0110e2fe1e048dfe18e9010ffec7fef508b7c0c0b735b2c7c3b60002004300000412048d000c0015005ab2061617111239b00610b010d000b0004558b0072f1bb107 1d3e59b0004558b0092f1bb1090f3e59b2110907111239b0112fb20a010a2b5821d81bf459b2010a11111239b00910b00cd0b00710b212010a2b5821d81bf45930313301263534363321112311230313 1416333311232206430116d6f0d301ccf3f1e62e616bdddd616b020a56d1a3b9fb7301bcfe4403224a59014a57000001000a000003ff048d000d0050b2010e0f11123900b0004558b0082f1bb1081d3e 59b0004558b0022f1bb1020f3e59b2070208111239b0072fb204070a2b5821d81bf459b001d0b00810b20b010a2b5821d81bf459b00710b00cd03031012311231123353311211521113302a7d6f3d4d4 0321fdd2d601e6fe1a01e6aa01fdc4fec7000001001afeaf066d048d001900a4b2081a1b11123900b0032fb0004558b0112f1bb1111d3e59b0004558b0052f1bb1050f3e59b0004558b0092f1bb1090f 3e59b0004558b00d2f1bb10d0f3e59b2170911111239b0172fb23f170171b25f170172b2cf170171b4af17bf17025db48f179f170272b207010a2b5821d81bf459b2000717111239b00510b201010a2b 5821d81bf459b00710b00bd0b20f1707111239b01710b012d0b01110b014d0b018d03031011333112311230323112311230321010121133311331133132104c1eebed0abfd5ff360fcfed3015cfec401 1ef754f354f7011e025dfe65fded015101d5fe2b01d5fe2b02540239fe2001e0fe2001e000010076feaf047c048d00100088b200111211123900b0042fb0004558b00c2f1bb10c1d3e59b0004558b00f 2f1bb10f1d3e59b0004558b0092f1bb1090f3e59b0004558b0062f1bb1060f3e59b20d090c111239b00d2fb23f0d0171b25f0d0172b2cf0d0171b4af0dbf0d025db48f0d9f0d0272b208010a2b5821d8 1bf459b200080d111239b00610b201010a2b5821d81bf4593031010133112311230123112311331133012102930121c8d09bfec26af3f3630138011d0252fe70fded015101d5fe2b048dfe2001e00001 0076000004fe048d00140080b205151611123900b0004558b0142f1bb1141d3e59b0004558b0062f1bb1061d3e59b0004558b0112f1bb1110f3e59b0004558b00a2f1bb10a0f3e59b2001114111239b0 002fb23f000171b25f000172b2cf000171b4af00bf00025db48f009f000272b004d0b00010b210010a2b5821d81bf459b00cd0b2080c0011123930310133353315330121010121012315233523112311 33016947a3370138011cfe7201aefed1fec23ea347f3f302addede01e0fdc4fdaf01d5cbcbfe2b048d00000100240000054e048d000e0085b2090f1011123900b0004558b0072f1bb1071d3e59b00045 58b00a2f1bb10a1d3e59b0004558b0022f1bb1020f3e59b0004558b00e2f1bb10e0f3e59b2080207111239b0082fb23f080171b25f080172b2cf080171b4af08bf08025db48f089f080272b201010a2b 5821d81bf459b00710b204010a2b5821d81bf459b20c0108111239303101231123112135211133012101012102e16af3fea00253630138011dfe7201adfed101d5fe2b03cac3fe2001e0fdc4fdaf0002 004fffeb059804a50023002e008cb2152f30111239b01510b024d000b0004558b01b2f1bb11b1d3e59b0004558b00b2f1bb10b1d3e59b0004558b0042f1bb1040f3e59b0004558b0002f1bb1000f3e59 b202041b111239b0022fb00b10b20c010a2b5821d81bf459b00410b213010a2b5821d81bf459b00010b223010a2b5821d81bf459b00210b026d0b01b10b22c010a2b5821d81bf4593031052227062320 00033534003315220615151416333337260335341233321217151007163301101736373534262322110598e3ae91a9fedafeac040108db717fcbc01b1bc002dcbfc6dd01a35f5cfd94bea201535bb310 393e013c01183afe012eccb4b126cbcd02aa011e2cea010dfefcec48feffad0b01d2fef46f78f335a090fed2ffff000500000436048d002601d20000000701de003bfed500010015feaf048b048d000f 005ab20a101111123900b0072fb0004558b0012f1bb1011d3e59b0004558b00f2f1bb10f1d3e59b0004558b00b2f1bb10b0f3e59b0004558b0092f1bb1090f3e59b2000f0b111239b204010a2b5821d8 1bf459b20a0b0f1112393031011321010133112311230303210101210227f2011cfe890109c4cf92fffafee40181fe88011a02fa0193fdbefe77fded01510199fe67024b024200010024feaf062e048d 000f005cb209101111123900b0022fb0004558b0082f1bb1081d3e59b0004558b00e2f1bb10e1d3e59b0004558b0042f1bb1040f3e59b200010a2b5821d81bf459b00810b206010a2b5821d81bf459b0 0ad0b00bd0b00010b00cd0b00dd0303125330323112111213521152111211133056ac414defc44fea403a2feac0206f2c3fdec015103c9c4c4fcfa03ca000001004100000416048d0017004fb2041819 11123900b0004558b00c2f1bb10c1d3e59b0004558b0162f1bb1161d3e59b0004558b0012f1bb1010f3e59b210010c111239b0102fb207010a2b5821d81bf459b004d0b01010b013d030312123110607 152335262627113311141617353315363711330416f34c56a3cccf02f35456a34a58f301aa160accc80dd1bf016afe9f6b690cf3f20918021f00000100760000044b048d00110046b204121311123900 b0004558b0012f1bb1011d3e59b0004558b0102f1bb1100f3e59b0004558b0092f1bb1090f3e59b2041001111239b0042fb20d010a2b5821d81bf4593031133311363332161511231134262322071123 76f38680edeff375748185f3048dfe5626d6d1fe9e01617c6926fde00002000afff005a804a3001b00230064b20d2425111239b00d10b01dd000b0004558b00e2f1bb10e1d3e59b0004558b0002f1bb1 000f3e59b2200e00111239b0202fb212010a2b5821d81bf459b003d0b02010b00ad0b00010b215010a2b5821d81bf459b00e10b21c010a2b5821d81bf459303105200027262635331416173e02332000 1115211221323737170606032206072135342603c9fefafec00caebfc15458098ff19101000117fcc012014f86732f413bc5a180a008024c95100111ea0bddbb5d760c92e47efee5fef795fed02b12ba 212c03eea58c168695000002004ffff0048104a30016001e005eb2081f20111239b00810b017d000b0004558b0002f1bb1001d3e59b0004558b0082f1bb1080f3e59b20d0008111239b00d2fb00010b2 10010a2b5821d81bf459b00810b217010a2b5821d81bf459b00d10b21a010a2b5821d81bf4593031012000171514060623200011352126262322070727363613323637211514160239010b013b028cf9 96fefefeeb033f07b3a686762d4140c998819e0afdb49404a3fedcf97a9bf988011c010895969a2c11ba222bfc12a38e1686950000010042ffec03e8048d00190069b2121a1b11123900b0004558b002 2f1bb1021d3e59b0004558b00b2f1bb10b0f3e59b00210b200010a2b5821d81bf459b2040200111239b2190b02111239b0192fb005d0b20f0b02111239b00b10b212010a2b5821d81bf459b01910b218 070a2b5821d81bf45930310121352117011616151404232226353316163332363534232335028dfdde035201fec6a2c2ff00dfd0f7f30471657373f17d03c9c49bfec014bf8ba8c0b9a149505a53b0bb 0003004ffff0046f049d000e0015001c007eb2031d1e111239b00310b00fd0b00310b016d000b0004558b00b2f1bb10b1d3e59b0004558b0032f1bb1030f3e59b00b10b20f010a2b5821d81bf459b213 0b031112397cb0132f18b460137013025db430134013025db2f013015db200130171b00310b216010a2b5821d81bf459b01310b219010a2b5821d81bf459303101100023220011353412363332001101 22060721262603323637211616046ffedfedecfeda85f09bf00120fdf079940e02360e937879910efdcc0f95022cfef8fecc0135010c2eac01078bfec7fef5017f9d95959dfcdb9d93939d0000010038 0000041a049d002700aeb225282911123900b0004558b01d2f1bb11d1d3e59b0004558b00c2f1bb10c0f3e59b2061d0c111239b0062fb20f06015db001d0b0012fb2cf01015d40091f012f013f014f01 045db20001015db202020a2b5821d81bf459b00610b207020a2b5821d81bf459b00c10b20a010a2b5821d81bf459b00ed0b00fd0b00710b011d0b00610b013d0b00210b016d0b00110b018d0b01d10b2 24010a2b5821d81bf459b2212401111239b20c21015d30310121152117152115210607210721353336372335333527233533272636333216152334262322061701c40183fe8203017bfe731226029801 fc650a341296a1039e990106d8bfc4d7f354534d570502ba924216934535c3c30e6c930e4a9227ceeed0b65a677e790000010046fff003b0049e002200a0b20a232411123900b0004558b0162f1bb116 1d3e59b0004558b0092f1bb1090f3e59b2221609111239b0222fb20f22015db410222022025db200020a2b5821d81bf459b00910b204010a2b5821d81bf459b00010b00cd0b02210b00ed0b02210b013 d0b0132fb2cf13015db61f132f133f13035db20013015db210020a2b5821d81bf459b01610b21b010a2b5821d81bf459b01310b01dd0b01010b01fd03031012116163332371706232224272335333523 3533363633321707262322072115211521034efe83117b6f50791b766ed4feff1a979292981affd36c7a165b75d622017cfe7d018301846a681cbf1fd0c4925c93c3d620bf1cd6935c00000400760000 07c7049e0003000f001d002700aab21e2829111239b01e10b001d0b01e10b004d0b01e10b010d000b0004558b0262f1bb1261d3e59b0004558b0242f1bb1241d3e59b0004558b0062f1bb1061d3e59b0 004558b0212f1bb1210f3e59b0004558b01f2f1bb11f0f3e59b00610b00dd0b00d2fb002d0b0022fb6000210022002035db201020a2b5821d81bf459b00d10b213020a2b5821d81bf459b00610b21a02 0a2b5821d81bf459b2202421111239b2251f261112393031252135210134362016151514062026351714163332363735342623220615012301112311330111330788fdc5023bfd8abf0136c0befecac1 af5a535058025d4f4e5dfea6f2fdf4f3f3020cf2c89501f296b9b89c4896b8b89b0557656254535764635bfcb4031bfce5048dfce4031c0000020028000004aa048d0015001e008cb20d1f20111239b0 0d10b017d000b0004558b00c2f1bb10c1d3e59b0004558b0032f1bb1030f3e59b206030c111239b0062fb205010a2b5821d81bf459b001d0b00610b00ad0b00a2fb60f0a1f0a2f0a035db68f0a9f0aaf 0a035db41f0a2f0a0271b209010a2b5821d81bf459b013d0b00610b014d0b00a10b016d0b00c10b21e010a2b5821d81bf459303125211523352335333523353311213216100607211521013332363534 26232302f6fef5f3d0d0d0d001ebd1f6edc8fef6010bfef5f86173755ef9999999b64db7023ad3feb4cd054d0104675556650002007cffec04460600000f001a0064b2131b1c111239b01310b00cd000 b0092fb0004558b00c2f1bb10c1b3e59b0004558b0032f1bb1030f3e59b0004558b0062f1bb1060f3e59b2050c03111239b20a0c03111239b00c10b213010a2b5821d81bf459b00310b218010a2b5821 d81bf45930310114022322270723113311363332121127342623220711163332360446f3c7c06d11d2f369b2ccf0f38b7b9a4447997a8a0211f4fecf8e7a0600fdd27cfed6fefa08a6bb85fe3787bc00 00010050ffec0400044e001d004bb2171e1f11123900b0004558b0102f1bb1101b3e59b0004558b0082f1bb1080f3e59b200010a2b5821d81bf459b2030810111239b2141008111239b01010b217010a 2b5821d81bf459303125323637330e022322003535343636333216172326262322061515141602425a7a06e4047aca74e6fef27ae198c3f406e407785c798585ae694f66b064012bfe199efb87e4b45f 76b3b21badb00002004fffec041706000011001c0064b21a1d1e111239b01a10b004d000b0072fb0004558b0042f1bb1041b3e59b0004558b00d2f1bb10d0f3e59b0004558b0092f1bb1090f3e59b206 040d111239b20b040d111239b00d10b215010a2b5821d81bf459b00410b21a010a2b5821d81bf459303113343636333217113311232706232226263537141633323711262322064f70cd82ac6af3d311 6cbb7ecb74f38d7b944646927d8d02269ffd8c770229fa0075898cfd9b019dc28101d77dc100ffff005b000002b205b500060015b3000002004cffec0455044e000f00190043b2041a1b111239b00410 b017d000b0004558b0042f1bb1041b3e59b0004558b00c2f1bb10c0f3e59b212010a2b5821d81bf459b00410b217010a2b5821d81bf45930311334363633320015151406062322003517141632363534 2622064c82eb96e601207fed98e6fee1f295fc9397f89502279ffd8bfecdfc0d9dfc8d0131fe09a0c4c4b59fc5c60002007cfe600444044e0010001b006eb2191c1d111239b01910b00dd000b0004558 b00d2f1bb10d1b3e59b0004558b00a2f1bb10a1b3e59b0004558b0072f1bb107113e59b0004558b0042f1bb1040f3e59b2060d04111239b20b0d04111239b00d10b214010a2b5821d81bf459b00410b2 19010a2b5821d81bf45930310114060623222711231133173633321217073426232207111633323604446fc881b16cf3d90e6cbac1ef0af1917c92444593789302119efd8a74fe0005da7185feebec27 9fc278fe1778c3000002004ffe600416044e0010001b006bb2191c1d111239b01910b004d000b0004558b0042f1bb1041b3e59b0004558b0072f1bb1071b3e59b0004558b0092f1bb109113e59b00045 58b00d2f1bb10d0f3e59b206040d111239b20b040d111239b214010a2b5821d81bf459b00410b219010a2b5821d81bf4593031133436363332173733112311062322022737141633323711262322064f 6fcd86b76b11d2f36aaabef60bf293789046488c7e8f0226a2fc8a826efa2601fc70011ce2279ec57601f473c60000020053ffec040b044e0016001e007cb2081f20111239b00810b017d000b0004558 b0082f1bb1081b3e59b0004558b0002f1bb1000f3e59b21b0800111239b01b2fb4bf1bcf1b025db45f1b6f1b0271b41f1b2f1b0271b28f1b015db4ef1bff1b0271b20c070a2b5821d81bf459b00010b2 10010a2b5821d81bf459b00810b217010a2b5821d81bf4593031052200353534363633321215152116163332363717060603220607213534260276f2fecf7de28bddf1fd3e0fa98d5592313a3fbda766 7c1001d073140128f7219ef98bfef4f77b859d2f20a63239039f8d7c1a707f0000020051fe560404044e001900240083b2222526111239b02210b00bd000b0004558b0032f1bb1031b3e59b0004558b0 062f1bb1061b3e59b0004558b00b2f1bb10b113e59b0004558b0172f1bb1170f3e59b2050317111239b00b10b211010a2b5821d81bf459b20f1117111239b2150317111239b01710b21d010a2b5821d8 1bf459b00310b222010a2b5821d81bf45930311334123332173733111400232226273716333236353506232202371416333237112623220651e7c3bd6b11d0fefaed57af373575838e826aaebeeaf281 739743449476800226fd012b8672fc10f2fefe2e21b03f96942276012ff6a8b78501d17fb5000001006bffeb052605c5001d0040b20c1e1f11123900b0004558b00c2f1bb10c1f3e59b0004558b0032f 1bb1030f3e59b00c10b213010a2b5821d81bf459b00310b21a010a2b5821d81bf4593031010600232224022735341224333200172326262322021515141233323637052417fed2f9b6fedca0019e0120 b7fb013417fd16a390acccd2ac919b1601dae9fefab40145d23cd5014ab4fef3e99892fee6ef34ebfee48f960001006bffeb052605c500200055b20c212211123900b0004558b00c2f1bb10c1f3e59b0 004558b0032f1bb1030f3e59b00c10b212010a2b5821d81bf459b00310b219010a2b5821d81bf459b2200c03111239b0202fb21d010a2b5821d81bf45930312506042322240227353412243332041723 02212202071514123332363711213521052646fedcb0c0fecead029f0123b7f8012b1ff92efee9aad303e8bc649b1ffedd021fbc5f72b20148d131d9014fb6f0e30107fee5e933ecfedf3024011bc000 0002009b0000051705b0000b00150046b2031617111239b00310b00fd000b0004558b0012f1bb1011f3e59b0004558b0002f1bb1000f3e59b00110b20c010a2b5821d81bf459b00010b20d010a2b5821 d81bf4593031331121320412171514020407031133321235353402239b01bec80141b203b0fec0ccc4aedcf8f1da05b0b1fec3c838ccfebfb20304e4fbe6010ef026ea010c000002006bffeb057205c5 001100200046b2042122111239b00410b01dd000b0004558b00d2f1bb10d1f3e59b0004558b0042f1bb1040f3e59b00d10b215010a2b5821d81bf459b00410b21d010a2b5821d81bf459303101140204 23222402273534122433320412170734022322021515141616333212370572a6fed8b4b2fed8aa01a5012ab4b20126a804fbdcada9df66b66ea4d80a02c3cefeb0baba014ec931cb014dc0b7feb9c612 e40122fedbe82593f1860109da000002006bff03057205c5001400230046b2082425111239b00810b020d000b0004558b0102f1bb1101f3e59b0004558b0082f1bb1080f3e59b01010b218010a2b5821 d81bf459b00810b220010a2b5821d81bf459303101140207170725062322240227353412242004121707340223220215151416163332123505729789efa5fed5433eb3fedaaa02a7012801680127a801 fbdcadaade66b56faed902c6cafebd62c094f50db7014dcb2ed00152bbb7feafce05ec011ffeddef1d97f2840120f50000010097000002ef048c0006003200b0004558b0052f1bb1051d3e59b0004558 b0002f1bb1000f3e59b2040005111239b0042fb203010a2b5821d81bf45930312123110535253302eff3fe9b02391f03697acdd00001006e0000042c049e00190059b2091a1b11123900b0004558b011 2f1bb1111d3e59b0004558b0002f1bb1000f3e59b218010a2b5821d81bf459b2021800111239b2030011111239b01110b209010a2b5821d81bf459b20c0011111239b217110011123930312121350136 363534262322061523343636333216151406070121042cfc6001fb4639695a677bf379d785caea576efeb102499f01ba3f6340485a786073bc6ab79c5a9f66fed600000100760000039705c400070032 b203080911123900b0004558b0062f1bb1061d3e59b0004558b0052f1bb1050f3e59b00610b202010a2b5821d81bf4593031013311211123112102a4f3fdd2f3022e05c4fe05fc37048d0001000ffea3 03f2048d00190059b2121a1b11123900b00c2fb0004558b0022f1bb1021d3e59b200010a2b5821d81bf459b2040002111239b2050c02111239b0052fb00c10b211010a2b5821d81bf459b00510b21703 0a2b5821d81bf459b219170511123930310121352115011616151406042322273716333236353426232335029efdba0377fe9dabdb90fef2b0c7ce399dada4c4aab74803c9c48ffe801af7b0a3f38467 b658b89296927b0000020035fec4048b048c000a000e005200b0004558b0092f1bb1091d3e59b0004558b0022f1bb1020f3e59b0004558b0062f1bb1060f3e59b200010a2b5821d81bf459b00610b005 d0b0052fb2080600111239b00010b00cd0b20d0902111239303125331523112311212701330121110703d5b6b6f2fd580602a6fafd6401aa17c2c3fec5013b9403f9fc3602802a00ffff004b028d02aa 05b8030701d400000298001300b0004558b00a2f1bb10a1f3e59b010d0303100ffff0035029802be05ad030701d800000298001300b0004558b0092f1bb1091f3e59b00dd0303100ffff004f028d02ae 05ad030701d900000298001000b0004558b0012f1bb1011f3e593031ffff004d028d02b905ba030701da00000298001300b0004558b0002f1bb1001f3e59b014d0303100ffff0036029802ae05ad0307 01db00000298001000b0004558b0052f1bb1051f3e593031ffff004b028d02aa05b8030701dc00000298001900b0004558b0112f1bb1111f3e59b019d0b01110b01fd0303100ffff0046028f02a305b8 030701dd00000298001300b0004558b0082f1bb1081f3e59b01ad030310000010066fea0041e048c001c005db2191d1e11123900b00e2fb0004558b0012f1bb1011d3e59b203010a2b5821d81bf459b2 07010e111239b0072fb219010a2b5821d81bf459b2050719111239b00e10b213010a2b5821d81bf459b2111319111239b21c191311123930311313211521033637361215140606232227371633323635 342623220607875a0329fd9a2d6586cfed85f5a5e4b54a84bd8fab8e7853661b01750317d2feaa320202fef7e498f38275b263b39487a2353b0000010043fec40410048c0006002500b0012fb0004558 b0052f1bb1051d3e59b203010a2b5821d81bf459b20003051112393031010123012135210410fdb6f3023efd3203cd0406fabe0505c30002004ffff0066d049d0014001e0091b2161f20111239b01610 b00bd000b0004558b00a2f1bb10a1d3e59b0004558b00b2f1bb10b1d3e59b0004558b0002f1bb1000f3e59b0004558b0022f1bb1020f3e59b00b10b20d010a2b5821d81bf459b210000b111239b0102f b211010a2b5821d81bf459b00010b213010a2b5821d81bf459b00210b215010a2b5821d81bf459b00a10b218010a2b5821d81bf459303121210522001135341236330521152111211521112105371127 220615151416066dfd47feadecfeda85f09b015302b8fdb701f6fe0a024cfbf4cdcf869899100135010c2eac01078b10c4fef2c3feca0f08031409c0b735b2c700020073feb4045404a0001800240053 b21f2526111239b01f10b00cd000b0142fb0004558b00c2f1bb10c1d3e59b01410b200010a2b5821d81bf459b219140c1112397cb0192f18b205010a2b5821d81bf459b00c10b21f010a2b5821d81bf4 5930310532363706232202353436363332001115140204232227371613323735342623220615141601e998bd1972aad1f77bda87f1011491fef3b29e842f7dd1b052887f6d878a89c8be5a0112e599ed 80fed1fef6cee5feb2b23cb62f01e978aca5b4b1928ab00000020062ffeb048504a0000d001a0046b2031b1c111239b00310b017d000b0004558b00a2f1bb10a1d3e59b0004558b0032f1bb1030f3e59 b00a10b211010a2b5821d81bf459b00310b216010a2b5821d81bf45930310110002322260235100033321612073426200615151416333236370485fee3f39ef382011ff29ff281f29bfef6999a868597 02023efee9fec48e010cc70116013e8efef3a7b8c7c8ba2cb5cdc5b4ffffffb5fe4b0193043a0206009b0000ffffffb5fe4b0193043a0206009b0000ffff008f00000182043a0006008c0000fffffffb fe5c0182043a0026008c0000000600a3d20affff008f00000182043a0006008c000000010076ffeb0416049c00210065b201222311123900b0004558b0152f1bb1151d3e59b0004558b01f2f1bb11f0f 3e59b0004558b0102f1bb1100f3e59b01f10b202010a2b5821d81bf459b20a1f15111239b00a2fb019d0b208030a2b5821d81bf459b01510b20d010a2b5821d81bf45930312516333236353426232335 132623221511231136363332161703161615140623222701eb4b484d5c7c7454ca4651b1ef01d1cf78cd68f9a1aad9af7c6cdb3165525847a3010139f9fd1c02f0d7d5616ffed417a481afca3600ffff 00470209025402cd0206001100000002fff7000004f005b0000f001d0082b2101e1f111239b01010b006d000b0004558b0052f1bb1051f3e59b0004558b0002f1bb1000f3e59b2030005111239b0032f b2cf03015db23f030171b26f030171b21f030171b29f03015db20f030172b202070a2b5821d81bf459b011d0b00010b212010a2b5821d81bf459b00510b21b010a2b5821d81bf459b00310b01dd03031 331123353311213204121515140204231323113332363535342623231133b2bbbb01aec1012ba4a5fecfc53fe5a3cbd5cec4b1e5028caa027aacfec4cc49cffec6aa028cfe3efdf046edfafe52000002 fff7000004f005b0000f001d0082b2101e1f111239b01010b006d000b0004558b0052f1bb1051f3e59b0004558b0002f1bb1000f3e59b2030005111239b0032fb2cf03015db23f030171b26f030171b2 1f030171b29f03015db20f030172b202070a2b5821d81bf459b011d0b00010b212010a2b5821d81bf459b00510b21b010a2b5821d81bf459b00310b01dd0303133112335331121320412151514020423 1323113332363535342623231133b2bbbb01aec1012ba4a5fecfc53fe5a3cbd5cec4b1e5028caa027aacfec4cc49cffec6aa028cfe3efdf046edfafe52000001ffd400000416060000180074b20c191a 11123900b0152fb0004558b0042f1bb1041b3e59b0004558b0072f1bb1070f3e59b0004558b00f2f1bb10f0f3e59b22f15015db20f15015db2180f15111239b0182fb200070a2b5821d81bf459b20204 0f111239b00410b20c010a2b5821d81bf459b00010b011d0b01810b013d03031012311363320131123113426232207112311233533353315330271e777b6015a05f3615e9248f3c3c3f3e704c7fefd8a fe75fd3d02ba705d82fcfb04c7aa8f8f0001002d000004b005b0000f004c00b0004558b00a2f1bb10a1f3e59b0004558b0022f1bb1020f3e59b20f0a02111239b00f2fb200070a2b5821d81bf459b004 d0b00f10b006d0b00a10b208010a2b5821d81bf459b00cd030310123112311233533112135211521113303b9cffbd3d3fe3e0483fe3acf0312fcee0312aa0128ccccfed80001ffe8ffec02850541001c 0072b2001d1e11123900b0004558b01b2f1bb11b1b3e59b0004558b0112f1bb1110f3e59b01b10b001d0b01b10b218010a2b5821d81bf459b004d0b01b10b017d0b0172fb005d0b0052fb01710b21407 0a2b5821d81bf459b008d0b01110b20c010a2b5821d81bf459b01b10b01cd0b01c2f3031011133152315331523111416333237150623201111233533352335331101adbfbfd8d8313f2a2b534dfee8d2 d2b2b20541fef9b4a5aafef33e370abc1701350116aaa5b40107ffff00120000054207360226002500000107004401230136001300b0004558b0042f1bb1041f3e59b00cdc303100ffff001200000542 07360226002500000107007501c20136001300b0004558b0052f1bb1051f3e59b00ddc303100ffff00120000054207370226002500000107009d00c30136001300b0004558b0042f1bb1041f3e59b00f dc303100ffff001200000542072c022600250000010700a400c50137000900b0042fb016dc303100ffff00120000054207020226002500000107006a00ee0136001600b0004558b0042f1bb1041f3e59 b012dcb01bd03031ffff0012000005420794022600250000010700a20158016a000c00b0042fb010dcb015d03031ffff00120000054207b1022600250000000701df015e011cffff0066fe3c04eb05c4 0226002700000007007901c9fffbffff00940000044c073d0226002900000107004400e8013d001300b0004558b0062f1bb1061f3e59b00ddc303100ffff00940000044c073d02260029000001070075 0187013d001300b0004558b0062f1bb1061f3e59b00edc303100ffff00940000044c073e0226002900000107009d0088013d001300b0004558b0062f1bb1061f3e59b010dc303100ffff00940000044c 07090226002900000107006a00b3013d001600b0004558b0062f1bb1061f3e59b013dcb01cd03031ffffffc8000001a0073d0226002d000001070044ff97013d001300b0004558b0022f1bb1021f3e59 b005dc303100ffff00a30000027d073d0226002d0000010700750035013d001300b0004558b0032f1bb1031f3e59b006dc303100ffffffcb0000027a073e0226002d00000107009dff37013d001300b0 004558b0022f1bb1021f3e59b008dc303100ffffffbf0000028507090226002d00000107006aff62013d001600b0004558b0022f1bb1021f3e59b00bdcb014d03031ffff009400000517072c02260032 0000010700a400ee0137000900b0052fb015dc303100ffff0066ffec051e073602260033000001070044013a0136001300b0004558b00c2f1bb10c1f3e59b020dc303100ffff0066ffec051e07360226 003300000107007501d90136001300b0004558b00d2f1bb10d1f3e59b021dc303100ffff0066ffec051e07370226003300000107009d00da0136001300b0004558b00c2f1bb10c1f3e59b023dc303100 ffff0066ffec051e072c022600330000010700a400dc0137001300b0004558b00d2f1bb10d1f3e59b022dc303100ffff0066ffec051e07020226003300000107006a01050136001600b0004558b00c2f 1bb10c1f3e59b026dcb02fd03031ffff007dffec04bd07360226003900000107004401110136001300b0004558b0092f1bb1091f3e59b012dc303100ffff007dffec04bd073602260039000001070075 01b00136000900b0002fb013dc303100ffff007dffec04bd07370226003900000107009d00b10136001300b0004558b0092f1bb1091f3e59b015dc303100ffff007dffec04bd07020226003900000107 006a00dc0136001600b0004558b0092f1bb1091f3e59b018dcb021d03031ffff0007000004d607360226003d00000107007501870136001300b0004558b0012f1bb1011f3e59b00bdc303100ffff005a ffec03fb06000226004500000107004400ad0000001300b0004558b0172f1bb1171b3e59b02bdc303100ffff005affec03fb060002260045000001070075014c0000000900b0172fb02cdc303100ffff 005affec03fb06010226004500000106009d4d00001300b0004558b0172f1bb1171b3e59b02edc303100ffff005affec03fb05f6022600450000010600a44f01001300b0004558b0172f1bb1171b3e59 b02ddc303100ffff005affec03fb05cc0226004500000106006a7800001600b0004558b0172f1bb1171b3e59b031dcb03ad03031ffff005affec03fb065e022600450000010700a200e20034001600b0 004558b0172f1bb1171b3e59b02fdcb037d03031ffff005affec03fb067c022600450000000701df00e8ffe7ffff004ffe3c03f5044e02260047000000070079013dfffbffff0053ffec040b06000226 004900000107004400a10000001300b0004558b0082f1bb1081b3e59b01fdc303100ffff0053ffec040b06000226004900000107007501400000000900b0082fb020dc303100ffff0053ffec040b0601 0226004900000106009d4100001300b0004558b0082f1bb1081b3e59b022dc303100ffff0053ffec040b05cc0226004900000106006a6c00001600b0004558b0082f1bb1081b3e59b025dcb02ed03031 ffffffb40000018c05f90226008c00000106004483f9001300b0004558b0022f1bb1021b3e59b005dc303100ffff008f0000026905f90226008c00000106007521f9001300b0004558b0032f1bb1031b 3e59b006dc303100ffffffb70000026605fa0226008c00000107009dff23fff9001300b0004558b0022f1bb1021b3e59b008dc303100ffffffab0000027105c50226008c00000107006aff4efff90016 00b0004558b0022f1bb1021b3e59b00bdcb014d03031ffff0079000003f805f6022600520000010600a45501000900b0032fb01cdc303100ffff004fffec043d06000226005300000107004400b60000 001300b0004558b0042f1bb1041b3e59b01cdc303100ffff004fffec043d06000226005300000107007501550000000900b0042fb01ddc303100ffff004fffec043d06010226005300000106009d5600 001300b0004558b0042f1bb1041b3e59b01fdc303100ffff004fffec043d05f6022600530000010600a45801000900b0042fb026dc303100ffff004fffec043d05cc0226005300000107006a00810000 001600b0004558b0042f1bb1041b3e59b022dcb02bd03031ffff0077ffec03f706000226005900000107004400af0000001300b0004558b0072f1bb1071b3e59b012dc303100ffff0077ffec03f70600 02260059000001070075014e0000000900b0062fb013dc303100ffff0077ffec03f706010226005900000106009d4f00001300b0004558b0072f1bb1071b3e59b015dc303100ffff0077ffec03f705cc 0226005900000106006a7a00001600b0004558b0072f1bb1071b3e59b018dcb021d03031ffff000cfe4b03d606000226005d00000107007501160000000900b0012fb012dc303100ffff000cfe4b03d6 05cc0226005d00000106006a4200001600b0004558b00f2f1bb10f1b3e59b017dcb020d03031ffff00120000054206ea0226002500000107007000be013a001300b0004558b0042f1bb1041f3e59b00c dc303100ffff005affec03fb05b4022600450000010600704804000900b0172fb02adc303100ffff001200000542071c022600250000010700a000f60136001300b0004558b0042f1bb1041f3e59b00e dc303100ffff005affec03fb05e6022600450000010700a000800000001300b0004558b0172f1bb1171b3e59b02ddc30310000020012fe52054205b0001600190074b2191a1b111239b01910b016d000 b0004558b0162f1bb1161f3e59b0004558b0142f1bb1140f3e59b0004558b0012f1bb1010f3e59b0004558b00c2f1bb10c113e59b207030a2b5821d81bf459b00110b011d0b0112fb2171416111239b0 172fb213010a2b5821d81bf459b219161411123930310101230606151433323717062322263534370321032101032103031b02273e574a472c2e15495c5f749573fdcc76fef902266201a6d305b0fa50 385e3144178e2c6e5b8d620149fead05b0fc6f025c000002005afe5203fb044e002d003800a6b217393a111239b01710b02fd000b0004558b0172f1bb1171b3e59b0004558b0292f1bb129113e59b000 4558b0042f1bb1040f3e59b0004558b01e2f1bb11e0f3e59b000d0b0002fb2021704111239b20b1704111239b00b2fb01710b20f010a2b5821d81bf459b2120b0f11123940090c121c122c123c12045d b02910b224030a2b5821d81bf459b00410b22e010a2b5821d81bf459b00b10b232010a2b5821d81bf4593031252627062322263534243333353426232206152334363633321617111417152306061514 33323717062322263534033236373523220615141602ff0b0d74a8a3ce0101ef955e60536af376cb7dbee203292a574a472c2e15495c5f7476487f208387885d07194579ba89adb94754655340599b58 bfadfe18925711385e3144178e2c6e5b8c0108463bcc5e564653ffff0066ffec04eb074b0226002700000107007501c0014b000900b00c2fb020dc303100ffff004fffec03f506000226004700000107 007501290000000900b00f2fb01fdc303100ffff0066ffec04eb074c0226002700000107009d00c1014b001300b0004558b00c2f1bb10c1f3e59b020dc303100ffff004fffec03f50601022600470000 0106009d2a00001300b0004558b00f2f1bb10f1b3e59b01fdc303100ffff0066ffec04eb0729022600270000010700a101a70154001300b0004558b00c2f1bb10c1f3e59b026dc303100ffff004fffec 03f505de022600470000010700a101100009001300b0004558b00f2f1bb10f1b3e59b025dc303100ffff0066ffec04eb074c0226002700000107009e00d8014b000900b00c2fb022dc303100ffff004f ffec03f506010226004700000106009e4100000900b00f2fb021dc303100ffff0094000004d2073e0226002800000107009e0067013d000900b0012fb01adc303100ffff004fffec055b060200260048 0000010701a2040104fc000600b01e2f3031ffff00940000044c06f10226002900000107007000830141001300b0004558b0062f1bb1061f3e59b00ddc303100ffff0053ffec040b05b4022600490000 010600703c04000900b0082fb01edc303100ffff00940000044c0723022600290000010700a000bb013d001300b0004558b0062f1bb1061f3e59b00fdc303100ffff0053ffec040b05e6022600490000 010600a07400001300b0004558b0082f1bb1081b3e59b021dc303100ffff00940000044c071b022600290000010700a1016e0146001300b0004558b0062f1bb1061f3e59b014dc303100ffff0053ffec 040b05de022600490000010700a101270009001300b0004558b0082f1bb1081b3e59b026dc30310000010094fe52044c05b0001b0080b2111c1d11123900b0004558b0162f1bb1161f3e59b0004558b0 0f2f1bb10f113e59b0004558b0042f1bb1040f3e59b0004558b0142f1bb1140f3e59b21a1416111239b01a2fb201010a2b5821d81bf459b01410b202010a2b5821d81bf459b003d0b00f10b20a030a2b 5821d81bf459b01610b218010a2b5821d81bf45930310121112115230606151433323717062322263534372111211521112103e7fdaa02bb6f574a472c2e15495c5f7487fd9303b1fd4c0256028afe40 ca385e3144178e2c6e5b865f05b0ccfe6e0000020053fe6d040b044e0023002b00a5b2112c2d111239b01110b024d000b0004558b0192f1bb1191b3e59b0004558b00c2f1bb10c113e59b0004558b011 2f1bb1110f3e59b2021119111239b00c10b207030a2b5821d81bf459b2281911111239b0282fb41f282f280271b4bf28cf28025db28f28015db45f286f280271b4ef28ff280271b21d070a2b5821d81b f459b01110b221010a2b5821d81bf459b2231911111239b01910b224010a2b5821d81bf45930312506070606151433323717062322263534372600273534363633321211152116163332370122060721 35262603fa4971574a472c2e15495c5f7450cffefb067de28bddf1fd3d0b9d77a769fec5647b1101cf0872b86a33385e3144178e2c6e5b66520d0113d73aa2ff8efee6fefe62869c8702568c7d127a7d ffff00940000044c073e0226002900000107009e009f013d001300b0004558b0062f1bb1061f3e59b011dc303100ffff0053ffec040b06010226004900000106009e5800000900b0082fb022dc303100 ffff006affec04f0074c0226002b00000107009d00be014b001300b0004558b00b2f1bb10b1f3e59b021dc303100ffff0052fe56040c06010226004b00000106009d4000001300b0004558b0032f1bb1 031b3e59b027dc303100ffff006affec04f007310226002b0000010700a000f1014b001300b0004558b00b2f1bb10b1f3e59b022dc303100ffff0052fe56040c05e60226004b0000010600a073000013 00b0004558b0032f1bb1031b3e59b028dc303100ffff006affec04f007290226002b0000010700a101a40154001300b0004558b00b2f1bb10b1f3e59b027dc303100ffff0052fe56040c05de0226004b 0000010700a101260009001300b0004558b0032f1bb1031b3e59b02ddc303100ffff006afdf904f005c40226002b0000000701a201bbfe92ffff0052fe56040c06a90226004b0000010701b90127007e 000900b0032fb029dc303100ffff009400000518073e0226002c00000107009d00e2013d001300b0004558b0072f1bb1071f3e59b010dc303100ffff0079000003f8075e0226004c00000107009d0017 015d000900b0102fb013dc303100ffffffb30000029007330226002d0000010700a4ff39013e001300b0004558b0032f1bb1031f3e59b007dc303100ffffff9f0000027c05ef0226008c0000010700a4 ff25fffa000900b0022fb00fdc303100ffffffb90000029006f10226002d000001070070ff320141001300b0004558b0022f1bb1021f3e59b005dc303100ffffffa50000027c05ad0226008c00000107 0070ff1efffd001300b0004558b0022f1bb1021b3e59b005dc303100ffffffdf0000026507230226002d0000010700a0ff6a013d001300b0004558b0022f1bb1021f3e59b007dc303100ffffffcb0000 025105df0226008c0000010700a0ff56fff9001300b0004558b0022f1bb1021b3e59b007dc303100ffff0017fe58019f05b00226002d0000000600a3ee06ffff0000fe52019005d50226004d00000006 00a3d700ffff009d000001a3071b0226002d0000010700a1001c0146001300b0004558b0022f1bb1021f3e59b00cdc303100ffff00a3ffec062605b00026002d00000007002e02420000ffff007dfe4b 039005d50026004d00000007004e020b0000ffff002dffec04ab07370226002e00000107009d01680136001300b0004558b0002f1bb1001f3e59b014dc303100ffffffb5fe4b026b05df0226009b0000 0107009dff28ffde001300b0004558b00c2f1bb10c1b3e59b011dc303100ffff0094fdf9051805b00226002f0000000701a2019dfe92ffff007dfdf9043606000226004f0000000701a2012dfe92ffff 00940000042607360226003000000107007500290136001300b0004558b0052f1bb1051f3e59b008dc303100ffff008a00000262079102260050000001070075001a0191001300b0004558b0032f1bb1 03213e59b006dc303100ffff0094fdf9042605b0022600300000000701a2016dfe92ffff0055fdf9017f0600022600500000000701a20010fe92ffff00940000042605b1022600300000010701a2020a 04ab001000b0004558b00a2f1bb10a1f3e593031ffff008c000002e70602002600500000010701a2018d04fc001000b0004558b0082f1bb108213e593031ffff00940000042605b00226003000000007 00a101cafdd4ffff008c000002eb0600002600500000000700a10164fdafffff00940000051707360226003200000107007501eb0136001300b0004558b0082f1bb1081f3e59b00cdc303100ffff0079 000003f806000226005200000107007501520000000900b0032fb013dc303100ffff0094fdf9051705b0022600320000000701a201dcfe92ffff0079fdf903f8044e022600520000000701a20141fe92 ffff00940000051707370226003200000107009e01030136001300b0004558b0062f1bb1061f3e59b00fdc303100ffff0079000003f806010226005200000106009e6a00000900b0032fb015dc303100 ffffffa5000003f80603022600520000010701a2ff6004fd001000b0004558b0152f1bb115213e593031ffff0066ffec051e06ea0226003300000107007000d5013a001300b0004558b00c2f1bb10c1f 3e59b020dc303100ffff004fffec043d05b4022600530000010600705104000900b0042fb01bdc303100ffff0066ffec051e071c022600330000010700a0010d0136001300b0004558b00c2f1bb10c1f 3e59b022dc303100ffff004fffec043d05e6022600530000010700a000890000001300b0004558b0042f1bb1041b3e59b01edc303100ffff0066ffec051e0735022600330000010700a5016301360016 00b0004558b00d2f1bb10d1f3e59b021dcb025d03031ffff004fffec043d05ff022600530000010700a500df0000001600b0004558b0042f1bb1041b3e59b01ddcb021d03031ffff0094000004de0736 0226003600000107007501710136000900b0042fb01adc303100ffff007c000002f506000226005600000107007500ad0000000900b00b2fb010dc303100ffff0094fdf904de05b00226003600000007 01a2016efe92ffff004ffdf902b4044e022600560000000701a2000afe92ffff0094000004de07370226003600000107009e00890136000900b0042fb01cdc303100ffff0038000002fa060102260056 00000106009ec600000900b00b2fb012dc303100ffff004affec048a073602260037000001070075018e0136000900b0092fb02adc303100ffff004bffec03ca060002260057000001070075013a0000 000900b0092fb029dc303100ffff004affec048a07370226003700000107009d008f0136001300b0004558b0092f1bb1091f3e59b02adc303100ffff004bffec03ca06010226005700000106009d3b00 001300b0004558b0092f1bb1091b3e59b029dc303100ffff004afe41048a05c402260037000000070079019d0000ffff004bfe3803ca044e022600570000000700790144fff7ffff004afdf9048a05c4 022600370000000701a20189fe92ffff004bfdf903ca044e022600570000000701a20130fe92ffff004affec048a07370226003700000107009e00a60136000900b0092fb02cdc303100ffff004bffec 03ca06010226005700000106009e5200000900b0092fb02bdc303100ffff002dfdf904b005b0022600380000000701a20177fe92ffff0008fdf902720541022600580000000701a200c8fe92ffff002d fe4404b005b002260038000000070079018b0003ffff0008fe4102a505410226005800000007007900dc0000ffff002d000004b007370226003800000107009e00980136001300b0004558b0062f1bb1 061f3e59b00ddc303100ffff0008ffec03270683002600580000000701a201cd057dffff007dffec04bd072c022600390000010700a400b30137001300b0004558b0102f1bb1101f3e59b014dc303100 ffff0077ffec03f705f6022600590000010600a45101001300b0004558b00d2f1bb10d1b3e59b014dc303100ffff007dffec04bd06ea0226003900000107007000ac013a000900b0002fb011dc303100 ffff0077ffec03f705b4022600590000010600704a04001300b0004558b0062f1bb1061b3e59b012dc303100ffff007dffec04bd071c022600390000010700a000e40136001300b0004558b0092f1bb1 091f3e59b014dc303100ffff0077ffec03f705e6022600590000010700a000820000001300b0004558b0072f1bb1071b3e59b014dc303100ffff007dffec04bd0794022600390000010700a20146016a 000c00b0002fb016dcb01bd03031ffff0077ffec03f7065e022600590000010700a200e40034000c00b0062fb016dcb01bd03031ffff007dffec04bd0735022600390000010700a5013a0136001600b0 004558b0102f1bb1101f3e59b013dcb017d03031ffff0077ffec042e05ff022600590000010700a500d80000000c00b0062fb013dcb015d030310001007dfe8904bd05b0001f0057b21c202111123900 b0004558b0182f1bb1181f3e59b0004558b0132f1bb1130f3e59b0004558b00e2f1bb10e173e59b2041318111239b209030a2b5821d81bf459b01310b21c010a2b5821d81bf459b01810b01fd0303101 1114060706061514333237170623222635343720003511331114163320111104bd857e3d4f472c2e15495c5f7436ff00fedbfc9490012405b0fc3298e43d29593744178e2c6e5b5545010ceb03cdfc32 929a013403c600010077fe5203f7043a001f0066b21a202111123900b0004558b0172f1bb1171b3e59b0004558b0122f1bb1120f3e59b0004558b01f2f1bb11f0f3e59b0004558b00a2f1bb10a113e59 b205030a2b5821d81bf459b01f10b00fd0b00f2fb01210b21a010a2b5821d81bf459b01710b01dd03031210606151433323717062322263534372706232226351133111433323711331103e2574a472c 2e15495c5f7492056bc5b0b5f3abb13ef3385e3144178e2c6e5b8c61627ecec302bdfd46ce7f0309fbc6ffff0030000006e507370226003b00000107009d01a80136001300b0004558b00c2f1bb10c1f 3e59b00fdc303100ffff0021000005cc06010226005b00000107009d010a0000001300b0004558b00b2f1bb10b1b3e59b011dc303100ffff0007000004d607370226003d00000107009d008801360013 00b0004558b0012f1bb1011f3e59b00bdc303100ffff000cfe4b03d606010226005d00000106009d1700001300b0004558b00f2f1bb10f1b3e59b014dc303100ffff0007000004d607020226003d0000 0107006a00b30136001600b0004558b0082f1bb1081f3e59b010dcb019d03031ffff00500000048c07360226003e00000107007501830136001300b0004558b0072f1bb1071f3e59b00cdc303100ffff 0052000003c006000226005e000001070075011b0000001300b0004558b0072f1bb1071b3e59b00cdc303100ffff00500000048c07140226003e0000010700a1016a013f001300b0004558b0072f1bb1 071f3e59b012dc303100ffff0052000003c005de0226005e0000010700a101020009001300b0004558b0072f1bb1071b3e59b012dc303100ffff00500000048c07370226003e00000107009e009b0136 000900b0072fb00edc303100ffff0052000003c006010226005e00000106009e3300000900b0072fb00edc303100fffffff60000075707420226008100000107007502bb0142001300b0004558b0062f 1bb1061f3e59b015dc303100ffff0048ffec068406010226008600000107007502710001000900b0172fb03fdc303100ffff0069ffa1052207800226008300000107007501e00180001300b0004558b0 102f1bb1101f3e59b02cdc303100ffff004fff77043d05fe022600890000010700750130fffe001300b0004558b0042f1bb1041b3e59b028dc303100ffffffa60000042a048d022601bd0000010701de ff16ff6e004600b21f170171b26f170171b2ff170171b20f170172b6af17bf17cf170372b2ff170172b25f170172b6bf17cf17df170371b23f170171b4df17ef17025db41f172f17025d3031ffffffa6 0000042a048d022601bd0000010701deff16ff6e004600b21f170171b26f170171b2ff170171b20f170172b6af17bf17cf170372b2ff170172b25f170172b6bf17cf17df170371b23f170171b4df17ef 17025db41f172f17025d3031ffff002400000416048d022601cd0000010601de32be000800b2000b015d3031ffff000900000494061e022601ba00000107004400c7001e001300b0004558b0042f1bb1 041d3e59b00cdc303100ffff000900000494061e022601ba0000010700750166001e001300b0004558b0052f1bb1051d3e59b00ddc303100ffff000900000494061f022601ba00000106009d671e0013 00b0004558b0042f1bb1041d3e59b00fdc303100ffff0009000004940614022601ba0000010600a4691f000900b0042fb016dc303100ffff00090000049405ea022601ba00000107006a0092001e0016 00b0004558b0042f1bb1041d3e59b012dcb01bd03031ffff000900000494067c022601ba0000010700a200fc0052001600b0004558b0042f1bb1041d3e59b010dcb018d03031ffff0009000004940699 022601ba0000000701df01020004ffff004ffe410443049d022601bc000000070079016b0000ffff0076000003b5061e022601be0000010700440096001e001300b0004558b0062f1bb1061d3e59b00d dc303100ffff0076000003b5061e022601be0000010700750135001e001300b0004558b0072f1bb1071d3e59b00edc303100ffff0076000003b5061f022601be00000106009d361e001300b0004558b0 062f1bb1061d3e59b010dc303100ffff0076000003b505ea022601be00000106006a611e001600b0004558b0062f1bb1061d3e59b013dcb01cd03031ffffffa60000017e061e022601c2000001070044 ff75001e001300b0004558b0022f1bb1021d3e59b005dc303100ffff00830000025b061e022601c2000001060075131e001300b0004558b0032f1bb1031d3e59b006dc303100ffffffa900000258061f 022601c200000107009dff15001e001300b0004558b0022f1bb1021d3e59b008dc303100ffffff9d0000026305ea022601c200000107006aff40001e001600b0004558b0022f1bb1021d3e59b00bdcb0 14d03031ffff0076000004670614022601c70000010700a40088001f000900b0052fb015dc303100ffff004ffff0046f061e022601c800000107004400d5001e001300b0004558b00b2f1bb10b1d3e59 b01edc303100ffff004ffff0046f061e022601c80000010700750174001e000900b00b2fb01fdc303100ffff004ffff0046f061f022601c800000106009d751e001300b0004558b00b2f1bb10b1d3e59 b021dc303100ffff004ffff0046f0614022601c80000010600a4771f000900b00b2fb028dc303100ffff004ffff0046f05ea022601c800000107006a00a0001e001600b0004558b00b2f1bb10b1d3e59 b024dcb02dd03031ffff0067fff0041e061e022601ce00000107004400b5001e001300b0004558b0082f1bb1081d3e59b011dc303100ffff0067fff0041e061e022601ce0000010700750154001e0013 00b0004558b00f2f1bb10f1d3e59b012dc303100ffff0067fff0041e061f022601ce00000106009d551e001300b0004558b0082f1bb1081d3e59b014dc303100ffff0067fff0041e05ea022601ce0000 0107006a0080001e001600b0004558b0082f1bb1081d3e59b017dcb020d03031ffff000500000436061e022601d2000001070075012d001e001300b0004558b0012f1bb1011d3e59b00bdc303100ffff 00090000049405d2022601ba0000010600706222001300b0004558b0042f1bb1041d3e59b00cdc303100ffff0009000004940604022601ba0000010700a0009a001e001300b0004558b0042f1bb1041d 3e59b00edc30310000020009fe520494048d001600190071b2191a1b111239b01910b016d000b0004558b0002f1bb1001d3e59b0004558b0142f1bb1140f3e59b0004558b0012f1bb1010f3e59b00045 58b00c2f1bb10c113e59b207030a2b5821d81bf459b00110b011d0b2171400111239b0172fb213010a2b5821d81bf459b219001411123930310101230606151433323717062322263534372721072301 03210302bf01d536574a472c2e15495c5f749d59fe1e5ff501d73c0154aa048dfb73385e3144178e2c6e5b9261ebf9048dfd2501ba00ffff004ffff00443061e022601bc0000010700750163001e0009 00b00b2fb01edc303100ffff004ffff00443061f022601bc00000106009d641e001300b0004558b00b2f1bb10b1d3e59b020dc303100ffff004ffff0044305fc022601bc0000010700a1014a00270013 00b0004558b00b2f1bb10b1d3e59b024dc303100ffff004ffff00443061f022601bc00000106009e7b1e000900b00b2fb020dc303100ffff006a0000042a061f022601bd00000106009ef81e000900b0 012fb018dc303100ffff0076000003b505d2022601be0000010600703122001300b0004558b0062f1bb1061d3e59b00ddc303100ffff0076000003b50604022601be0000010600a0691e001300b00045 58b0062f1bb1061d3e59b00fdc303100ffff0076000003b505fc022601be0000010700a1011c0027001300b0004558b0062f1bb1061d3e59b014dc30310000010076fe5203b5048d001b0080b2111c1d 11123900b0004558b0162f1bb1161d3e59b0004558b00f2f1bb10f113e59b0004558b0042f1bb1040f3e59b0004558b0142f1bb1140f3e59b21b1604111239b01b2fb200010a2b5821d81bf459b01410 b202010a2b5821d81bf459b003d0b00f10b20a030a2b5821d81bf459b01610b218010a2b5821d81bf459303101211121152306061514333237170623222635343721112115211121035ffe0a024c5e57 4a472c2e15495c5f7487fdfb033cfdb701f601f8fecac2385e3144178e2c6e5b865f048dc4fef200ffff0076000003b5061f022601be00000106009e4d1e001300b0004558b0062f1bb1061d3e59b011 dc303100ffff0054fff00448061f022601c000000106009d681e001300b0004558b00a2f1bb10a1d3e59b021dc303100ffff0054fff004480604022601c00000010700a0009b001e001300b0004558b0 0a2f1bb10a1d3e59b020dc303100ffff0054fff0044805fc022601c00000010700a1014e0027001300b0004558b00a2f1bb10a1d3e59b025dc303100ffff0054fdf90448049d022601c00000000701a2 016afe92ffff007600000468061f022601c100000106009d7b1e001300b0004558b0072f1bb1071d3e59b010dc303100ffffff910000026e0614022601c20000010700a4ff17001f000900b0022fb00f dc303100ffffff970000026e05d2022601c2000001070070ff100022001300b0004558b0022f1bb1021d3e59b005dc303100ffffffbd000002430604022601c20000010700a0ff48001e001300b00045 58b0022f1bb1021d3e59b007dc303100ffff0015fe52018d048d022601c20000000600a3ec00ffff007c0000018205fc022601c20000010600a1fb27001300b0004558b0022f1bb1021d3e59b00cdc30 3100ffff0024fff00437061f022601c300000107009d00f4001e001300b0004558b0002f1bb1001d3e59b013dc303100ffff0076fdf90468048d022601c40000000701a20112fe92ffff007600000394 061e022601c50000010600750a1e001300b0004558b0052f1bb1051d3e59b008dc303100ffff0076fdf90394048d022601c50000000701a20110fe92ffff0076000003940490022601c50000010701a2 0195038a001000b0004558b00a2f1bb10a1d3e593031ffff007600000394048d022601c50000000700a10172fd46ffff007600000467061e022601c70000010700750185001e001300b0004558b0082f 1bb1081d3e59b00cdc303100ffff0076fdf90467048d022601c70000000701a20178fe92ffff007600000467061f022601c700000107009e009d001e001300b0004558b0062f1bb1061d3e59b00fdc30 3100ffff004ffff0046f05d2022601c80000010600707022000900b00b2fb01ddc303100ffff004ffff0046f0604022601c80000010700a000a8001e001300b0004558b00b2f1bb10b1d3e59b020dc30 3100ffff004ffff0046f061d022601c80000010700a500fe001e000c00b00b2fb01fdcb021d03031ffff007600000439061e022601cb0000010700750117001e000900b0042fb019dc303100ffff0076 fdf90439048d022601cb0000000701a20118fe92ffff007600000439061f022601cb00000106009e2f1e000900b0042fb01bdc303100ffff003efff003ef061e022601cc0000010700750141001e0009 00b0092fb028dc303100ffff003efff003ef061f022601cc00000106009d421e001300b0004558b0092f1bb1091d3e59b02adc303100ffff003efe4103ef049d022601cc000000070079014f0000ffff 003efff003ef061f022601cc00000106009e591e000900b0092fb02adc303100ffff0024fdf90416048d022601cd0000000701a20125fe92ffff002400000416061f022601cd00000106009e471e0013 00b0004558b0062f1bb1061d3e59b00ddc303100ffff0024fe470416048d022601cd00000007007901390006ffff0067fff0041e0614022601ce0000010600a4571f001300b0004558b00f2f1bb10f1d 3e59b013dc303100ffff0067fff0041e05d2022601ce0000010600705022000900b0002fb010dc303100ffff0067fff0041e0604022601ce0000010700a00088001e001300b0004558b0082f1bb1081d 3e59b013dc303100ffff0067fff0041e067c022601ce0000010700a200ea0052000c00b0002fb015dcb01ad03031ffff0067fff00434061d022601ce0000010700a500de001e000c00b0002fb012dcb0 14d0303100010067fe82041e048d001e0061b21b1f2011123900b0004558b0172f1bb1171d3e59b0004558b0002f1bb1001d3e59b0004558b00d2f1bb10d173e59b0004558b0122f1bb1120f3e59b204 1200111239b00d10b208030a2b5821d81bf459b01210b21b010a2b5821d81bf459303101110606070615143332371706232226353437262627113311141633323711041e017d777f472c2e15495c5f74 40cdf202f17e6ce504048dfcfc81bd32565a44178e2c6e5b5d4906d6bb0305fd007368d40307ffff0028000005e5061f022601d000000107009d0119001e001300b0004558b0012f1bb1011d3e59b00f dc303100ffff000500000436061f022601d200000106009d2e1e001300b0004558b0082f1bb1081d3e59b00ddc303100ffff00050000043605ea022601d200000106006a591e001600b0004558b0082f 1bb1081d3e59b010dcb019d03031ffff0041000003f3061e022601d30000010700750130001e001300b0004558b0082f1bb1081d3e59b00cdc303100ffff0041000003f305fc022601d30000010700a1 01170027001300b0004558b0072f1bb1071d3e59b012dc303100ffff0041000003f3061f022601d300000106009e481e001300b0004558b0072f1bb1071d3e59b00fdc303100ffff0012000005420641 022600250000000600adbf00ffffff4a000004b00641002600296400000700adfe840000ffffff530000057c06410026002c6400000700adfe8d0000ffffff560000020306430026002d6400000700ad fe900002ffffffa7ffec05320641002600331400000700adfee10000fffffee10000053a06410026003d6400000700adfe1b0000ffffffb2000004f10641002600b91400000700adfeec0000ffffff87 fff402da069a022600c20000010700aeff20ffeb001c00b0004558b00c2f1bb10c1b3e59b018dcb010d0b01810b021d03031ffff00120000054205b0020600250000ffff0094000004a305b002060026 0000ffff00940000044c05b0020600290000ffff00500000048c05b00206003e0000ffff00940000051805b00206002c0000ffff00a30000019f05b00206002d0000ffff00940000051805b00206002f 0000ffff00940000066a05b0020600310000ffff00940000051705b0020600320000ffff0066ffec051e05c4020600330000ffff0094000004d405b0020600340000ffff002d000004b005b002060038 0000ffff0007000004d605b00206003d0000ffff0029000004e905b00206003c0000ffffffbf0000028507090226002d00000107006aff62013d001600b0004558b0022f1bb1021f3e59b00bdcb014d0 3031ffff0007000004d607020226003d00000107006a00b30136001600b0004558b0082f1bb1081f3e59b010dcb019d03031ffff0056ffeb04790641022600ba0000010700ad01500000000900b0132f b024dc303100ffff0060ffec040c0641022600be0000010700ad01190000000900b0092fb02adc303100ffff007efe6104060641022600c00000010700ad01230000000900b0032fb014dc303100ffff 00a9fff40261062c022600c20000010600ad0feb000900b0002fb00fdc303100ffff0080ffeb040806a2022600ca0000010600ae1df3001c00b0004558b0002f1bb1001b3e59b01edcb015d0b01e10b0 27d03031ffff008e0000046b043a0206008d0000ffff004fffec043d044e020600530000ffff0092fe60041f043a020600760000ffff0016000003da043a0206005a0000ffff001f000003e8043a0206 005c0000ffffffccfff4029205b7022600c200000107006aff6fffeb001600b0004558b00c2f1bb10c1b3e59b014dcb01dd03031ffff0080ffeb040805bf022600ca00000106006a6cf3001600b00045 58b0002f1bb1001b3e59b01adcb023d03031ffff004fffec043d0641022600530000010700ad01220000000900b0042fb01ddc303100ffff0080ffeb04080634022600ca0000010700ad010dfff30009 00b0002fb015dc303100ffff0066ffec062d0632022600cd0000010700ad022cfff1000900b0002fb023dc303100ffff00940000044c07090226002900000107006a00b3013d001600b0004558b0062f 1bb1061f3e59b013dcb01cd03031ffff009b00000437073d022600b00000010700750182013d001300b0004558b0042f1bb1041f3e59b008dc3031000001004affec048a05c400270063b21128291112 3900b0004558b0092f1bb1091f3e59b0004558b01d2f1bb11d0f3e59b2021d09111239b20e091d111239b00910b211010a2b5821d81bf459b00210b217010a2b5821d81bf459b2221d09111239b01d10 b225010a2b5821d81bf459303101342624272635342433321616152334262322061514160416161514042322242635331416333236038d87fea068c7011fe598ee88fc8f857c89940154ce60fee9ef9e fef793fda4998485017760686a417dc9b0e470cf7e72816a5f506b6581a770b6d775ce897c886b00ffff00a30000019f05b00206002d0000ffffffbf0000028507090226002d00000107006aff62013d 001600b0004558b0022f1bb1021f3e59b00bdcb014d03031ffff002dffec03e405b00206002e0000ffff009b0000053005b0020601e30000ffff00940000051807360226002f000001070075016e0136 001300b0004558b0052f1bb1051f3e59b00fdc303100ffff0039ffeb04dd0723022600dd0000010700a000d9013d001300b0004558b00f2f1bb10f1f3e59b013dc303100ffff00120000054205b00206 00250000ffff0094000004a305b0020600260000ffff009b0000043705b0020600b00000ffff00940000044c05b0020600290000ffff00940000050d0723022600db0000010700a0011d013d001300b0 004558b0082f1bb1081f3e59b00ddc303100ffff00940000066a05b0020600310000ffff00940000051805b00206002c0000ffff0066ffec051e05c4020600330000ffff009b0000051405b0020600b5 0000ffff0094000004d405b0020600340000ffff0066ffec04eb05c4020600270000ffff002d000004b005b0020600380000ffff0029000004e905b00206003c0000ffff005affec03fb044e02060045 0000ffff0053ffec040b044e020600490000ffff00860000041205d9022600ef0000010700a00097fff3001300b0004558b0082f1bb1081b3e59b00ddc303100ffff004fffec043d044e020600530000 ffff007cfe600430044e0206005400000001004fffec03f5044e001c004bb2001d1e11123900b0004558b00f2f1bb10f1b3e59b0004558b0082f1bb1080f3e59b200010a2b5821d81bf459b203080f11 1239b2130f08111239b00f10b216010a2b5821d81bf459303125323637330e0223220011353400333216172326262322060715141602395b7804e50476ca75e3fef60108e4c1f306e504775c7680017f ae6a4e65af660126010319f70129e1b75d78abae27b0ad00ffff000cfe4b03d6043a0206005d0000ffff001f000003e8043a0206005c0000ffff0053ffec040b05cc0226004900000106006a6c000016 00b0004558b0082f1bb1081b3e59b025dcb02ed03031ffff00850000034d05f3022600eb00000107007500c2fff3001300b0004558b0042f1bb1041b3e59b008dc303100ffff004bffec03ca044e0206 00570000ffff007d0000019005d50206004d0000ffffffab0000027105c50226008c00000107006aff4efff9001600b0004558b0022f1bb1021b3e59b00bdcb014d03031ffffffb5fe4b018505d50206 004e0000ffff008f0000046505f2022600f00000010700750144fff2001300b0004558b0042f1bb1041b3e59b00fdc303100ffff000cfe4b03d605e60226005d0000010600a04a00001300b0004558b0 0f2f1bb10f1b3e59b013dc303100ffff0030000006e507360226003b00000107004402080136001300b0004558b00b2f1bb10b1f3e59b00edc303100ffff0021000005cc06000226005b000001070044 016a0000001300b0004558b00b2f1bb10b1b3e59b00edc303100ffff0030000006e507360226003b00000107007502a70136001300b0004558b00c2f1bb10c1f3e59b00fdc303100ffff0021000005cc 06000226005b00000107007502090000001300b0004558b00c2f1bb10c1b3e59b00fdc303100ffff0030000006e507020226003b00000107006a01d30136000c00b0012fb016dcb00dd03031ffff0021 000005cc05cc0226005b00000107006a01350000000c00b0012fb016dcb00dd03031ffff0007000004d607360226003d00000107004400e80136001300b0004558b0082f1bb1081f3e59b00adc303100 ffff000cfe4b03d606000226005d0000010600447700000900b0012fb010dc303100ffff005203fc010b06000306000b0000001600b0004558b0042f1bb104213e59b001d0b0012f3031ffff006503f4 02400600030600060000002c00b0004558b0092f1bb109213e59b0004558b0042f1bb104213e59b00910b006d0b0062fb001d0b0012f3031ffff008ffff203c805b00026000500000007000502250000 ffffffb1fe4b027305df0226009b00000107009eff3fffde000900b0002fb011dc303100ffff00330400016506000206016d0000ffff00940000066a07360226003100000107007502900136001300b0 004558b0022f1bb1021f3e59b011dc303100ffff007c0000067906000226005100000107007502a00000000900b0032fb020dc303100ffff0012fe6d054205b0022600250000000700a6017a0003ffff 005afe7103fb044e022600450000000700a600ad0007ffff00940000044c073d0226002900000107004400e8013d001300b0004558b0062f1bb1061f3e59b00ddc303100ffff00940000050d073d0226 00db000001070044014a013d001300b0004558b0082f1bb1081f3e59b00bdc303100ffff0053ffec040b06000226004900000107004400a10000001300b0004558b0082f1bb1081b3e59b01fdc303100 ffff00860000041205f3022600ef00000107004400c4fff3001300b0004558b0082f1bb1081b3e59b00bdc303100ffff00440000055c05b0020600b80000ffff004ffe22057e043a020600cc0000ffff 0010000004f306fc022601180000010700ab0449010e001600b0004558b00f2f1bb10f1f3e59b011dcb015d03031fffffff10000041805d0022601190000010700ab03e5ffe2001600b0004558b0112f 1bb1111b3e59b013dcb017d03031ffff004ffe4b0864044e0026005300000007005d048e0000ffff0066fe4b095c05c40026003300000007005d05860000ffff0049fe3a047f05c3022600da00000007 01b00192ffa0ffff004dfe3b03c4044d022600ee0000000701b00139ffa1ffff0066fe3e04eb05c4022600270000000701b001d6ffa4ffff004ffe3e03f5044e022600470000000701b0014affa4ffff 0007000004d605b00206003d0000ffff0020fe5f03f5043a020600bc0000ffff00a30000019f05b00206002d0000ffff00160000079b0723022600d90000010700a0021d013d001300b0004558b00d2f 1bb10d1f3e59b019dc303100ffff001e0000065c05d9022600ed0000010700a00187fff3001300b0004558b00d2f1bb10d1b3e59b019dc303100ffff00a30000019f05b00206002d0000ffff00120000 0542071c022600250000010700a000f60136001300b0004558b0042f1bb1041f3e59b00edc303100ffff005affec03fb05e6022600450000010700a000800000001300b0004558b0172f1bb1171b3e59 b02ddc303100ffff00120000054207020226002500000107006a00ee0136001600b0004558b0042f1bb1041f3e59b012dcb01bd03031ffff005affec03fb05cc0226004500000106006a7800001600b0 004558b0172f1bb1171b3e59b031dcb03ad03031fffffff60000075705b0020600810000ffff0048ffec06840450020600860000ffff00940000044c0723022600290000010700a000bb013d001300b0 004558b0062f1bb1061f3e59b00fdc303100ffff0053ffec040b05e6022600490000010600a07400001300b0004558b0082f1bb1081b3e59b021dc303100ffff0051ffeb051e06db0226014500000107 006a00c2010f001600b0004558b0002f1bb1001f3e59b026dcb02fd03031ffff0059ffec03f8044f0206009c0000ffff0059ffec03f805cd0226009c00000106006a6901001600b0004558b0002f1bb1 001b3e59b026dcb02fd03031ffff00160000079b0709022600d900000107006a0215013d001600b0004558b00d2f1bb10d1f3e59b01ddcb026d03031ffff001e0000065c05bf022600ed00000107006a 017ffff3001600b0004558b00d2f1bb10d1b3e59b01ddcb026d03031ffff0049ffed047f0717022600da00000107006a00a3014b001600b0004558b00b2f1bb10b1f3e59b031dcb03ad03031ffff004d ffec03c405cc022600ee00000106006a4e00001600b0004558b0252f1bb1251b3e59b02fdcb038d03031ffff00940000050d06f1022600db00000107007000e50141001300b0004558b0082f1bb1081f 3e59b00bdc303100ffff00860000041205a7022600ef0000010600705ff7001300b0004558b0072f1bb1071b3e59b00bdc303100ffff00940000050d0709022600db00000107006a0115013d001600b0 004558b0082f1bb1081f3e59b011dcb01ad03031ffff00860000041205bf022600ef00000107006a008ffff3001600b0004558b0082f1bb1081b3e59b011dcb01ad03031ffff0066ffec051e07020226 003300000107006a01050136001600b0004558b00c2f1bb10c1f3e59b026dcb02fd03031ffff004fffec043d05cc0226005300000107006a00810000001600b0004558b0042f1bb1041b3e59b022dcb0 2bd03031ffff005fffec051705c4020601160000ffff004fffec043d044e020601170000ffff005fffec051707060226011600000107006a0113013a001600b0004558b00c2f1bb10c1f3e59b026dcb0 2fd03031ffff004fffec043d05cc0226011700000106006a7300001600b0004558b0042f1bb1041b3e59b025dcb02ed03031ffff006bffec04f10718022600e600000107006a00e3014c001600b00045 58b0132f1bb1131f3e59b027dcb030d03031ffff0051ffec03e805cc022600fe00000106006a5900001600b0004558b0082f1bb1081b3e59b028dcb031d03031ffff0039ffeb04dd06f1022600dd0000 0107007000a10141000900b0012fb010dc303100ffff000cfe4b03d605b40226005d0000010600701204000900b0012fb010dc303100ffff0039ffeb04dd0709022600dd00000107006a00d1013d0016 00b0004558b00f2f1bb10f1f3e59b017dcb020d03031ffff000cfe4b03d605cc0226005d00000106006a4200001600b0004558b00f2f1bb10f1b3e59b017dcb020d03031ffff0039ffeb04dd073c0226 00dd0000010700a5012f013d001600b0004558b00f2f1bb10f1f3e59b016dcb012d03031ffff000cfe4b03f605ff0226005d0000010700a500a00000001600b0004558b00f2f1bb10f1b3e59b016dcb0 12d03031ffff008e000004ee0709022600e000000107006a010f013d001600b0004558b00a2f1bb10a1f3e59b019dcb022d03031ffff005f000003e005bf022600f800000106006a67f3001600b00045 58b0092f1bb1091b3e59b019dcb022d03031ffff009b00000658070a002600e50b000027002d04b900000107006a01c2013e001600b0004558b00b2f1bb10b1f3e59b020dcb029d03031ffff008f0000 05c905bf002600fd00000027008c044700000107006a0174fff3001600b0004558b00b2f1bb10b1b3e59b01fdcb028d03031ffff0029fe4b055105b00226003c0000000701af03c30000ffff001ffe4b 0456043a0226005c0000000701af02c80000ffff004fffec04030600020600480000ffff002dfe4b05fd05b0022600dc0000000701af046f0000ffff0021fe4b0507043a022600f10000000701af0379 0000ffff0012fe97054205b0022600250000000700ac050d0003ffff005afe9b03fb044e022600450000000700ac04400007ffff00120000054207bb022600250000010700aa0505013c000900b0042f b00bdc303100ffff005affec03fb0685022600450000010700aa048f0006000900b0172fb02adc303100ffff00120000054a07b1022600250000010701b700bf0121001700b0004558b0052f1bb1051f 3e59b10e09f4b014d0303100ffff005affec04d4067c022600450000010601b749ec000c00b0172fb02cdcb031d03031ffff00100000054207ae022600250000010701b600c4012b001700b0004558b0 042f1bb1041f3e59b10e09f4b013d0303100ffffff9affec03fb0679022600450000010601b64ef6000c00b0172fb02adcb031d03031ffff00120000054207de022600250000010701b500c30113000c 00b0042fb00bdcb012d03031ffff005affec045706a9022600450000010601b54dde000c00b0172fb02adcb031d03031ffff00120000054207d6022600250000010701b400c40105000c00b0042fb00b dcb012d03031ffff005affec03fb06a1022600450000010601b44ed0000c00b0172fb02adcb031d03031ffff0012fe97054207370226002500000027009d00c30136000700ac050d0003ffff005afe9b 03fb06010226004500000026009d4d00000700ac04400007ffff00120000054207ae022600250000010701b300ef0130000c00b0042fb00edcb019d03031ffff005affec03fb06790226004500000106 01b379fb000c00b0172fb02ddcb038d03031ffff00120000054207ae022600250000010701b800ef0130000c00b0042fb00edcb019d03031ffff005affec03fb0679022600450000010601b879fb000c 00b0172fb02ddcb038d03031ffff001200000542083e022600250000010701b200ee0136000c00b0042fb00edcb019d03031ffff005affec03fb0708022600450000010601b27800000c00b0172fb02d dcb038d03031ffff0012000005420818022600250000010701b100f1013c000c00b0042fb014dcb018d03031ffff005affec03fb06e2022600450000010601b17b06000c00b0172fb033dcb037d03031 ffff0012fe970542071c022600250000002700a000f60136000700ac050d0003ffff005afe9b03fb05e6022600450000002700a000800000000700ac04400007ffff0094fe9e044c05b0022600290000 000700ac04cb000affff0053fe94040b044e022600490000000700ac048f0000ffff00940000044c07c2022600290000010700aa04ca0143000900b0062fb00cdc303100ffff0053ffec040b06850226 00490000010700aa04830006000900b0082fb01edc303100ffff00940000044c0733022600290000010700a4008a013e000900b0062fb017dc303100ffff0053ffec040b05f6022600490000010600a4 4301000900b0082fb029dc303100ffff00940000050f07b8022600290000010701b700840128001700b0004558b0072f1bb1071f3e59b10f09f4b015d0303100ffff0053ffec04c8067c022600490000 010601b73dec000c00b0082fb020dcb025d03031ffffffd50000044c07b5022600290000010701b600890132001700b0004558b0062f1bb1061f3e59b10f09f4b014d0303100ffffff8effec040b0679 022600490000010601b642f6000c00b0082fb01edcb025d03031ffff00940000049207e5022600290000010701b50088011a000c00b0062fb00cdcb013d03031ffff0053ffec044b06a9022600490000 010601b541de000c00b0082fb01edcb025d03031ffff00940000044c07dd022600290000010701b40089010c000c00b0062fb00cdcb013d03031ffff0053ffec040b06a1022600490000010601b442d0 000c00b0082fb01edcb025d03031ffff0094fe9e044c073e0226002900000027009d0088013d000700ac04cb000affff0053fe94040b06010226004900000026009d4100000700ac048f0000ffff00a3 0000021107c20226002d0000010700aa03780143000900b0022fb004dc303100ffff008f000001fd067e0226008c0000010700aa0364ffff000900b0022fb004dc303100ffff0094fe9a01a705b00226 002d0000000700ac03780006ffff0078fe9e019005d50226004d0000000700ac035c000affff0066fe94051e05c4022600330000000700ac051d0000ffff004ffe92043d044e022600530000000700ac 049dfffeffff0066ffec051e07bb022600330000010700aa051c013c000900b0142fb01fdc303100ffff004fffec043d0685022600530000010700aa04980006000900b0042fb01bdc303100ffff0066 ffec056107b1022600330000010701b700d60121000c00b0142fb021dcb026d03031ffff004fffec04dd067c022600530000010601b752ec000c00b0042fb01ddcb022d03031ffff0027ffec051e07ae 022600330000010701b600db012b000c00b0142fb01fdcb026d03031ffffffa3ffec043d0679022600530000010601b657f6000c00b0042fb01bdcb022d03031ffff0066ffec051e07de022600330000 010701b500da0113000c00b0142fb01fdcb026d03031ffff004fffec046006a9022600530000010601b556de000c00b0042fb01bdcb022d03031ffff0066ffec051e07d6022600330000010701b400db 0105000c00b0142fb01fdcb026d03031ffff004fffec043d06a1022600530000010601b457d0000c00b0042fb01bdcb022d03031ffff0066fe94051e07370226003300000027009d00da0136000700ac 051d0000ffff004ffe92043d06010226005300000026009d5600000700ac049dfffeffff0058ffec05aa07330226009700000007007501d30133ffff004fffec04bb0600022600980000010700750158 0000000900b0092fb025dc303100ffff0058ffec05aa07330226009700000007004401340133ffff004fffec04bb06000226009800000107004400b90000000900b0092fb023dc303100ffff0058ffec 05aa07b8022600970000000700aa05160139ffff004fffec04bb0685022600980000010700aa049b0006000900b0092fb023dc303100ffff0058ffec05aa0729022600970000000700a400d60134ffff 004fffec04bb05f6022600980000010600a45b01000900b0092fb02edc303100ffff0058fe9405aa062e022600970000000700ac05060000ffff004ffe8b04bb04a8022600980000000700ac049afff7 ffff007dfe9404bd05b0022600390000000700ac04f20000ffff0077fe9403f7043a022600590000000700ac04410000ffff007dffec04bd07bb022600390000010700aa04f3013c000900b0002fb011 dc303100ffff0077ffec03f70685022600590000010700aa04910006000900b0062fb011dc303100ffff007dffec063d07420226009900000107007501d70142000900b0042fb01bdc303100ffff0077 ffec052805ec0226009a0000010700750157ffec000900b0002fb01cdc303100ffff007dffec063d07420226009900000107004401380142000900b0042fb019dc303100ffff0077ffec052805ec0226 009a00000107004400b8ffec000900b0002fb01adc303100ffff007dffec063d07c7022600990000010700aa051a0148000900b0042fb019dc303100ffff0077ffec052806710226009a0000010700aa 049afff2000900b0002fb01adc303100ffff007dffec063d0738022600990000010700a400da0143000900b0042fb024dc303100ffff0077ffec052805e20226009a0000010600a45aed000900b0002f b025dc303100ffff007dfe8b063d0601022600990000000700ac0519fff7ffff0077fe94052804930226009a0000000700ac04450000ffff0007fea404d605b00226003d0000000700ac04c60010ffff 000cfe0f03d6043a0226005d0000000700ac0546ff7bffff0007000004d607bb0226003d0000010700aa04ca013c000900b0012fb009dc303100ffff000cfe4b03d606850226005d0000010700aa0459 0006000900b0012fb010dc303100ffff0007000004d6072c0226003d0000010700a4008a0137000900b0012fb014dc303100ffff000cfe4b03d605f60226005d0000010600a41901000900b0012fb01b dc3031000002004fffec04b2060000160021008cb21f2223111239b01f10b010d000b0132fb0004558b00c2f1bb10c1b3e59b0004558b0062f1bb1060f3e59b0004558b0022f1bb1020f3e59b22f1301 5db20f13015db2160213111239b0162fb200070a2b5821d81bf459b2040c06111239b20e0c06111239b00fd0b01610b011d0b00610b21a010a2b5821d81bf459b00c10b21f010a2b5821d81bf4593031 0123112327062322021134123332173523353335331533011416333237112623220604b2afdc0c6db6beebe8c3ac6afbfbf3affc907f7595454395768004c9fb37708401320107fa012f78f3aa8d8dfc 9da5b98501ce82bbffff004ffeae04b20600002600480000002701de01850242010700430099ff6d001200b22f1c015db21f1c0171b29f1c015d3031ffff009bfe9a057e05b0022601e30000000701b0 042f0000ffff008ffe9a04c2043a022600f00000000701b003730000ffff0094fe9a05db05b00226002c0000000701b0048c0000ffff0086fe9a04d5043a022600f30000000701b003860000ffff002d fe9a04b005b0022600380000000701b0024d0000ffff0023fe9a03d0043a022600f50000000701b001e60000ffff0029fe9a052205b00226003c0000000701b003d30000ffff001ffe9a0427043a0226 005c0000000701b002d80000ffff008efe9a05ad05b0022600e00000000701b0045e0000ffff005ffe9a04a4043b022600f80000000701b003550000ffff008efe9a04ee05b0022600e00000000701b0 02cf0000ffff005ffe9a03e0043b022600f80000000701b001c60000ffff009bfe9a043705b0022600b00000000701b001070000ffff0085fe9a034d043a022600eb0000000701b000ec0000ffff0016 fe9a080505b0022600d90000000701b006b60000ffff001efe9a06b4043a022600ed0000000701b005650000ffff0016fe4305bc05c40226013f0000000701b002edffa9ffffffcbfe46048b044e0226 01400000000701b001f5ffacffff0079000003f806000206004c00000002ffd0000004c105b00013001c006eb2001d1e111239b016d000b0004558b0102f1bb1101f3e59b0004558b00a2f1bb10a0f3e 59b213100a111239b0132fb200070a2b5821d81bf459b202100a111239b0022fb00010b00cd0b01310b00ed0b00210b214010a2b5821d81bf459b00a10b215010a2b5821d81bf4593031012315213216 1615140407211123353335331533031121323635342627026de0012aa0ee7cfeebeffdd3c0c0fde0e00129808f8c7c0447c46eca85ccf8020447aabfbffdc7fe128b736e80020002ffd0000004c105b0 0013001c006eb2001d1e111239b016d000b0004558b0102f1bb1101f3e59b0004558b00a2f1bb10a0f3e59b213100a111239b0132fb200070a2b5821d81bf459b202100a111239b0022fb00010b00cd0 b01310b00ed0b00210b214010a2b5821d81bf459b00a10b215010a2b5821d81bf45930310123152132161615140407211123353335331533031121323635342627026de0012aa0ee7cfeebeffdd3c0c0 fde0e00129808f8c7c0447c46eca85ccf8020447aabfbffdc7fe128b736e80020001fff00000043705b0000d004900b0004558b0082f1bb1081f3e59b0004558b0022f1bb1020f3e59b20d0802111239 b00d2fb200070a2b5821d81bf459b004d0b00d10b006d0b00810b20a010a2b5821d81bf45930310123112311233533112115211133028df6fcabab039cfd60f6029ffd61029faa0267ccfe650001ffe2 0000034d043a000d004900b0004558b0082f1bb1081b3e59b0004558b0022f1bb1020f3e59b20d0802111239b00d2fb200070a2b5821d81bf459b004d0b00d10b006d0b00810b20a010a2b5821d81bf4 5930310121112311233533112115211521027ffef8f2a3a302c8fe2a010801d1fe2f01d1aa01bfc4fb000001ffe30000054405b00014007400b0004558b0082f1bb1081f3e59b0004558b0102f1bb110 1f3e59b0004558b0022f1bb1020f3e59b0004558b0132f1bb1130f3e59b20e0802111239b00e2fb201010a2b5821d81bf459b2070802111239b0072fb204010a2b5821d81bf459b00710b00ad0b00410 b00cd0b212010e11123930310123112311233533353315331523153301210101210257acfcccccfcd5d58b01ac0136fe0c0220fed00270fd90043faac7c7aaf30264fd47fd090001ffae000004490600 0014007400b0004558b0082f1bb108213e59b0004558b0102f1bb1101b3e59b0004558b0022f1bb1020f3e59b0004558b0132f1bb1130f3e59b20e1002111239b00e2fb201010a2b5821d81bf459b207 0810111239b0072fb204070a2b5821d81bf459b00710b00ad0b00410b00cd0b212010e111239303101231123112335333533153315231133012101012101f66ff2e7e7f2c4c469010f011cfe9f018ffe e601d9fe2704bbaa9b9baafde1019efe11fdb500ffff0094fe7e05dd0723022600db0000002700a0011d013d010700100480ffc6001300b0004558b0082f1bb1081f3e59b00ddc303100ffff0086fe7e 04e405d9022600ef0000002700a00097fff3010700100387ffc6001300b0004558b0082f1bb1081b3e59b00ddc303100ffff0094fe7e05e905b00226002c000000070010048cffc6ffff0086fe7e04e3 043a022600f30000000700100386ffc6ffff0094fe7e073205b00226003100000007001005d5ffc6ffff008ffe7e0641043a022600f200000007001004e4ffc6ffff002dfe7e05dc05b0022600dc0000 00070010047fffc6ffff0021fe7e04e6043a022600f10000000700100389ffc600010007000004d605b0000e0056b20a0f1011123900b0004558b0082f1bb1081f3e59b0004558b00b2f1bb10b1f3e59 b0004558b0022f1bb1020f3e59b2060208111239b0062fb205070a2b5821d81bf459b001d0b20a0802111239b00610b00ed0303101231123112335330121010121013303c3d5feca7afe670119014f01 4f0118fe67860204fdfc0204aa0302fd4e02b2fcfe0000010020fe5f03f5043a000e0063b20a0f1011123900b0004558b0082f1bb1081b3e59b0004558b00b2f1bb10b1b3e59b0004558b0022f1bb102 113e59b0004558b0002f1bb1000f3e59b0004558b0042f1bb1040f3e59b206070a2b5821d81bf459b20a0b00111239b00dd0b00ed030310523112311233533013313133301330360dcf3cea2febbfbf3 ecfbfebcaf01fe6001a0aa0391fd0102fffc6f0000010029000004e905b00011006300b0004558b00b2f1bb10b1f3e59b0004558b00e2f1bb10e1f3e59b0004558b0022f1bb1020f3e59b0004558b005 2f1bb1050f3e59b2110b02111239b0112fb200070a2b5821d81bf459b2040b02111239b007d0b01110b009d0b20d0b02111239303101230121010121012335330121010121013303db870195fed9fec7 fec6feda01968173fe820124013201320124fe83790295fd6b0216fdea0295aa0271fdf2020efd8f0001001f000003e8043a0011006300b0004558b00b2f1bb10b1b3e59b0004558b00e2f1bb10e1b3e 59b0004558b0022f1bb1020f3e59b0004558b0052f1bb1050f3e59b2110e02111239b0112fb200070a2b5821d81bf459b2040e02111239b007d0b01110b009d0b20d0e02111239303101230121030321 01233533012113132101330357950126fef4d8d7fef201258a82feef010ccace010efeee8c01d7fe290172fe8e01d7aa01b9fe9c0164fe47ffff0060ffec040c044d020600be0000ffff000200000431 05b00226002a0000000701deff72fe69ffff0081026d05d1033100460197850066664000ffff00510000044005c4020600160000ffff004fffec041505c4020600170000ffff00340000045805b00206 00180000ffff0081ffec043a05b0020600190000ffff005dfffa041205c40006001d0000ffff007dffec043605c4000600141400ffff006affec04f0074b0226002b00000107007501bd014b000900b0 0b2fb021dc303100ffff0052fe56040c06000226004b000001070075013f0000000900b0032fb027dc303100ffff009400000517073602260032000001070044014c0136001300b0004558b0062f1bb1 061f3e59b00bdc303100ffff0079000003f806000226005200000107004400b30000001300b0004558b0002f1bb1001b3e59b012dc303100ffff0012000005420721022600250000010700ab04770133 001600b0004558b0042f1bb1041f3e59b00cdcb010d03031ffff000dffec03fb05ec022600450000010700ab0401fffe001600b0004558b0172f1bb1171b3e59b02bdcb02fd03031ffff00480000044c 0728022600290000010700ab043c013a001600b0004558b0062f1bb1061f3e59b00ddcb011d03031ffff0001ffec040b05ec022600490000010700ab03f5fffe001600b0004558b0082f1bb1081b3e59 b01fdcb023d03031fffffef60000021e07280226002d0000010700ab02ea013a001600b0004558b0022f1bb1021f3e59b005dcb009d03031fffffee20000020a05e40226008c0000010700ab02d6fff6 001600b0004558b0022f1bb1021b3e59b005dcb009d03031ffff0066ffec051e0721022600330000010700ab048e0133001600b0004558b00c2f1bb10c1f3e59b020dcb024d03031ffff0016ffec043d 05ec022600530000010700ab040afffe001600b0004558b0042f1bb1041b3e59b01cdcb020d03031ffff0032000004de0721022600360000010700ab04260133001600b0004558b0042f1bb1041f3e59 b019dcb01dd03031ffffff6e000002b405ec022600560000010700ab0362fffe001600b0004558b0072f1bb1071b3e59b00fdcb013d03031ffff0071ffec04bd0721022600390000010700ab04650133 001600b0004558b0092f1bb1091f3e59b012dcb016d03031ffff000fffec03f705ec022600590000010700ab0403fffe001600b0004558b0072f1bb1071b3e59b012dcb016d03031fffffeac00000502 0641002600cf6400000700adfde60000ffff0094fe9e04a305b0022600260000000700ac04b9000affff007cfe8b04320600022600460000000700ac04cbfff7ffff0094fe9e04d205b0022600280000 000700ac0494000affff004ffe9404030600022600480000000700ac04b40000ffff0094fdf904d205b0022600280000000701a20148fe92ffff004ffdf904030600022600480000000701a20168fe92 ffff0094fe9e051805b00226002c0000000700ac0526000affff0079fe9e03f806000226004c0000000700ac04a1000affff00940000051807360226002f000001070075016e0136000900b0042fb00f dc303100ffff007d00000436073d0226004f000001070075016b013d000900b0042fb00fdc303100ffff0094fedf051805b00226002f0000000700ac04e9004bffff007dfeca043606000226004f0000 000700ac04790036ffff0094fe9e042605b0022600300000000700ac04b9000affff0078fe9e018b0600022600500000000700ac035c000affff0094fe9e066a05b0022600310000000700ac05d6000a ffff007cfe9e0679044e022600510000000700ac05d9000affff0094fe9a051705b0022600320000000700ac05280006ffff0079fe9e03f8044e022600520000000700ac048d000affff0094000004d4 07420226003400000107007501720142000900b0032fb016dc303100ffff007cfe60043005f702260054000001070075019dfff7000900b00c2fb01ddc303100ffff0094fe9e04de05b0022600360000 000700ac04ba000affff0072fe9e02b4044e022600560000000700ac0356000affff004afe94048a05c4022600370000000700ac04d50000ffff004bfe8b03ca044e022600570000000700ac047cfff7 ffff002dfe9704b005b0022600380000000700ac04c30003ffff0008fe9402720541022600580000000700ac04140000ffff00120000051d07380226003a0000010700a400b00143000900b0012fb012 dc303100ffff0016000003da05ed0226005a0000010600a418f8000900b0012fb012dc303100ffff0012fe9e051d05b00226003a0000000700ac04ef000affff0016fe9e03da043a0226005a00000007 00ac0457000affff0030fe9e06e505b00226003b0000000700ac05e6000affff0021fe9e05cc043a0226005b0000000700ac054e000affff0050fe9e048c05b00226003e0000000700ac04c1000affff 0052fe9e03c0043a0226005e0000000700ac0463000afffffe1cffec056405d70026003346000007015afdb50000ffff000900000494051e022601ba0000000700adff76feddffffff2a000003f10521 002601be3c00000700adfe64fee0ffffff37000004a4051c002601c13c00000700adfe71fedbffffff39000001b30521002601c23c00000700adfe73fee0ffffff93fff00479051e002601c80a000007 00adfecdfeddfffffee800000472051e002601d23c00000700adfe22feddffffffa40000048e051e002601f30a00000700adfedefeddffff000900000494048d020601ba0000ffff00760000040a048d 020601bb0000ffff0076000003b5048d020601be0000ffff0041000003f3048d020601d30000ffff007600000468048d020601c10000ffff008500000177048d020601c20000ffff007600000468048d 020601c40000ffff00760000058f048d020601c60000ffff004ffff0046f049d020601c80000ffff00760000042c048d020601c90000ffff002400000416048d020601cd0000ffff000500000436048d 020601d20000ffff00150000044a048d020601d10000ffffff9d0000026305ea022601c200000107006aff40001e001600b0004558b0022f1bb1021d3e59b00bdcb014d03031ffff00050000043605ea 022601d200000106006a591e001600b0004558b0082f1bb1081d3e59b010dcb019d03031ffff0076000003b505ea022601be00000106006a611e001600b0004558b0062f1bb1061d3e59b013dcb01cd0 3031ffff007600000397061e022601ea0000010700750123001e000900b0042fb008dc303100ffff003efff003ef049d020601cc0000ffff008500000177048d020601c20000ffffff9d0000026305ea 022601c200000107006aff40001e001600b0004558b0022f1bb1021d3e59b00bdcb014d03031ffff0024fff00364048d020601c30000ffff007600000468061e022601c40000010700750117001e0009 00b0042fb00fdc303100ffff001fffec04390604022602010000010600a07a1e001300b0004558b00f2f1bb10f1d3e59b013dc303100ffff000900000494048d020601ba0000ffff00760000040a048d 020601bb0000ffff007600000397048d020601ea0000ffff0076000003b5048d020601be0000ffff00760000046e0604022601fe0000010700a000ba001e001300b0004558b0082f1bb1081d3e59b00d dc303100ffff00760000058f048d020601c60000ffff007600000468048d020601c10000ffff004ffff0046f049d020601c80000ffff007600000462048d020601ef0000ffff00760000042c048d0206 01c90000ffff004ffff00443049d020601bc0000ffff002400000416048d020601cd0000ffff00150000044a048d020601d1000000010042fe3903e7049d002800a4b227292a11123900b0172fb00045 58b00a2f1bb10a1d3e59b0004558b0192f1bb1190f3e59b00a10b203010a2b5821d81bf459b2060a19111239b227190a111239b0272fb25f270172b23f270171b2cf270171b2ff270171b20f270172b4 6f277f270271b4af27bf27025db28f270172b2bf270172b224010a2b5821d81bf459b2102427111239b01910b016d0b21d190a111239b01910b21f010a2b5821d81bf459303101342623220615233436 3332161514060716161514060711231126263533163332363534272335333602e2706b5b66f3f3c3d8f46e5d6f6ebbacf39bb0f30bca7774e0949ac70343464f463c94b3a7965b8a2724915b86ae18fe 4101c218ac87935748a603b0040000010076fe9a052c048d000f00a8b203101111123900b0004558b00c2f1bb10c1d3e59b0004558b0092f1bb1091d3e59b0004558b0012f1bb101173e59b0004558b0 062f1bb1060f3e59b0004558b0032f1bb1030f3e59b20a0609111239b00a2fb4af0abf0a025db23f0a0171b2cf0a0171b23f0a0172b2ff0a0171b20f0a0172b46f0a7f0a0271b4df0aef0a025db41f0a 2f0a025db25f0a0172b205010a2b5821d81bf459b00310b20e070a2b5821d81bf459303101231123112111231133112111331133052cf3c4fdf4f3f3020cf3c4fe9a016601dbfe25048dfe1101effc28 0001004ffe430443049d001e005eb21b1f2011123900b0004558b00e2f1bb10e1d3e59b0004558b0042f1bb104113e59b0004558b0032f1bb1030f3e59b006d0b2120e03111239b00e10b215010a2b58 21d81bf459b00310b21b010a2b5821d81bf459b21e030e11123930310106060711231126022735343636333204172326262320111514163332363704420cc6a9f3b5cf017eec9cd6010414f30c7d72fe ed8687787c0d01849fd01bfe4901b924011fdd4fa9ff8adac27069fe8e48b9b56270ffff000500000436048d020601d20000ffff000afe3a05a804a3022602170000000701b002e6ffa0ffff00760000 046e05d2022601fe00000107007000820022000900b0002fb00adc303100ffff001fffec043905d2022602010000010600704222000900b0022fb010dc303100ffff00500000054d048d020601f10000 ffff0012fe55054205b0022600250000000700a301820003ffff005afe5903fb044e022600450000000700a300b50007ffff0094fe5c044c05b0022600290000000700a30140000affff0053fe52040b 044e022600490000000700a301040000ffff0078fe9e018b043a0226008c0000000700ac035c000a0000000f00ba0003000104090000005e00000003000104090001001a005e0003000104090002000e 00780003000104090003001a005e0003000104090004001a005e0003000104090005002c00860003000104090006001a00b20003000104090007004000cc0003000104090009000c010c000300010409 000b00140118000300010409000c0026012c000300010409000d005c0152000300010409000e005401ae0003000104090010000c02020003000104090011000c020e0043006f00700079007200690067 006800740020003200300031003100200047006f006f0067006c006500200049006e0063002e00200041006c006c0020005200690067006800740073002000520065007300650072007600650064002e 0052006f0062006f0074006f0020004d0065006400690075006d0052006500670075006c0061007200560065007200730069006f006e00200032002e003000300031003100350032003b002000320030 003100340052006f0062006f0074006f002d004d0065006400690075006d0052006f0062006f0074006f00200069007300200061002000740072006100640065006d00610072006b0020006f00660020 0047006f006f0067006c0065002e0047006f006f0067006c00650047006f006f0067006c0065002e0063006f006d00430068007200690073007400690061006e00200052006f00620065007200740073 006f006e004c006900630065006e00730065006400200075006e006400650072002000740068006500200041007000610063006800650020004c006900630065006e00730065002c0020005600650072 00730069006f006e00200032002e00300068007400740070003a002f002f007700770077002e006100700061006300680065002e006f00720067002f006c006900630065006e007300650073002f004c 004900430045004e00530045002d0032002e00300052006f0062006f0074006f004d0065006400690075006d0003000000000000ff6a0064000000000000000000000000000000000000000000010002 00080002ffff000f00010000000a005c00ac000444464c54001a6379726c00286772656b00366c61746e0044000400000000ffff000200000004000400000000ffff000200010005000400000000ffff 000200020006000400000000ffff000200030007000863707370003263707370003863707370003e6370737000446b65726e004a6b65726e004a6b65726e004a6b65726e004a00000001000100000001 00030000000100020000000100000000000100040005000c000c000c000c01de00010000000100080001000a000500240048000100de000800250026002700280029002a002b002c002d002e002f0030 003100320033003400350036003700380039003a003b003c003d003e00650067009200b000b100b200b300b400b500b600b700b800b900d100d200d300d400d500d600d700d800d900da00db00dc00dd 00de00df00e000e100e200e300e400e500e600e700e8012c013001320138013a013c013e013f01450146017f0185018a018d024602470249024b024c024d024e024f0250025102520253025402550256 025702580259025a025b025c025d025e025f0260026102620263026402650282028402860288028a028c028e02900292029402960298029a029c029e02a002a202a402a602a802aa02ac02ae02b102b3 02b502b702b902bb02bd02bf02c102c402c602c802ca02cc02ce02d002d202d402d802da02dc02de02e002e202e402e602e802ea02ec02ee02f002f102f302f50352035303540355035603570358035a 035b035c035d035e035f0360036103630364036503660367036803690379037a037b037c037d037e037f0380038103820383038403850386038703880389038a038b038c038d038e03ba03bc03be03d3 03d903df0448044a044e04560458045d0469000200000002000a3bba0001036c0004000001b106b2369e369e06dc07323740364c36ca3b8a37d807383ade3ade381e3a8c35ea3ade3ade3b8a36560a72 0af4383e381e36a4367839323b00362a0b5e37b636dc37ee0ba00cca0cd43996399637f836dc36180dca38240e2c399038240e4636dc0e8839ca37403b8a37400f020ffc10fa11d812763824127c3996 153a1714182618401846184c1a461a4c1a821ab41b321ca81e5a20183ade214e22e03932252e3ade3ade36f63ade3ade25f8279239a02870293229c02a1e2af839282b8239902c4c2c762ddc36dc3062 30a031d2339036dc325432da3304335a3390374037f836a4382433b636dc39ca39283a8c3a8c3928369e33e0369e369e369e355235783582358c35aa35bc35ce35e036ca3b8a3b8a3b8a3b8a383e3740 37403740374037403740374036ca37d837d837d837d83ade3ade3ade3ade3ade3b8a3b8a3b8a3b8a3b8a381e381e381e381e3b0037b637b637b637b637b637b637b637ee37ee37ee37ee399637f837f8 37f837f837f838243824374037b6374037b6374037b636ca36ca36ca36ca3b8a37d837ee37d837ee37d837ee37d837ee37d837ee3ade39963ade3ade3ade3ade3ade381e3a8c35ea35ea35ea35ea3ade 39963ade39963ade399639963b8a37f83b8a37f83b8a37f8361836183618383e383e383e381e381e381e381e381e381e36783b0038243b00362a362a362a374037d83ade3ade3b8a3b003740364c37d8 362a3ade3ade3a8c3ade3ade3b8a3656383e3b0039323ade3b00399637f8382437f837d839ca3ade3ade381e3a8c3a8c36f63740364c39ca37d83ade3ade3b8a365636ca383e393237b637ee37f836dc 3824399037ee392838243678367836783b003824369e369e369e3ade3996374037b637d837ee36a4382436ca3b0038243ade393239903ade374037b6374037b637d837ee37ee37ee393239903b8a37f8 37f836dc36f6382436f6382436f6382439323990374037b6374037b6374037b6374037b6374037b6374037b6374037b6374037b6374037b6374037b6374037b6374037b637d837ee37d837ee37d837ee 37d837ee37d837ee37d837ee37d837ee37d837ee3ade3ade3b8a37f83b8a37f83b8a37f83b8a37f83b8a37f83b8a37f83b8a37f837f8381e381e3b0038243b0038243b0038243a8c3ade383e39323990 39ca392839323990399639a039ca3a8c3ade3ade3b003b8a0002008b000400040000000600060001000b000c00020013001300040025002a0005002c0036000b0038003f001600450046001e0049004a 0020004c004c0022004f004f0023005100540024005600560028005800580029005a005d002a005f005f002e008a008a002f009c009c003000b000b4003100b600b8003600ba00ba003900bc00bc003a 00bf00c0003b00c200c2003d00c400c4003e00c600cd003f00d100d1004700d300dd004800df00df005300e100e3005400e500ee005700f000f0006100f500f7006200fa00fb006500fd00ff00670102 0104006a01090109006d010c010c006e01170119006f012101210072012b012d0073013001300076013201320077014901490078016c016d0079016f0171007b01ba01ba007e01bd01bd007f01c401c5 008001c801c8008201ca01cb008301cd01cd0085022802280086022a022b008702460247008902490249008b024b026c008c026e027100ae0276027b00b20280028800b8028a028a00c1028c028c00c2 028e028e00c30290029000c40292029b00c502a402a600cf02a802a800d202aa02aa00d302ac02ac00d402ae02ae00d502b102b100d602b302b300d702b502b500d802b702b700d902b902b900da02bb 02bb00db02bd02c900dc02cb02cb00e902cd02cd00ea02cf02cf00eb02da02da00ec02dc02dc00ed02de02de00ee02e002e000ef02e202e200f002e402e400f102e602e600f202e802e800f302ea02ea 00f402ec02ec00f502ee02f100f602f302f300fa02f502f500fb0352035700fc035a03690102036c036c01120370037001130372037201140376037601150379037a0116037c03850118038703890122 038b0390012503920393012b03950398012d039e039f013103a103a1013303a303a3013403a503a8013503ab03b0013903b203b2013f03b603b7014003bc03bc014203be03c7014303ca03cb014d03cd 03d0014f03d703d8015303dc03dc015503de03e4015603e903ea015d03ee0416015f041804180188041a04270189042f042f019704320432019804340434019904400445019a0448044801a0044a044a 01a1044c044c01a2044e044f01a30454045701a5045a045a01a9045c045d01aa045f045f01ac0463046301ad0465046501ae0469046901af04a904a901b0000a0038ffc400d1ffc400d5ffc40132ffc4 013affc402daffc402dcffc402deffc4038dffc4044cffc40015003a0014003b0026003d0016011800140265001602ec002602ee001602f00016035700160366001603690016039f002603a1002603a3 002603a5001603b6001403be00160440001604420016044400160469001600010013ff0800ce0010feee0012feee0025ff40002eff30003800140045ffde0047ffeb0048ffeb0049ffeb004bffeb0053 ffeb0055ffeb0056ffe60059ffea005affe8005dffe80093ffeb0098ffeb009affea00b1ff4000b3ff4000baffeb00bcffe800c7ffeb00c8ffeb00caffea00d1001400d5001400f6ffeb0102ffeb010c ff400117ffeb0119ffe8011dffeb0121ffeb013200140139ffeb013a0014014bffeb014cffeb0156ffeb016efeee0172feee0176feee0177feee01baffc0024bff40024cff40024dff40024eff40024f ff400250ff400251ff400266ffde0267ffde0268ffde0269ffde026affde026bffde026cffde026dffeb026effeb026fffeb0270ffeb0271ffeb0277ffeb0278ffeb0279ffeb027affeb027bffeb027c ffea027dffea027effea027fffea0280ffe80281ffe80282ff400283ffde0284ff400285ffde0286ff400287ffde0289ffeb028bffeb028dffeb028fffeb0291ffeb0293ffeb0295ffeb0297ffeb0299 ffeb029bffeb029dffeb029fffeb02a1ffeb02a3ffeb02b1ff3002c5ffeb02c7ffeb02c9ffeb02da001402dc001402de001402e1ffea02e3ffea02e5ffea02e7ffea02e9ffea02ebffea02efffe80352 ff40035aff40036affeb036effea0370ffeb0372ffe80375ffea0376ffeb0377ffea037eff300382ff40038d0014038fffde0390ffeb0392ffeb0394ffeb0395ffe80397ffeb039effe803a6ffe803ae ff4003afffde03b2ffeb03b7ffe803b8ffeb03bdffeb03bfffe803c4ff4003c5ffde03c6ff4003c7ffde03cbffeb03cdffeb03ceffeb03d8ffeb03daffeb03dcffeb03e0ffe803e2ffe803e4ffe803eb ffeb03eeff4003efffde03f0ff4003f1ffde03f2ff4003f3ffde03f4ff4003f5ffde03f6ff4003f7ffde03f8ff4003f9ffde03faff4003fbffde03fcff4003fdffde03feff4003ffffde0400ff400401 ffde0402ff400403ffde0404ff400405ffde0407ffeb0409ffeb040bffeb040dffeb040fffeb0411ffeb0413ffeb0415ffeb041bffeb041dffeb041fffeb0421ffeb0423ffeb0425ffeb0427ffeb0429 ffeb042bffeb042dffeb042fffeb0431ffeb0433ffea0435ffea0437ffea0439ffea043bffea043dffea043fffea0441ffe80443ffe80445ffe8044c001400200038ffdf003affe4003bffec003dffdd 00d1ffdf00d5ffdf0118ffe40132ffdf013affdf01ba000e0265ffdd02daffdf02dcffdf02deffdf02ecffec02eeffdd02f0ffdd0357ffdd0366ffdd0369ffdd038dffdf039fffec03a1ffec03a3ffec 03a5ffdd03b6ffe403beffdd0440ffdd0442ffdd0444ffdd044cffdf0469ffdd001a0038ffce003affed003dffd000d1ffce00d5ffce0118ffed0132ffce013affce0265ffd002daffce02dcffce02de ffce02eeffd002f0ffd00357ffd00366ffd00369ffd0038dffce03a5ffd003b6ffed03beffd00440ffd00442ffd00444ffd0044cffce0469ffd00010002effee0039ffee0261ffee0262ffee0263ffee 0264ffee02b1ffee02e0ffee02e2ffee02e4ffee02e6ffee02e8ffee02eaffee037effee0432ffee0434ffee004a00060010000b0010000d0014004100120047ffe80048ffe80049ffe8004bffe80055 ffe8006100130093ffe80098ffe800baffe800c7ffe800c8ffe800f6ffe80102ffe8011dffe80121ffe80139ffe8014bffe8014cffe80156ffe8016c0010016d0010016f00100170001001710010026d ffe8026effe8026fffe80270ffe80271ffe80289ffe8028bffe8028dffe8028fffe80291ffe80293ffe80295ffe80297ffe80299ffe8029bffe8029dffe8029fffe802a1ffe802a3ffe8036affe80390 ffe80394ffe80397ffe803a7001003a8001003ab001003b2ffe803b8ffe803bdffe803cbffe803cdffe803ceffe803daffe803ebffe80407ffe80409ffe8040bffe8040dffe8040fffe80411ffe80413 ffe80415ffe80429ffe8042bffe8042dffe80431ffe8000200f5ffd6016dff98003d0047ffec0048ffec0049ffec004bffec0055ffec0093ffec0098ffec00baffec00c7ffec00c8ffec00f6ffec0102 ffec011dffec0121ffec0139ffec014bffec014cffec0156ffec026dffec026effec026fffec0270ffec0271ffec0289ffec028bffec028dffec028fffec0291ffec0293ffec0295ffec0297ffec0299 ffec029bffec029dffec029fffec02a1ffec02a3ffec036affec0390ffec0394ffec0397ffec03b2ffec03b8ffec03bdffec03cbffec03cdffec03ceffec03daffec03ebffec0407ffec0409ffec040b ffec040dffec040fffec0411ffec0413ffec0415ffec0429ffec042bffec042dffec0431ffec00180053ffe20117ffe2016d00180277ffe20278ffe20279ffe2027affe2027bffe202c5ffe202c7ffe2 02c9ffe20370ffe20376ffe20392ffe203d8ffe203dcffe2041bffe2041dffe2041fffe20421ffe20423ffe20425ffe20427ffe2042fffe200060010ff840012ff84016eff840172ff840176ff840177 ff840010002effec0039ffec0261ffec0262ffec0263ffec0264ffec02b1ffec02e0ffec02e2ffec02e4ffec02e6ffec02e8ffec02eaffec037effec0432ffec0434ffec001e0006fff2000bfff2005a fff3005dfff300bcfff300f5fff50119fff3016cfff2016dfff2016ffff20170fff20171fff20280fff30281fff302effff30372fff30395fff3039efff303a6fff303a7fff203a8fff203abfff203b7 fff303bffff303e0fff303e2fff303e4fff30441fff30443fff30445fff3003e0027fff3002bfff30033fff30035fff30083fff30092fff30097fff300b2fff300c3000d00d2fff30107fff30116fff3 011afff3011cfff3011efff30120fff30138fff30155fff30228fff30229fff3022bfff3022cfff30252fff3025cfff3025dfff3025efff3025ffff30260fff30288fff3028afff3028cfff3028efff3 029cfff3029efff302a0fff302a2fff302c4fff302c6fff302c8fff302f9fff30356fff30363fff30389fff3038cfff303b9fff303bcfff303d7fff303d9fff303dbfff3041afff3041cfff3041efff3 0420fff30422fff30424fff30426fff30428fff3042afff3042cfff3042efff30430fff304a9fff3003f0027ffe6002bffe60033ffe60035ffe60083ffe60092ffe60097ffe600b2ffe600b7ffc200c3 001000d2ffe60107ffe60116ffe6011affe6011cffe6011effe60120ffe60138ffe60155ffe60228ffe60229ffe6022bffe6022cffe60252ffe6025cffe6025dffe6025effe6025fffe60260ffe60288 ffe6028affe6028cffe6028effe6029cffe6029effe602a0ffe602a2ffe602c4ffe602c6ffe602c8ffe602f9ffe60356ffe60363ffe60389ffe6038cffe603b9ffe603bcffe603d7ffe603d9ffe603db ffe6041affe6041cffe6041effe60420ffe60422ffe60424ffe60426ffe60428ffe6042affe6042cffe6042effe60430ffe604a9ffe600370025ffe4003cffd2003dffd300b1ffe400b3ffe400c3ffe2 00d9ffd2010cffe4024bffe4024cffe4024dffe4024effe4024fffe40250ffe40251ffe40265ffd30282ffe40284ffe40286ffe402eeffd302f0ffd30352ffe40357ffd3035affe40366ffd30367ffd2 0369ffd30382ffe4038effd203a5ffd303aeffe403beffd303c1ffd203c4ffe403c6ffe403cfffd203e9ffd203eeffe403f0ffe403f2ffe403f4ffe403f6ffe403f8ffe403faffe403fcffe403feffe4 0400ffe40402ffe40404ffe40440ffd30442ffd30444ffd3044effd20456ffd20469ffd300270010ff460012ff460025ffcd00b1ffcd00b3ffcd00c6fff2010cffcd016eff460172ff460176ff460177 ff46024bffcd024cffcd024dffcd024effcd024fffcd0250ffcd0251ffcd0282ffcd0284ffcd0286ffcd0352ffcd035affcd0382ffcd03aeffcd03c4ffcd03c6ffcd03eeffcd03f0ffcd03f2ffcd03f4 ffcd03f6ffcd03f8ffcd03faffcd03fcffcd03feffcd0400ffcd0402ffcd0404ffcd000100c3000e00af0047ffdc0048ffdc0049ffdc004bffdc0051ffc10052ffc10053ffd60054ffc10055ffdc0059 ffdd005affe1005dffe10093ffdc0098ffdc009affdd00baffdc00bcffe100beffe600c0ffc100c1ffeb00c2ffe900c4fff000c5ffe700c7ffdc00c8ffdc00c9ffe300caffdd00cbffce00ccffd400cd ffdb00ebffc100efffc100f0ffc100f2ffc100f3ffc100f4ffc100f6ffdc00f7ffc100f9ffc100faffc100fdffc100ffffc10102ffdc0104ffc10117ffd60119ffe1011dffdc0121ffdc0135ffc10139 ffdc0144ffc10149ffc1014bffdc014cffdc0156ffdc026dffdc026effdc026fffdc0270ffdc0271ffdc0276ffc10277ffd60278ffd60279ffd6027affd6027bffd6027cffdd027dffdd027effdd027f ffdd0280ffe10281ffe10289ffdc028bffdc028dffdc028fffdc0291ffdc0293ffdc0295ffdc0297ffdc0299ffdc029bffdc029dffdc029fffdc02a1ffdc02a3ffdc02beffc102c0ffc102c2ffc102c3 ffc102c5ffd602c7ffd602c9ffd602e1ffdd02e3ffdd02e5ffdd02e7ffdd02e9ffdd02ebffdd02efffe1036affdc036cffc1036effdd0370ffd60372ffe10375ffdd0376ffd60377ffdd0390ffdc0391 ffc10392ffd60393ffc10394ffdc0395ffe10397ffdc0398ffc1039dffc1039effe103a6ffe103adffc103b2ffdc03b3ffc103b7ffe103b8ffdc03bdffdc03bfffe103cbffdc03cdffdc03ceffdc03d4 ffc103d6ffc103d8ffd603daffdc03dcffd603e0ffe103e2ffe103e4ffe103e8ffc103ebffdc0407ffdc0409ffdc040bffdc040dffdc040fffdc0411ffdc0413ffdc0415ffdc041bffd6041dffd6041f ffd60421ffd60423ffd60425ffd60427ffd60429ffdc042bffdc042dffdc042fffd60431ffdc0433ffdd0435ffdd0437ffdd0439ffdd043bffdd043dffdd043fffdd0441ffe10443ffe10445ffe10449 ffc1044bffc10455ffc10462ffc10464ffc10466ffc100760006ffda000bffda0047fff00048fff00049fff0004bfff00055fff00059ffef005affdc005dffdc0093fff00098fff0009affef00bafff0 00bcffdc00c1ffec00c3000f00c5ffea00c7fff000c8fff000c9ffce00caffef00cbffe700f6fff00102fff00119ffdc011dfff00121fff00139fff0014bfff0014cfff00156fff0016cffda016dffda 016fffda0170ffda0171ffda026dfff0026efff0026ffff00270fff00271fff0027cffef027dffef027effef027fffef0280ffdc0281ffdc0289fff0028bfff0028dfff0028ffff00291fff00293fff0 0295fff00297fff00299fff0029bfff0029dfff0029ffff002a1fff002a3fff002e1ffef02e3ffef02e5ffef02e7ffef02e9ffef02ebffef02efffdc036afff0036effef0372ffdc0375ffef0377ffef 0390fff00394fff00395ffdc0397fff0039effdc03a6ffdc03a7ffda03a8ffda03abffda03b2fff003b7ffdc03b8fff003bdfff003bfffdc03cbfff003cdfff003cefff003dafff003e0ffdc03e2ffdc 03e4ffdc03ebfff00407fff00409fff0040bfff0040dfff0040ffff00411fff00413fff00415fff00429fff0042bfff0042dfff00431fff00433ffef0435ffef0437ffef0439ffef043bffef043dffef 043fffef0441ffdc0443ffdc0445ffdc00440010000c0012000c0047ffe70048ffe70049ffe7004bffe70055ffe70093ffe70098ffe700baffe700c3000f00c7ffe700c8ffe700f6ffe70102ffe7011d ffe70121ffe70139ffe7014bffe7014cffe70156ffe7016e000c0172000c0176000c0177000c026dffe7026effe7026fffe70270ffe70271ffe70289ffe7028bffe7028dffe7028fffe70291ffe70293 ffe70295ffe70297ffe70299ffe7029bffe7029dffe7029fffe702a1ffe702a3ffe7036affe70390ffe70394ffe70397ffe703b2ffe703b8ffe703bdffe703cbffe703cdffe703ceffe703daffe703eb ffe70407ffe70409ffe7040bffe7040dffe7040fffe70411ffe70413ffe70415ffe70429ffe7042bffe7042dffe70431ffe7000600c9ffea00ecffee00f5ffd500fdffed0133ffec0158ffec000100f5 ffc0000100c90020007e0006000c000b000c0047ffe80048ffe80049ffe8004a000c004bffe80053ffea0055ffe8005a000b005d000b0093ffe80098ffe800baffe800bc000b00c3ff9000c5000b00c7 ffe800c8ffe800c9000c00f6ffe80102ffe80117ffea0119000b011dffe80121ffe80139ffe8014bffe8014cffe80156ffe8016c000c016d000c016f000c0170000c0171000c01baffbf01bcffee01c0 ffec01c8ffed01caffec01ccfff501cd000e01cf000d01d2000d026dffe8026effe8026fffe80270ffe80271ffe80277ffea0278ffea0279ffea027affea027bffea0280000b0281000b0289ffe8028b ffe8028dffe8028fffe80291ffe80293ffe80295ffe80297ffe80299ffe8029bffe8029dffe8029fffe802a1ffe802a3ffe802c5ffea02c7ffea02c9ffea02ef000b036affe80370ffea0372000b0376 ffea0390ffe80392ffea0394ffe80395000b0397ffe8039e000b03a6000b03a7000c03a8000c03ab000c03b2ffe803b7000b03b8ffe803bdffe803bf000b03cbffe803cdffe803ceffe803d8ffea03da ffe803dcffea03e0000b03e2000b03e4000b03ebffe80407ffe80409ffe8040bffe8040dffe8040fffe80411ffe80413ffe80415ffe8041bffea041dffea041fffea0421ffea0423ffea0425ffea0427 ffea0429ffe8042bffe8042dffe8042fffea0431ffe80441000b0443000b0445000b000100f5ffe2000d005cffed005effed00edffed00f5ffc002f2ffed02f4ffed02f6ffed0396ffed03c2ffed03d0 ffed03eaffed044fffed0457ffed000c005cfff2005efff200edfff202f2fff202f4fff202f6fff20396fff203c2fff203d0fff203eafff2044ffff20457fff2001f005afff4005cfff2005dfff4005e fff300bcfff400edfff20119fff40280fff40281fff402effff402f2fff302f4fff302f6fff30372fff40395fff40396fff2039efff403a6fff403b7fff403bffff403c2fff203d0fff203e0fff403e2 fff403e4fff403eafff20441fff40443fff40445fff4044ffff20457fff2005d0006ffca000bffca0038ffd2003affd4003cfff4003dffd3005affe6005cffef005dffe600bcffe600d1ffd200d5ffd2 00d9fff400ddffed00e0ffe100e5ffd400edffef00f5ffc900fdffd10108ffe50118ffd40119ffe6011fffe30132ffd20133ffc4013affd2013cffe1014dffd4014efff5014fffe70157ff640158ffc9 016cffca016dffca016fffca0170ffca0171ffca0265ffd30280ffe60281ffe602daffd202dcffd202deffd202eeffd302efffe602f0ffd30357ffd30366ffd30367fff40369ffd30372ffe60381ffed 038dffd2038efff40395ffe60396ffef039effe603a5ffd303a6ffe603a7ffca03a8ffca03abffca03b6ffd403b7ffe603beffd303bfffe603c1fff403c2ffef03cffff403d0ffef03dfffed03e0ffe6 03e1ffed03e2ffe603e3ffed03e4ffe603e5ffe103e9fff403eaffef0440ffd30441ffe60442ffd30443ffe60444ffd30445ffe6044cffd2044efff4044fffef0450ffe10452ffe10456fff40457ffef 0469ffd3006c0006ffc0000bffc00038ff9d003affc7003cfff0003dffab0051ffd20052ffd20054ffd200c0ffd200d1ff9d00d3fff500d5ff9d00d9fff000dcfff500ddffea00e0ffe500e5ffc100eb ffd200efffd200f0ffd200f2ffd200f3ffd200f4ffd200f5ffcd00f7ffd200f9ffd200faffd200fdffd200ffffd20104ffd20118ffc70132ff9d0133ffcc0135ffd2013aff9d013cffe5013fffdf0144 ffd20149ffd2014dffce014fffea0151fff50157ff9e0158ffce016cffc0016dffc0016fffc00170ffc00171ffc00265ffab0276ffd202beffd202c0ffd202c2ffd202c3ffd202daff9d02dcff9d02de ff9d02eeffab02f0ffab0357ffab0366ffab0367fff00369ffab036cffd20381ffea038dff9d038efff00391ffd20393ffd20398ffd2039dffd203a5ffab03a7ffc003a8ffc003abffc003adffd203b3 ffd203b6ffc703beffab03c1fff003cffff003d4ffd203d6ffd203dfffea03e1ffea03e3ffea03e5ffe503e8ffd203e9fff003ecfff50440ffab0442ffab0444ffab0449ffd2044bffd2044cff9d044e fff00450ffe50452ffe50455ffd20456fff00462ffd20464ffd20466ffd20467fff50469ffab006f0006ffb1000bffb10038ff9e003affc5003cfff2003dffa80051ffcf0052ffcf0054ffcf005cffef 00c0ffcf00d1ff9e00d5ff9e00d9fff200ddffec00e0ffe100e5ffc200ebffcf00edffef00efffcf00f0ffcf00f2ffcf00f3ffcf00f4ffcf00f5ffc600f7ffcf00f9ffcf00faffcf00fdffcf00ffffcf 0104ffcf0118ffc50132ff9e0133ffc00135ffcf013aff9e013cffe1013fffdf0144ffcf0149ffcf014dffcd014fffe80157ff9f0158ffc6016cffb1016dffb1016fffb10170ffb10171ffb10265ffa8 0276ffcf02beffcf02c0ffcf02c2ffcf02c3ffcf02daff9e02dcff9e02deff9e02eeffa802f0ffa80357ffa80366ffa80367fff20369ffa8036cffcf0381ffec038dff9e038efff20391ffcf0393ffcf 0396ffef0398ffcf039dffcf03a5ffa803a7ffb103a8ffb103abffb103adffcf03b3ffcf03b6ffc503beffa803c1fff203c2ffef03cffff203d0ffef03d4ffcf03d6ffcf03dfffec03e1ffec03e3ffec 03e5ffe103e8ffcf03e9fff203eaffef0440ffa80442ffa80444ffa80449ffcf044bffcf044cff9e044efff2044fffef0450ffe10452ffe10455ffcf0456fff20457ffef0462ffcf0464ffcf0466ffcf 0469ffa8004d0038ffbe0051ffe10052ffe10054ffe1005affef005dffef00bcffef00c0ffe100d1ffbe00d5ffbe00e5ffc900ebffe100efffe100f0ffe100f2ffe100f3ffe100f4ffe100f5ffdf00f7 ffe100f9ffe100faffe100fdffe100ffffe10104ffe10108ffed0119ffef011fffeb0132ffbe0133ffdf0135ffe1013affbe013fffe90144ffe10149ffe1014efff50158ffe00276ffe10280ffef0281 ffef02beffe102c0ffe102c2ffe102c3ffe102daffbe02dcffbe02deffbe02efffef036cffe10372ffef038dffbe0391ffe10393ffe10395ffef0398ffe1039dffe1039effef03a6ffef03adffe103b3 ffe103b7ffef03bfffef03d4ffe103d6ffe103e0ffef03e2ffef03e4ffef03e8ffe10441ffef0443ffef0445ffef0449ffe1044bffe1044cffbe0455ffe10462ffe10464ffe10466ffe100640038ffe6 003affe7003cfff2003dffe70051ffd60052ffd60054ffd6005cfff100c0ffd600d1ffe600d5ffe600d9fff200ddffee00e0ffe800e5ffe600ebffd600edfff100efffd600f0ffd600f2ffd600f3ffd6 00f4ffd600f5ffd000f7ffd600f9ffd600faffd600fdffd600ffffd60104ffd60118ffe70132ffe60133ffce0135ffd6013affe6013cffe80144ffd60149ffd6014dffe7014fffed0157ffe60158ffd0 0265ffe70276ffd602beffd602c0ffd602c2ffd602c3ffd602daffe602dcffe602deffe602eeffe702f0ffe70357ffe70366ffe70367fff20369ffe7036cffd60381ffee038dffe6038efff20391ffd6 0393ffd60396fff10398ffd6039dffd603a5ffe703adffd603b3ffd603b6ffe703beffe703c1fff203c2fff103cffff203d0fff103d4ffd603d6ffd603dfffee03e1ffee03e3ffee03e5ffe803e8ffd6 03e9fff203eafff10440ffe70442ffe70444ffe70449ffd6044bffd6044cffe6044efff2044ffff10450ffe80452ffe80455ffd60456fff20457fff10462ffd60464ffd60466ffd60469ffe700930025 00100027ffe8002bffe80033ffe80035ffe80038ffe0003affe0003dffdf0083ffe80092ffe80097ffe800b1001000b2ffe800b3001000d1ffe000d2ffe800d3001000d5ffe000d8001400dc001000e0 ffe100e5ffe000ec001300f1001000f8ffe0010300100107ffe8010c00100116ffe80118ffe0011affe8011cffe8011effe80120ffe80132ffe00138ffe8013affe0013cffe1013dffe00140ffe10145 ffe9014dffdf014fffde015100100155ffe80157ffdf0159fff20228ffe80229ffe8022bffe8022cffe8024b0010024c0010024d0010024e0010024f001002500010025100100252ffe8025cffe8025d ffe8025effe8025fffe80260ffe80265ffdf0282001002840010028600100288ffe8028affe8028cffe8028effe8029cffe8029effe802a0ffe802a2ffe802c4ffe802c6ffe802c8ffe802daffe002dc ffe002deffe002eeffdf02f0ffdf02f9ffe8035200100356ffe80357ffdf035a00100363ffe80366ffdf0369ffdf038200100389ffe8038cffe8038dffe003a5ffdf03ae001003b6ffe003b9ffe803bc ffe803beffdf03c4001003c6001003d7ffe803d9ffe803dbffe803e5ffe103e6ffe003ec001003ed001003ee001003f0001003f2001003f4001003f6001003f8001003fa001003fc001003fe00100400 00100402001004040010041affe8041cffe8041effe80420ffe80422ffe80424ffe80426ffe80428ffe8042affe8042cffe8042effe80430ffe80440ffdf0442ffdf0444ffdf044cffe00450ffe10451 ffe00452ffe10453ffe004670010046800100469ffdf04a9ffe80032001bfff20038fff1003afff4003cfff4003dfff000d1fff100d3fff500d5fff100d9fff400dcfff500ddfff300e5fff10118fff4 0132fff1013afff1014dfff2014ffff20151fff50157fff20265fff002dafff102dcfff102defff102eefff002f0fff00357fff00366fff00367fff40369fff00381fff3038dfff1038efff403a5fff0 03b6fff403befff003c1fff403cffff403dffff303e1fff303e3fff303e9fff403ecfff50440fff00442fff00444fff0044cfff1044efff40456fff40467fff50469fff000660025000f0038ffe6003a ffe6003c000e003dffe600b1000f00b3000f00d1ffe600d3000e00d5ffe600d8001300d9000e00dc000e00dd000b00e0ffe500e5ffe600e6fff400ec001200f1000f00f5ffe700f8ffe800fdffe70103 000f010c000f0118ffe60132ffe60133ffe7013affe6013cffe5013dffe8014dffe6014fffe60151000e0157ffe60158ffe7024b000f024c000f024d000f024e000f024f000f0250000f0251000f0265 ffe60282000f0284000f0286000f02daffe602dcffe602deffe602eeffe602f0ffe60352000f0357ffe6035a000f0366ffe60367000e0369ffe60381000b0382000f038dffe6038e000e03a5ffe603ae 000f03b6ffe603beffe603c1000e03c4000f03c6000f03cf000e03df000b03e1000b03e3000b03e5ffe503e6ffe803e9000e03ec000e03ed000f03ee000f03f0000f03f2000f03f4000f03f6000f03f8 000f03fa000f03fc000f03fe000f0400000f0402000f0404000f0440ffe60442ffe60444ffe6044cffe6044e000e0450ffe50451ffe80452ffe50453ffe80456000e0467000e0468000f0469ffe60037 0006ffbf000bffbf0038ff9f003affc9003dffad00d1ff9f00d5ff9f00ddffec00e0ffe600e5ffc400f5ffcd00fdffd50118ffc90132ff9f0133ffcc013aff9f013cffe6013fffdf014dffd1014fffec 0157ffa10158ffcf016cffbf016dffbf016fffbf0170ffbf0171ffbf0265ffad02daff9f02dcff9f02deff9f02eeffad02f0ffad0357ffad0366ffad0369ffad0381ffec038dff9f03a5ffad03a7ffbf 03a8ffbf03abffbf03b6ffc903beffad03dfffec03e1ffec03e3ffec03e5ffe60440ffad0442ffad0444ffad044cff9f0450ffe60452ffe60469ffad00300038ffe3003cffe5003dffe400d1ffe300d3 ffe500d5ffe300d8ffe200d9ffe500dcffe500ddffe900f1ffea0103ffea0132ffe3013affe30151ffe50157ffe40265ffe402daffe302dcffe302deffe302eeffe402f0ffe40357ffe40366ffe40367 ffe50369ffe40381ffe9038dffe3038effe503a5ffe403beffe403c1ffe503cfffe503dfffe903e1ffe903e3ffe903e9ffe503ecffe503edffea0440ffe40442ffe40444ffe4044cffe3044effe50456 ffe50467ffe50468ffea0469ffe400230038ffe2003cffe400d1ffe200d3ffe400d5ffe200d8ffe100d9ffe400dcffe400ddffe900ecffe400f1ffeb0103ffeb0132ffe2013affe20151ffe402daffe2 02dcffe202deffe20367ffe40381ffe9038dffe2038effe403c1ffe403cfffe403dfffe903e1ffe903e3ffe903e9ffe403ecffe403edffeb044cffe2044effe40456ffe40467ffe40468ffeb00170038 ffeb003dfff300d1ffeb00d5ffeb0132ffeb013affeb0265fff302daffeb02dcffeb02deffeb02eefff302f0fff30357fff30366fff30369fff3038dffeb03a5fff303befff30440fff30442fff30444 fff3044cffeb0469fff300360051ffef0052ffef0054ffef005cfff000c0ffef00ebffef00ecffee00edfff000efffef00f0ffef00f2ffef00f3ffef00f4ffef00f5ffee00f7ffef00f9ffef00faffef 00fdffef00ffffef0104ffef0108fff4011ffff10133ffef0135ffef0144ffef0149ffef0158ffef0276ffef02beffef02c0ffef02c2ffef02c3ffef036cffef0391ffef0393ffef0396fff00398ffef 039dffef03adffef03b3ffef03c2fff003d0fff003d4ffef03d6ffef03e8ffef03eafff00449ffef044bffef044ffff00455ffef0457fff00462ffef0464ffef0466ffef00220006fff2000bfff2005a fff5005dfff500bcfff500f5fff400fdfff40108fff50119fff50133fff50158fff5016cfff2016dfff2016ffff20170fff20171fff20280fff50281fff502effff50372fff50395fff5039efff503a6 fff503a7fff203a8fff203abfff203b7fff503bffff503e0fff503e2fff503e4fff50441fff50443fff50445fff500320051ffee0052ffee0054ffee00c0ffee00ebffee00ec001400efffee00f0ffee 00f2ffee00f3ffee00f4ffee00f5ffed00f7ffee00f8ffed00f9ffee00faffee00fbffd000fdffee00ffffee0104ffee0133ffed0135ffee013dffed0144ffee0149ffee0158ffed0276ffee02beffee 02c0ffee02c2ffee02c3ffee036cffee0391ffee0393ffee0398ffee039dffee03adffee03b3ffee03d4ffee03d6ffee03e6ffed03e8ffee0449ffee044bffee0451ffed0453ffed0455ffee0462ffee 0464ffee0466ffee000a0006fff5000bfff5016cfff5016dfff5016ffff50170fff50171fff503a7fff503a8fff503abfff500590047fff00048fff00049fff0004bfff00053ffc70055fff00093fff0 0098fff000bafff000c7fff000c8fff000f6fff00102fff00117ffc7011bffeb011dfff00121fff00139fff0014bfff0014cfff00156fff001bcffeb01c0ffe901c8ffeb01caffeb026dfff0026efff0 026ffff00270fff00271fff00277ffc70278ffc70279ffc7027affc7027bffc70289fff0028bfff0028dfff0028ffff00291fff00293fff00295fff00297fff00299fff0029bfff0029dfff0029ffff0 02a1fff002a3fff002c5ffc702c7ffc702c9ffc7036afff00370ffc70376ffc70390fff00392ffc70394fff00397fff003b2fff003b8fff003bdfff003cbfff003cdfff003cefff003d8ffc703dafff0 03dcffc703ebfff00407fff00409fff0040bfff0040dfff0040ffff00411fff00413fff00415fff0041bffc7041dffc7041fffc70421ffc70423ffc70425ffc70427ffc70429fff0042bfff0042dfff0 042fffc70431fff000a10006000d000b000d0045fff00047ffc00048ffc00049ffc0004a000d004bffc00053ffe20055ffc0005a000b005d000b0093ffc00098ffc000baffc000bc000b00c6ffd600c7 ffc000c8ffc000cbffd500ecffc800f1ffd700f6ffc00102ffc00103ffd70117ffe20119000b011bffec011dffc0011f000c0121ffc00139ffc0014bffc0014cffc0014e000b0150000b0156ffc0016c 000d016d000d016f000d0170000d0171000d01baffbf01bcffee01c0ffec01c8ffed01caffec01ccfff501cd000e01cf000d01d2000d0266fff00267fff00268fff00269fff0026afff0026bfff0026c fff0026dffc0026effc0026fffc00270ffc00271ffc00277ffe20278ffe20279ffe2027affe2027bffe20280000b0281000b0283fff00285fff00287fff00289ffc0028bffc0028dffc0028fffc00291 ffc00293ffc00295ffc00297ffc00299ffc0029bffc0029dffc0029fffc002a1ffc002a3ffc002c5ffe202c7ffe202c9ffe202ef000b036affc00370ffe20372000b0376ffe2038ffff00390ffc00392 ffe20394ffc00395000b0397ffc0039e000b03a6000b03a7000d03a8000d03ab000d03affff003b2ffc003b7000b03b8ffc003bdffc003bf000b03c5fff003c7fff003cbffc003cdffc003ceffc003d8 ffe203daffc003dcffe203e0000b03e2000b03e4000b03ebffc003edffd703effff003f1fff003f3fff003f5fff003f7fff003f9fff003fbfff003fdfff003fffff00401fff00403fff00405fff00407 ffc00409ffc0040bffc0040dffc0040fffc00411ffc00413ffc00415ffc0041bffe2041dffe2041fffe20421ffe20423ffe20425ffe20427ffe20429ffc0042bffc0042dffc0042fffe20431ffc00441 000b0443000b0445000b0468ffd7000f00ec001400f1001000f5fff000f8fff000fdfff001000016010300100133ffe6013dffdc0158fff003e6fff003ed00100451fff00453fff004680010004c0047 ffee0048ffee0049ffee004bffee0055ffee0093ffee0098ffee00baffee00c7ffee00c8ffee00ec001200f1000e00f5ffe300f6ffee00f8ffe300fbffb800fdffe30102ffee0103000e011dffee0121 ffee0133ffba0139ffee013dffd9014bffee014cffee0156ffee0158ffe3026dffee026effee026fffee0270ffee0271ffee0289ffee028bffee028dffee028fffee0291ffee0293ffee0295ffee0297 ffee0299ffee029bffee029dffee029fffee02a1ffee02a3ffee036affee0390ffee0394ffee0397ffee03b2ffee03b8ffee03bdffee03cbffee03cdffee03ceffee03daffee03e6ffe303ebffee03ed 000e0407ffee0409ffee040bffee040dffee040fffee0411ffee0413ffee0415ffee0429ffee042bffee042dffee0431ffee0451ffe30453ffe30468000e0020005affc0005dffc000bcffc000f5ff80 00f8ffee00fdfff00108ffdb0119ffc0011fffdc0133ff47013dffee014e00070150fff40158ff7f0280ffc00281ffc002efffc00372ffc00395ffc0039effc003a6ffc003b7ffc003bfffc003e0ffc0 03e2ffc003e4ffc003e6ffee0441ffc00443ffc00445ffc00451ffee0453ffee0021005afff4005cfff0005dfff400bcfff400ecffef00edfff000f1fff300fdffee0103fff30119fff40280fff40281 fff402effff40372fff40395fff40396fff0039efff403a6fff403b7fff403bffff403c2fff003d0fff003e0fff403e2fff403e4fff403eafff003edfff30441fff40443fff40445fff4044ffff00457 fff00468fff3000a0006ffd6000bffd6016cffd6016dffd6016fffd60170ffd60171ffd603a7ffd603a8ffd603abffd60015005cffe000edffe000f5ff7600f8ffc200fdffd30108ffd9011fffdb0133 ff1e013dffed014efff00150fff20158ff560396ffe003c2ffe003d0ffe003e6ffc203eaffe0044fffe00451ffc20453ffc20457ffe0000d00f5ff6400f8ffd200fdffd90108ffd9011fffdb0133ff1e 013dffed014efff00150fff20158ff5603e6ffd20451ffd20453ffd2000900f5ff6a00fdffc60108ffd9011fffdb0133ff1e013dffed014efff00150fff20158ff56000a0006ffd7000bffd7016cffd7 016dffd7016fffd70170ffd70171ffd703a7ffd703a8ffd703abffd7005c0047ff980048ff980049ff98004bff980053ff700055ff980057ff18005b000b0093ff980098ff9800baff9800c7ff9800c8 ff9800f6ff980102ff980117ff70011dff980121ff980139ff98014bff98014cff980156ff98026dff98026eff98026fff980270ff980271ff980277ff700278ff700279ff70027aff70027bff700289 ff98028bff98028dff98028fff980291ff980293ff980295ff980297ff980299ff98029bff98029dff98029fff9802a1ff9802a3ff9802c5ff7002c7ff7002c9ff7002d1ff1802d3ff1802d5ff1802d7 ff1802d9ff18036aff980370ff700376ff700390ff980392ff700394ff980397ff980399ff1803b2ff9803b8ff9803bdff9803cbff9803cdff9803ceff9803d8ff7003daff9803dcff7003ebff980407 ff980409ff98040bff98040dff98040fff980411ff980413ff980415ff98041bff70041dff70041fff700421ff700423ff700425ff700427ff700429ff98042bff98042dff98042fff700431ff980009 01bcfff201c0fff201c8fff201cafff201cdffc001ceffec01cfffc701d0ffd801d2ffbf000201cfffee01d0fff5000201c8ffeb01caffeb000701c8ffef01cafff001cdffbb01ceffec01cfffb701d0 ffd501d2ffb4000401cdffee01cffff101d1ffec01d2ffea000401cdffe901cfffeb01d0fff101d2ffe5000401cdfff201cffff101d0fff501d2ffee000201cf000d01d2000d000b005bffcc01ba0013 01bcfff301c0fff101c8fff201cafff201cdffbd01ceffee01cfffb801d0ffd701d2ffb70004004a001400580032005b0011016d00100008005bffe500b7ffcb00ccffe401ba000d01bcffed01c0ffeb 01c8ffec01caffec00020110000b0157ffe600080058000e0081fed700c3ff9800c6ffc700d8ff1200ecff52014affcf01baff800009000d000f0041000c0056ffeb0061000e01baffcb01bcffe901c0 ffe701c8ffe701caffe70001005b000b0009000d0014004100110056ffe20061001301baffb401bcffd901c0ffd901c8ffd901caffd90004000dffe60041fff40061ffef0140ffed000600c9ffea00ec ffee00f5ffd600fdffed0133ffec0158ffec001200d8ffae00e5001200eaffe000ecffad00eeffd600fcffdf0100ffd20106ffe0011bffce012bffdd012dffe20131ffe00137ffe0013dffe90140ffda 014affbd0154ffdf01570011001d0023ffaf0058ffef005bffdf0099ffee00b7ffe500b8ffd100c3001100c9ffc800d8001300e5ffc500f5ffca00fdffd00133ff81013cff65013dff85013fff660140 ffdd0145fff2014dffb1014fffca0157ffa90158ffc801c0fff501c8fff501cdffc701cefff101cfffcd01d0ffdd01d2ffc4000800f5fff000fdfff00108fff1011ffff30133fff1014efff30150fff3 0158fff10005004affee005bffea01cffff001d0ffed01d2fff0000200f5fff5016dffc0000900c9ffea00ecffb800f5ffe20108fff0011ffff10133ffeb014efff50158ffec016dff90000101baffeb 0006004a000d00c5000b00c6ffea00c9000c00ecffc8011bfff1003a0004ffc40056ffbf005bffd1006dff6c007cff6e0081ff430086ffac0089ffa100b7ffb800beff7e00c2ff7b00c5ff9b00c6ff79 00c9ffb200cbff7e00ccff7d00cdff7c00d8ffaf00e5000f00e9ffe400eaffa000ecff7400eeff8000f5ffb200fcff7d00fdffb200feff800100ff79010100280106ff7d0108ff7f011bff66011fffda 012bff81012dff980131ff7d0133ffb30137ffa0013dff7c013fff9a0140ff6c0145ffe6014aff6b014eff920150ffad0154ff7b0157000f0158ff910159fff201baffaf01bcffb901c0ffb901c8ffb9 01caffb901ccffbc01cdfff101d0fff101d1ffed000200ecff68011bffee001700b7ffd400c1ffed00c3001100c9ffe000cbffe700ccffe500cdffee00d8001200e9ffe900f5ffd70133ffd7013dffd3 013fffd60140ffc50145ffe7014d000d014f000c0158ffd60159fff201bcffe901c0ffe701c8ffe701caffe90001011bfff1000200f5ffd6016dff88000a00e5ffc300f5ffcf00fdffd40133ffce013c ffe7013fffdf014dffd1014fffec0157ffa00158ffd100300056ff7e005bff9d006dfef1007cfef40081feab0086ff5e0089ff4b00b7ff7200beff0f00c2ff0a00c5ff4100c6ff0700c9ff6800cbff0f 00ccff0e00cdff0c00d8ff6300e5000500e9ffbd00eaff4900ecfefe00eeff1300f5ff6800fcff0e00fdff6800feff130100ff07010100300106ff0e0108ff11011bfee7011fffac012bff15012dff3c 0131ff0e0133ff6a0137ff49013dff0c013fff3f0140fef10145ffc0014afeef014eff310150ff5f0154ff0a015700050158ff300159ffd50014005bffc100b7ffc500c9ffb400e9ffd700f5ffb900fd ffe90108ffb2011bffd2011fffc80133ffa0013dffc50145ffe4014effcc0150ffcc0158ffcb0159ffef01bcffe801c0ffe601c8ffe701caffe7000800d8001500ec0015013cffe4013dffe5013fffe4 014dffe3014fffe20157ffe40022000affe2000d0014000effcf00410012004affea0056ffd80058ffea00610013006dffae007cffcd0081ffa00086ffc10089ffc000b7ffd000bbffea00beffc600bf 000d00c1ffe900c2ffd600c5ffe800c6ffba00c9ffe900cbffcb00ccffda00cdffc70175ffd301baffab01bcffcd01c0ffcb01c8ffcb01caffcb01cdfff301d0fff301d1ffef00090081ffdf00b4fff3 00b6fff000c3ffea00d8ffdf00e5ffe00157ffe001baffed01d1fff50002078a000400000a5e12360021001d0000ffdbff88ffceffc5ffecffa5ffa40000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000fee3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000ff88000000000000ffd0fff40000ffebff88ffefffb3ffd9ff6afff5ffce000c0011ffc90012ffdf00000000000000000000000000000000000000000000000000000000000000000000ffe50000 ffe80000ffc90000000000000000000000000000fff30000000000000000000000000000000000000000000000000000000000000000ffe3000000000000000000000000000000000000000000000000 000000000000000000000000000000000000ffeb000000000000000000000000ffab0000ffea0000ffd5000000000000ffe10000000000000000ff86ffeaffe900000000000000000000000000000000 ffed0000ffed0000000000140000000000000000ffefffe60000000000000000000000000000000000000000000000000000000000000012000000000000000000000000ffe3000000000000ffe40000 000000000011ffe40011ffe50000000000110000000000000000000000000000ffea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000ffe60000ffe50000ffe100000000000000000000ffe9ffd80000000000000000ffa30000000000000000ff5c0000000000000000fee0001300000000000000000000 ffc0ff33ffe8ff32ffa3fee9fff2ff85000000000000000000000000000000000000000000000000000000000000ff4efff5fff30000fff300000000000000000000000000000000000f0000ff6f0000 ffa700000000fe6cffcdffdc0000ff480000000000000000ff88ff58ffa7ffa7ff30ffb4ffe4001000000010000f0010ffbfffaeffc4ffcb0000ff7eff7c0000fefe00000000fef0ff28fff0ffb30000 0000ffb5ffd2ffd40000ffd20000fff300000000000000000000ffe4fff5000000000000000000000000ff2900000000ff6300000000000000000000ffd5ffdfffe10000ffe100000000000e00000000 00000000ffed0000000000000000000000000000ff7100000000ffc40000000000000000000000000000ffe60000ffeb0000ffe700000000000e00000000ffebffe10000001100000011ffd100000000 00000000ff6400000000000000000000ff6affc1ffbfffd8ffbfffc6ffe30011ffa0001200110012ffd9ffecffe200000000000000000000ff19000d0000ff68ffa0fff0ffe900000000000d0000ffeb 0000ffeb0000ffe600000000000000000000ffedffe500000000000000000000000000000000000000000000000000000000ffef0000000000000000000000000000000000000000000000000000fff1 00000000000000000000000000000000000000000000000000000000ffe30000000000000000000000000000000000000000000000000000fff5fff100000000fff20000000000000000000000000000 0000fff10000fff50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fff20000000000000000000000000000 000000000000000000000000fff300000000000000000000000000000000000000000000000000000000ffb0000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000ffa80000000000000000000000000000000000000000000000000000fff1fff000000000fff000000000000000000000000000000000ffeb00000010 0000ffe2ffed0000ffdc000000000000000000000000000000000012000000000000000000000000ff530000000000000000000000000000000f0000fff1fff30000fff1000000000000000000000000 000000000000000000000000ffd700000000ff590000000000000000000000000000000000000000ffec0000ffd800000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000fff00000fff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff33ff5fff55ff55 ff66ff6bffbd00070000000700050007ff7eff61ff86ff920000ff0fff0c0000fe3600000000fe1e0000ffd1ff6a0000ffc00000000000000000000000000000ff9f0000ffc80000ffad000000000000 0000ffe700000000ffeb000000000000000000000000ffc900000000ffa5ffafffbdffaeffbdffd2ffe900120000000000000012000000000000ffca0000ffbbffe90000fe7700000000ff3900000000 00000000000000000000ffec0000ffec000000000000000000000000000000000000000000000000ffd80000000000000000000000000000000000000000ff7900000000000000000000000000000000 00000000000000000000ffb50000000000000000ffe30000000000000000000000000000ffeb00020078000600060000000b000b0001001000100002001200120003002500290004002c003400090038 003e001200450047001900490049001c004c004c001d00510054001e005600560022005a005a0023005c005e0024008a008a002700b000b3002800bc00bc002c00c000c0002d00c600c6002e00d300d4 002f00d600d6003100d900d9003200db00dd003300df00df003600e100e1003700e300e3003800e500e5003900eb00eb003a00ed00ed003b00f600f6003c00fb00fb003d00fd00fe003e010301040040 010901090042010c010c0043011701190044012b012d004701300130004a01320132004b01490149004c016c0172004d017601770054022802280056022a022b005702460247005902490249005b024b 0271005c0276027b00830280029000890292029b009a02a402a600a402a802a800a702aa02aa00a802ac02ac00a902ae02ae00aa02b102b100ab02b302b300ac02b502b500ad02b702b700ae02b902b9 00af02bb02bb00b002bd02c900b102cb02cb00be02cd02cd00bf02cf02cf00c002da02da00c102dc02dc00c202de02de00c302e002e000c402e202e200c502e402e400c602e602e600c702e802e800c8 02ea02ea00c902ec02ec00ca02ee02f600cb0352035700d4035a036900da036c036c00ea0370037000eb0372037200ec0376037600ed0379037a00ee037c038500f00387038900fa038b039000fd0392 03980103039e039f010a03a103a1010c03a303a3010d03a503a8010e03ab03b0011203b203b2011803b603b7011903bc03c7011b03ca03cb012703cd03d0012903d703d8012d03dc03dc012f03de03e4 013003e903ea013703ee04160139041804180162041a04270163042f042f017104320432017204340434017304400445017404480448017a044a044a017b044c044c017c044e044f017d04540457017f 045a045a0183045c045d0184045f045f018604630463018704650465018804690469018904a904a9018a0002014e00100010000100120012000100250025000200260026000300270027000400280028 0005002900290006002c002d0007002e002e0008002f002f000900300030000a00310032000700330033000500340034000b00380038000c003900390008003a003a000d003b003b000e003c003c000f 003d003d0010003e003e0011004500450012004600460013004700470014004900490015004c004c0016005100520016005300530017005400540013005600560018005a005a0019005c005c001a005d 005d0019005e005e001b008a008a001300b000b0001c00b100b1000200b200b2000500b300b3000200bc00bc001900c000c0001600c600c6001300d300d4001d00d600d6000700d900d9000f00db00dc 000700dd00dd001e00df00df000700e100e1000700e300e3001d00e500e5001d00eb00eb001f00ed00ed001a00f600f6001300fb00fb002000fd00fd002000fe00fe0013010301040020010901090020 010c010c000201170117001701180118000d011901190019012b012b0013012c012c001c012d012d001f01300130000901320132000901490149001f016e016e00010172017200010176017700010228 02280004022a022b000502460247000502490249000c024b025100020252025200040253025600060257025b0007025c026000050261026400080265026500100266026c0012026d026d0014026e0271 00150276027600160277027b0017028002810019028202820002028302830012028402840002028502850012028602860002028702870012028802880004028902890014028a028a0004028b028b0014 028c028c0004028d028d0014028e028e0004028f028f0014029002900005029202920006029302930015029402940006029502950015029602960006029702970015029802980006029902990015029a 029a0006029b029b001502a402a4000702a502a5001602a602a6000702a802a8000702aa02aa000702ac02ac000702ae02ae000702b102b1000802b302b3000902b502b5000a02b702b7000a02b902b9 000a02bb02bb000a02bd02bd000702be02be001602bf02bf000702c002c0001602c102c1000702c202c3001602c402c4000502c502c5001702c602c6000502c702c7001702c802c8000502c902c90017 02cb02cb001802cd02cd001802cf02cf001802da02da000c02dc02dc000c02de02de000c02e002e0000802e202e2000802e402e4000802e602e6000802e802e8000802ea02ea000802ec02ec000e02ee 02ee001002ef02ef001902f002f0001002f102f1001102f202f2001b02f302f3001102f402f4001b02f502f5001102f602f6001b03520352000203530353000603540355000703560356000503570357 0010035a035a0002035b035b0003035c035c0006035d035d0011035e035f000703600360000903610362000703630363000503640364000b03650365000c03660366001003670367000f036803680007 036903690010036c036c0016037003700017037203720019037603760017037903790006037a037a001c037c037d0007037e037e0008037f0380000903810381001e0382038200020383038300030384 0384001c038503850006038703880007038903890005038b038b000b038c038c0004038d038d000c038e038e000f038f038f001203900390001503920392001703930393001303940394001403950395 001903960396001a03970397001503980398001f039e039e0019039f039f000e03a103a1000e03a303a3000e03a503a5001003a603a6001903ac03ac000703ad03ad001603ae03ae000203af03af0012 03b003b0000603b203b2001503b603b6000d03b703b7001903bc03bc000403bd03bd001403be03be001003bf03bf001903c003c0000703c103c1000f03c203c2001a03c303c3000703c403c4000203c5 03c5001203c603c6000203c703c7001203ca03ca000603cb03cb001503cd03ce001503cf03cf000f03d003d0001a03d703d7000503d803d8001703dc03dc001703de03de001303df03df001e03e003e0 001903e103e1001e03e203e2001903e303e3001e03e403e4001903e903e9000f03ea03ea001a03ee03ee000203ef03ef001203f003f0000203f103f1001203f203f2000203f303f3001203f403f40002 03f503f5001203f603f6000203f703f7001203f803f8000203f903f9001203fa03fa000203fb03fb001203fc03fc000203fd03fd001203fe03fe000203ff03ff00120400040000020401040100120402 04020002040304030012040404040002040504050012040604060006040704070015040804080006040904090015040a040a0006040b040b0015040c040c0006040d040d0015040e040e0006040f040f 0015041004100006041104110015041204120006041304130015041404140006041504150015041604160007041804180007041a041a0005041b041b0017041c041c0005041d041d0017041e041e0005 041f041f0017042004200005042104210017042204220005042304230017042404240005042504250017042604260005042704270017042f042f00170432043200080434043400080440044000100441 04410019044204420010044304430019044404440010044504450019044804480009044a044a0007044c044c000c044e044e000f044f044f001a04540454001c04550455001f04560456000f04570457 001a045a045a0016045c045c001d045d045d001c045f045f000904630463000704650465000704690469001004a904a900050002016d000600060001000b000b00010010001000160011001100190012 00120016002500250002002700270008002b002b0008002e002e001a00330033000800350035000800370037001b00380038000900390039000a003a003a000b003b003b000c003c003c0017003d003d 000d003e003e0018004500450003004700490004004b004b000400510052000500530053000600540054000500550055000400570057000700590059000e005a005a000f005c005c001c005d005d000f 005e005e0010008300830008009200920008009300930004009700970008009800980004009a009a000e00b100b1000200b200b2000800b300b3000200ba00ba000400bc00bc000f00c000c0000500c7 00c8000400ca00ca000e00d100d1000900d200d2000800d300d3001100d500d5000900d900d9001700dc00dc001100dd00dd001500e000e0001200eb00eb000500ed00ed001c00ef00f0000500f100f1 001300f200f4000500f600f6000400f700f7000500f800f8001400f900fa000500fd00fd000500ff00ff0005010201020004010301030013010401040005010701070008010c010c0002011601160008 01170117000601180118000b01190119000f011a011a0008011c011c0008011d011d0004011e011e0008012001200008012101210004013201320009013501350005013801380008013901390004013a 013a0009014401440005014901490005014b014c00040151015100110155015500080156015600040169016a0019016c016d0001016e016e0016016f0171000101720172001601760177001602280229 0008022b022c0008024502450019024b02510002025202520008025c0260000802610264000a02650265000d0266026c0003026d027100040276027600050277027b0006027c027f000e02800281000f 028202820002028302830003028402840002028502850003028602860002028702870003028802880008028902890004028a028a0008028b028b0004028c028c0008028d028d0004028e028e0008028f 028f0004029102910004029302930004029502950004029702970004029902990004029b029b0004029c029c0008029d029d0004029e029e0008029f029f000402a002a0000802a102a1000402a202a2 000802a302a3000402b102b1001a02be02be000502c002c0000502c202c3000502c402c4000802c502c5000602c602c6000802c702c7000602c802c8000802c902c9000602d002d0001b02d102d10007 02d202d2001b02d302d3000702d402d4001b02d502d5000702d602d6001b02d702d7000702d802d8001b02d902d9000702da02da000902dc02dc000902de02de000902e002e0000a02e102e1000e02e2 02e2000a02e302e3000e02e402e4000a02e502e5000e02e602e6000a02e702e7000e02e802e8000a02e902e9000e02ea02ea000a02eb02eb000e02ec02ec000c02ee02ee000d02ef02ef000f02f002f0 000d02f102f1001802f202f2001002f302f3001802f402f4001002f502f5001802f602f6001002f902f9000803520352000203560356000803570357000d035a035a0002035d035d0018036303630008 03660366000d03670367001703690369000d036a036a0004036c036c0005036e036e000e03700370000603720372000f03750375000e03760376000603770377000e037e037e001a0381038100150382 03820002038903890008038c038c0008038d038d0009038e038e0017038f038f000303900390000403910391000503920392000603930393000503940394000403950395000f03960396001c03970397 0004039803980005039903990007039d039d0005039e039e000f039f039f000c03a103a1000c03a303a3000c03a503a5000d03a603a6000f03a703a8000103ab03ab000103ad03ad000503ae03ae0002 03af03af000303b203b2000403b303b3000503b603b6000b03b703b7000f03b803b8000403b903b9000803bc03bc000803bd03bd000403be03be000d03bf03bf000f03c103c1001703c203c2001c03c4 03c4000203c503c5000303c603c6000203c703c7000303cb03cb000403cd03ce000403cf03cf001703d003d0001c03d403d4000503d603d6000503d703d7000803d803d8000603d903d9000803da03da 000403db03db000803dc03dc000603df03df001503e003e0000f03e103e1001503e203e2000f03e303e3001503e403e4000f03e503e5001203e603e6001403e803e8000503e903e9001703ea03ea001c 03eb03eb000403ec03ec001103ed03ed001303ee03ee000203ef03ef000303f003f0000203f103f1000303f203f2000203f303f3000303f403f4000203f503f5000303f603f6000203f703f7000303f8 03f8000203f903f9000303fa03fa000203fb03fb000303fc03fc000203fd03fd000303fe03fe000203ff03ff000304000400000204010401000304020402000204030403000304040404000204050405 0003040704070004040904090004040b040b0004040d040d0004040f040f0004041104110004041304130004041504150004041a041a0008041b041b0006041c041c0008041d041d0006041e041e0008 041f041f0006042004200008042104210006042204220008042304230006042404240008042504250006042604260008042704270006042804280008042904290004042a042a0008042b042b0004042c 042c0008042d042d0004042e042e0008042f042f000604300430000804310431000404320432000a04330433000e04340434000a04350435000e04370437000e04390439000e043b043b000e043d043d 000e043f043f000e04400440000d04410441000f04420442000d04430443000f04440444000d04450445000f044904490005044b044b0005044c044c0009044e044e0017044f044f001c045004500012 04510451001404520452001204530453001404550455000504560456001704570457001c04620462000504640464000504660466000504670467001104680468001304690469000d046f046f001904a9 04a9000800010000000a02060810000444464c54001a6379726c00486772656b00766c61746e00a4000400000000ffff00120000000a0014001e002800340041004b0055005f00690073007d00870091 009b00a500af000400000000ffff00120001000b0015001f002900350042004c00560060006a0074007e00880092009c00a600b0000400000000ffff00120002000c00160020002a00360043004d0057 0061006b0075007f00890093009d00a700b100280006415a4520005443525420007e4d4f4c2000a84e41562000d4524f4d20010054555220012c0000ffff00130003000d00170021002b003200370044 004e00580062006c00760080008a0094009e00a800b20000ffff00120004000e00180022002c00380045004f00590063006d00770081008b0095009f00a900b30000ffff00120005000f00190023002d 003900460050005a0064006e00780082008c009600a000aa00b40000ffff001300060010001a0024002e003a003e00470051005b0065006f00790083008d009700a100ab00b50000ffff001300070011 001b0025002f003b003f00480052005c00660070007a0084008e009800a200ac00b60000ffff001300080012001c00260030003c004000490053005d00670071007b0085008f009900a300ad00b70000 ffff001300090013001d002700310033003d004a0054005e00680072007c00860090009a00a400ae00b800b963327363045863327363045e63327363046463327363046a63327363046a63327363046a 63327363046a63327363046a63327363046a63327363046a63636d70047063636d70047063636d70047063636d70047063636d70047063636d70047063636d70047063636d70047063636d7004706363 6d700470646c69670478646c6967047e646c69670484646c6967048a646c6967048a646c6967048a646c6967048a646c6967048a646c6967048a646c6967048a646e6f6d0490646e6f6d0496646e6f6d 049c646e6f6d04a2646e6f6d04a2646e6f6d04a2646e6f6d04a2646e6f6d04a2646e6f6d04a2646e6f6d04a26672616304a86672616304a86672616304a86672616304a86672616304a86672616304a8 6672616304a86672616304a86672616304a86672616304a86c69676104b26c69676104ba6c6e756d04c06c6e756d04c66c6e756d04cc6c6e756d04d26c6e756d04d26c6e756d04d26c6e756d04d26c6e 756d04d26c6e756d04d26c6e756d04d26c6f636c04d86c6f636c04de6c6f636c04e46e756d7204ea6e756d7204f06e756d7204f66e756d7204fc6e756d7204fc6e756d7204fc6e756d7204fc6e756d72 04fc6e756d7204fc6e756d7204fc6f6e756d05026f6e756d05086f6e756d050e6f6e756d05146f6e756d05146f6e756d05146f6e756d05146f6e756d05146f6e756d05146f6e756d0514706e756d051a 706e756d0520706e756d0526706e756d052c706e756d052c706e756d052c706e756d052c706e756d052c706e756d052c706e756d052c736d63700532736d63700538736d6370053e736d63700544736d 63700544736d63700544736d63700544736d63700544736d63700544736d6370054473733031054a73733031055073733031055673733031055c73733031055c73733031055c73733031055c73733031 055c73733031055c73733031055c73733032056273733032056873733032056e73733032057473733032057473733032057473733032057473733032057473733032057473733032057473733033057a 73733033058073733033058673733033058c73733033058c73733033058c73733033058c73733033058c73733033058c73733033058c73733034059273733034059873733034059e7373303405a47373 303405a47373303405a47373303405a47373303405a47373303405a47373303405a47373303505aa7373303505b07373303505b67373303505bc7373303505bc7373303505bc7373303505bc73733035 05bc7373303505bc7373303505bc7373303605c27373303605c87373303605ce7373303605d47373303605d47373303605d47373303605d47373303605d47373303605d47373303605d47373303705da 7373303705e07373303705e67373303705ec7373303705ec7373303705ec7373303705ec7373303705ec7373303705ec7373303705ec746e756d05f2746e756d05f8746e756d05fe746e756d0604746e 756d0604746e756d0604746e756d0604746e756d0604746e756d0604746e756d0604000000010001000000010003000000010002000000010000000000020008000900000001000e0000000100100000 0001000f00000001000d00000001004300000001004500000001004400000001004200000003003f00400041000000020011001200000001001200000001003c00000001003e00000001003d00000001 003b00000001000a00000001000c00000001000b00000001004700000001004900000001004800000001004600000001003000000001003200000001003100000001002f00000001003800000001003a 00000001003900000001003700000001000500000001000700000001000600000001000400000001001400000001001600000001001500000001001300000001001800000001001a0000000100190000 0001001700000001001c00000001001e00000001001d00000001001b00000001002000000001002200000001002100000001001f00000001002400000001002600000001002500000001002300000001 002800000001002a00000001002900000001002700000001002c00000001002e00000001002d00000001002b000000010034000000010036000000010035000000010033004b00980098009800980426 042604260426071407c00e500e500e660e880e880e880e880ebe0ee40f120f120f120f120f260f260f260f260f3a0f3a0f3a0f3a0f4e0f4e0f4e0f4e0f600f600f600f600f7a0f7a0f7a0f7a0fbc0fbc 0fbc0fbc0fda0fda0fda0fda0ff80ff80ff80ff8102a102a102a102a105c105c105c105c108e10a210da10cc10cc10cc10cc10da10da10da10da11060001000000010008000201c400df01e701ba01bb 01bc01bd01be01bf01c001c101c201c301c401c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301e801e90243023b01ea01eb01ec01ed01ee01ef01f001f101f201f301f401f5 01f601f701f801f901fa01fb01fc01fd01fe0200020104dc02020203020402050206020702080209020a020b022f020f02100211021402150216021702180219021b021c021e021d02fb02fc02fd02fe 02ff0300030103020303030403050306030703080309030a030b030c030d030e030f0310031103120313031403150316031703180319031a031b031c031d031e031f0320032103220323032403250326 032703280329032a032b032c032d032e032f0330033103320333033403350336033703380339033a033b033c033d033e033f0340034103420343034503440346034703480349034a034b034c034d034e 034f0350035104aa04ab04ac04ad04ae04af04b004b104b204b304b404b504b604b704b804b904ba04bb04bc04bd04be04bf04c004c104c204c304c404c501ff04c604c704c804c904ca04cb04cc04cd 04ce04cf04d004d104d204d304d404d504d704d804da021a04db020e04d60213020d04d9020c0212000100df000800250026002700280029002a002b002c002d002e002f003000310032003300340035 0036003700380039003a003b003c003d003e006500670085009200b000b100b200b300b400b500b600b700b800b900d100d200d300d400d500d600d700d800d900da00db00dc00dd00de00df00e000e1 00e200e300e400e500e600e700e8012c013001320138013a013c013e013f01450146017f0185018a018d024602470249024b024c024d024e024f0250025102520253025402550256025702580259025a 025b025c025d025e025f0260026102620263026402650282028402860288028a028c028e02900292029402960298029a029c029e02a002a202a402a602a802aa02ac02ae02b102b302b502b702b902bb 02bd02bf02c102c402c602c802ca02cc02ce02d002d202d402d802da02dc02de02e002e202e402e602e802ea02ec02ee02f002f102f302f50352035303540355035603570358035a035b035c035d035e 035f0360036103630364036503660367036803690379037a037b037c037d037e037f0380038103820383038403850386038703880389038a038b038c038d038e03ba03bc03be03d303d903df0448044a 044e04560458045d046900010000000100080002017400b701ba01bb01bc01bd01be01bf01c001c101c201c301c401c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d302fc032f 023b01fa04c904ca01fb01fc01fd01fe01ff020004cd04ce04d004d304dc02020203020402050206020702080209020a020b01f401f501f601f701f801f9022f020f02100211021402150217021902fd 02fe02ff0300030103020303030403050306030703080309030a030b030c030d030e030f031003110312031303140315031603170318034e0319031a031b031c031d031e031f03200321032203230324 03250326032703280329032a032b032c032d032e0330033103320333033403350336033703380339033a033b033c033d033e033f0340034103420343034503440346034703480349034a034b034c034d 034f0350035104c804cb04cc04cf04d104d2020104d404c004c104c204c304c404c504c604c704d504d704d8021804da021a04db02fb020e04d60213020d04d90216020c0212000100b7004500460047 00480049004a004b004c004d004e004f0050005100520053005400550056005700580059005a005b005c005d005e0087008c009300e900ea00eb00ec00ed00ee00ef00f000f100f200f300f400f500f6 00f700f800f900fa00fb00fc00fd00fe00ff0100010101020103010401050106012d013101330139013b013d01400147024a0266026702680269026a026b026c026d026e026f02700271027202730274 02750276027702780279027a027b027c027d027e027f028002810283028502870289028b028d028f02910293029502970299029b029d029f02a102a302a502a702a902ab02ad02b202b402b602b802ba 02bc02be02c002c202c502c702c902cb02cd02cf02d102d302d502d902db02dd02df02e102e302e502e702e902eb02ed02ef02f202f402f6038f0390039103920393039403950396039703980399039a 039b039c039d039e03bb03bd03bf03cd03d403da03e004460449044b044f04570459045a045e046a0006000000060012002a0042005a0072008a00030000000100120001009000010000004a00010001 004d00030000000100120001007800010000004a00010001004e00030000000100120001006000010000004a0001000102ad00030000000100120001004800010000004a00010001039a000300000001 00120001003000010000004a00010001039c00030000000100120001001800010000004a0001000104190002000100a700ab000000040000000100080001061e0036007200a400ae00b800ca00fc010e 0118014a0164017e019001ba01ec01f60218023202440276028802a202cc02de0310031a0324033603680372037c038603a003ba03cc03f6042804320454046e048004b204c404de0508051a0524052e 05380542056c059605c005ea06140006000e0014001a00200026002c024b000200a7024c000200a8024e000200a903f0000200aa047a000200ab03ee000200ac000100040487000200ac000100040288 000200a800020006000c0489000200ac048b000201a20006000e0014001a00200026002c0253000200a70254000200a8040a000200a90408000200aa047c000200ab0406000200ac00020006000c0476 000200a802a2000201a200010004048d000200ac0006000e0014001a00200026002c0257000200a70258000200a802a6000200a90416000200aa047e000200ab0418000200ac00030008000e0014048f 000200a80491000200ac02b3000201a200030008000e001402b5000200a80493000200ac02b7000201a200020006000c03ac000200a80495000200ac0005000c00120018001e00240478000200a702bd 000200a8025b000200a90497000200ac02bf000201a20006000e0014001a00200026002c025c000200a7025d000200a8025f000200a9041c000200aa0480000200ab041a000200ac0001000404990002 00a80004000a00100016001c02ca000200a80482000200ab049b000200ac02cc000201a200030008000e001402d0000200a8049d000200ac02d6000201a200020006000c049f000200ac02da000201a2 0006000e0014001a00200026002c0261000200a70262000200a802e0000200a90434000200aa0484000200ab0432000200ac00020006000c04a1000200a904a3000200ac00030008000e0014039f0002 00a703a1000200a804a5000200ac0005000c00120018001e002403a5000200a70265000200a80444000200a90442000200aa0440000200ac00020006000c02f1000200a804a7000200ac0006000e0014 001a00200026002c0266000200a70267000200a80269000200a903f1000200aa047b000200ab03ef000200ac000100040488000200ac000100040289000200a800020006000c048a000200ac048c0002 01a20006000e0014001a00200026002c026e000200a7026f000200a8040b000200a90409000200aa047d000200ab0407000200ac000100040477000200a800010004048e000200ac0001000404190002 00ac00030008000e00140490000200a80492000200ac02b4000201a200030008000e001402b6000200a80494000200ac02b8000201a200020006000c03ad000200a80496000200ac0005000c00120018 001e00240479000200a702be000200a80276000200a90498000200ac02c0000201a20006000e0014001a00200026002c0277000200a70278000200a8027a000200a9041d000200aa0481000200ab041b 000200ac00010004049a000200a80004000a00100016001c02cb000200a80483000200ab049c000200ac02cd000201a200030008000e001402d1000200a8049e000200ac02d7000201a200020006000c 04a0000200ac02db000201a20006000e0014001a00200026002c027c000200a7027d000200a802e1000200a90435000200aa0485000200ab0433000200ac00020006000c04a2000200a904a4000200ac 00030008000e001403a0000200a703a2000200a804a6000200ac0005000c00120018001e002403a6000200a70280000200a80445000200a90443000200aa0441000200ac00020006000c02f2000200a8 04a8000200ac0001000402f7000200a80001000402f9000200a80001000402f8000200a80001000402fa000200a80005000c00120018001e00240272000200a70273000200a802a7000200a904170002 00aa047f000200ab0005000c00120018001e0024042a000200a70428000200a8042e000200a9042c000200aa0430000200ac0005000c00120018001e0024042b000200a70429000200a8042f000200a9 042d000200aa0431000200ac0005000c00120018001e00240438000200a70436000200a8043c000200a9043a000200aa043e000200ac0005000c00120018001e00240439000200a70437000200a8043d 000200a9043b000200aa043f000200ac000100040486000200a800020011002500290000002b002d0005002f003400080036003b000e003d003e0014004500490016004b004d001b004f0054001e0056 005b0024005d005e002a00810081002c00830083002d00860086002e00890089002f008c008c00300097009a003100cf00cf003500010000000100080001000600020001000202d402d5000100000001 00080002000e000404dd04de04df04e00001000402860287029802990004000000010008000100260002000a001c00020006000c01a30002004a01a8000200580001000401a90002005800010002004a 00570004000000010008000100440002000a00140001000401a40002004d0001000401a60002004d00040000000100080001001e0002000a00140001000401a5000200500001000401a7000200500001 0002004a01a3000100000001000800010006019500010001004b00010000000100080001000601270001000100ba00010000000100080001000601ac00010001003600010000000100080002001c0002 01e301e400010000000100080002000a000201e501e600010002002f004f00010000000100080002001e000c0228022a0229022b022c021f0220022101ae0223022402250001000c00270028002b0033 0035004600470048004b00530054005500010000000100080002000c0003022602270227000100030049004b01ae0001000000010008000200660008023d022d022e023002310239023a023c00010000 00010008000200160008001b00150016001700180019001d00140001000801ad0222047004710472047304740475000100000001000800020016000804750222047004710472047301ad047400010008 001400150016001700180019001b001d000100000001000800020016000800150016001700180019001b001d001400010008022d022e023002310239023a023c023d0001000000010008000100060169 000100010013000600000001000800030001001200010052000000010000004a00020002017c017c000001d401dd000100010000000100080001002801c000010000000100080002001a000a0232007a 00730074023302340235023602370238000200010014001d0000000100000001000800020026001001d401d501d601d701d801d901da01db01dc01dd0240023e02410242023f04e10001001000140015 0016001700180019001a001b001c001d004d004e02ad039a039c0419 ]], } end __FILES['imgui_internal.lua'] = function() --- Dear ImGui WIP -- (internal structures/api) --- @meta local type = ImGui._GetTypeFunc() local rawget = rawget local mathMin = math.min; local mathMax = math.max local mathFloor = math.floor; local mathCeil = math.ceil local bitNot = bit32.bnot local bitAnd = bit32.band; local bitOr = bit32.bor local bitLShift = bit32.lshift; local bitRShift = bit32.rshift local t_sort = table.sort --- @alias ImGuiTableColumnIdx ImS16 -- TODO: Implement actual ImString type --- @alias ImString char[]|string --- @alias ImStringBuffer char[] -- NOTE: temporary solution --- @param buf char[] --- @param buf_begin int --- @param buf_end int # exclusive function ImGui._ByteArrayToString(buf, buf_begin, buf_end) local str = {} for i = buf_begin, buf_end - 1 do table.insert(str, string.char(buf[i])) end return table.concat(str) end --- ImPool: pool of objects keyed by ID. Public indices are 0-based like upstream (Buf is stored 1-based). --- `ctor` creates a new element. Removed slots are recycled via FreeIdx (-1 = none; free slots chain through `_NextFree`). local IM_POOL = {} IM_POOL.__index = IM_POOL function ImPool(ctor) return setmetatable({ Buf = {}, Map = {}, FreeIdx = 0, AliveCount = 0, BufSize = 0, _Ctor = ctor }, IM_POOL) end function IM_POOL:GetByKey(key) local i = self.Map[key]; return i and self.Buf[i + 1] or nil end function IM_POOL:GetByIndex(n) return self.Buf[n + 1] end function IM_POOL:GetIndex(p) return p._PoolIdx end function IM_POOL:Contains(p) return p ~= nil and self.Buf[(p._PoolIdx or -1) + 1] == p end function IM_POOL:GetMapSize() return self.BufSize end function IM_POOL:Clear() self.Buf = {}; self.Map = {}; self.FreeIdx = 0; self.AliveCount = 0; self.BufSize = 0 end function IM_POOL:Add() local idx if self._Free and #self._Free > 0 then idx = table.remove(self._Free) else idx = self.BufSize; self.BufSize = self.BufSize + 1 end local p = self._Ctor and self._Ctor() or {} p._PoolIdx = idx self.Buf[idx + 1] = p self.AliveCount = self.AliveCount + 1 return p end function IM_POOL:GetOrAddByKey(key) local i = self.Map[key] if i then return self.Buf[i + 1] end local p = self:Add(); self.Map[key] = p._PoolIdx; return p end function IM_POOL:Remove(key, p) if type(key) == "table" then p = key; key = nil end if key == nil then for k, i in pairs(self.Map) do if i == p._PoolIdx then key = k break end end end if key ~= nil then self.Map[key] = nil end self.Buf[p._PoolIdx + 1] = false self._Free = self._Free or {} table.insert(self._Free, p._PoolIdx) self.AliveCount = self.AliveCount - 1 end function IM_POOL:Reserve(n) end -- NOTE: removed slots hold `false`; iterate with `for i = 0, pool:GetMapSize() - 1 do local t = pool:GetByIndex(i) if t then ... end end` --- @type ImGuiContext? local GImGui -- Sets local `GImGui` in this file(imgui_internal.lua). -- This is currently only used in main code `ImGui.SetCurrentContext()` --- @param ctx ImGuiContext? function ImGui._SetCurrentContext_Internal(ctx) GImGui = ctx end local setmetatable = setmetatable local MT = ImGui.GetMetatables() IM_TABSIZE = 4 FLT_MIN = 1.1754943508223e-38 FLT_MAX = 3.4028234663853e+38 DBL_MAX = 1.7976931348623e+308 INT_MIN = -0x7fffffff - 1 INT_MAX = 0x7fffffff UINT_MAX = 0x7fffffff * 2 + 1 NAV_WINDOWING_HIGHLIGHT_DELAY = 0.5 NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10 NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY = 0.60 IM_PI = math.pi ImPow = math.pow ImLog = math.log ImAbs = math.abs ImFabs = math.abs ImFmod = function(a, b) if b < 0 then b = -b end; if a < 0 then return -(-a % b) else return a % b end; end ImRound64 = function(val) return math.floor(val + 0.5) end -- FIXME: Positive values only ImCeil = math.ceil ImSin = math.sin ImCos = math.cos ImAcos = math.acos ImAtan2 = math.atan2 ImSqrt = math.sqrt --- @generic T: number --- @param a T --- @param b T --- @param mn T --- @param mx T --- @return T function ImAddClampOverflow(a, b, mn, mx) if b < 0 and (a < mn - b) then return mn end if b > 0 and (a > mx - b) then return mx end return a + b end --- @generic T: number --- @param a T --- @param b T --- @param mn T --- @param mx T --- @return T function ImSubClampOverflow(a, b, mn, mx) if b > 0 and (a < mn + b) then return mn end if b < 0 and (a > mx + b) then return mx end return a - b end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 @native function ImMin(lhs, rhs) if type(lhs) == "number" then return mathMin(lhs, rhs) end return ImVec2(mathMin(lhs.x, rhs.x), mathMin(lhs.y, rhs.y)) end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 @native function ImMax(lhs, rhs) if type(lhs) == "number" then return mathMax(lhs, rhs) end return ImVec2(mathMax(lhs.x, rhs.x), mathMax(lhs.y, rhs.y)) end --- @param base table --- @param count int --- @param cmp_func fun(lhs, rhs): bool ImStd.ImQsort = function(base, count, cmp_func) if count > 0 then t_sort(base, cmp_func) end end --- @overload fun(v: number, mn: number, mx: number): number --- @overload fun(v: ImVec2, mn: ImVec2, mx: ImVec2): ImVec2 @native function ImClamp(v, mn, mx) if type(v) == "number" and type(mn) == "number" and type(mx) == "number" then return mathMin(mathMax(v, mn), mx) elseif type(v) == "table" and type(mn) == "table" and type(mx) == "table" then return ImVec2(mathMax(mn.x, mathMin(v.x, mx.x)), mathMax(mn.y, mathMin(v.y, mx.y))) end end --- @overload fun(a: number, b: number, t: number): number --- @overload fun(a: ImVec2, b: ImVec2, t: number): ImVec2 --- @overload fun(a: ImVec2, b: ImVec2, t: ImVec2): ImVec2 @native function ImLerp(a, b, t) if type(a) == "number" and type(b) == "number" and type(t) == "number" then return ((a) + ((b) - (a)) * (t)) elseif type(a) == "table" and type(b) == "table" and type(t) == "number" then return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t) elseif type(a) == "table" and type(b) == "table" and type(t) == "table" then return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y) end end local function _Trunc(val) if val >= 0 then return mathFloor(val) else return mathCeil(val) end end --- @overload fun(v: float): float --- @overload fun(v: ImVec2): ImVec2 function ImTrunc(v) if type(v) == "number" then return _Trunc(v) elseif type(v) == "table" then return ImVec2(_Trunc(v.x), _Trunc(v.y)) end end ImTrunc64 = _Trunc --- @param f float function ImCeilFast(f) local i if f >= 0 then i = math.floor(f) else i = math.ceil(f) end -- same as `ImTrunc()` if f > i then return i + 1 end return i end function IM_ROUNDUP_TO_EVEN(n) return (ImCeil((n) / 2) * 2) end function ImRsqrt(x) return (1 / ImSqrt(x)) end function IM_TRUNC(VAL) return math.floor(VAL) end -- Positive values only! function IM_ROUND(VAL) return math.floor(VAL + 0.5) end function ImFloor(f) if f >= 0 or math.floor(f) == f then return math.floor(f) else return math.floor(f) - 1 end end --- @param v int function ImIsPowerOfTwo(v) return (v ~= 0) and (bitAnd(v, (v - 1)) == 0) end function ImUpperPowerOfTwo(v) if v <= 0 then return 0 end if v <= 1 then return 1 end v = v - 1 v = bitOr(v, bitRShift(v, 1)) v = bitOr(v, bitRShift(v, 2)) v = bitOr(v, bitRShift(v, 4)) v = bitOr(v, bitRShift(v, 8)) v = bitOr(v, bitRShift(v, 16)) return v + 1 end --- @param v unsigned_int --- @return unsigned_int function ImCountSetBits(v) local count = 0 while v > 0 do v = bitAnd(v, v - 1) count = count + 1 end return count end --- @param avg float --- @param sample float --- @param n int --- @return float function ImStd.ImExponentialMovingAverage(avg, sample, n) avg = avg - avg / n avg = avg + sample / n return avg end -- Uses `string.match` internally --- @param str string function ImAtof(str) return tonumber(string.match(str, "[+-]?%d*%.?%d+")) end --- @param s table # 1-based --- @param c any --- @param n int function ImStd.memset(s, c, n) for i = 1, n do s[i] = c end end do local _memmove = function(dest, dest_start, src, src_start, count) if count <= 0 then return end -- more compact instead of writing separate if-else and for loops local c = (dest == src and dest_start >= src_start) for i = (c and count - 1 or 0), (c and 0 or count - 1), (c and -1 or 1) do dest[dest_start + i] = src[src_start + i] end end if table.move then --- [GMod] Platform specific: the `table.move` polyfill in non-x86-64 currently uses `unpack` which will break if too many elements -- Remove this check when the polyfill is fixed or removed if not gmod or (gmod and BRANCH == "x86-64") then _memmove = function(dest, dest_start, src, src_start, count) table.move(src, src_start, src_start + count - 1, dest_start, dest) end end end ImStd.memmove = _memmove end --- @param str1 ImStringBuffer --- @param str2 ImStringBuffer function ImStd.strcmp(str1, str2) local i = 1 while true do local c1 = str1[i] or 0 local c2 = str2[i] or 0 if c1 ~= c2 then return c1 - c2 end if c1 == 0 then return 0 end i = i + 1 end end --- @param str1 ImStringBuffer --- @param str2 ImStringBuffer --- @param max_count int function ImStd.strncmp(str1, str2, max_count) for i = 1, max_count do local c1 = str1[i] or 0 local c2 = str2[i] or 0 if c1 ~= c2 then return c1 - c2 end if c1 == 0 then return 0 end end return 0 end function ImSaturate(f) return ((f < 0.0 and 0.0) or (f > 1.0 and 1.0) or f) end IM_F32_TO_INT8_UNBOUND = function(val) return math.floor(val * 255.0 + (val >= 0 and 0.5 or -0.5)) end IM_F32_TO_INT8_SAT = function(val) return math.floor(ImSaturate(val) * 255.0 + 0.5) end --- @param s ImString --- @param i int --- @return char function ImStrByte(s, i) if type(s) == "string" then return string.byte(s, i, i) else --- @cast s char[] return s[i] end end --- @class ImGuiColorMod --- @field Col ImGuiCol --- @field BackupValue ImVec4 --- @param col ImGuiCol --- @param backup_value ImVec4 --- @return ImGuiColorMod function ImGuiColorMod(col, backup_value) local this = { Col = col, BackupValue = ImVec4() } ImVec4_Copy(this.BackupValue, backup_value) return this end --- @param lhs ImVec2 --- @return float function ImLengthSqr(lhs) return (lhs.x * lhs.x) + (lhs.y * lhs.y) end --- @param v ImVec2 --- @param cos_a float --- @param sin_a float --- @return ImVec2 --- @nodiscard function ImRotate(v, cos_a, sin_a) return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a) end --- @param a ImVec2 --- @param b ImVec2 function ImDot(a, b) return a.x * b.x + a.y * b.y end --- @param lhs ImVec2 --- @param rhs ImVec2 --- @nodiscard function ImMul(lhs, rhs) return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y) end --- @param str char[] --- @param begin? int function ImStd.ImStrlen(str, begin) if begin == nil then begin = 1 end local l = #str for i = begin, l do if str[i] == 0 then return i - begin end end IM_ASSERT(false) end -- FIXME: should also accept count? -- FIXME: avoid dynamic type checking? -- string.find with patterns disabled --- @param str string|char[] --- @param s string|char --- @param start_pos? int --- @return int? function ImMemchr(str, s, start_pos) local start = start_pos or 1 if start < 1 then start = 1 end if type(str) == "table" then for i = start, #str do if str[i] == 0 then break end if str[i] == s then return i end end return nil end --- @cast str string local pos = string.find(str, s, start, true) return pos end IMGUI_FONT_SIZE_MAX = 512.0 IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE = 128.0 IMGUI_WINDOW_HARD_MIN_SIZE = 4.0 IM_DRAWLIST_ARCFAST_TABLE_SIZE = 48 IM_DRAWLIST_ARCFAST_SAMPLE_MAX = IM_DRAWLIST_ARCFAST_TABLE_SIZE -- Upstream: `if (!(expr) && ErrorLog(msg)) IM_ASSERT(0)`. ErrorLog() returns io.ConfigErrorRecoveryEnableAssert. function IM_ASSERT_USER_ERROR(_EXPR, _MSG) if not (_EXPR) or (_EXPR) == 0 then if not ImGui.ErrorLog or ImGui.ErrorLog(_MSG) then error(_MSG, 2) end end end function IM_ASSERT_USER_ERROR_RET(_EXPR, _MSG) if not (_EXPR) or (_EXPR) == 0 then error(_MSG, 2) end end local function DebugLogIf(flag, fmt, ...) local g = GImGui if g and bitAnd(g.DebugLogFlags, flag) ~= 0 then ImGui.DebugLog(fmt, ...) end end function IMGUI_DEBUG_LOG_ACTIVEID(...) DebugLogIf(ImGuiDebugLogFlags.EventActiveId, ...) end function IMGUI_DEBUG_LOG_POPUP(...) DebugLogIf(ImGuiDebugLogFlags.EventPopup, ...) end function IMGUI_DEBUG_LOG_FONT(...) DebugLogIf(ImGuiDebugLogFlags.EventFont, ...) end function IMGUI_DEBUG_LOG_VIEWPORT(...) DebugLogIf(ImGuiDebugLogFlags.EventViewport, ...) end function IMGUI_DEBUG_LOG_FOCUS(...) DebugLogIf(ImGuiDebugLogFlags.EventFocus, ...) end function IMGUI_DEBUG_LOG_NAV(...) DebugLogIf(ImGuiDebugLogFlags.EventNav, ...) end function IMGUI_DEBUG_LOG_IO(...) DebugLogIf(ImGuiDebugLogFlags.EventIO, ...) end function IMGUI_DEBUG_LOG_INPUTROUTING(...) DebugLogIf(ImGuiDebugLogFlags.EventInputRouting, ...) end function IMGUI_DEBUG_LOG_TABLE(...) DebugLogIf(ImGuiDebugLogFlags.EventTable, ...) end function IMGUI_DEBUG_LOG_DOCKING(...) DebugLogIf(ImGuiDebugLogFlags.EventDocking, ...) end function IMGUI_DEBUG_LOG_SELECTION(...) DebugLogIf(ImGuiDebugLogFlags.EventSelection, ...) end function IMGUI_DEBUG_LOG_CLIPPER(...) DebugLogIf(ImGuiDebugLogFlags.EventClipper, ...) end function IMGUI_DEBUG_LOG_ERROR(...) DebugLogIf(ImGuiDebugLogFlags.EventError, ...) end --- @alias ImGuiSelectionUserData any ImGuiSelectionUserData_Invalid = -1 ImGuiKeyOwner_Any = 0 ImGuiKeyOwner_NoOwner = 4294967295 --- @param button ImGuiMouseButton --- @return ImGuiKey function ImGui.MouseButtonToKey(button) IM_ASSERT(button >= 0 and button < ImGuiMouseButton.COUNT) return ImGuiKey.MouseLeft + button end --- @param key ImGuiKey function ImGui.IsNamedKey(key) return key >= ImGuiKey.NamedKey_BEGIN and key < ImGuiKey.NamedKey_END end --- @param key ImGuiKey function ImGui.IsKeyboardKey(key) return key >= ImGuiKey_Keyboard_BEGIN and key < ImGuiKey_Keyboard_END end --- @param key ImGuiKey function ImGui.IsGamepadKey(key) return key >= ImGuiKey_Gamepad_BEGIN and key < ImGuiKey_Gamepad_END end --- @param key ImGuiKey function ImGui.IsMouseKey(key) return key >= ImGuiKey_Mouse_BEGIN and key < ImGuiKey_Mouse_END end --- @param key ImGuiKey function ImGui.IsAliasKey(key) return key >= ImGuiKey_Aliases_BEGIN and key < ImGuiKey_Aliases_END end --- @param key ImGuiKey function ImGui.IsLRModKey(key) return key >= ImGuiKey.LeftCtrl and key <= ImGuiKey.RightSuper end --- @param key ImGuiKey --- @return bool function ImGui.IsNamedKeyOrMod(key) return (key >= ImGuiKey.NamedKey_BEGIN and key < ImGuiKey.NamedKey_END) or key == ImGuiMod_Ctrl or key == ImGuiMod_Shift or key == ImGuiMod_Alt or key == ImGuiMod_Super end --- @param key ImGuiKey --- @return ImGuiKey function ImGui.ConvertSingleModFlagToKey(key) if key == ImGuiMod_Ctrl then return ImGuiKey.ReservedForModCtrl elseif key == ImGuiMod_Shift then return ImGuiKey.ReservedForModShift elseif key == ImGuiMod_Alt then return ImGuiKey.ReservedForModAlt elseif key == ImGuiMod_Super then return ImGuiKey.ReservedForModSuper end return key end --- @param ctx ImGuiContext --- @param key ImGuiKey function ImGui.GetKeyOwnerData(ctx, key) if bitAnd(key, ImGuiMod_Mask_) ~= 0 then key = ImGui.ConvertSingleModFlagToKey(key) end IM_ASSERT(ImGui.IsNamedKey(key)) return ctx.KeysOwnerData[key - ImGuiKey.NamedKey_BEGIN] end --- @class ImGuiKeyOwnerData --- @return ImGuiKeyOwnerData --- @nodiscard function ImGuiKeyOwnerData() return { OwnerCurr = ImGuiKeyOwner_NoOwner, OwnerNext = ImGuiKeyOwner_NoOwner, LockThisFrame = false, LockUntilRelease = false } end --- @param size float --- @return float function ImGui.GetRoundedFontSize(size) return IM_ROUND(size) end --- @param window ImGuiWindow --- @param r ImRect --- @return ImRect --- @nodiscard function ImGui.WindowRectAbsToRel(window, r) local off = window.DC.CursorStartPos return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y) end --- @param window ImGuiWindow --- @param r ImRect --- @nodiscard function ImGui.WindowRectRelToAbs(window, r) local off = window.DC.CursorStartPos return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y) end --- @param dir ImGuiDir --- @return bool function ImGui.IsActiveIdUsingNavDir(dir) local g = GImGui return bit32.band(g.ActiveIdUsingNavDirMask, bit32.lshift(1, dir)) ~= 0 end --- @param window ImGuiWindow --- @param p ImVec2 --- @return ImVec2 --- @nodiscard function ImGui.WindowPosAbsToRel(window, p) local off = window.DC.CursorStartPos return ImVec2(p.x - off.x, p.y - off.y) end --- @param c char --- @return bool # True if this character is a ' ' or '\t' function ImCharIsBlankA(c) return c == 32 or c == 9 end --- @param c char function ImCharIsBlankW(c) return c == 32 or c == 9 or c == 0x3000 end --- @enum ImGuiNavMoveFlags ImGuiNavMoveFlags = { None = 0, LoopX = bitLShift(1, 0), LoopY = bitLShift(1, 1), WrapX = bitLShift(1, 2), WrapY = bitLShift(1, 3), AllowCurrentNavId = bitLShift(1, 4), AlsoScoreVisibleSet = bitLShift(1, 5), ScrollToEdgeY = bitLShift(1, 6), Forwarded = bitLShift(1, 7), DebugNoResult = bitLShift(1, 8), FocusApi = bitLShift(1, 9), IsTabbing = bitLShift(1, 10), IsPageMove = bitLShift(1, 11), Activate = bitLShift(1, 12), NoSelect = bitLShift(1, 13), NoSetNavCursorVisible = bitLShift(1, 14), NoClearActiveId = bitLShift(1, 15), } ImGuiNavMoveFlags.WrapMask_ = bitOr(ImGuiNavMoveFlags.LoopX, ImGuiNavMoveFlags.LoopY, ImGuiNavMoveFlags.WrapX, ImGuiNavMoveFlags.WrapY) --- @enum ImGuiNavLayer ImGuiNavLayer = { Main = 0, Menu = 1, COUNT = 2 } ImGuiItemFlags.ReadOnly = bitLShift(1, 11) ImGuiItemFlags.MixedValue = bitLShift(1, 12) ImGuiItemFlags.NoWindowHoverableCheck = bitLShift(1, 13) ImGuiItemFlags.AllowOverlap = bitLShift(1, 14) ImGuiItemFlags.NoNavDisableMouseHover = bitLShift(1, 15) ImGuiItemFlags.NoMarkEdited = bitLShift(1, 16) ImGuiItemFlags.NoFocus = bitLShift(1, 17) ImGuiItemFlags.Inputable = bitLShift(1, 20) ImGuiItemFlags.HasSelectionUserData = bitLShift(1, 21) ImGuiItemFlags.IsMultiSelect = bitLShift(1, 22) ImGuiItemFlags.Default_ = bitOr(ImGuiItemFlags.AutoClosePopups, ImGuiItemFlags.LiveEditOnInputText) --- @enum ImDrawTextFlags ImDrawTextFlags = { None = 0, CpuFineClip = bitLShift(1, 0), WrapKeepBlanks = bitLShift(1, 1), StopOnNewLine = bitLShift(1, 2) } --- @enum ImGuiFocusRequestFlags ImGuiFocusRequestFlags = { None = 0, RestoreFocusedChild = bitLShift(1, 0), UnlessBelowModal = bitLShift(1, 1) } --- @enum ImGuiTextFlags ImGuiTextFlags = { None = 0, NoWidthForLargeClippedText = bitLShift(1, 0) } --- @enum ImWcharClass ImWcharClass = { Blank = 0, Punct = 1, Other = 2 } --- @class ImVec1 --- @field x number local IM_VEC1 = {} IM_VEC1.__index = IM_VEC1 local function ImVec1(x) return setmetatable({x = x or 0}, IM_VEC1) end function IM_VEC1:__tostring() return string.format("ImVec1(%g)", self.x) end --- @param dest ImVec1 --- @param src ImVec1 function ImVec1_Copy(dest, src) dest.x = src.x end --- @class ImRect --- @field [1] ImVec2 --- @field [2] ImVec2 --- @field Min ImVec2 --- @field Max ImVec2 local IM_RECT = {} setmetatable(IM_RECT, { __index = function(_, k) if k ~= "Min" and k ~= "Max" then error("ImRect: unknown key " .. tostring(k), 2) end end }) --- @param t ImRect --- @param k string IM_RECT.__index = IM_RECT -- [Luau] plain table: fast method lookup. Use r.Min / r.Max (numeric r[1]/r[2] are not supported) -- [Luau] Min/Max are named fields, so `r.Min = v` assigns the reference: use ImVec2_Copy(r.Min, v) to keep copy semantics IM_RECT.__newindex = function(t, k, v) IM_ASSERT(false, "ImRect: unknown field " .. tostring(k)) end --- @return ImRect --- @nodiscard @native function ImRect(a, b, c, d) if c and d then return setmetatable({ Min = ImVec2(a, b), Max = ImVec2(c, d) }, IM_RECT) end return setmetatable({ Min = ImVec2(a and a.x or 0, a and a.y or 0), Max = ImVec2(b and b.x or 0, b and b.y or 0) }, IM_RECT) end function IM_RECT:__eq(other) return self.Min == other.Min and self.Max == other.Max end function IM_RECT:__tostring() return string.format("ImRect(Min: %g,%g, Max: %g,%g)", self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param p ImRect|ImVec2 @native function IM_RECT:Contains(p) if p.Min then --- @cast p ImRect return p.Min.x >= self.Min.x and p.Max.x <= self.Max.x and p.Min.y >= self.Min.y and p.Max.y <= self.Max.y else --- @cast p ImVec2 return p.x >= self.Min.x and p.y >= self.Min.y and p.x < self.Max.x and p.y < self.Max.y end end --- @param p ImVec2 --- @param pad ImVec2 function IM_RECT:ContainsWithPad(p, pad) return p.x >= self.Min.x - pad.x and p.y >= self.Min.y - pad.y and p.x < self.Max.x + pad.x and p.y < self.Max.y + pad.y end --- @param r ImRect @native function IM_RECT:Overlaps(r) return self.Min.x <= r.Max.x and self.Max.x >= r.Min.x and self.Min.y <= r.Max.y and self.Max.y >= r.Min.y end --- @nodiscard function IM_RECT:GetCenter() return ImVec2((self.Min.x + self.Max.x) * 0.5, (self.Min.y + self.Max.y) * 0.5) end function IM_RECT:GetWidth() return self.Max.x - self.Min.x end function IM_RECT:GetHeight() return self.Max.y - self.Min.y end --- @nodiscard @native function IM_RECT:GetSize() return ImVec2(self.Max.x - self.Min.x, self.Max.y - self.Min.y) end --- @nodiscard function IM_RECT:GetTL() return ImVec2(self.Min.x, self.Min.y) end --- @nodiscard function IM_RECT:GetTR() return ImVec2(self.Max.x, self.Min.y) end --- @nodiscard function IM_RECT:GetBL() return ImVec2(self.Min.x, self.Max.y) end --- @nodiscard function IM_RECT:GetBR() return ImVec2(self.Max.x, self.Max.y) end --- @param r ImRect @native function IM_RECT:ClipWith(r) ImVec2_Copy(self.Min, ImMax(self.Min, r.Min)); ImVec2_Copy(self.Max, ImMin(self.Max, r.Max)) end --- @param r ImRect @native function IM_RECT:ClipWithFull(r) ImVec2_Copy(self.Min, ImClamp(self.Min, r.Min, r.Max)); ImVec2_Copy(self.Max, ImClamp(self.Max, r.Min, r.Max)) end --- @param p ImRect|ImVec2 @native function IM_RECT:Add(p) if p.Min then --- @cast p ImRect if (self.Min.x > p.Min.x) then self.Min.x = p.Min.x end if (self.Min.y > p.Min.y) then self.Min.y = p.Min.y end if (self.Max.x < p.Max.x) then self.Max.x = p.Max.x end if (self.Max.y < p.Max.y) then self.Max.y = p.Max.y end else --- @cast p ImVec2 if p.x < self.Min.x then self.Min.x = p.x end if p.y < self.Min.y then self.Min.y = p.y end if p.x > self.Max.x then self.Max.x = p.x end if p.y > self.Max.y then self.Max.y = p.y end end end --- @param amount float|ImVec2 @native function IM_RECT:Expand(amount) if type(amount) == "number" then self.Min.x = self.Min.x - amount; self.Min.y = self.Min.y - amount self.Max.x = self.Max.x + amount; self.Max.y = self.Max.y + amount elseif type(amount) == "table" then self.Min.x = self.Min.x - amount.x; self.Min.y = self.Min.y - amount.y self.Max.x = self.Max.x + amount.x; self.Max.y = self.Max.y + amount.y end end --- @nodiscard function IM_RECT:ToVec4() return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param d ImVec2 @native function IM_RECT:Translate(d) self.Min.x = self.Min.x + d.x; self.Min.y = self.Min.y + d.y self.Max.x = self.Max.x + d.x; self.Max.y = self.Max.y + d.y end --- @param dx float function IM_RECT:TranslateX(dx) self.Min.x = self.Min.x + dx; self.Max.x = self.Max.x + dx end --- @param dy float function IM_RECT:TranslateY(dy) self.Min.y = self.Min.y + dy; self.Max.y = self.Max.y + dy end function IM_RECT:IsInverted() return self.Min.x > self.Max.x or self.Min.y > self.Max.y end function IM_RECT:GetArea() return (self.Max.x - self.Min.x) * (self.Max.y - self.Min.y) end --- @nodiscard function IM_RECT:AsVec4() return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param dest ImRect --- @param src ImRect @native function ImRect_Copy(dest, src) dest.Min.x = src.Min.x; dest.Min.y = src.Min.y dest.Max.x = src.Max.x; dest.Max.y = src.Max.y end --- @param dest ImRect --- @param src ImVec4 function ImRect_CopyFromV4(dest, src) dest.Min.x = src.x; dest.Min.y = src.y dest.Max.x = src.z; dest.Max.y = src.w end --- @param _ARRAY ImU32[] --- @param _N int function IM_BITARRAY_TESTBIT(_ARRAY, _N) return bitAnd(_ARRAY[bitRShift(_N - 1, 5) + 1], bitLShift(1, bitAnd(_N - 1, 31))) ~= 0 end --- @param _ARRAY ImU32[] --- @param _N int function IM_BITARRAY_CLEARBIT(_ARRAY, _N) local idx = bitRShift(_N - 1, 5) + 1 _ARRAY[idx] = bitAnd(_ARRAY[idx], bitNot(bitLShift(1, bitAnd(_N - 1, 31)))) end --- @param arr ImU32[] --- @param n int function ImBitArraySetBit(arr, n) local mask = bitLShift(1, bitAnd(n - 1, 31)) local idx = bitRShift(n - 1, 5) + 1 arr[idx] = bitOr(arr[idx], mask) end --- @alias ImBitArrayForNamedKeys ImBitArray --- NOTE: This struct is expensive to create --- @class ImBitArray --- @field Data ImU32[] --- @param BITCOUNT int --- @param OFFSET? int --- @return ImBitArray function ImBitArray(BITCOUNT, OFFSET) if OFFSET == nil then OFFSET = 0 end local this = { Data = {} } local size = bitRShift(BITCOUNT + 31, 5) this.ClearAllBits = function(self) local data = self.Data; for i = 1, size do data[i] = 0 end end this.SetAllBits = function(self) local data = self.Data; for i = 1, size do data[i] = 0xFFFFFFFF end end --- @param n int # 1-based --- @return boolean this.TestBit = function(self, n) n = n + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT); return IM_BITARRAY_TESTBIT(self.Data, n); end --- @param n int # 1-based this.SetBit = function(self, n) n = n + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT); ImBitArraySetBit(self.Data, n); end this:ClearAllBits() return this end function MT.ImDrawList:PathClear() self._Path:clear() end --- @param pos ImVec2 @native function MT.ImDrawList:PathLineTo(pos) self._Path:push_back(pos) end function MT.ImDrawList:PathLineToMergeDuplicate(pos) local path_size = self._Path.Size if path_size == 0 or self._Path.Data[path_size].x ~= pos.x or self._Path.Data[path_size].y ~= pos.y then self._Path:push_back(pos) end end @native function MT.ImDrawList:PathFillConvex(col) self:AddConvexPolyFilled(self._Path.Data, self._Path.Size, col) self._Path.Size = 0 end --- @param col ImU32 --- @param thickness? float --- @param flags? ImDrawFlags function MT.ImDrawList:PathStroke(col, thickness, flags) if not thickness then thickness = 1.0 end if not flags then flags = 0 end self:AddPolyline(self._Path.Data, self._Path.Size, col, thickness, flags) self._Path.Size = 0 end --- @param col ImU32 function ImGui.SetNextItemColorMarker(col) local g = GImGui g.NextItemData.HasFlags = bitOr(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasColorMarker) g.NextItemData.ColorMarker = col end --- @class ImDrawListSharedData --- @field TexUvWhitePixel ImVec2 --- @field TexUvLines ImVec4[] --- @field FontAtlas ImFontAtlas --- @field Font ImFont --- @field FontSize float --- @field FontScale float --- @field CurveTessellationTol float --- @field CircleTessellationMaxError float --- @field InitialFringeScale float --- @field InitialFlags ImDrawListFlags --- @field ClipRectFullscreen? ImVec4 --- @field TempBuffer ImVector --- @field DrawLists ImVector --- @field Context? ImGuiContext --- @field ArcFastVtx table # 1-based table --- @field ArcFastRadiusCutoff float --- @field CircleSegmentCounts table # 1-based table MT.ImDrawListSharedData = {} MT.ImDrawListSharedData.__index = MT.ImDrawListSharedData --- @return ImDrawListSharedData --- @nodiscard function ImDrawListSharedData() local this = setmetatable({ TexUvWhitePixel = nil, TexUvLines = nil, FontAtlas = nil, Font = nil, FontSize = 0, FontScale = 0, CurveTessellationTol = 0, CircleTessellationMaxError = 0, InitialFringeScale = 1, InitialFlags = 0, ClipRectFullscreen = nil, TempBuffer = ImVector(ImVec2), DrawLists = ImVector(), ArcFastVtx = {}, ArcFastRadiusCutoff = nil, CircleSegmentCounts = {}, Context = nil }, MT.ImDrawListSharedData) for i = 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE do local a = ((i - 1) * 2 * IM_PI) / IM_DRAWLIST_ARCFAST_TABLE_SIZE this.ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)) end return this end --- @class ImFontAtlasBuilder --- @field PackContext stbrp_context --- @field PackNodes ImVector --- @field Rects ImVector --- @field RectsIndex ImVector --- @field TempBuffer ImVector --- @field RectsIndexFreeListStart int --- @field RectsPackedCount int --- @field RectsPackedSurface int --- @field RectsDiscardedCount int --- @field RectsDiscardedSurface int --- @field FrameCount int --- @field MaxRectSize ImVec2 --- @field MaxRectBounds ImVec2 --- @field LockDisableResize bool --- @field PreloadedAllGlyphsRanges bool --- @field BakedPool ImVector --- @field BakedMap table # LUA: No ImGuiStorage --- @field BakedDiscardedCount int --- @field PackIdMouseCursors ImFontAtlasRectId --- @field PackIdLinesTexData ImFontAtlasRectId MT.ImFontAtlasBuilder = {} MT.ImFontAtlasBuilder.__index = MT.ImFontAtlasBuilder --- @return ImFontAtlasBuilder function ImFontAtlasBuilder() --- @type ImFontAtlasBuilder local this = setmetatable({}, MT.ImFontAtlasBuilder) this.PackContext = nil -- struct stbrp_context_opaque { char data[80]; }; this.PackNodes = ImVector() this.Rects = ImVector() this.RectsIndex = ImVector() this.TempBuffer = ImVector() this.RectsIndexFreeListStart = -1 this.RectsPackedCount = 0 this.RectsPackedSurface = 0 this.RectsDiscardedCount = 0 this.RectsDiscardedSurface = 0 this.FrameCount = -1 this.MaxRectSize = ImVec2() this.MaxRectBounds = ImVec2() this.LockDisableResize = false this.PreloadedAllGlyphsRanges = false this.BakedPool = ImVector() -- ImStableVector this.BakedMap = {} this.BakedDiscardedCount = 0 this.PackIdMouseCursors = -1 this.PackIdLinesTexData = -1 return this end --- @class ImFontStackData --- @field Font ImFont --- @field FontSizeBeforeScaling float --- @field FontSizeAfterScaling float --- @return ImFontStackData --- @param font ImFont --- @param font_size_before_scaling float --- @param font_size_after_scaling float --- @nodiscard function ImFontStackData(font, font_size_before_scaling, font_size_after_scaling) return { Font = font, FontSizeBeforeScaling = font_size_before_scaling, FontSizeAfterScaling = font_size_after_scaling } end --- `GetVarPtr()` is currently only used on `g.Style` in Dear ImGui, and we don't have pointers! --- @class ImGuiStyleVarInfo --- @field Count ImU32 --- @field DataType ImGuiDataType --- @field Key string # key in parent structure. Note that the cpp Dear ImGui uses `ImU32 Offset`! --- @param count ImU32 --- @param data_type ImGuiDataType --- @param key string --- @return ImGuiStyleVarInfo --- @nodiscard function ImGuiStyleVarInfo(count, data_type, key) return { Count = count, DataType = data_type, Key = key } end --- @class ImGuiStyleMod --- @field VarIdx ImGuiStyleVar --- @field BackupVal table --- @param idx ImGuiStyleVar --- @param v int|float|ImVec2 function ImGuiStyleMod(idx, v) local this = { VarIdx = idx, BackupVal = {nil, nil} } --- @cast this ImGuiStyleMod if type(v) == "number" then this.BackupVal[1] = v else -- ImVec2 this.BackupVal[1] = v.x; this.BackupVal[2] = v.y end return this end --- Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo() --- @class ImGuiDataTypeInfo --- @field Size size_t # Size in bytes --- @field Name string # Short descriptive name for the type, for debugging --- @field PrintFmt string # Default printf format for the type --- @field ScanFmt string # Default scanf format for the type --- @class ImGuiLastItemData --- @field ID ImGuiID --- @field ItemFlags ImGuiItemFlags --- @field StatusFlags ImGuiItemStatusFlags --- @field Rect ImRect --- @field NavRect ImRect --- @field DisplayRect ImRect --- @field ClipRect ImRect --- @field Shortcut ImGuiKeyChord --- @return ImGuiLastItemData --- @nodiscard function ImGuiLastItemData() return { ID = 0, ItemFlags = 0, StatusFlags = 0, Rect = ImRect(), NavRect = ImRect(), DisplayRect = ImRect(), ClipRect = ImRect(), Shortcut = 0 } end --- @param dest ImGuiLastItemData --- @param src ImGuiLastItemData function ImGuiLastItemData_Copy(dest, src) dest.ID = src.ID dest.ItemFlags = src.ItemFlags dest.StatusFlags = src.StatusFlags ImRect_Copy(dest.Rect, src.Rect) ImRect_Copy(dest.NavRect, src.NavRect) ImRect_Copy(dest.DisplayRect, src.DisplayRect) ImRect_Copy(dest.ClipRect, src.ClipRect) dest.Shortcut = src.Shortcut end --- @class ImGuiTreeNodeStackData --- @field ID ImGuiID --- @field TreeFlags ImGuiTreeNodeFlags --- @field ItemFlags ImGuiItemFlags --- @field NavRect ImRect --- @field DrawLinesX1 float --- @field DrawLinesToNodesY2 float --- @field DrawLinesTableColumn ImGuiTableColumnIdx --- @return ImGuiTreeNodeStackData --- @nodiscard local function ImGuiTreeNodeStackData() return { ID = nil, TreeFlags = nil, ItemFlags = nil, NavRect = ImRect(), DrawLinesX1 = nil, DrawLinesToNodesY2 = nil, DrawLinesTableColumn = nil } end --- @class ImGuiNextItemData --- @field HasFlags ImGuiNextItemDataFlags --- @field ItemFlagsSet ImGuiItemFlags --- @field FocusScopeId ImGuiID --- @field SelectionUserData any --- @field Width number --- @field Shortcut ImGuiKeyChord --- @field ShortcutFlags ImGuiInputFlags --- @field OpenVal boolean --- @field OpenCond ImGuiCond --- @field RefVal any --- @field StorageId ImGuiID --- @field ColorMarker ImU32 local IMGUI_NEXT_ITEM_DATA = {} IMGUI_NEXT_ITEM_DATA.__index = IMGUI_NEXT_ITEM_DATA function IMGUI_NEXT_ITEM_DATA:ClearFlags() self.HasFlags = ImGuiNextItemDataFlags.None self.ItemFlagsSet = ImGuiItemFlags.None end --- @return ImGuiNextItemData --- @nodiscard function ImGuiNextItemData() return setmetatable({ HasFlags = 0, ItemFlagsSet = 0, FocusScopeId = 0, SelectionUserData = -1, Width = 0.0, Shortcut = 0, ShortcutFlags = 0, OpenVal = false, OpenCond = 0, RefVal = 0, StorageId = 0, ColorMarker = 0 }, IMGUI_NEXT_ITEM_DATA) end --- @class ImGuiNextWindowData --- @field HasFlags ImGuiNextWindowDataFlags --- @field PosCond ImGuiCond --- @field SizeCond ImGuiCond --- @field CollapsedCond ImGuiCond --- @field PosVal ImVec2? --- @field PosPivotVal ImVec2? --- @field SizeVal ImVec2? --- @field ContentSizeVal ImVec2? --- @field ScrollVal ImVec2? --- @field WindowFlags ImGuiWindowFlags? --- @field ChildFlags ImGuiChildFlags? --- @field CollapsedVal boolean? --- @field SizeConstraintRect ImRect? --- @field SizeCallback function? --- @field SizeCallbackUserData any --- @field BgAlphaVal number? --- @field MenuBarOffsetMinVal ImVec2? --- @field RefreshFlagsVal int? local IMGUI_NEXT_WINDOW_DATA = {} IMGUI_NEXT_WINDOW_DATA.__index = IMGUI_NEXT_WINDOW_DATA function IMGUI_NEXT_WINDOW_DATA:ClearFlags() self.HasFlags = ImGuiNextWindowDataFlags.None end --- @return ImGuiNextWindowData --- @nodiscard function ImGuiNextWindowData() return setmetatable({ HasFlags = 0, PosCond = 0, SizeCond = 0, CollapsedCond = 0, PosVal = ImVec2(), PosPivotVal = ImVec2(), SizeVal = ImVec2(), ContentSizeVal = ImVec2(), ScrollVal = ImVec2(), WindowFlags = nil, ChildFlags = nil, WindowFlagsSet = 0, WindowFlagsClear = 0, ChildFlagsSet = 0, ChildFlagsClear = 0, ViewportId = 0, DockId = 0, DockCond = 0, PosUndock = false, WindowClass = nil, CollapsedVal = nil, SizeConstraintRect = nil, SizeCallback = nil, SizeCallbackUserData = nil, BgAlphaVal = nil, MenuBarOffsetMinVal = ImVec2(), RefreshFlagsVal = nil }, IMGUI_NEXT_WINDOW_DATA) end --- @enum ImGuiWindowBgClickFlags ImGuiWindowBgClickFlags = { None = 0, Move = bitLShift(1, 0), } --- @enum ImGuiNextWindowDataFlags ImGuiNextWindowDataFlags = { None = 0, HasPos = bitLShift(1, 0), HasSize = bitLShift(1, 1), HasContentSize = bitLShift(1, 2), HasCollapsed = bitLShift(1, 3), HasSizeConstraint = bitLShift(1, 4), HasFocus = bitLShift(1, 5), HasBgAlpha = bitLShift(1, 6), HasScroll = bitLShift(1, 7), HasWindowFlags = bitLShift(1, 8), HasChildFlags = bitLShift(1, 9), HasRefreshPolicy = bitLShift(1, 10), HasViewport = bitLShift(1, 11), HasDock = bitLShift(1, 12), HasWindowClass = bitLShift(1, 13) } --- @enum ImGuiLayoutType ImGuiLayoutType = { Horizontal = 0, Vertical = 1 } --- @enum ImGuiSeparatorFlags ImGuiSeparatorFlags = { None = 0, Horizontal = bitLShift(1, 0), -- Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar Vertical = bitLShift(1, 1), SpanAllColumns = bitLShift(1, 2) -- Make separator cover all columns of a legacy Columns() set } --- @class ImGuiStyle MT.ImGuiStyle = {} MT.ImGuiStyle.__index = MT.ImGuiStyle --- @return ImGuiStyle --- @nodiscard function ImGuiStyle() --- @type ImGuiStyle local this = { FontSizeBase = 0.0, FontScaleMain = 1.0, FontScaleDpi = 1.0, Alpha = 1.0, DisabledAlpha = 0.60, FramePadding = ImVec2(4, 3), FrameRounding = 0.0, FrameBorderSize = 0.0, WindowPadding = ImVec2(8, 8), TouchExtraPadding = ImVec2(0, 0), IndentSpacing = 21.0, WindowRounding = 0, WindowBorderSize = 1, ScrollbarSize = 14.0, ScrollbarRounding = 9.0, ScrollbarPadding = 2.0, GrabMinSize = 12.0, GrabRounding = 0.0, ImageRounding = 0.0, ImageBorderSize = 0.0, WindowBorderHoverPadding = 4.0, TreeLinesFlags = ImGuiTreeNodeFlags.DrawLinesNone, TreeLinesSize = 1.0, TreeLinesRounding = 0.0, MenuItemRounding = 0.0, SelectableRounding = 0.0, ColorMarkerSize = 3.0, ColorButtonPosition = ImGuiDir.Right, InputTextCursorSize = 1.0, SeparatorSize = 1.0, SeparatorTextBorderSize = 3.0, SeparatorTextAlign = ImVec2(0.0, 0.5), SeparatorTextPadding = ImVec2(20.0, 3.0), DisplaySafeAreaPadding = ImVec2(3, 3), DisplayWindowPadding = ImVec2(19, 19), AntiAliasedLines = true, AntiAliasedLinesUseTex = true, AntiAliasedFill = true, CurveTessellationTol = 1.25, CircleTessellationMaxError = 0.30, HoverStationaryDelay = 0.15, HoverDelayShort = 0.15, HoverDelayNormal = 0.40, Colors = {}, ButtonTextAlign = ImVec2(0.5, 0.5), SelectableTextAlign = ImVec2(0.0, 0.0), WindowMinSize = ImVec2(32, 32), WindowTitleAlign = ImVec2(0.0, 0.5), WindowMenuButtonPosition = ImGuiDir.Left, ChildRounding = 0.0, ChildBorderSize = 1.0, PopupRounding = 0.0, PopupBorderSize = 1.0, DockingSeparatorSize = 2.0, DockingNodeHasCloseButton = true, MouseCursorScale = 1.0, ItemSpacing = ImVec2(8, 4), ItemInnerSpacing = ImVec2(4, 4), CellPadding = ImVec2(4, 2), ColumnsMinSpacing = 6.0, LogSliderDeadzone = 4.0, TabRounding = 5.0, TabBorderSize = 0.0, TabMinWidthBase = 1.0, TabMinWidthShrink = 80.0, TabCloseButtonMinWidthSelected = -1.0, TabCloseButtonMinWidthUnselected = 0.0, TabBarBorderSize = 1.0, TabBarOverlineSize = 1.0, TableAngledHeadersAngle = 35.0 * (IM_PI / 180.0), TableAngledHeadersTextAlign = ImVec2(0.5, 0.0), DragDropTargetRounding = 0.0, DragDropTargetBorderSize = 2.0, DragDropTargetPadding = 3.0, HoverFlagsForTooltipMouse = bitOr(ImGuiHoveredFlags.Stationary, ImGuiHoveredFlags.DelayShort, ImGuiHoveredFlags.AllowWhenDisabled), HoverFlagsForTooltipNav = bitOr(ImGuiHoveredFlags.NoSharedDelay, ImGuiHoveredFlags.DelayNormal, ImGuiHoveredFlags.AllowWhenDisabled), -- [Internal] _MainScale = 1.0, _NextFrameFontSizeBase = 0.0 } ImGui.StyleColorsDark(this) setmetatable(this, MT.ImGuiStyle) return this end --- @class ImGuiWindowStackData --- @return ImGuiWindowStackData --- @nodiscard function ImGuiWindowStackData() return { Window = nil, ParentLastItemDataBackup = ImGuiLastItemData(), StackSizesInBegin = nil, DisabledOverrideReenable = nil, DisabledOverrideReenableAlphaBackup = nil } end --- @class ImGuiComboPreviewData --- @field PreviewRect ImRect --- @field BackupCursorPos ImVec2 --- @field BackupCursorMaxPos ImVec2 --- @field BackupCursorPosPrevLine ImVec2 --- @field BackupPrevLineTextBaseOffset float --- @field BackupLayout ImGuiLayoutType --- @return ImGuiComboPreviewData --- @nodiscard local function ImGuiComboPreviewData() return { PreviewRect = ImRect(), BackupCursorPos = ImVec2(), BackupCursorMaxPos = ImVec2(), BackupCursorPosPrevLine = ImVec2(), BackupPrevLineTextBaseOffset = 0.0, BackupLayout = 0 } end --- @alias IMSTB_TEXTEDIT_STRING ImGuiInputTextState --- @alias ImStbTexteditState STB_TexteditState --- @class ImGuiInputTextState --- @field Ctx ImGuiContext # parent UI context (needs to be set explicitly by parent) --- @field Stb ImStbTexteditState # State for stb_textedit.lua --- @field Flags ImGuiInputTextFlags --- @field ID ImGuiID # widget id owning the text state --- @field TextLen int # UTF-8 length of the string in TextA (in bytes) --- @field TextSrc ImStringBuffer # == TextA.Data unless read-only, in which case == buf passed to InputText(). For _ReadOnly fields, pointer will be null outside the InputText() call --- @field TextA ImVector # main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1) --- @field TextToRevertTo ImVector # value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) --- @field CallbackTextBackup ImVector # temporary storage for callback to support automatic reconcile of undo-stack --- @field BufCapacity int # end-user buffer capacity (include zero terminator) --- @field Scroll ImVec2 # horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) --- @field LineCount int # last line count (solely for debugging) --- @field WrapWidth float # word-wrapping width --- @field CursorAnim float # timer for cursor blink, reset on every user action so the cursor reappears immediately --- @field CursorFollow bool # set when we want scrolling to follow the current cursor position (not always!) --- @field CursorCenterY bool # set when we want scrolling to be centered over the cursor position (while resizing a word-wrapping field) --- @field SelectedAllMouseLock bool # after a double-click to select all, we ignore further mouse drags to update selection --- @field EditedBefore bool # edited since activated --- @field EditedThisFrame bool # edited this frame MT.ImGuiInputTextState = {} MT.ImGuiInputTextState.__index = MT.ImGuiInputTextState local function ImGuiInputTextState() local this = { Ctx = nil, Stb = STB_TexteditState(), -- FIXME: no global! Flags = 0, ID = 0, TextLen = 0, TextSrc = nil, TextA = ImVector(), TextToRevertTo = ImVector(), CallbackTextBackup = ImVector(), BufCapacity = 0, Scroll = ImVec2(), LineCount = 0, WrapWidth = 0.0, CursorAnim = 0.0, CursorFollow = false, CursorCenterY = false, SelectedAllMouseLock = false, EditedBefore = false, EditedThisFrame = false, } return setmetatable(this, MT.ImGuiInputTextState) end --- @class ImGuiInputTextDeactivatedState --- @field ID ImGuiID # widget id owning the text state (which just got deactivated) --- @field ElapseFrame int --- @field TextA ImVector # text buffer local IMGUI_INPUT_TEXT_DEACTIVATED_STATE = {} IMGUI_INPUT_TEXT_DEACTIVATED_STATE.__index = IMGUI_INPUT_TEXT_DEACTIVATED_STATE function IMGUI_INPUT_TEXT_DEACTIVATED_STATE:ClearFreeMemory() self.ID = 0 self.ElapseFrame = 0 self.TextA:clear() end --- @return ImGuiInputTextDeactivatedState --- @nodiscard local function ImGuiInputTextDeactivatedState() return setmetatable({ ID = 0, ElapseFrame = 0, TextA = ImVector() }, IMGUI_INPUT_TEXT_DEACTIVATED_STATE) end --- @alias ImGuiKeyRoutingIndex ImS16 --- @class ImGuiKeyRoutingData --- @field NextEntryIndex ImGuiKeyRoutingIndex --- @field Mods ImU16 --- @field RoutingCurrScore ImU16 --- @field RoutingNextScore ImU16 --- @field RoutingCurr ImGuiID --- @field RoutingNext ImGuiID --- @return ImGuiKeyRoutingData --- @nodiscard function ImGuiKeyRoutingData() return { NextEntryIndex = -1, Mods = 0, RoutingCurrScore = 0, RoutingNextScore = 0, RoutingCurr = ImGuiKeyOwner_NoOwner, RoutingNext = ImGuiKeyOwner_NoOwner } end --- @class ImGuiKeyRoutingTable --- @field Index ImGuiKeyRoutingIndex[] --- @field Entries ImVector --- @field EntriesNext ImVector local _ImGuiKeyRoutingTable = {} _ImGuiKeyRoutingTable.__index = _ImGuiKeyRoutingTable function _ImGuiKeyRoutingTable:Clear() for n = 1, ImGuiKey.NamedKey_COUNT do self.Index[n] = -1 end self.Entries:clear() self.EntriesNext:clear() end --- @return ImGuiKeyRoutingTable local function ImGuiKeyRoutingTable() local this = setmetatable({ Index = {}, Entries = ImVector(), EntriesNext = ImVector() }, _ImGuiKeyRoutingTable) this:Clear() return this end --- @class ImGuiTextIndex --- @field Offsets ImVector --- @field EndOffset int local IMGUI_TEXT_INDEX = {} IMGUI_TEXT_INDEX.__index = IMGUI_TEXT_INDEX function IMGUI_TEXT_INDEX:clear() self.Offsets:clear(); self.EndOffset = 0; end function IMGUI_TEXT_INDEX:get_line_begin(base, n) return base + (self.Offsets.Size ~= 0 and self.Offsets[n] or 0) end function IMGUI_TEXT_INDEX:get_line_end(base, n) return base + ((n + 1 < self.Offsets.Size) and (self.Offsets[n + 1] - 1) or self.EndOffset) end --- @return ImGuiTextIndex local function ImGuiTextIndex() return setmetatable({ Offsets = ImVector(), EndOffset = 0 }, IMGUI_TEXT_INDEX) end --- @class ImGuiDebugAllocEntry --- @field FrameCount int --- @field AllocCount int --- @field FreeCount int --- @return ImGuiDebugAllocEntry local function ImGuiDebugAllocEntry() return { FrameCount = 0, AllocCount = 0, FreeCount = 0 } end --- @class ImGuiDebugAllocInfo --- @field TotalAllocCount int --- @field TotalFreeCount int --- @field LastEntriesIdx ImS16 --- @field LastEntriesBuf ImGuiDebugAllocEntry[] --- @return ImGuiDebugAllocInfo local function ImGuiDebugAllocInfo() local this = { TotalAllocCount = 0, TotalFreeCount = 0, LastEntriesIdx = 1, LastEntriesBuf = {nil, nil, nil, nil, nil, nil}, } for i = 1, 6 do this.LastEntriesBuf[i] = ImGuiDebugAllocEntry() end return this end --- @class ImGuiMetricsConfig --- @return ImGuiMetricsConfig local function ImGuiMetricsConfig() return { HighlightMonitorIdx = -1, HighlightViewportID = 0, } end --- @class ImGuiNavItemData --- @field Window ImGuiWindow? --- @field ID ImGuiID --- @field FocusScopeId ImGuiID --- @field RectRel ImRect --- @field ItemFlags ImGuiItemFlags --- @field SelectionUserData ImGuiSelectionUserData --- @field DistBox float --- @field DistCenter float --- @field DistAxial float local IMGUI_NAV_ITEM_DATA = {} IMGUI_NAV_ITEM_DATA.__index = IMGUI_NAV_ITEM_DATA function IMGUI_NAV_ITEM_DATA:Clear() self.Window = nil self.ID = 0 self.FocusScopeId = 0 self.ItemFlags = 0 self.SelectionUserData = ImGuiSelectionUserData_Invalid self.DistBox = FLT_MAX self.DistCenter = FLT_MAX self.DistAxial = FLT_MAX end --- @return ImGuiNavItemData local function ImGuiNavItemData() local this = setmetatable({ }, IMGUI_NAV_ITEM_DATA) this.RectRel = ImRect() this:Clear() return this end --- @class ImGuiContext --- @field Initialized bool --- @field WithinFrameScope bool --- @field WithinFrameScopeWithImplicitWindow bool --- @field FrameCount int --- @field FrameCountEnded int --- @field CurrentWindow ImGuiWindow --- @field HoveredWindow ImGuiWindow --- @field Style ImGuiStyle --- @field FontAtlases ImVector --- @field Font ImFont --- @field FontBaked ImFontBaked? --- @field FontSize float --- @field FontSizeBase float --- @field FontBakedScale float --- @field FontRasterizerDensity float --- @field DrawListSharedData ImDrawListSharedData --- @field NextItemData ImGuiNextItemData --- @field LastItemData ImGuiLastItemData --- @field NextWindowData ImGuiNextWindowData --- @field WithinEndChildID ImGuiID --- @field WithinEndPopupID ImGuiID --- @field StyleVarStack ImVector --- @field AnyIdHasBeenEditedThisFrame bool --- @field ActiveId ImGuiID --- @field ActiveIdMouseButton ImS8 --- @field Windows ImVector --- @field WindowsFocusOrder ImVector --- @field WindowsTempSortBuffer ImVector --- @field CurrentWindowStack ImVector --- @field FocusScopeStack ImVector --- @field ItemFlagsStack ImVector --- @field GroupStack ImVector --- @field OpenPopupStack ImVector --- @field BeginPopupStack ImVector --- @field TreeNodeStack ImVector --- @field IO ImGuiIO --- @field PlatformIO ImGuiPlatformIO --- @field Viewports ImVector --- @field DebugLogFlags ImGuiDebugLogFlags --- @field DebugFlashStyleColorIdx ImGuiCol --- @field ColorEditCurrentID ImGuiID # Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others) --- @field ColorEditSavedID ImGuiID # ID we are saving/restoring HS for --- @field ColorEditSavedHue float # Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips --- @field ColorEditSavedSat float # Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips --- @field ColorEditSavedColor ImU32 # RGB value with alpha set to 0 --- @field ColorPickerRef ImVec4 # Initial/reference color at the time of opening the color picker --- @field MenusIdSubmittedThisFrame ImVector --- @field InputTextState ImGuiInputTextState --- @field InputTextLineIndex ImGuiTextIndex --- @field InputTextDeactivatedState ImGuiInputTextDeactivatedState --- @field InputTextPasswordFontBackupBaked ImFontBaked --- @field KeysMayBeCharInput ImBitArrayForNamedKeys --- @field KeysOwnerData ImGuiKeyOwnerData[] --- @field KeysRoutingTable ImGuiKeyRoutingTable --- @field NavFocusRoute ImVector --- @field PlatformImeData ImGuiPlatformImeData --- @field PlatformImeDataPrev ImGuiPlatformImeData --- @field UserTextures ImVector --- @field DebugMetricsConfig ImGuiMetricsConfig --- @field DebugAllocInfo ImGuiDebugAllocInfo --- @field TempBuffer ImVector ---------------------------------------------------------------- -- [SECTION] Tab bar, Tab item support (public flags from imgui.h + private extensions) ---------------------------------------------------------------- --- @enum ImGuiTabBarFlags ImGuiTabBarFlags = { None = 0, Reorderable = bitLShift(1, 0), AutoSelectNewTabs = bitLShift(1, 1), TabListPopupButton = bitLShift(1, 2), NoCloseWithMiddleMouseButton = bitLShift(1, 3), NoTabListScrollingButtons = bitLShift(1, 4), NoTooltip = bitLShift(1, 5), DrawSelectedOverline = bitLShift(1, 6), FittingPolicyMixed = bitLShift(1, 7), FittingPolicyShrink = bitLShift(1, 8), FittingPolicyScroll = bitLShift(1, 9), -- Private DockNode = bitLShift(1, 20), IsFocused = bitLShift(1, 21), SaveSettings = bitLShift(1, 22), } ImGuiTabBarFlags.FittingPolicyMask_ = bitOr(ImGuiTabBarFlags.FittingPolicyMixed, ImGuiTabBarFlags.FittingPolicyShrink, ImGuiTabBarFlags.FittingPolicyScroll) ImGuiTabBarFlags.FittingPolicyDefault_ = ImGuiTabBarFlags.FittingPolicyMixed ImGuiTabBarFlags.FittingPolicyResizeDown = ImGuiTabBarFlags.FittingPolicyShrink --- @enum ImGuiTabItemFlags ImGuiTabItemFlags = { None = 0, UnsavedDocument = bitLShift(1, 0), SetSelected = bitLShift(1, 1), NoCloseWithMiddleMouseButton = bitLShift(1, 2), NoPushId = bitLShift(1, 3), NoTooltip = bitLShift(1, 4), NoReorder = bitLShift(1, 5), Leading = bitLShift(1, 6), Trailing = bitLShift(1, 7), NoAssumedClosure = bitLShift(1, 8), -- Private NoCloseButton = bitLShift(1, 20), Button = bitLShift(1, 21), Invisible = bitLShift(1, 22), Unsorted = bitLShift(1, 23), } ImGuiTabItemFlags.SectionMask_ = bitOr(ImGuiTabItemFlags.Leading, ImGuiTabItemFlags.Trailing) -- Storage for one active tab item. In this port the label is stored in `Name` (C++ uses NameOffset into TabBar.TabsNames) --- @class ImGuiTabItem --- @return ImGuiTabItem function ImGuiTabItem() return { ID = 0, Flags = 0, Window = nil, LastFrameVisible = -1, LastFrameSelected = -1, Offset = 0.0, Width = 0.0, ContentWidth = 0.0, RequestedWidth = -1.0, NameOffset = -1, Name = nil, BeginOrder = -1, -- 0-based IndexDuringLayout = -1, -- 0-based WantClose = false, } end -- Storage for a tab bar. Tabs: ImVector of ImGuiTabItem tables (references; "pointers" stay valid across reorders) --- @class ImGuiTabBar --- @return ImGuiTabBar function ImGuiTabBar() return { Window = nil, Tabs = ImVector(), Flags = 0, ID = 0, SelectedTabId = 0, NextSelectedTabId = 0, NextScrollToTabId = 0, VisibleTabId = 0, CurrFrameVisible = -1, PrevFrameVisible = -1, BarRect = ImRect(), BarRectPrevWidth = 0.0, CurrTabsContentsHeight = 0.0, PrevTabsContentsHeight = 0.0, WidthAllTabs = 0.0, WidthAllTabsIdeal = 0.0, ScrollingAnim = 0.0, ScrollingTarget = 0.0, ScrollingTargetDistToVisibility = 0.0, ScrollingSpeed = 0.0, ScrollingRectMinX = 0.0, ScrollingRectMaxX = 0.0, SeparatorMinX = 0.0, SeparatorMaxX = 0.0, ReorderRequestTabId = 0, ReorderRequestOffset = 0, BeginCount = 0, WantLayout = false, VisibleTabWasSubmitted = false, TabsAddedNew = false, ScrollButtonEnabled = false, TabsActiveCount = 0, LastTabItemIdx = -1, -- 0-based ItemSpacingY = 0.0, FramePadding = ImVec2(), BackupCursorPos = ImVec2(), } end --- @class ImGuiShrinkWidthItem function ImGuiShrinkWidthItem() return { Index = 0, Width = 0.0, InitialWidth = 0.0 } end --- @param shared_font_atlas? ImFontAtlas --- @return ImGuiContext --- @nodiscard function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this structure local this = { Style = ImGuiStyle(), ColorStack = ImVector(), StyleVarStack = ImVector(), Config = nil, Initialized = false, WithinFrameScope = false, WithinFrameScopeWithImplicitWindow = false, Windows = ImVector(), -- Windows sorted in display order, back to front WindowsById = {}, -- Map window's ID to window ref WindowsBorderHoverPadding = 0, WindowsActiveCount = 0, WindowsTempSortBuffer = ImVector(), CurrentWindowStack = ImVector(), CurrentWindow = nil, WindowsFocusOrder = ImVector(), IO = ImGuiIO(), PlatformIO = ImGuiPlatformIO(), ConfigFlagsCurrFrame = ImGuiConfigFlags.None, ConfigFlagsLastFrame = ImGuiConfigFlags.None, MouseLastValidPos = ImVec2(), KeysMayBeCharInput = ImBitArray(ImGuiKey.NamedKey_COUNT, -ImGuiKey.NamedKey_BEGIN), KeysOwnerData = {}, -- size = ImGuiKey.NamedKey_COUNT KeysRoutingTable = ImGuiKeyRoutingTable(), InputEventsQueue = ImVector(), InputEventsNextMouseSource = ImGuiMouseSource.Mouse, InputEventsNextEventId = 1, MovingWindow = nil, WheelingWindow = nil, WheelingWindowStartFrame = -1, WheelingWindowScrolledFrame = -1, WheelingWindowReleaseTimer = 0.0, WheelingWindowRefMousePos = ImVec2(), WheelingWindowWheelRemainder = ImVec2(), WheelingAxisAvg = ImVec2(), ActiveIdClickOffset = ImVec2(), HoveredWindow = nil, HoveredWindowUnderMovingWindow = nil, HoveredIdIsDisabled = false, ActiveIdFromShortcut = false, AnyIdHasBeenEditedThisFrame = false, ActiveId = 0, ActiveIdWindow = nil, ActiveIdMouseButton = -1, ActiveIdIsJustActivated = false, ActiveIdWasSelected = false, ActiveIdWasSoleSelected = false, LastActiveIdWasSelected = false, LastActiveIdWasSoleSelected = false, ActiveIdNoClearOnFocusLoss = false, ActiveIdHasBeenPressedBefore = false, ActiveIdIsAlive = nil, ActiveIdPreviousFrame = 0, ActiveIdTimer = 0.0, LastActiveId = 0, LastActiveIdTimer = 0.0, ActiveIdUsingNavDirMask = 0x00, ActiveIdUsingAllKeyboardKeys = false, DeactivatedItemData = { ID = 0, ElapseFrame = 0, HasBeenEditedBefore = false, IsAlive = false }, HoveredId = 0, HoveredIdTimer = 0.0, HoveredIdNotActiveTimer = 0.0, HoveredIdAllowOverlap = false, HoverItemDelayId = 0, HoverItemDelayIdPreviousFrame = 0, HoverItemUnlockedStationaryId = 0, HoverWindowUnlockedStationaryId = 0, HoverItemDelayTimer = 0.0, HoverItemDelayClearTimer = 0.0, ActiveIdAllowOverlap = false, NavLayer = ImGuiNavLayer.Main, NavId = 0, NavOpenContextMenuItemId = 0, NavOpenContextMenuWindowId = 0, NavWindow = nil, NavHighlightActivatedId = 0, NavHighlightActivatedTimer = 0.0, NavCursorVisible = false, NavCursorHideFrames = 0, NavHighlightItemUnderNav = false, NavIdIsAlive = false, NavInputSource = ImGuiInputSource.Keyboard, NavWindowingTarget = nil, NavWindowingTargetAnim = nil, NavWindowingListWindow = nil, NavWindowingTimer = 0.0, NavWindowingHighlightAlpha = 0.0, NavWindowingToggleLayer = false, NavWindowingToggleKey = ImGuiKey.None, NavWindowingInputSource = ImGuiInputSource.None, NavWindowingAccumDeltaPos = ImVec2(0.0, 0.0), NavWindowingAccumDeltaSize = ImVec2(0.0, 0.0), DimBgRatio = 0.0, LastKeyboardKeyPressTime = -1.0, LastKeyModsChangeTime = -1.0, LastKeyModsChangeFromNoneTime = -1.0, ConfigNavWindowingKeyNext = bit32.bor(ImGuiMod_Ctrl, ImGuiKey.Tab), ConfigNavWindowingKeyPrev = bit32.bor(ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey.Tab), ConfigNavWindowingWithGamepad = true, NavFocusRoute = ImVector(), NavAnyRequest = false, NavInitRequest = false, NavInitRequestFromMove = false, NavInitResult = ImGuiNavItemData(), NavMoveSubmitted = false, NavMoveScoringItems = false, NavMoveForwardToNextFrame = false, NavMoveFlags = ImGuiNavMoveFlags.None, NavMoveScrollFlags = ImGuiScrollFlags.None, NavMoveKeyMods = ImGuiMod_None, NavMoveDir = ImGuiDir.None, NavMoveDirForDebug = ImGuiDir.None, NavMoveClipDir = ImGuiDir.None, NavMoveResultLocal = ImGuiNavItemData(), NavMoveResultOther = ImGuiNavItemData(), NavMoveResultLocalVisible = ImGuiNavItemData(), NavTabbingResultFirst = ImGuiNavItemData(), NavScoringRect = ImRect(), NavScoringNoClipRect = ImRect(), ConfigNavEnableTabbing = true, NavTabbingCounter = 0, NavTabbingDir = 0, NavNextActivateId = 0, NavNextActivateFlags = ImGuiActivateFlags.None, NavActivateId = 0, NavActivateDownId = 0, NavActivatePressedId = 0, NavActivateFlags = ImGuiActivateFlags.None, FrameCount = -1, FrameCountEnded = -1, FrameCountPlatformEnded = -1, FrameCountRendered = -1, Time = 0, NextItemData = ImGuiNextItemData(), LastItemData = ImGuiLastItemData(), NextWindowData = ImGuiNextWindowData(), Viewports = ImVector(), FallbackMonitor = nil, GcCompactAll = false, CurrentViewport = nil, MouseViewport = nil, MouseLastHoveredViewport = nil, PlatformLastFocusedViewportId = 1, ViewportCreatedCount = 0, PlatformWindowsCreatedCount = 0, ViewportFocusedStampCount = 0, Font = nil, FontSize = 0.0, FontSizeBase = 0.0, CurrentDpiScale = 0.0, FontRefSize = 0.0, FontRasterizerDensity = 1.0, FontAtlases = ImVector(), FontStack = ImVector(), OpenPopupStack = ImVector(), BeginPopupStack = ImVector(), TreeNodeStack = ImVector(ImGuiTreeNodeStackData), WithinEndChildID = 0, WithinEndPopupID = 0, BeginMenuDepth = 0, BeginComboDepth = 0, ColorEditCurrentID = 0, ColorEditSavedID = 0, ColorEditSavedHue = 0.0, ColorEditSavedSat = 0.0, ColorEditSavedColor = 0, ColorPickerRef = ImVec4(), MenusIdSubmittedThisFrame = ImVector(), DrawListSharedData = ImDrawListSharedData(), StackSizesInBeginForCurrentWindow = nil, MouseCursor = ImGuiMouseCursor.Arrow, MouseStationaryTimer = 0.0, InputTextState = ImGuiInputTextState(), InputTextLineIndex = ImGuiTextIndex(), InputTextDeactivatedState = ImGuiInputTextDeactivatedState(), InputTextPasswordFontBackupBaked = ImFontBaked(), InputTextReactivateId = 0, TempInputId = 0, ActiveIdValueOnActivation = 0, DataTypeZeroValue = 0, ComboPreviewData = ImGuiComboPreviewData(), CurrentTabBar = nil, TabBars = ImPool(ImGuiTabBar), -- ImPool -- Docking DockContext = ImGuiDockContext(), DockNodeWindowMenuHandler = nil, DebugHoveredDockNode = nil, CurrentTabBarStack = ImVector(), -- holds ImGuiTabBar references directly (no ImGuiPtrOrIndex needed in Lua) ShrinkWidthBuffer = ImVector(), -- ImGuiShrinkWidthItem WindowResizeBorderExpectedRect = ImRect(), WindowResizeRelativeMode = false, ScrollbarSeekMode = 0, ScrollbarClickDeltaToGrabCenter = 0.0, SliderGrabClickOffset = 0.0, SliderCurrentAccum = 0.0, SliderCurrentAccumDirty = false, DragCurrentAccumDirty = false, DragCurrentAccum = 0.0, DragSpeedDefaultRatio = 1.0 / 100.0, TooltipOverrideCount = 0, TooltipPreviousWindow = nil, FocusScopeStack = ImVector(), CurrentFocusScopeId = 0, CurrentItemFlags = ImGuiItemFlags.None, DisabledAlphaBackup = 0.0, DisabledStackSize = 0, ItemFlagsStack = ImVector(), GroupStack = ImVector(), PlatformImeData = ImGuiPlatformImeData(), PlatformImeDataPrev = ImGuiPlatformImeData(), -- Extensions UserTextures = ImVector(), -- Settings SettingsLoaded = false, SettingsDirtyTimer = 0.0, SettingsIniData = "", -- In memory .ini settings (string) SettingsHandlers = ImVector(), -- List of .ini settings handlers SettingsWindows = ImVector(), SettingsTables = ImVector(), -- Hooks Hooks = ImVector(), HookIdNext = 0, -- Drag and Drop DragDropActive = false, DragDropWithinSource = false, DragDropWithinTarget = false, DragDropSourceFlags = 0, DragDropSourceFrameCount = -1, DragDropMouseButton = -1, DragDropPayload = ImGuiPayload(), DragDropTargetRect = ImRect(), DragDropTargetClipRect = ImRect(), DragDropTargetId = 0, DragDropTargetFullViewport = 0, DragDropAcceptFlagsCurr = 0, DragDropAcceptFlagsPrev = 0, DragDropAcceptIdCurrRectSurface = 0.0, DragDropAcceptFrameCount = -1, DragDropHoldJustPressedId = 0, DragDropAcceptIdPrev = 0, DragDropAcceptIdCurr = 0, -- Clipper ClipperTempDataStacked = 0, ClipperTempData = ImVector(), -- Logging LogEnabled = false, LogLineFirstItem = false, LogFlags = 0, LogWindow = nil, LogFile = nil, LogBuffer = ImGuiTextBuffer(), LogNextPrefix = nil, LogNextSuffix = nil, LogLinePosY = FLT_MAX, LogDepthRef = 0, LogDepthToExpand = 2, LogDepthToExpandDefault = 2, -- Error handling ErrorCallback = nil, ErrorCallbackUserData = nil, ErrorTooltipLockedPos = ImVec2(), ErrorFirst = true, ErrorCountCurrentFrame = 0, StackSizesInNewFrame = nil, ContextName = "", DebugBreakInWindow = 0, LocalizationTable = {}, DebugLogFlags = bitOr(ImGuiDebugLogFlags.EventError, ImGuiDebugLogFlags.OutputToTTY), DebugFlashStyleColorIdx = nil, DebugMetricsConfig = ImGuiMetricsConfig(), DebugHookIdInfoId = 0, DebugAllocInfo = ImGuiDebugAllocInfo(), --- Misc FramerateSecPerFrame = {}, -- size = 60 FramerateSecPerFrameIdx = 0, FramerateSecPerFrameCount = 0, FramerateSecPerFrameAccum = 0, WantCaptureMouseNextFrame = -1, WantCaptureKeyboardNextFrame = -1, WantTextInputNextFrame = -1, TempBuffer = ImVector(), -- Tables (imgui_tables.lua) CurrentTable = nil, DebugBreakInTable = 0, TablesTempDataStacked = 0, TablesTempData = ImVector(), Tables = ImPool(), -- ImPool, 0-based indices (imgui_tables.lua) TablesLastTimeActive = ImVector(), -- [table_idx + 1] = float DrawChannelsTempMergeBuffer = ImVector(), SettingsTables = ImVector(), -- ImChunkStream: plain vector, SettingsOffset = 1-based index } for i = 0, 59 do this.FramerateSecPerFrame[i] = 0 end this.IO.Fonts = (shared_font_atlas ~= nil) and shared_font_atlas or ImFontAtlas() if shared_font_atlas == nil then this.IO.Fonts.OwnerContext = this end for i = 0, ImGuiKey.NamedKey_COUNT - 1 do this.KeysOwnerData[i] = ImGuiKeyOwnerData() end this.IO.Ctx = this this.InputTextState.Ctx = this ImVec2_Copy(this.PlatformImeDataPrev.InputPos, ImVec2(-1.0, -1.0)) return this end --- @class ImGuiWindowSettings --- @field ID int # Window ID --- @field Pos ImVec2 # Window position --- @field Size ImVec2 # Window size --- @field Collapsed bool # Whether window is collapsed --- @field IsChild bool # Whether window is a child window --- @field WantApply bool # Set when loaded from .ini data --- @field WantDelete bool # Set to invalidate/delete the settings entry --- @field Name string # Window name local IMGUI_WINDOW_SETTINGS = {} IMGUI_WINDOW_SETTINGS.__index = IMGUI_WINDOW_SETTINGS function IMGUI_WINDOW_SETTINGS:GetName() return self.Name end function ImGuiWindowSettings() return setmetatable({ ID = 0, Pos = ImVec2(0, 0), Size = ImVec2(0, 0), Collapsed = false, IsChild = false, WantApply = false, WantDelete = false, Name = "", ViewportId = 0, ViewportPos = ImVec2(0, 0), DockId = 0, DockOrder = -1, ClassId = 0, LastUsedDate = 0, }, IMGUI_WINDOW_SETTINGS) end --- @class ImGuiMenuColumns --- @field TotalWidth ImU32 --- @field NextTotalWidth ImU32 --- @field Spacing ImU16 --- @field OffsetIcon ImU16 # Always zero for now --- @field OffsetLabel ImU16 # Offsets are locked in Update() --- @field OffsetShortcut ImU16 --- @field OffsetMark ImU16 --- @field Widths ImU16[] # Width of: Icon, Label, Shortcut, Mark (accumulators for current frame) MT.ImGuiMenuColumns = {} MT.ImGuiMenuColumns.__index = MT.ImGuiMenuColumns --- @return ImGuiMenuColumns local function ImGuiMenuColumns() return setmetatable({ TotalWidth = 0, NextTotalWidth = 0, Spacing = 0, OffsetIcon = 0, OffsetLabel = 0, OffsetShortcut = 0, OffsetMark = 0, Widths = {0, 0, 0, 0} }, MT.ImGuiMenuColumns) end --- @class ImGuiWindowTempData --- @field CursorPos ImVec2 --- @field CursorPosPrevLine ImVec2 --- @field CursorStartPos ImVec2 --- @field CursorMaxPos ImVec2 --- @field IdealMaxPos ImVec2 --- @field CurrLineSize ImVec2 --- @field PrevLineSize ImVec2 --- @field CurrLineTextBaseOffset float --- @field PrevLineTextBaseOffset float --- @field IsSameLine bool --- @field IsSetPos bool --- @field Indent ImVec1 --- @field ColumnsOffset ImVec1 --- @field GroupOffset ImVec1 --- @field CursorStartPosLossyness ImVec2 --- @field TextWrapPos float --- @field TextWrapPosStack ImVector --- @field MenuBarAppending bool --- @field MenuBarOffset ImVec2 --- @field MenuColumns ImGuiMenuColumns --- @field TreeDepth int --- @field TreeHasStackDataDepthMask ImU32 --- @field TreeRecordsClippedNodesY2Mask ImU32 --- @field ChildWindows ImVector --- @field LayoutType ImGuiLayoutType --- @return ImGuiWindowTempData --- @nodiscard local function ImGuiWindowTempData() return { DockTabItemStatusFlags = 0, DockTabItemRect = ImRect(), CursorPos = ImVec2(), CursorPosPrevLine = ImVec2(), CursorStartPos = ImVec2(), CursorMaxPos = ImVec2(), IdealMaxPos = ImVec2(), CurrLineSize = ImVec2(), PrevLineSize = ImVec2(), CurrLineTextBaseOffset = 0, PrevLineTextBaseOffset = 0, IsSameLine = false, IsSetPos = false, NavLayersActiveMask = 0, NavLayersActiveMaskNext = 0, Indent = ImVec1(), ColumnsOffset = ImVec1(), GroupOffset = ImVec1(), CursorStartPosLossyness = ImVec2(), ItemWidth = 0, ItemWidthDefault = 0, TextWrapPos = 0, ItemWidthStack = ImVector(), TextWrapPosStack = ImVector(), MenuBarAppending = false, -- FIXME: Remove this MenuBarOffset = ImVec2(), MenuColumns = ImGuiMenuColumns(), TreeDepth = 0, TreeHasStackDataDepthMask = nil, TreeRecordsClippedNodesY2Mask = nil, ChildWindows = ImVector(), CurrentTableIdx = -1, -- 0-based index into g.Tables, -1 if none CurrentColumns = nil, -- ImGuiOldColumns (legacy Columns API) StateStorage = nil, LayoutType = nil } end --- @class ImGuiWindow --- @field Ctx ImGuiContext --- @field Name string --- @field ID ImGuiID --- @field Flags ImGuiWindowFlags --- @field FlagsPreviousFrame ImGuiWindowFlags --- @field ChildFlags ImGuiChildFlags --- @field WindowClass ImGuiWindowClass --- @field Viewport ImGuiViewportP --- @field ViewportId ImGuiID --- @field ViewportPos ImVec2 --- @field ViewportAllowPlatformMonitorExtend int --- @field Pos ImVec2 --- @field Size ImVec2 --- @field SizeFull ImVec2 --- @field ContentSize ImVec2 --- @field ContentSizeIdeal ImVec2 --- @field ContentSizeExplicit ImVec2 --- @field Scroll ImVec2 --- @field IsExplicitChild bool --- @field FocusOrder short # 1-based, order within WindowsFocusOrder, altered when windows are focused. Can be -1 if invalid --- @field IDStack ImVector --- @field DC ImGuiWindowTempData --- @field OuterRectClipped ImRect --- @field InnerRect ImRect --- @field InnerClipRect ImRect --- @field WorkRect ImRect --- @field ParentWorkRect ImRect --- @field ClipRect ImRect --- @field ContentRegionRect ImRect --- @field DrawList ImDrawList # Points to DrawListInst --- @field DrawListInst ImDrawList --- @field ParentWindow? ImGuiWindow --- @field RootWindow ImGuiWindow --- @field RootWindowPopupTree ImGuiWindow --- @field RootWindowDockTree ImGuiWindow --- @field StateStorage {[ImGuiID]: bool} --- @field MemoryDrawListIdxCapacity int --- @field MemoryDrawListVtxCapacity int --- @field MemoryCompacted bool MT.ImGuiWindow = {} MT.ImGuiWindow.__index = MT.ImGuiWindow --- @return ImRect --- @nodiscard function MT.ImGuiWindow:Rect() return ImRect(self.Pos.x, self.Pos.y, self.Pos.x + self.Size.x, self.Pos.y + self.Size.y) end --- @return ImRect --- @nodiscard function MT.ImGuiWindow:TitleBarRect() return ImRect(self.Pos, ImVec2(self.Pos.x + self.SizeFull.x, self.Pos.y + self.TitleBarHeight)) end --- @return ImRect --- @nodiscard function MT.ImGuiWindow:MenuBarRect() local y1 = self.Pos.y + self.TitleBarHeight return ImRect(self.Pos.x, y1, self.Pos.x + self.SizeFull.x, y1 + self.MenuBarHeight) end --- @return ImGuiWindow --- @nodiscard function ImGuiWindow(ctx, name) local this = { ID = 0, MoveId = 0, Ctx = ctx, Name = name, Flags = 0, ChildFlags = 0, WindowClass = ImGuiWindowClass(), Pos = ImVec2(), Size = ImVec2(), -- Current size (==SizeFull or collapsed title bar size) SizeFull = ImVec2(), Active = false, WasActive = false, Collapsed = false, SkipItems = false, SkipRefresh = false, Appearing = false, Hidden = false, IsFallbackWindow = false, IsExplicitChild = nil, ResizeBorderHovered = -1, ResizeBorderHeld = -1, BeginCount = 0, BeginCountPreviousFrame = 0, BeginOrderWithinParent = 0, BeginOrderWithinContext = 0, FocusOrder = nil, HiddenFramesCanSkipItems = 0, HiddenFramesCannotSkipItems = 0, HiddenFramesForRenderOnly = 0, DisableInputsFrames = 0, WindowRounding = 0, WindowBorderSize = 1, TitleBarHeight = 0, MenuBarHeight = 0, DecoOuterSizeX1 = 0, DecoOuterSizeY1 = 0, DecoOuterSizeX2 = 0, DecoOuterSizeY2 = 0, DecoInnerSizeX1 = 0, DecoInnerSizeY1 = 0, ContentSize = ImVec2(), ContentSizeIdeal = ImVec2(), ContentSizeExplicit = ImVec2(), AutoFitFramesX = -1, AutoFitFramesY = -1, AutoFitOnlyGrows = false, HasCloseButton = true, BgClickFlags = 0, SetWindowPosAllowFlags = 0, SetWindowSizeAllowFlags = 0, SetWindowCollapsedAllowFlags = 0, SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX), SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX), SettingsOffset = -1, ScrollbarSizes = ImVec2(), Scroll = ImVec2(), ScrollbarX = false, ScrollbarY = false, ScrollMax = ImVec2(), ScrollTarget = ImVec2(FLT_MAX, FLT_MAX), ScrollTargetCenterRatio = ImVec2(0.5, 0.5), ScrollTargetEdgeSnapDist = ImVec2(), ScrollbarXStabilizeToggledHistory = 0, DrawList = nil, DrawListInst = ImDrawList(ctx.DrawListSharedData), RootWindow = nil, RootWindowPopupTree = nil, RootWindowDockTree = nil, ParentWindow = nil, ParentWindowInBeginStack = nil, IDStack = ImVector(), ViewportAllowPlatformMonitorExtend = -1, Viewport = nil, ViewportId = 0, ViewportPos = ImVec2(FLT_MAX, FLT_MAX), ViewportOwned = nil, DC = ImGuiWindowTempData(), OuterRectClipped = ImRect(), InnerRect = ImRect(), InnerClipRect = ImRect(), WorkRect = ImRect(), ParentWorkRect = ImRect(), ContentRegionRect = ImRect(), ClipRect = ImRect(), LastFrameActive = -1, LastFrameJustFocused = -1, LastTimeActive = -1.0, StateStorage = {}, ColumnsStorage = ImVector(), -- ImVector WriteAccessed = false, FontWindowScale = 1.0, FontWindowScaleParents = 1.0, HitTestHoleSize = ImVec2(), NavLastChildNavWindow = nil, NavLastIds = {[0] = 0, [1] = 0}, -- FIXME: 1-based instead NavRectRel = {[0] = ImRect(), [1] = ImRect()}, NavPreferredScoringPosRel = {[0] = ImVec2(), [1] = ImVec2()}, NavRootFocusScopeId = 0 } this.DrawList = this.DrawListInst this.DrawList._OwnerName = name setmetatable(this, MT.ImGuiWindow) this.ID = ImHashStr(name) this.IDStack:push_back(this.ID) this.MoveId = this:GetID("#MOVE") this.TabId = this:GetID("#TAB") -- Docking this.ChildId = this.ChildId or 0 this.SetWindowDockAllowFlags = 0 this.ParentWindowForFocusRoute = nil this.DockIsActive = false this.DockNodeIsVisible = false this.DockTabIsVisible = false this.DockTabWantClose = false this.DockOrder = -1 this.DockStyle = { Colors = {} } for i = 0, 8 do this.DockStyle.Colors[i] = 0 end this.DockNode = nil this.DockNodeAsHost = nil this.DockId = 0 return this end --- @class ImDrawDataBuilder --- @field Layers [ImVector?, ImVector?] --- @field LayerData1 ImVector --- @return ImDrawDataBuilder --- @nodiscard local function ImDrawDataBuilder() return { Layers = {nil, nil}, LayerData1 = ImVector() } end --- @class ImGuiViewportP : ImGuiViewport --- @field Window? ImGuiWindow --- @field Idx int # Initial value = -1, then becomes 1-based index --- @field LastFrameActive int --- @field LastFocusedStampCount int --- @field LastNameHash ImGuiID --- @field LastPos ImVec2 --- @field LastSize ImVec2 --- @field Alpha float --- @field LastAlpha float --- @field LastFocusedHadNavWindow bool --- @field PlatformMonitor short --- @field BgFgDrawListsLastTimeActive [int, int] # 1-based --- @field BgFgDrawLists [ImDrawList, ImDrawList] # 1-based --- @field DrawDataP ImDrawData --- @field DrawDataBuilder ImDrawDataBuilder --- @field LastPlatformPos ImVec2 --- @field LastPlatformSize ImVec2 --- @field LastRendererSize ImVec2 --- @field WorkInsetMin ImVec2 --- @field WorkInsetMax ImVec2 --- @field BuildWorkInsetMin ImVec2 --- @field BuildWorkInsetMax ImVec2 local IMGUI_VIEWPORT_P = {} IMGUI_VIEWPORT_P.__index = IMGUI_VIEWPORT_P setmetatable(IMGUI_VIEWPORT_P, {__index = MT.ImGuiViewport}) function IMGUI_VIEWPORT_P:ClearRequestFlags() self.PlatformRequestClose = false self.PlatformRequestMove = false self.PlatformRequestResize = false end function IMGUI_VIEWPORT_P:CalcWorkRectPos(inset_min) return ImVec2(self.Pos.x + inset_min.x, self.Pos.y + inset_min.y) end function IMGUI_VIEWPORT_P:CalcWorkRectSize(inset_min, inset_max) return ImVec2(ImMax(0.0, self.Size.x - inset_min.x - inset_max.x), ImMax(0.0, self.Size.y - inset_min.y - inset_max.y)) end function IMGUI_VIEWPORT_P:UpdateWorkRect() self.WorkPos = self:CalcWorkRectPos(self.WorkInsetMin) self.WorkSize = self:CalcWorkRectSize(self.WorkInsetMin, self.WorkInsetMax) end --- @nodiscard function IMGUI_VIEWPORT_P:GetMainRect() return ImRect(self.Pos.x, self.Pos.y, self.Pos.x + self.Size.x, self.Pos.y + self.Size.y) end --- @nodiscard function IMGUI_VIEWPORT_P:GetWorkRect() return ImRect(self.WorkPos.x, self.WorkPos.y, self.WorkPos.x + self.WorkSize.x, self.WorkPos.y + self.WorkSize.y) end --- @nodiscard function IMGUI_VIEWPORT_P:GetBuildWorkRect() local pos = self:CalcWorkRectPos(self.BuildWorkInsetMin) local size = self:CalcWorkRectSize(self.BuildWorkInsetMin, self.BuildWorkInsetMax) return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y) end --- @return ImGuiViewportP --- @nodiscard function ImGuiViewportP() local this = setmetatable(ImGuiViewport(), IMGUI_VIEWPORT_P) --- @cast this ImGuiViewportP this.Window = nil this.Idx = -1 this.LastFrameActive = -1 this.LastFocusedStampCount = -1 this.LastNameHash = 0 this.LastPos = ImVec2() -- ImGuiViewport() { memset(this, 0, sizeof(*this)); } this.LastSize = ImVec2() this.Alpha = 1.0 this.LastAlpha = 1.0 this.LastFocusedHadNavWindow = false this.PlatformMonitor = -1 this.BgFgDrawListsLastTimeActive = {-1, -1} this.BgFgDrawLists = {nil, nil} this.DrawDataP = ImDrawData() this.DrawDataBuilder = ImDrawDataBuilder() this.LastPlatformPos = ImVec2(FLT_MAX, FLT_MAX) this.LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX) this.LastRendererSize = ImVec2(FLT_MAX, FLT_MAX) this.WorkInsetMin = ImVec2(0, 0) this.WorkInsetMax = ImVec2(0, 0) this.BuildWorkInsetMin = ImVec2(0, 0) this.BuildWorkInsetMax = ImVec2(0, 0) return this end --- @class ImFontLoader --- @field Name string --- @field LoaderInit? fun(atlas: ImFontAtlas): bool --- @field LoaderShutdown? fun(atlas: ImFontAtlas) --- @field FontSrcInit? fun(atlas: ImFontAtlas, src: ImFontConfig): bool --- @field FontSrcDestroy? fun(atlas: ImFontAtlas, src: ImFontConfig) --- @field FontSrcContainsGlyph? fun(atlas: ImFontAtlas, src: ImFontConfig, codepoint: ImWchar): bool --- @field FontBakedInit? fun(atlas: ImFontAtlas, src: ImFontConfig, baked: ImFontBaked, loader_data_for_baked_src?: any): bool --- @field FontBakedDestroy? fun(atlas: ImFontAtlas, src: ImFontConfig, baked: ImFontBaked, loader_data_for_baked_src?: any) --- @field FontBakedLoadGlyph fun(atlas: ImFontAtlas, src: ImFontConfig, baked: ImFontBaked, loader_data_for_baked_src?: any, codepoint: ImWchar, out_glyph?: ImFontGlyph, advance_x?: float): bool, float? --- @field FontBakedSrcLoaderDataSize unsigned_int MT.ImFontLoader = {} MT.ImFontLoader.__index = MT.ImFontLoader --- @return ImFontLoader --- @nodiscard function ImFontLoader() --- @type ImFontLoader local this = setmetatable({}, MT.ImFontLoader) this.Name = nil this.LoaderInit = nil this.LoaderShutdown = nil this.FontSrcInit = nil this.FontSrcDestroy = nil this.FontSrcContainsGlyph = nil this.FontBakedInit = nil this.FontBakedDestroy = nil this.FontBakedLoadGlyph = nil this.FontBakedSrcLoaderDataSize = 0 return this end --- @class ImFontAtlasRectEntry --- @field TargetIndex int # 0-based! When IsUsed = true, TargetIndex = this rect's index in Rects; IsUsed = false, TargetIndex = the next unused RectsIndex entry's index --- @field Generation unsigned_int # How many times this entry is reused --- @field IsUsed bool --- @return ImFontAtlasRectEntry --- @nodiscard function ImFontAtlasRectEntry() return { TargetIndex = 0, Generation = 0, IsUsed = false } end local ImFontAtlasRectId_IndexMask_ = 0x0007FFFF local ImFontAtlasRectId_GenerationMask_ = 0x3FF00000 local ImFontAtlasRectId_GenerationShift_ = 20 --- @param id ImFontAtlasRectId # Expects 0-based! --- @return int # 0-based! function ImFontAtlasRectId_GetIndex(id) return bitAnd(id, ImFontAtlasRectId_IndexMask_) end --- @param id ImFontAtlasRectId # Expects 0-based! --- @return unsigned_int function ImFontAtlasRectId_GetGeneration(id) return bitRShift(bitAnd(id, ImFontAtlasRectId_GenerationMask_), ImFontAtlasRectId_GenerationShift_) end --- @param index_idx int # Expects 0-based! --- @param gen_idx int --- @return ImFontAtlasRectId # 0-based! function ImFontAtlasRectId_Make(index_idx, gen_idx) IM_ASSERT(index_idx >= 0 and index_idx <= ImFontAtlasRectId_IndexMask_ and gen_idx <= bitRShift(ImFontAtlasRectId_GenerationMask_, ImFontAtlasRectId_GenerationShift_)) return bitOr(index_idx, bitLShift(gen_idx, ImFontAtlasRectId_GenerationShift_)) end --- @class ImFontAtlasPostProcessData --- @field FontAtlas ImFontAtlas --- @field Font ImFont --- @field FontSrc ImFontConfig --- @field FontBaked ImFontBaked --- @field Glyph ImFontGlyph --- @field Pixels unsigned_char[] --- @field _PixelsBase int # LUA: in cpp code the `Pixels` is a pointer. we can do this to avoid creating another custom structure to mimic it --- @field Format ImTextureFormat --- @field Pitch int --- @field Width int --- @field Height int --- @param atlas ImFontAtlas --- @param font ImFont --- @param font_src ImFontConfig --- @param font_baked ImFontBaked --- @param glyph ImFontGlyph --- @param pixels unsigned_char[] --- @param pixels_base int --- @param format ImTextureFormat --- @param pitch int --- @param width int --- @param height int --- @return ImFontAtlasPostProcessData --- @nodiscard function ImFontAtlasPostProcessData(atlas, font, font_src, font_baked, glyph, pixels, pixels_base, format, pitch, width, height) return { FontAtlas = atlas, Font = font, FontSrc = font_src, FontBaked = font_baked, Glyph = glyph, Pixels = pixels, _PixelsBase = pixels_base, Format = format, Pitch = pitch, Width = width, Height = height, } end --- @enum ImGuiInputSource ImGuiInputSource = { None = 0, Mouse = 1, Keyboard = 2, Gamepad = 3, COUNT = 4 } --- @class ImGuiInputEventMousePos --- @field PosX float --- @field PosY float --- @field MouseSource ImGuiMouseSource --- @return ImGuiInputEventMousePos --- @nodiscard function ImGuiInputEventMousePos() return { PosX = 0, PosY = 0, MouseSource = ImGuiMouseSource.Mouse } end --- @class ImGuiInputEventMouseButton --- @field Button int --- @field Down bool --- @field MouseSource ImGuiMouseSource --- @return ImGuiInputEventMouseButton --- @nodiscard function ImGuiInputEventMouseButton() return { Button = 0, Down = false, MouseSource = ImGuiMouseSource.Mouse } end --- @class ImGuiInputEventMouseWheel --- @field WheelX float --- @field WheelY float --- @field MouseSource ImGuiMouseSource --- @return ImGuiInputEventMouseWheel --- @nodiscard function ImGuiInputEventMouseWheel() return { WheelX = 0, WheelY = 0, MouseSource = ImGuiMouseSource.Mouse } end --- @class ImGuiInputEventKey --- @field Key ImGuiKey --- @field Down bool --- @field AnalogValue float --- @return ImGuiInputEventKey --- @nodiscard function ImGuiInputEventKey() return { Key = 0, Down = false, AnalogValue = 0 } end --- @class ImGuiInputEventText --- @field Char unsigned_int --- @return ImGuiInputEventText --- @nodiscard function ImGuiInputEventText() return { Char = nil } end --- @class ImGuiInputEventAppFocused --- @field Focused bool --- @return ImGuiInputEventAppFocused --- @nodiscard function ImGuiInputEventAppFocused() return { Focused = nil } end --- @class ImGuiInputEventMouseViewport --- @field HoveredViewportID ImGuiID --- @return ImGuiInputEventMouseViewport --- @nodiscard function ImGuiInputEventMouseViewport() return { HoveredViewportID = 0 } end --- @class ImGuiInputEvent --- @return ImGuiInputEvent --- @nodiscard function ImGuiInputEvent() return { Type = 0, Source = 0, EventId = 0, -- union MousePos = nil, -- if Type == ImGuiInputEventType.MousePos MouseWheel = nil, -- if Type == ImGuiInputEventType.MouseWheel MouseButton = nil, -- if Type == ImGuiInputEventType.MouseButton MouseViewport = nil, -- if Type == ImGuiInputEventType.MouseViewport Key = nil, -- if Type == ImGuiInputEventType.Key Text = nil, -- if Type == ImGuiInputEventType.Text AppFocused = nil, -- if Type == ImGuiInputEventType.Focus } end ImGuiKey_Keyboard_BEGIN = ImGuiKey.NamedKey_BEGIN ImGuiKey_Keyboard_END = ImGuiKey.GamepadStart ImGuiKey_Gamepad_BEGIN = ImGuiKey.GamepadStart ImGuiKey_Gamepad_END = ImGuiKey.GamepadRStickDown + 1 ImGuiKey_Mouse_BEGIN = ImGuiKey.MouseLeft ImGuiKey_Mouse_END = ImGuiKey.MouseWheelY + 1 ImGuiKey_Aliases_BEGIN = ImGuiKey_Mouse_BEGIN ImGuiKey_Aliases_END = ImGuiKey_Mouse_END ImGuiKey.NavKeyboardTweakSlow = ImGuiMod_Ctrl ImGuiKey.NavKeyboardTweakFast = ImGuiMod_Shift ImGuiKey.NavGamepadTweakSlow = ImGuiKey.GamepadL1 ImGuiKey.NavGamepadTweakFast = ImGuiKey.GamepadR1 ImGuiKey.NavGamepadMenu = ImGuiKey.GamepadFaceLeft ImGuiKey.NavGamepadContextMenu = ImGuiKey.GamepadFaceUp --- @enum ImGuiInputEventType ImGuiInputEventType = { None = 0, MousePos = 1, MouseWheel = 2, MouseButton = 3, MouseViewport = 4, Key = 5, Text = 6, Focus = 7, COUNT = 8 } ImGuiInputFlags.RepeatRateDefault = bitLShift(1, 1) ImGuiInputFlags.RepeatRateNavMove = bitLShift(1, 2) ImGuiInputFlags.RepeatRateNavTweak = bitLShift(1, 3) ImGuiInputFlags.RepeatUntilRelease = bitLShift(1, 4) ImGuiInputFlags.RepeatUntilKeyModsChange = bitLShift(1, 5) ImGuiInputFlags.RepeatUntilKeyModsChangeFromNone = bitLShift(1, 6) ImGuiInputFlags.RepeatUntilOtherKeyPress = bitLShift(1, 7) ImGuiInputFlags.LockThisFrame = bitLShift(1, 20) ImGuiInputFlags.LockUntilRelease = bitLShift(1, 21) ImGuiInputFlags.CondHovered = bitLShift(1, 22) ImGuiInputFlags.CondActive = bitLShift(1, 23) ImGuiInputFlags.CondDefault_ = bitOr(ImGuiInputFlags.CondHovered, ImGuiInputFlags.CondActive) ImGuiInputFlags.RepeatRateMask_ = bitOr(ImGuiInputFlags.RepeatRateDefault, ImGuiInputFlags.RepeatRateNavMove, ImGuiInputFlags.RepeatRateNavTweak) ImGuiInputFlags.RepeatUntilMask_ = bitOr(ImGuiInputFlags.RepeatUntilRelease, ImGuiInputFlags.RepeatUntilKeyModsChange, ImGuiInputFlags.RepeatUntilKeyModsChangeFromNone, ImGuiInputFlags.RepeatUntilOtherKeyPress) ImGuiInputFlags.RepeatMask_ = bitOr(ImGuiInputFlags.Repeat, ImGuiInputFlags.RepeatRateMask_, ImGuiInputFlags.RepeatUntilMask_) ImGuiInputFlags.CondMask_ = bitOr(ImGuiInputFlags.CondHovered, ImGuiInputFlags.CondActive) ImGuiInputFlags.RouteTypeMask_ = bitOr(ImGuiInputFlags.RouteActive, ImGuiInputFlags.RouteFocused, ImGuiInputFlags.RouteGlobal, ImGuiInputFlags.RouteAlways) ImGuiInputFlags.RouteOptionsMask_ = bitOr(ImGuiInputFlags.RouteOverFocused, ImGuiInputFlags.RouteOverActive, ImGuiInputFlags.RouteUnlessBgFocused, ImGuiInputFlags.RouteFromRootWindow) ImGuiInputFlags.SupportedByIsKeyPressed = ImGuiInputFlags.RepeatMask_ ImGuiInputFlags.SupportedByIsMouseClicked = ImGuiInputFlags.Repeat ImGuiInputFlags.SupportedByShortcut = bitOr(ImGuiInputFlags.RepeatMask_, ImGuiInputFlags.RouteTypeMask_, ImGuiInputFlags.RouteOptionsMask_) ImGuiInputFlags.SupportedBySetNextItemShortcut = bitOr(ImGuiInputFlags.RepeatMask_, ImGuiInputFlags.RouteTypeMask_, ImGuiInputFlags.RouteOptionsMask_, ImGuiInputFlags.Tooltip) ImGuiInputFlags.SupportedBySetKeyOwner = bitOr(ImGuiInputFlags.LockThisFrame, ImGuiInputFlags.LockUntilRelease) ImGuiInputFlags.SupportedBySetItemKeyOwner = bitOr(ImGuiInputFlags.SupportedBySetKeyOwner, ImGuiInputFlags.CondMask_) --- @enum ImGuiAxis # can be used to index ImVec2 ImGuiAxis = { None = 0, X = 1, Y = 2 } --- @enum ImGuiPlotType ImGuiPlotType = { Lines = 0, Histogram = 1 } --- @enum ImGuiActivateFlags ImGuiActivateFlags = { None = 0, PreferInput = bitLShift(1, 0), PreferTweak = bitLShift(1, 1), TryToPreserveState = bitLShift(1, 2), FromTabbing = bitLShift(1, 3), FromShortcut = bitLShift(1, 4), FromFocusApi = bitLShift(1, 5) } --- @enum ImGuiScrollFlags ImGuiScrollFlags = { None = 0, KeepVisibleEdgeX = bitLShift(1, 0), KeepVisibleEdgeY = bitLShift(1, 1), KeepVisibleCenterX = bitLShift(1, 2), KeepVisibleCenterY = bitLShift(1, 3), AlwaysCenterX = bitLShift(1, 4), AlwaysCenterY = bitLShift(1, 5), NoScrollParent = bitLShift(1, 6), } ImGuiScrollFlags.MaskX_ = bitOr(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleCenterX, ImGuiScrollFlags.AlwaysCenterX) ImGuiScrollFlags.MaskY_ = bitOr(ImGuiScrollFlags.KeepVisibleEdgeY, ImGuiScrollFlags.KeepVisibleCenterY, ImGuiScrollFlags.AlwaysCenterY) --- @class ImGuiGroupData --- @field WindowID ImGuiID --- @field BackupCursorPos ImVec2 --- @field BackupCursorMaxPos ImVec2 --- @field BackupCursorPosPrevLine ImVec2 --- @field BackupIndent ImVec1 --- @field BackupGroupOffset ImVec1 --- @field BackupCurrLineSize ImVec2 --- @field BackupCurrLineTextBaseOffset float --- @field BackupActiveIdIsAlive ImGuiID --- @field BackupAnyIdHasBeenEditedThisFrame bool --- @field BackupDeactivatedIdIsAlive bool --- @field BackupHoveredIdIsAlive bool --- @field BackupIsSameLine bool --- @field EmitItem bool --- @return ImGuiGroupData --- @nodiscard function ImGuiGroupData() return { WindowID = nil, BackupCursorPos = ImVec2(), BackupCursorMaxPos = ImVec2(), BackupCursorPosPrevLine = ImVec2(), BackupIndent = ImVec1(), BackupGroupOffset = ImVec1(), BackupCurrLineSize = ImVec2(), BackupCurrLineTextBaseOffset = nil, BackupActiveIdIsAlive = nil, BackupAnyIdHasBeenEditedThisFrame = nil, BackupDeactivatedIdIsAlive = nil, BackupHoveredIdIsAlive = nil, BackupIsSameLine = nil, EmitItem = nil } end --- @enum ImGuiTooltipFlags ImGuiTooltipFlags = { None = 0, OverridePrevious = bitLShift(1, 1) } --- @enum ImGuiPopupPositionPolicy ImGuiPopupPositionPolicy = { Default = 0, ComboBox = 1, Tooltip = 2 } --- @class ImGuiPopupData --- @field PopupId ImGuiID --- @field Window ImGuiWindow --- @field RestoreNavWindow ImGuiWindow --- @field ParentNavLayer int --- @field OpenFrameCount int --- @field OpenParentId ImGuiID --- @field OpenPopupPos ImVec2 --- @field OpenMousePos ImVec2 --- @return ImGuiPopupData --- @nodiscard function ImGuiPopupData() return { PopupId = 0, Window = nil, RestoreNavWindow = nil, ParentNavLayer = -1, OpenFrameCount = -1, OpenParentId = 0, OpenPopupPos = ImVec2(), OpenMousePos = ImVec2() } end --- @enum ImGuiWindowRefreshFlags ImGuiWindowRefreshFlags = { None = 0, TryToAvoidRefresh = bitLShift(1, 0), RefreshOnHover = bitLShift(1, 1), RefreshOnFocus = bitLShift(1, 2) } --- @enum ImGuiNavRenderCursorFlags ImGuiNavRenderCursorFlags = { None = 0, Compact = bitLShift(1, 1), -- Compact highlight, no padding/distance from focused item AlwaysDraw = bitLShift(1, 2), -- Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse } --- @enum ImGuiDebugLogFlags ImGuiDebugLogFlags = { -- Event types None = 0, EventError = bitLShift(1, 0), -- Error submitted by IM_ASSERT_USER_ERROR() EventActiveId = bitLShift(1, 1), EventFocus = bitLShift(1, 2), EventPopup = bitLShift(1, 3), EventNav = bitLShift(1, 4), EventClipper = bitLShift(1, 5), EventSelection = bitLShift(1, 6), EventIO = bitLShift(1, 7), EventFont = bitLShift(1, 8), EventInputRouting = bitLShift(1, 9), EventDocking = bitLShift(1, 10), EventViewport = bitLShift(1, 11), EventTable = bitLShift(1, 12), OutputToTTY = bitLShift(1, 20), OutputToDebugger = bitLShift(1, 21), OutputToTestEngine = bitLShift(1, 22), } ImGuiDebugLogFlags.EventMask_ = bitOr( ImGuiDebugLogFlags.EventError, ImGuiDebugLogFlags.EventActiveId, ImGuiDebugLogFlags.EventFocus, ImGuiDebugLogFlags.EventPopup, ImGuiDebugLogFlags.EventNav, ImGuiDebugLogFlags.EventClipper, ImGuiDebugLogFlags.EventSelection, ImGuiDebugLogFlags.EventTable, ImGuiDebugLogFlags.EventIO, ImGuiDebugLogFlags.EventFont, ImGuiDebugLogFlags.EventInputRouting, ImGuiDebugLogFlags.EventDocking, ImGuiDebugLogFlags.EventViewport ) --- @enum ImGuiLocKey ImGuiLocKey = { VersionStr = 1, TableSizeOne = 2, TableSizeAllFit = 3, TableSizeAllDefault = 4, TableReset = 5, TableResetOrder = 6, TableResetVisibility = 7, WindowingMainMenuBar = 8, WindowingPopup = 9, WindowingUntitled = 10, OpenLink_s = 11, CopyLink = 12, DockingHideTabBar = 13, DockingHoldShiftToDock = 14, DockingDragToUndockOrMoveNode = 15, COUNT = 15 } --- @class ImGuiLocEntry --- @field Key ImGuiLocKey --- @field Text string --- @param key ImGuiLocKey --- @return string function ImGui.LocalizeGetMsg(key) local g = GImGui local msg = g.LocalizationTable[key] if msg then return msg else return "*Missing Text*" end end --- @param id ImGuiID function ImGui.TempInputIsActive(id) local g = GImGui return (g.TempInputId == id and g.ActiveId == id) or (g.InputTextDeactivatedState.ID == id) end --- @param id ImGuiID --- @return ImGuiInputTextState? function ImGui.GetInputTextState(id) local g = GImGui if id ~= 0 and g.InputTextState.ID == id then return g.InputTextState end return nil end -- Storage for PushFocusScope(), g.FocusScopeStack[], g.NavFocusRoute[] --- @class ImGuiFocusScopeData --- @field ID ImGuiID --- @field WindowID ImGuiID --- @return ImGuiFocusScopeData --- @nodiscard function ImGuiFocusScopeData() return { ID = nil, WindowID = nil } end return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imgui_tables.lua'] = function() --- Dear ImGui WIP -- (Tables and Columns Code) -- 1:1 port of imgui_tables.cpp (docking branch, 1.93 WIP) -- -- Port notes: -- - Column indices / display orders / draw channel indices are 0-based VALUES like upstream. -- Per-column arrays (table.Columns, table.DisplayOrderToIndex, table.RowCellData) are Lua tables with 0-based keys. -- table.ColumnsSize mirrors upstream `table->Columns.size()`. -- - ImBitArray masks are Lua tables { [n] = true }. -- - table.ColumnsNames is a Lua array of strings, column.NameOffset is a 0-based index into it (-1 = none). -- - g.SettingsTables is a plain vector of ImGuiTableSettings; table.SettingsOffset is a 1-based index into it (-1 = none). -- Each settings entry owns `Columns` (0-based Lua table of ImGuiTableColumnSettings). -- - ImGuiTableSortSpecs.Specs is a 1-based Lua array of ImGuiTableColumnSortSpecs. --- @type ImGuiContext? local GImGui local MT = ImGui.GetMetatables() -- Sets local `GImGui` in this file(imgui_tables.lua). -- This is currently only used in main code `ImGui.SetCurrentContext()` --- @param ctx ImGuiContext? function ImGui._SetCurrentContext_Tables(ctx) GImGui = ctx end local bit32 = bit32 local band, bor, bnot, lshift, rshift = bit32.band, bit32.bor, bit32.bnot, bit32.lshift, bit32.rshift IM_COL32_DISABLE = IM_COL32(0, 0, 0, 1) IMGUI_TABLE_MAX_COLUMNS = 512 local function IMGUI_DEBUG_LOG_TABLE(fmt, ...) local g = GImGui if band(g.DebugLogFlags, ImGuiDebugLogFlags.EventTable) ~= 0 then ImGui.DebugLog(fmt, ...) end end ---------------------------------------------------------------- -- [SECTION] Structs ---------------------------------------------------------------- local function BitArrayClearAll(arr) table.clear(arr) end local function BitArraySet(arr, n) arr[n] = true end local function BitTest(arr, n) return arr[n] == true end --- @class ImGuiTableColumnSortSpecs function ImGuiTableColumnSortSpecs() return { ColumnUserID = 0, ColumnIndex = 0, SortOrder = 0, SortDirection = ImGuiSortDirection.None } end --- @class ImGuiTableSortSpecs function ImGuiTableSortSpecs() return { Specs = nil, SpecsCount = 0, SpecsDirty = false } end --- @class ImGuiTableColumn function ImGuiTableColumn() return { Flags = 0, WidthGiven = 0.0, MinX = 0.0, MaxX = 0.0, WidthRequest = -1.0, WidthAuto = 0.0, WidthMax = 0.0, StretchWeight = -1.0, InitStretchWeightOrWidth = 0.0, ClipRect = ImRect(), ID = 0, UserData = 0, WorkMinX = 0.0, WorkMaxX = 0.0, ItemWidth = 0.0, ContentMaxXFrozen = 0.0, ContentMaxXUnfrozen = 0.0, ContentMaxXHeadersUsed = 0.0, ContentMaxXHeadersIdeal = 0.0, NameOffset = -1, DisplayOrder = -1, IndexWithinEnabledSet = -1, PrevEnabledColumn = -1, NextEnabledColumn = -1, SortOrder = -1, DrawChannelCurrent = -1, DrawChannelFrozen = -1, DrawChannelUnfrozen = -1, IsEnabled = false, IsUserEnabled = false, IsUserEnabledNextFrame = false, IsVisibleX = false, IsVisibleY = false, IsRequestOutput = false, IsSkipItems = false, IsPreserveWidthAuto = false, IsJustCreated = true, IsLoadedSettings = false, IsNeedReconcileSrc = false, IsNeedReconcileDst = false, NavLayerCurrent = 0, AutoFitQueue = 0, CannotSkipItemsQueue = 0, SortDirection = ImGuiSortDirection.None, SortDirectionsAvailCount = 0, SortDirectionsAvailMask = 0, SortDirectionsAvailList = 0, } end --- `*dst = *src` local function TableColumnCopy(dst, src) for k, v in pairs(src) do if k ~= "ClipRect" then dst[k] = v end end ImRect_Copy(dst.ClipRect, src.ClipRect) return dst end local function TableColumnClone(src) return TableColumnCopy(ImGuiTableColumn(), src) end --- @class ImGuiTableInstanceData function ImGuiTableInstanceData() return { TableInstanceID = 0, LastOuterHeight = 0.0, LastTopHeadersRowHeight = 0.0, LastFrozenHeight = 0.0, HoveredRowLast = -1, HoveredRowNext = -1 } end --- @class ImGuiTableTempData function ImGuiTableTempData() return { WindowID = 0, TableIndex = 0, LastTimeActive = -1.0, AngledHeadersExtraWidth = 0.0, AngledHeadersRequests = ImVector(), ReconcileColumnsRequests = ImVector(), OldColumnsRawData = nil, OldColumnsData = nil, OldColumnsDataSize = 0, UserOuterSize = ImVec2(), DrawSplitter = ImDrawListSplitter(), HostBackupWorkRect = ImRect(), HostBackupParentWorkRect = ImRect(), HostBackupPrevLineSize = ImVec2(), HostBackupCurrLineSize = ImVec2(), HostBackupCursorMaxPos = ImVec2(), HostBackupColumnsOffset = 0.0, HostBackupItemWidth = 0.0, HostBackupItemWidthStackSize = 0, } end --- @class ImGuiTable function ImGuiTable() return { ID = 0, Flags = 0, RawData = nil, TempData = nil, Columns = {}, ColumnsSize = 0, DisplayOrderToIndex = {}, RowCellData = {}, EnabledMaskByDisplayOrder = {}, EnabledMaskByIndex = {}, VisibleMaskByIndex = {}, SettingsLoadedFlags = 0, SettingsOffset = 0, LastFrameActive = -1, ColumnsCount = 0, CurrentRow = 0, CurrentColumn = 0, InstanceCurrent = 0, InstanceInteracted = 0, RowPosY1 = 0.0, RowPosY2 = 0.0, RowMinHeight = 0.0, RowCellPaddingY = 0.0, RowTextBaseline = 0.0, RowIndentOffsetX = 0.0, RowFlags = 0, LastRowFlags = 0, RowBgColorCounter = 0, RowBgColor = { [0] = 0, [1] = 0 }, BorderColorStrong = 0, BorderColorLight = 0, BorderX1 = 0.0, BorderX2 = 0.0, HostIndentX = 0.0, MinColumnWidth = 0.0, OuterPaddingX = 0.0, CellPaddingX = 0.0, CellSpacingX1 = 0.0, CellSpacingX2 = 0.0, InnerWidth = 0.0, ColumnsGivenWidth = 0.0, ColumnsAutoFitWidth = 0.0, ColumnsStretchSumWeights = 0.0, ResizedColumnNextWidth = 0.0, ResizeLockMinContentsX2 = 0.0, RefScale = 0.0, AngledHeadersHeight = 0.0, AngledHeadersSlope = 0.0, OuterRect = ImRect(), InnerRect = ImRect(), WorkRect = ImRect(), InnerClipRect = ImRect(), BgClipRect = ImRect(), Bg0ClipRectForDrawCmd = ImRect(), Bg2ClipRectForDrawCmd = ImRect(), HostClipRect = ImRect(), HostBackupInnerClipRect = ImRect(), OuterWindow = nil, InnerWindow = nil, ColumnsNames = {}, DrawSplitter = nil, InstanceDataFirst = ImGuiTableInstanceData(), InstanceDataExtra = ImVector(), SortSpecs = ImGuiTableSortSpecs(), SortSpecsMulti = {}, SortSpecsSingle = ImGuiTableColumnSortSpecs(), SortSpecsCount = 0, ColumnsEnabledCount = 0, ColumnsEnabledFixedCount = 0, DeclColumnsCount = 0, AngledHeadersCount = 0, HoveredColumnBody = 0, HoveredColumnBorder = 0, HighlightColumnHeader = 0, AutoFitSingleColumn = 0, ResizedColumn = 0, LastResizedColumn = 0, HeldHeaderColumn = 0, LastHeldHeaderColumn = 0, ReorderColumn = 0, ReorderColumnDstOrder = 0, LeftMostEnabledColumn = 0, RightMostEnabledColumn = 0, LeftMostStretchedColumn = 0, RightMostStretchedColumn = 0, ContextPopupColumn = 0, FreezeRowsRequest = 0, FreezeRowsCount = 0, FreezeColumnsRequest = 0, FreezeColumnsCount = 0, RowCellDataCurrent = 0, DummyDrawChannel = 0, Bg2DrawChannelCurrent = 0, Bg2DrawChannelUnfrozen = 0, NavLayer = 0, IsLayoutLocked = false, IsInsideRow = false, IsNewTable = false, IsInitializing = false, IsReconcileMode = false, IsSortSpecsDirty = false, IsUsingHeaders = false, IsContextPopupOpen = false, DisableDefaultContextMenu = false, IsSettingsRequestLoad = false, IsSettingsDirty = false, IsDefaultDisplayOrder = false, IsDefaultVisibility = false, IsResetAllRequest = false, IsResetDisplayOrderRequest = false, IsResetVisibilityRequest = false, IsUnfrozenRows = false, IsDefaultSizingPolicy = false, IsActiveIdAliveBeforeTable = false, IsActiveIdInTable = false, HasScrollbarYCurr = false, HasScrollbarYPrev = false, MemoryCompacted = false, HostSkipItems = false, } end --- @class ImGuiTableColumnSettings function ImGuiTableColumnSettings() return { WidthOrWeight = 0.0, ID = 0, Index = -1, DisplayOrder = -1, SortOrder = -1, SortDirection = ImGuiSortDirection.None, IsEnabled = -1, IsStretch = 0, IsLoaded = false } end --- @class ImGuiTableSettings function ImGuiTableSettings() return { ID = 0, SaveFlags = 0, RefScale = 0.0, ColumnsCount = 0, ColumnsCountMax = 0, LastUsedDate = 0, WantApply = false, Columns = {} } end --- @class ImGuiOldColumnData function ImGuiOldColumnData() return { OffsetNorm = 0.0, OffsetNormBeforeResize = 0.0, Flags = 0, ClipRect = ImRect() } end --- @class ImGuiOldColumns function ImGuiOldColumns() return { ID = 0, Flags = 0, IsFirstFrame = false, IsBeingResized = false, Current = 0, Count = 0, OffMinX = 0.0, OffMaxX = 0.0, LineMinY = 0.0, LineMaxY = 0.0, HostCursorPosY = 0.0, HostCursorMaxPosX = 0.0, HostInitialClipRect = ImRect(), HostBackupClipRect = ImRect(), HostBackupParentWorkRect = ImRect(), Columns = ImVector(), Splitter = ImDrawListSplitter() } end ImGuiOldColumnFlags = ImGuiOldColumnFlags or { None = 0, NoBorder = lshift(1, 0), NoResize = lshift(1, 1), NoPreserveWidths = lshift(1, 2), NoForceWithinWindow = lshift(1, 3), GrowParentContentsSize = lshift(1, 4), } ImGuiTableColumnFlags.NoDirectResize_ = ImGuiTableColumnFlags.NoDirectResize_ or lshift(1, 30) local function Rect(r) return ImRect(r.Min.x, r.Min.y, r.Max.x, r.Max.y) end local function V2(v) return ImVec2(v.x, v.y) end ---------------------------------------------------------------- -- [SECTION] Tables: Main code ---------------------------------------------------------------- -- Configuration local TABLE_DRAW_CHANNEL_BG0 = 0 local TABLE_DRAW_CHANNEL_BG2_FROZEN = 1 local TABLE_DRAW_CHANNEL_NOCLIP = 2 -- When using ImGuiTableFlags_NoClip (this becomes the last visible channel) local TABLE_BORDER_SIZE = 1.0 -- FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering. local TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0 -- Extend outside inner borders. local TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06 -- Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped. -- Helper local function TableFixFlags(flags, outer_window) -- Adjust flags: set default sizing policy if band(flags, ImGuiTableFlags.SizingMask_) == 0 then flags = bor(flags, (band(flags, ImGuiTableFlags.ScrollX) ~= 0 or band(outer_window.Flags, ImGuiWindowFlags.AlwaysAutoResize) ~= 0) and ImGuiTableFlags.SizingFixedFit or ImGuiTableFlags.SizingStretchSame) end -- Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame if band(flags, ImGuiTableFlags.SizingMask_) == ImGuiTableFlags.SizingFixedSame then flags = bor(flags, ImGuiTableFlags.NoKeepColumnsVisible) end -- Adjust flags: enforce borders when resizable if band(flags, ImGuiTableFlags.Resizable) ~= 0 then flags = bor(flags, ImGuiTableFlags.BordersInnerV) end -- Adjust flags: disable NoHostExtendX/NoHostExtendY if we have any scrolling going on if band(flags, bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY)) ~= 0 then flags = band(flags, bnot(bor(ImGuiTableFlags.NoHostExtendX, ImGuiTableFlags.NoHostExtendY))) end -- Adjust flags: NoBordersInBodyUntilResize takes priority over NoBordersInBody if band(flags, ImGuiTableFlags.NoBordersInBodyUntilResize) ~= 0 then flags = band(flags, bnot(ImGuiTableFlags.NoBordersInBody)) end -- Adjust flags: disable saved settings if there's nothing to save if band(flags, bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Sortable)) == 0 then flags = bor(flags, ImGuiTableFlags.NoSavedSettings) end -- Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set) if band(outer_window.RootWindow.Flags, ImGuiWindowFlags.NoSavedSettings) ~= 0 then flags = bor(flags, ImGuiTableFlags.NoSavedSettings) end return flags end function ImGui.TableFindByID(id) local g = GImGui return g.Tables:GetByKey(id) end --- @param table_ ImGuiTable --- @param instance_no int function ImGui.TableGetInstanceData(table_, instance_no) if instance_no == 0 then return table_.InstanceDataFirst end return table_.InstanceDataExtra.Data[instance_no] end function ImGui.TableGetInstanceID(table_, instance_no) return ImGui.TableGetInstanceData(table_, instance_no).TableInstanceID end -- Read about "TABLE SIZING" at the top of this file. --- @param str_id string --- @param columns_count int --- @param flags? ImGuiTableFlags --- @param outer_size? ImVec2 --- @param inner_width? float function ImGui.BeginTable(str_id, columns_count, flags, outer_size, inner_width) local id = ImGui.GetID(str_id) return ImGui.BeginTableEx(str_id, id, columns_count, flags, outer_size, inner_width) end function ImGui.BeginTableEx(name, id, columns_count, flags, outer_size, inner_width) if flags == nil then flags = 0 end if outer_size == nil then outer_size = ImVec2(0.0, 0.0) end if inner_width == nil then inner_width = 0.0 end local g = GImGui local outer_window = ImGui.GetCurrentWindow() if outer_window.SkipItems then -- Consistent with other tables + beneficial side effect that assert on miscalling EndTable() will be more visible. return false end -- Sanity checks IM_ASSERT(columns_count > 0 and columns_count < IMGUI_TABLE_MAX_COLUMNS) if band(flags, ImGuiTableFlags.ScrollX) ~= 0 then IM_ASSERT(inner_width >= 0.0) end -- If an outer size is specified ahead we will be able to early out when not visible. Exact clipping criteria may evolve. local use_child_window = band(flags, bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY)) ~= 0 local avail_size = ImGui.GetContentRegionAvail() local actual_outer_size = ImTrunc(ImGui.CalcItemSize(outer_size, ImMax(avail_size.x, IMGUI_WINDOW_HARD_MIN_SIZE), use_child_window and ImMax(avail_size.y, IMGUI_WINDOW_HARD_MIN_SIZE) or 0.0)) local outer_rect = ImRect(outer_window.DC.CursorPos, outer_window.DC.CursorPos + actual_outer_size) local outer_window_is_measuring_size = (outer_window.AutoFitFramesX > 0) or (outer_window.AutoFitFramesY > 0) -- Doesn't apply to AlwaysAutoResize windows! if use_child_window and ImGui.IsClippedEx(outer_rect, 0) and not outer_window_is_measuring_size then ImGui.ItemSize(outer_rect) ImGui.ItemAdd(outer_rect, id) g.NextWindowData:ClearFlags() return false end -- Acquire storage for the table local table_ = g.Tables:GetOrAddByKey(id) if table_.Columns == nil then -- pool created a plain table for k, v in pairs(ImGuiTable()) do table_[k] = v end end -- Acquire temporary buffers local table_idx = g.Tables:GetIndex(table_) g.TablesTempDataStacked = g.TablesTempDataStacked + 1 while g.TablesTempDataStacked > g.TablesTempData.Size do g.TablesTempData:push_back(ImGuiTableTempData()) end local temp_data = g.TablesTempData.Data[g.TablesTempDataStacked] table_.TempData = temp_data temp_data.TableIndex = table_idx temp_data.ReconcileColumnsRequests:resize(0) table_.DrawSplitter = table_.TempData.DrawSplitter table_.DrawSplitter:Clear() -- Fix flags table_.IsDefaultSizingPolicy = band(flags, ImGuiTableFlags.SizingMask_) == 0 flags = TableFixFlags(flags, outer_window) -- Initialize local previous_frame_active = table_.LastFrameActive local instance_no = (previous_frame_active ~= g.FrameCount) and 0 or (table_.InstanceCurrent + 1) local previous_flags = table_.Flags table_.ID = id table_.Flags = flags table_.LastFrameActive = g.FrameCount table_.OuterWindow = outer_window table_.InnerWindow = outer_window table_.ColumnsCount = columns_count table_.IsLayoutLocked = false table_.InnerWidth = inner_width table_.NavLayer = outer_window.DC.NavLayerCurrent table_.IsNewTable = (previous_frame_active == -1) ImVec2_Copy(temp_data.UserOuterSize, outer_size) -- Instance data (for instance 0, TableID == TableInstanceID) local instance_id table_.InstanceCurrent = instance_no if instance_no > 0 then IM_ASSERT(table_.ColumnsCount == columns_count, "BeginTable(): Cannot change columns count mid-frame while preserving same ID") if table_.InstanceDataExtra.Size < instance_no then table_.InstanceDataExtra:push_back(ImGuiTableInstanceData()) end instance_id = ImGui.GetIDWithSeed(instance_no, ImGui.GetIDWithSeed("##Instances", nil, id)) -- Push "##Instances" followed by (int)instance_no in ID stack. else instance_id = id end local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) table_instance.TableInstanceID = instance_id -- When not using a child window, WorkRect.Max will grow as we append contents. if use_child_window then -- Ensure no vertical scrollbar appears if we only want horizontal one, to make flag consistent local override_content_size = ImVec2(FLT_MAX, FLT_MAX) if band(flags, ImGuiTableFlags.ScrollX) ~= 0 and band(flags, ImGuiTableFlags.ScrollY) == 0 then override_content_size.y = FLT_MIN end -- Ensure specified width (when not specified, Stretched columns will act as if the width == OuterWidth and never lead to any scrolling). if band(flags, ImGuiTableFlags.ScrollX) ~= 0 and inner_width > 0.0 then override_content_size.x = inner_width end if override_content_size.x ~= FLT_MAX or override_content_size.y ~= FLT_MAX then ImGui.SetNextWindowContentSize(ImVec2((override_content_size.x ~= FLT_MAX) and override_content_size.x or 0.0, (override_content_size.y ~= FLT_MAX) and override_content_size.y or 0.0)) end -- Reset scroll if we are reactivating it if band(previous_flags, bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY)) == 0 then if band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasScroll) == 0 then ImGui.SetNextWindowScroll(ImVec2(0.0, 0.0)) end end -- Create scrolling region (without border and zero window padding) local child_window_flags = (band(flags, ImGuiTableFlags.ScrollX) ~= 0) and ImGuiWindowFlags.HorizontalScrollbar or ImGuiWindowFlags.None ImGui.BeginChildEx(name, instance_id, outer_rect:GetSize(), ImGuiChildFlags.None, child_window_flags) table_.InnerWindow = g.CurrentWindow ImRect_Copy(table_.WorkRect, table_.InnerWindow.WorkRect) ImRect_Copy(table_.OuterRect, table_.InnerWindow:Rect()) ImRect_Copy(table_.InnerRect, table_.InnerWindow.InnerRect) IM_ASSERT(table_.InnerWindow.WindowPadding.x == 0.0 and table_.InnerWindow.WindowPadding.y == 0.0 and table_.InnerWindow.WindowBorderSize == 0.0) -- Allow submitting when host is measuring if table_.InnerWindow.SkipItems and outer_window_is_measuring_size then table_.InnerWindow.SkipItems = false end -- When using multiple instances, ensure they have the same amount of horizontal decorations (aka vertical scrollbar) so stretched columns can be aligned if instance_no == 0 then table_.HasScrollbarYPrev = table_.HasScrollbarYCurr table_.HasScrollbarYCurr = false end table_.HasScrollbarYCurr = table_.HasScrollbarYCurr or table_.InnerWindow.ScrollbarY else -- For non-scrolling tables, WorkRect == OuterRect == InnerRect. ImRect_Copy(table_.WorkRect, outer_rect) ImRect_Copy(table_.OuterRect, outer_rect) ImRect_Copy(table_.InnerRect, outer_rect) table_.HasScrollbarYPrev = false table_.HasScrollbarYCurr = false table_.InnerWindow.DC.TreeDepth = table_.InnerWindow.DC.TreeDepth + 1 -- This is designed to always linking ImGuiTreeNodeFlags_DrawLines linking across a table end -- Push a standardized ID for both child-using and not-child-using tables ImGui.PushOverrideID(id) if instance_no > 0 then ImGui.PushOverrideID(instance_id) end -- Backup a copy of host window members we will modify local inner_window = table_.InnerWindow table_.HostIndentX = inner_window.DC.Indent.x ImRect_Copy(table_.HostClipRect, inner_window.ClipRect) table_.HostSkipItems = inner_window.SkipItems temp_data.WindowID = inner_window.ID ImRect_Copy(temp_data.HostBackupWorkRect, inner_window.WorkRect) ImRect_Copy(temp_data.HostBackupParentWorkRect, inner_window.ParentWorkRect) temp_data.HostBackupColumnsOffset = outer_window.DC.ColumnsOffset.x ImVec2_Copy(temp_data.HostBackupPrevLineSize, inner_window.DC.PrevLineSize) ImVec2_Copy(temp_data.HostBackupCurrLineSize, inner_window.DC.CurrLineSize) ImVec2_Copy(temp_data.HostBackupCursorMaxPos, inner_window.DC.CursorMaxPos) temp_data.HostBackupItemWidth = outer_window.DC.ItemWidth temp_data.HostBackupItemWidthStackSize = outer_window.DC.ItemWidthStack.Size inner_window.DC.PrevLineSize.x = 0.0; inner_window.DC.PrevLineSize.y = 0.0 inner_window.DC.CurrLineSize.x = 0.0; inner_window.DC.CurrLineSize.y = 0.0 -- Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752) if inner_window ~= outer_window then local border_size = TABLE_BORDER_SIZE if band(flags, ImGuiTableFlags.BordersOuterV) ~= 0 then table_.HostClipRect.Min.x = ImMin(table_.HostClipRect.Min.x + border_size, table_.HostClipRect.Max.x) if inner_window.DecoOuterSizeX2 == 0.0 then table_.HostClipRect.Max.x = ImMax(table_.HostClipRect.Max.x - border_size, table_.HostClipRect.Min.x) end end if band(flags, ImGuiTableFlags.BordersOuterH) ~= 0 then table_.HostClipRect.Min.y = ImMin(table_.HostClipRect.Min.y + border_size, table_.HostClipRect.Max.y) if inner_window.DecoOuterSizeY2 == 0.0 then table_.HostClipRect.Max.y = ImMax(table_.HostClipRect.Max.y - border_size, table_.HostClipRect.Min.y) end end end -- Padding and Spacing local pad_outer_x if band(flags, ImGuiTableFlags.NoPadOuterX) ~= 0 then pad_outer_x = false elseif band(flags, ImGuiTableFlags.PadOuterX) ~= 0 then pad_outer_x = true else pad_outer_x = band(flags, ImGuiTableFlags.BordersOuterV) ~= 0 end local pad_inner_x = band(flags, ImGuiTableFlags.NoPadInnerX) == 0 local inner_spacing_for_border = (band(flags, ImGuiTableFlags.BordersInnerV) ~= 0) and TABLE_BORDER_SIZE or 0.0 local inner_spacing_explicit = (pad_inner_x and band(flags, ImGuiTableFlags.BordersInnerV) == 0) and g.Style.CellPadding.x or 0.0 local inner_padding_explicit = (pad_inner_x and band(flags, ImGuiTableFlags.BordersInnerV) ~= 0) and g.Style.CellPadding.x or 0.0 table_.CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border table_.CellSpacingX2 = inner_spacing_explicit table_.CellPaddingX = inner_padding_explicit local outer_padding_for_border = (band(flags, ImGuiTableFlags.BordersOuterV) ~= 0) and TABLE_BORDER_SIZE or 0.0 local outer_padding_explicit = pad_outer_x and g.Style.CellPadding.x or 0.0 table_.OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table_.CellPaddingX table_.CurrentColumn = -1 table_.CurrentRow = -1 table_.RowBgColorCounter = 0 table_.LastRowFlags = ImGuiTableRowFlags.None ImRect_Copy(table_.InnerClipRect, (inner_window == outer_window) and table_.WorkRect or inner_window.ClipRect) table_.InnerClipRect:ClipWith(table_.WorkRect) -- We need this to honor inner_width table_.InnerClipRect:ClipWithFull(table_.HostClipRect) table_.InnerClipRect.Max.y = (band(flags, ImGuiTableFlags.NoHostExtendY) ~= 0) and ImMin(table_.InnerClipRect.Max.y, inner_window.WorkRect.Max.y) or table_.HostClipRect.Max.y table_.RowPosY1 = table_.WorkRect.Min.y -- This is needed somehow table_.RowPosY2 = table_.WorkRect.Min.y table_.RowTextBaseline = 0.0 -- This will be cleared again by TableBeginRow() table_.RowCellPaddingY = 0.0 table_.FreezeRowsRequest = 0; table_.FreezeRowsCount = 0 -- This will be setup by TableSetupScrollFreeze(), if any table_.FreezeColumnsRequest = 0; table_.FreezeColumnsCount = 0 table_.IsUnfrozenRows = true table_.DeclColumnsCount = 0; table_.AngledHeadersCount = 0 if previous_frame_active + 1 < g.FrameCount then table_.IsActiveIdInTable = false end table_.AngledHeadersHeight = 0.0 temp_data.AngledHeadersExtraWidth = 0.0 -- Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders() table_.BorderColorStrong = ImGui.GetColorU32(ImGuiCol.TableBorderStrong) table_.BorderColorLight = ImGui.GetColorU32(ImGuiCol.TableBorderLight) -- Make table current g.CurrentTable = table_ inner_window.DC.NavIsScrollPushableX = false -- Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); outer_window.DC.CurrentTableIdx = table_idx if inner_window ~= outer_window then -- So EndChild() within the inner window can restore the table properly. inner_window.DC.CurrentTableIdx = table_idx end if band(previous_flags, ImGuiTableFlags.Reorderable) ~= 0 and band(flags, ImGuiTableFlags.Reorderable) == 0 then table_.IsResetDisplayOrderRequest = true end -- Mark as used to avoid GC while table_idx >= g.TablesLastTimeActive.Size do g.TablesLastTimeActive:push_back(-1.0) end g.TablesLastTimeActive.Data[table_idx + 1] = g.Time temp_data.LastTimeActive = g.Time table_.MemoryCompacted = false -- Setup memory buffer (clear data if columns count changed) local old_columns_count = table_.ColumnsSize if old_columns_count ~= 0 and old_columns_count ~= columns_count then -- Attempt to preserve width and other settings on column count/specs change (#4046, #9108) IMGUI_DEBUG_LOG_TABLE("[table] Table 0x%08X column count %d -> %d, recreating storage.\n", table_.ID, old_columns_count, columns_count) IM_ASSERT(temp_data.OldColumnsRawData == nil) temp_data.OldColumnsRawData = table_.RawData -- Freed during layout temp_data.OldColumnsData = table_.Columns temp_data.OldColumnsDataSize = table_.ColumnsSize for n = 0, temp_data.OldColumnsDataSize - 1 do temp_data.OldColumnsData[n].IsNeedReconcileSrc = true end table_.RawData = nil end if table_.RawData == nil then ImGui.TableBeginInitMemory(table_, columns_count) table_.IsInitializing = true end if table_.IsResetAllRequest then ImGui.TableResetSettings(table_) end if table_.IsInitializing then -- Initialize if table_.IsNewTable then table_.SettingsOffset = -1 table_.IsSettingsRequestLoad = true end table_.IsSortSpecsDirty = true table_.IsSettingsDirty = true -- Records itself into .ini file even when in default state (#7934) table_.IsReconcileMode = false table_.InstanceInteracted = -1 table_.ContextPopupColumn = -1 table_.ReorderColumn = -1; table_.ReorderColumnDstOrder = -1; table_.ResizedColumn = -1; table_.LastResizedColumn = -1 table_.AutoFitSingleColumn = -1 table_.HoveredColumnBody = -1; table_.HoveredColumnBorder = -1 for n = 0, columns_count - 1 do local column = table_.Columns[n] if temp_data.OldColumnsData and n < temp_data.OldColumnsDataSize then TableColumnCopy(column, temp_data.OldColumnsData[n]) else local width_auto = column.WidthAuto TableColumnCopy(column, ImGuiTableColumn()) column.WidthAuto = width_auto column.IsPreserveWidthAuto = true -- Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker column.IsEnabled = true; column.IsUserEnabled = true; column.IsUserEnabledNextFrame = true column.DisplayOrder = n end table_.DisplayOrderToIndex[n] = column.DisplayOrder end end -- Load settings if table_.IsSettingsRequestLoad then ImGui.TableLoadSettings(table_) end -- Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. inner_window.SkipItems = true -- Clear names if #table_.ColumnsNames > 0 then table.clear(table_.ColumnsNames) end return true end function ImGui.TableBeginInitMemory(table_, columns_count) table_.RawData = true table_.Columns = {} table_.DisplayOrderToIndex = {} table_.RowCellData = {} for n = 0, columns_count - 1 do table_.Columns[n] = ImGuiTableColumn() table_.Columns[n].WidthAuto = 0.0 table_.DisplayOrderToIndex[n] = 0 table_.RowCellData[n] = { BgColor = 0, Column = 0 } end table_.ColumnsSize = columns_count table_.EnabledMaskByDisplayOrder = {} table_.EnabledMaskByIndex = {} table_.VisibleMaskByIndex = {} end -- Apply queued resizing/reordering/hiding requests function ImGui.TableApplyQueuedRequests(table_) -- Handle resizing request if table_.InstanceCurrent == 0 then if table_.ResizedColumn ~= -1 and table_.ResizedColumnNextWidth ~= FLT_MAX then ImGui.TableSetColumnWidth(table_.ResizedColumn, table_.ResizedColumnNextWidth) end table_.LastResizedColumn = table_.ResizedColumn table_.ResizedColumnNextWidth = FLT_MAX table_.ResizedColumn = -1 -- Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy. if table_.AutoFitSingleColumn ~= -1 then ImGui.TableSetColumnWidth(table_.AutoFitSingleColumn, table_.Columns[table_.AutoFitSingleColumn].WidthAuto) table_.AutoFitSingleColumn = -1 end end -- Handle reordering request if table_.InstanceCurrent == 0 then table_.LastHeldHeaderColumn = table_.HeldHeaderColumn table_.HeldHeaderColumn = -1 if table_.ReorderColumn ~= -1 and table_.ReorderColumnDstOrder ~= -1 then ImGui.TableSetColumnDisplayOrder(table_, table_.ReorderColumn, table_.ReorderColumnDstOrder) table_.ReorderColumnDstOrder = -1 end -- Release local g = GImGui if g.ActiveId == 0 then -- FIXME: Need to revisit. See 38f5e5a. table_.ReorderColumn = -1 end end -- Handle display order / visibility reset requests if table_.IsResetDisplayOrderRequest then for n = 0, table_.ColumnsCount - 1 do table_.Columns[n].DisplayOrder = n table_.DisplayOrderToIndex[n] = n end table_.IsResetDisplayOrderRequest = false table_.IsSettingsDirty = true end if table_.IsResetVisibilityRequest then for n = 0, table_.ColumnsSize - 1 do local column = table_.Columns[n] local v = band(column.Flags, ImGuiTableColumnFlags.DefaultHide) == 0 column.IsUserEnabled = v; column.IsUserEnabledNextFrame = v end table_.IsResetVisibilityRequest = false table_.IsSettingsDirty = true end end -- Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints. function ImGui.TableSetColumnDisplayOrder(table_, column_n, dst_order) IM_ASSERT(column_n >= 0 and column_n < table_.ColumnsCount) IM_ASSERT(dst_order >= 0 and dst_order < table_.ColumnsCount) local src_column = table_.Columns[column_n] local src_order = src_column.DisplayOrder if src_order == dst_order then return end local reorder_dir = (dst_order < src_order) and -1 or 1 src_column.DisplayOrder = dst_order local order_n = src_order + reorder_dir while order_n ~= dst_order + reorder_dir do local c = table_.Columns[table_.DisplayOrderToIndex[order_n]] c.DisplayOrder = c.DisplayOrder - reorder_dir order_n = order_n + reorder_dir end -- Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. for n = 0, table_.ColumnsCount - 1 do table_.DisplayOrderToIndex[table_.Columns[n].DisplayOrder] = n end table_.IsSettingsDirty = true end local function TableGetMaxDisplayOrderAllowed(table_, src_order, dst_order) dst_order = ImClamp(dst_order, 0, table_.ColumnsCount - 1) if src_order == dst_order then return dst_order end -- Cannot cross over the frozen column limit when interactively reordering. if table_.FreezeColumnsRequest > 0 then dst_order = (src_order < table_.FreezeColumnsRequest) and ImMin(dst_order, table_.FreezeColumnsRequest - 1) or ImMax(dst_order, table_.FreezeColumnsRequest) end -- Cannot cross over a column with the ImGuiTableColumnFlags_NoReorder flag. local reorder_dir = (src_order < dst_order) and 1 or -1 local order_n = src_order while (src_order < dst_order and order_n <= dst_order) or (dst_order < src_order and order_n >= dst_order) do if band(table_.Columns[table_.DisplayOrderToIndex[order_n]].Flags, ImGuiTableColumnFlags.NoReorder) ~= 0 then dst_order = (order_n == src_order) and src_order or (order_n - reorder_dir) break end order_n = order_n + reorder_dir end return dst_order end -- Reorder requested by user interaction. function ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, dst_order) local src_order = table_.Columns[column_n].DisplayOrder table_.ReorderColumn = column_n table_.ReorderColumnDstOrder = -1 dst_order = TableGetMaxDisplayOrderAllowed(table_, src_order, dst_order) if table_.IsLayoutLocked and dst_order == src_order then -- We allow calling the function before layout w/ reconcile so don't early out. return end table_.ReorderColumnDstOrder = dst_order end -- Adjust flags: default width mode + stretch columns are not allowed when auto extending local function TableSetupColumnFlags(table_, column, column_n, flags_in) local flags = flags_in -- Sizing Policy if band(flags, ImGuiTableColumnFlags.WidthMask_) == 0 then local table_sizing_policy = band(table_.Flags, ImGuiTableFlags.SizingMask_) if table_sizing_policy == ImGuiTableFlags.SizingFixedFit or table_sizing_policy == ImGuiTableFlags.SizingFixedSame then flags = bor(flags, ImGuiTableColumnFlags.WidthFixed) else flags = bor(flags, ImGuiTableColumnFlags.WidthStretch) end else IM_ASSERT(ImIsPowerOfTwo(band(flags, ImGuiTableColumnFlags.WidthMask_))) -- Check that only 1 of each set is used. end -- Resize if band(table_.Flags, ImGuiTableFlags.Resizable) == 0 then flags = bor(flags, ImGuiTableColumnFlags.NoResize) end -- Sorting if band(flags, ImGuiTableColumnFlags.NoSortAscending) ~= 0 and band(flags, ImGuiTableColumnFlags.NoSortDescending) ~= 0 then flags = bor(flags, ImGuiTableColumnFlags.NoSort) end -- Indentation if band(flags, ImGuiTableColumnFlags.IndentMask_) == 0 then flags = bor(flags, (column_n == 0) and ImGuiTableColumnFlags.IndentEnable or ImGuiTableColumnFlags.IndentDisable) end -- Preserve status flags column.Flags = bor(flags, band(column.Flags, ImGuiTableColumnFlags.StatusMask_)) -- Build an ordered list of available sort directions column.SortDirectionsAvailCount = 0; column.SortDirectionsAvailMask = 0; column.SortDirectionsAvailList = 0 if band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 then local count, mask, list = 0, 0, 0 local Asc, Desc = ImGuiSortDirection.Ascending, ImGuiSortDirection.Descending if band(flags, ImGuiTableColumnFlags.PreferSortAscending) ~= 0 and band(flags, ImGuiTableColumnFlags.NoSortAscending) == 0 then mask = bor(mask, lshift(1, Asc)); list = bor(list, lshift(Asc, lshift(count, 1))); count = count + 1 end if band(flags, ImGuiTableColumnFlags.PreferSortDescending) ~= 0 and band(flags, ImGuiTableColumnFlags.NoSortDescending) == 0 then mask = bor(mask, lshift(1, Desc)); list = bor(list, lshift(Desc, lshift(count, 1))); count = count + 1 end if band(flags, ImGuiTableColumnFlags.PreferSortAscending) == 0 and band(flags, ImGuiTableColumnFlags.NoSortAscending) == 0 then mask = bor(mask, lshift(1, Asc)); list = bor(list, lshift(Asc, lshift(count, 1))); count = count + 1 end if band(flags, ImGuiTableColumnFlags.PreferSortDescending) == 0 and band(flags, ImGuiTableColumnFlags.NoSortDescending) == 0 then mask = bor(mask, lshift(1, Desc)); list = bor(list, lshift(Desc, lshift(count, 1))); count = count + 1 end if band(table_.Flags, ImGuiTableFlags.SortTristate) ~= 0 or count == 0 then mask = bor(mask, lshift(1, ImGuiSortDirection.None)); count = count + 1 end column.SortDirectionsAvailList = band(list, 0xFF) column.SortDirectionsAvailMask = band(mask, 0xFF) column.SortDirectionsAvailCount = count ImGui.TableFixColumnSortDirection(table_, column) end end -- Layout columns for the frame. This is in essence the followup to BeginTable() and this is our largest function. -- Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() and other TableSetupXXXXX() functions to be called first. function ImGui.TableUpdateLayout(table_) local g = GImGui local temp_data = table_.TempData IM_ASSERT(table_.IsLayoutLocked == false) local columns_count = table_.ColumnsCount -- Reconcile moved columns if temp_data.ReconcileColumnsRequests.Size > 0 then ImGui.TableReconcileColumns(table_) end if temp_data.OldColumnsRawData then temp_data.OldColumnsRawData = nil temp_data.OldColumnsData = nil temp_data.OldColumnsDataSize = 0 end -- Apply columns settings if table_.IsSettingsRequestLoad then ImGui.TableLoadSettingsForColumns(table_) end if table_.IsInitializing or table_.IsSettingsRequestLoad then for n = 0, table_.ColumnsSize - 1 do local column = table_.Columns[n] local init_flags if table_.IsSettingsRequestLoad then init_flags = column.IsLoadedSettings and bnot(table_.SettingsLoadedFlags) or bnot(0) else init_flags = column.IsJustCreated and bnot(0) or 0 end ImGui.TableInitColumnDefaults(table_, column, n, init_flags) end ImGui.TableFixDisplayOrder(table_) -- Call even for non _Reorderable table as we loaded .ini data. table_.IsSettingsRequestLoad = false end -- Apply queued resizing/reordering/hiding requests ImGui.TableApplyQueuedRequests(table_) -- Handle DPI/font resize local new_ref_scale_unit = g.FontSize if table_.RefScale ~= 0.0 and table_.RefScale ~= new_ref_scale_unit then local scale_factor = new_ref_scale_unit / table_.RefScale for n = 0, columns_count - 1 do table_.Columns[n].WidthRequest = table_.Columns[n].WidthRequest * scale_factor end end table_.RefScale = new_ref_scale_unit local table_sizing_policy = band(table_.Flags, ImGuiTableFlags.SizingMask_) table_.IsDefaultDisplayOrder = true; table_.IsDefaultVisibility = true table_.ColumnsEnabledCount = 0 BitArrayClearAll(table_.EnabledMaskByIndex) BitArrayClearAll(table_.EnabledMaskByDisplayOrder) table_.LeftMostEnabledColumn = -1 table_.MinColumnWidth = ImMax(1.0, g.Style.FramePadding.x * 1.0) -- g.Style.ColumnsMinSpacing; // FIXME-TABLE -- [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns. local count_fixed = 0 local count_stretch = 0 local prev_visible_column_idx = -1 local has_auto_fit_request = false local has_resizable = false local stretch_sum_width_auto = 0.0 local fixed_max_width_auto = 0.0 for order_n = 0, columns_count - 1 do local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] -- Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame. if table_.DeclColumnsCount <= column_n then TableSetupColumnFlags(table_, column, column_n, ImGuiTableColumnFlags.None) column.NameOffset = -1 column.ID = 0; column.UserData = 0 column.InitStretchWeightOrWidth = -1.0 end -- Update Enabled state, mark settings and sort specs dirty if band(table_.Flags, ImGuiTableFlags.Hideable) == 0 or band(column.Flags, ImGuiTableColumnFlags.NoHide) ~= 0 then column.IsUserEnabledNextFrame = true end if column.IsUserEnabled ~= column.IsUserEnabledNextFrame then column.IsUserEnabled = column.IsUserEnabledNextFrame table_.IsSettingsDirty = true end column.IsEnabled = column.IsUserEnabled and band(column.Flags, ImGuiTableColumnFlags.Disabled) == 0 column.IsJustCreated = false if column.IsEnabled ~= (band(column.Flags, ImGuiTableColumnFlags.DefaultHide) == 0) then table_.IsDefaultVisibility = false end if column_n ~= order_n then table_.IsDefaultDisplayOrder = false end if column.SortOrder ~= -1 and not column.IsEnabled then table_.IsSortSpecsDirty = true end if column.SortOrder > 0 and band(table_.Flags, ImGuiTableFlags.SortMulti) == 0 then table_.IsSortSpecsDirty = true end -- Auto-fit unsized columns local start_auto_fit if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 then start_auto_fit = column.WidthRequest < 0.0 else start_auto_fit = column.StretchWeight < 0.0 end if start_auto_fit then column.AutoFitQueue = lshift(1, 3) - 1 -- Fit for three frames column.CannotSkipItemsQueue = lshift(1, 3) - 1 end if not column.IsEnabled then column.IndexWithinEnabledSet = -1 else -- Mark as enabled and link to previous/next enabled column column.PrevEnabledColumn = prev_visible_column_idx column.NextEnabledColumn = -1 if prev_visible_column_idx ~= -1 then table_.Columns[prev_visible_column_idx].NextEnabledColumn = column_n else table_.LeftMostEnabledColumn = column_n end column.IndexWithinEnabledSet = table_.ColumnsEnabledCount table_.ColumnsEnabledCount = table_.ColumnsEnabledCount + 1 BitArraySet(table_.EnabledMaskByIndex, column_n) BitArraySet(table_.EnabledMaskByDisplayOrder, column.DisplayOrder) prev_visible_column_idx = column_n IM_ASSERT(column.IndexWithinEnabledSet <= column.DisplayOrder) -- Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) if not column.IsPreserveWidthAuto and table_.InstanceCurrent == 0 then column.WidthAuto = ImGui.TableGetColumnWidthAuto(table_, column) end -- Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) local column_is_resizable = band(column.Flags, ImGuiTableColumnFlags.NoResize) == 0 if column_is_resizable then has_resizable = true end if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 and column.InitStretchWeightOrWidth > 0.0 and not column_is_resizable then column.WidthAuto = column.InitStretchWeightOrWidth end if column.AutoFitQueue ~= 0x00 then has_auto_fit_request = true end if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then stretch_sum_width_auto = stretch_sum_width_auto + column.WidthAuto count_stretch = count_stretch + 1 else fixed_max_width_auto = ImMax(fixed_max_width_auto, column.WidthAuto) count_fixed = count_fixed + 1 end end end if band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 and table_.SortSpecsCount == 0 and band(table_.Flags, ImGuiTableFlags.SortTristate) == 0 then table_.IsSortSpecsDirty = true end table_.RightMostEnabledColumn = prev_visible_column_idx IM_ASSERT(table_.LeftMostEnabledColumn >= 0 and table_.RightMostEnabledColumn >= 0) -- [Part 2] Disable child window clipping while fitting columns. if has_auto_fit_request and table_.OuterWindow ~= table_.InnerWindow then table_.InnerWindow.SkipItems = false end if has_auto_fit_request then table_.IsSettingsDirty = true end -- [Part 3] Fix column flags and record a few extra information. local sum_width_requests = 0.0 local stretch_sum_weights = 0.0 table_.LeftMostStretchedColumn = -1; table_.RightMostStretchedColumn = -1 for column_n = 0, columns_count - 1 do if BitTest(table_.EnabledMaskByIndex, column_n) then local column = table_.Columns[column_n] local column_is_resizable = band(column.Flags, ImGuiTableColumnFlags.NoResize) == 0 if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 then -- Apply same widths policy local width_auto = column.WidthAuto if table_sizing_policy == ImGuiTableFlags.SizingFixedSame and (column.AutoFitQueue ~= 0x00 or not column_is_resizable) then width_auto = fixed_max_width_auto end -- Apply automatic width if column.AutoFitQueue ~= 0x00 then column.WidthRequest = width_auto elseif band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 and not column_is_resizable and column.IsRequestOutput then column.WidthRequest = width_auto end -- FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets if column.AutoFitQueue > 0x01 and table_.IsInitializing and not column.IsPreserveWidthAuto then column.WidthRequest = ImMax(column.WidthRequest, table_.MinColumnWidth * 4.0) -- FIXME-TABLE: Another constant/scale? end sum_width_requests = sum_width_requests + column.WidthRequest else -- Initialize stretch weight if column.AutoFitQueue ~= 0x00 or column.StretchWeight < 0.0 or not column_is_resizable then if column.InitStretchWeightOrWidth > 0.0 then column.StretchWeight = column.InitStretchWeightOrWidth elseif table_sizing_policy == ImGuiTableFlags.SizingStretchProp then column.StretchWeight = (column.WidthAuto / stretch_sum_width_auto) * count_stretch else column.StretchWeight = 1.0 end end stretch_sum_weights = stretch_sum_weights + column.StretchWeight if table_.LeftMostStretchedColumn == -1 or table_.Columns[table_.LeftMostStretchedColumn].DisplayOrder > column.DisplayOrder then table_.LeftMostStretchedColumn = column_n end if table_.RightMostStretchedColumn == -1 or table_.Columns[table_.RightMostStretchedColumn].DisplayOrder < column.DisplayOrder then table_.RightMostStretchedColumn = column_n end end column.IsPreserveWidthAuto = false sum_width_requests = sum_width_requests + table_.CellPaddingX * 2.0 end end table_.ColumnsEnabledFixedCount = count_fixed table_.ColumnsStretchSumWeights = stretch_sum_weights -- [Part 4] Apply final widths based on requested widths local work_rect = Rect(table_.WorkRect) local width_spacings = (table_.OuterPaddingX * 2.0) + (table_.CellSpacingX1 + table_.CellSpacingX2) * (table_.ColumnsEnabledCount - 1) local width_removed = (table_.HasScrollbarYPrev and not table_.InnerWindow.ScrollbarY) and g.Style.ScrollbarSize or 0.0 -- To synchronize decoration width of synced tables with mismatching scrollbar state (#5920) local width_avail = ImMax(1.0, ((band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0 and table_.InnerWidth == 0.0) and table_.InnerClipRect:GetWidth() or work_rect:GetWidth()) - width_removed) local width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests local width_remaining_for_stretched_columns = width_avail_for_stretched_columns table_.ColumnsGivenWidth = width_spacings + (table_.CellPaddingX * 2.0) * table_.ColumnsEnabledCount for column_n = 0, columns_count - 1 do if BitTest(table_.EnabledMaskByIndex, column_n) then local column = table_.Columns[column_n] -- Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest) if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then local weight_ratio = column.StretchWeight / stretch_sum_weights column.WidthRequest = IM_TRUNC(ImMax(width_avail_for_stretched_columns * weight_ratio, table_.MinColumnWidth) + 0.01) width_remaining_for_stretched_columns = width_remaining_for_stretched_columns - column.WidthRequest end -- [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column if column.NextEnabledColumn == -1 and table_.LeftMostStretchedColumn ~= -1 then column.Flags = bor(column.Flags, ImGuiTableColumnFlags.NoDirectResize_) end -- Assign final width, record width in case we will need to shrink column.WidthGiven = ImTrunc(ImMax(column.WidthRequest, table_.MinColumnWidth)) table_.ColumnsGivenWidth = table_.ColumnsGivenWidth + column.WidthGiven end end -- [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). if width_remaining_for_stretched_columns >= 1.0 and band(table_.Flags, ImGuiTableFlags.PreciseWidths) == 0 then local order_n = columns_count - 1 while stretch_sum_weights > 0.0 and width_remaining_for_stretched_columns >= 1.0 and order_n >= 0 do if BitTest(table_.EnabledMaskByDisplayOrder, order_n) then local column = table_.Columns[table_.DisplayOrderToIndex[order_n]] if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then column.WidthRequest = column.WidthRequest + 1.0 column.WidthGiven = column.WidthGiven + 1.0 width_remaining_for_stretched_columns = width_remaining_for_stretched_columns - 1.0 end end order_n = order_n - 1 end end -- Determine if table is hovered which will be used to flag columns as hovered. local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) table_instance.HoveredRowLast = table_instance.HoveredRowNext table_instance.HoveredRowNext = -1 table_.HoveredColumnBody = -1; table_.HoveredColumnBorder = -1 local mouse_hit_rect = ImRect(table_.OuterRect.Min.x, table_.OuterRect.Min.y, table_.OuterRect.Max.x, ImMax(table_.OuterRect.Max.y, table_.OuterRect.Min.y + table_instance.LastOuterHeight)) local backup_active_id = g.ActiveId g.ActiveId = 0 local is_hovering_table = ImGui.ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags.None) g.ActiveId = backup_active_id -- Determine skewed MousePos.x to support angled headers. local mouse_skewed_x = g.IO.MousePos.x if table_.AngledHeadersHeight > 0.0 then if g.IO.MousePos.y >= table_.OuterRect.Min.y and g.IO.MousePos.y <= table_.OuterRect.Min.y + table_.AngledHeadersHeight then mouse_skewed_x = mouse_skewed_x + ImTrunc((table_.OuterRect.Min.y + table_.AngledHeadersHeight - g.IO.MousePos.y) * table_.AngledHeadersSlope) end end -- [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column local has_at_least_one_column_requesting_output = false local offset_x_frozen = (table_.FreezeColumnsCount > 0) local offset_x = ((table_.FreezeColumnsCount > 0) and table_.OuterRect.Min.x or work_rect.Min.x) + table_.OuterPaddingX - table_.CellSpacingX1 local host_clip_rect = Rect(table_.InnerClipRect) BitArrayClearAll(table_.VisibleMaskByIndex) for order_n = 0, columns_count - 1 do local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] -- Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen column.NavLayerCurrent = (table_.FreezeRowsCount > 0) and ImGuiNavLayer.Menu or table_.NavLayer if offset_x_frozen and table_.FreezeColumnsCount == order_n then offset_x = offset_x + work_rect.Min.x - table_.OuterRect.Min.x offset_x_frozen = false end -- Clear status flags column.Flags = band(column.Flags, bnot(ImGuiTableColumnFlags.StatusMask_)) if not BitTest(table_.EnabledMaskByDisplayOrder, order_n) then -- Hidden column: clear a few fields and we are done with it for the remainder of the function. column.MinX = offset_x; column.MaxX = offset_x; column.WorkMinX = offset_x column.ClipRect.Min.x = offset_x; column.ClipRect.Max.x = offset_x column.WidthGiven = 0.0 column.ClipRect.Min.y = work_rect.Min.y column.ClipRect.Max.y = FLT_MAX column.ClipRect:ClipWithFull(host_clip_rect) column.IsVisibleX = false; column.IsVisibleY = false; column.IsRequestOutput = false column.IsSkipItems = true column.ItemWidth = 1.0 else -- Lock start position column.MinX = offset_x -- Lock width based on start position and minimum/maximum width for this position column.WidthMax = ImGui.TableCalcMaxColumnWidth(table_, column_n) column.WidthGiven = ImMin(column.WidthGiven, column.WidthMax) column.WidthGiven = ImMax(column.WidthGiven, ImMin(column.WidthRequest, table_.MinColumnWidth)) column.MaxX = offset_x + column.WidthGiven + table_.CellSpacingX1 + table_.CellSpacingX2 + table_.CellPaddingX * 2.0 -- Lock other positions local previous_instance_work_min_x = column.WorkMinX column.WorkMinX = column.MinX + table_.CellPaddingX + table_.CellSpacingX1 column.WorkMaxX = column.MaxX - table_.CellPaddingX - table_.CellSpacingX2 -- Expected max column.ItemWidth = ImTrunc(column.WidthGiven * 0.65) column.ClipRect.Min.x = column.MinX column.ClipRect.Min.y = work_rect.Min.y column.ClipRect.Max.x = column.MaxX --column->WorkMaxX; column.ClipRect.Max.y = FLT_MAX column.ClipRect:ClipWithFull(host_clip_rect) -- Mark column as Clipped (not in sight) column.IsVisibleX = (column.ClipRect.Max.x > column.ClipRect.Min.x) column.IsVisibleY = true -- (column->ClipRect.Max.y > column->ClipRect.Min.y); local is_visible = column.IsVisibleX --&& column->IsVisibleY; if is_visible then BitArraySet(table_.VisibleMaskByIndex, column_n) end -- Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. column.IsRequestOutput = is_visible or column.AutoFitQueue ~= 0 or column.CannotSkipItemsQueue ~= 0 -- Mark column as SkipItems (ignoring all items/layout) column.IsSkipItems = not column.IsEnabled or table_.HostSkipItems if column.IsSkipItems then IM_ASSERT(not is_visible) end if column.IsRequestOutput and not column.IsSkipItems then has_at_least_one_column_requesting_output = true end -- Update status flags column.Flags = bor(column.Flags, ImGuiTableColumnFlags.IsEnabled) if is_visible then column.Flags = bor(column.Flags, ImGuiTableColumnFlags.IsVisible) end if column.SortOrder ~= -1 then column.Flags = bor(column.Flags, ImGuiTableColumnFlags.IsSorted) end -- Detect hovered column if is_hovering_table and mouse_skewed_x >= column.ClipRect.Min.x and mouse_skewed_x < column.ClipRect.Max.x then column.Flags = bor(column.Flags, ImGuiTableColumnFlags.IsHovered) table_.HoveredColumnBody = column_n end -- Reset content width variables if table_.InstanceCurrent == 0 then column.ContentMaxXFrozen = column.WorkMinX column.ContentMaxXUnfrozen = column.WorkMinX column.ContentMaxXHeadersUsed = column.WorkMinX column.ContentMaxXHeadersIdeal = column.WorkMinX else -- As we store an absolute value to make per-cell updates faster, we need to offset values used for width computation. local offset_from_previous_instance = column.WorkMinX - previous_instance_work_min_x column.ContentMaxXFrozen = column.ContentMaxXFrozen + offset_from_previous_instance column.ContentMaxXUnfrozen = column.ContentMaxXUnfrozen + offset_from_previous_instance column.ContentMaxXHeadersUsed = column.ContentMaxXHeadersUsed + offset_from_previous_instance column.ContentMaxXHeadersIdeal = column.ContentMaxXHeadersIdeal + offset_from_previous_instance end -- Don't decrement auto-fit counters until container window got a chance to submit its items if table_.HostSkipItems == false and table_.InstanceCurrent == 0 then column.AutoFitQueue = rshift(column.AutoFitQueue, 1) column.CannotSkipItemsQueue = rshift(column.CannotSkipItemsQueue, 1) end if order_n < table_.FreezeColumnsCount then host_clip_rect.Min.x = ImClamp(column.MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x) end offset_x = offset_x + column.WidthGiven + table_.CellSpacingX1 + table_.CellSpacingX2 + table_.CellPaddingX * 2.0 end end -- In case the table is visible (e.g. decorations) but all columns clipped, we keep a column visible. if has_at_least_one_column_requesting_output == false then table_.Columns[table_.LeftMostEnabledColumn].IsRequestOutput = true table_.Columns[table_.LeftMostEnabledColumn].IsSkipItems = false end -- [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it) local unused_x1 = ImMax(table_.WorkRect.Min.x, table_.Columns[table_.RightMostEnabledColumn].ClipRect.Max.x) if is_hovering_table and table_.HoveredColumnBody == -1 then if mouse_skewed_x >= unused_x1 then table_.HoveredColumnBody = columns_count end end if has_resizable == false and band(table_.Flags, ImGuiTableFlags.Resizable) ~= 0 then table_.Flags = band(table_.Flags, bnot(ImGuiTableFlags.Resizable)) end table_.IsActiveIdAliveBeforeTable = (g.ActiveIdIsAlive ~= 0) -- [Part 8] Lock actual OuterRect/WorkRect right-most position. if table_.RightMostStretchedColumn ~= -1 then table_.Flags = band(table_.Flags, bnot(ImGuiTableFlags.NoHostExtendX)) end if band(table_.Flags, ImGuiTableFlags.NoHostExtendX) ~= 0 then table_.OuterRect.Max.x = unused_x1; table_.WorkRect.Max.x = unused_x1 table_.InnerClipRect.Max.x = ImMin(table_.InnerClipRect.Max.x, unused_x1) end ImRect_Copy(table_.InnerWindow.ParentWorkRect, table_.WorkRect) table_.BorderX1 = table_.InnerClipRect.Min.x table_.BorderX2 = table_.InnerClipRect.Max.x -- Setup window's WorkRect.Max.y for GetContentRegionAvail(). Other values will be updated in each TableBeginCell() call. local window_content_max_y if band(table_.Flags, ImGuiTableFlags.NoHostExtendY) ~= 0 then window_content_max_y = table_.OuterRect.Max.y else window_content_max_y = ImMax(table_.InnerWindow.ContentRegionRect.Max.y, (band(table_.Flags, ImGuiTableFlags.ScrollY) ~= 0) and 0.0 or table_.OuterRect.Max.y) end table_.InnerWindow.WorkRect.Max.y = ImClamp(window_content_max_y - g.Style.CellPadding.y, table_.InnerWindow.WorkRect.Min.y, table_.InnerWindow.WorkRect.Max.y) -- [Part 9] Allocate draw channels and setup background cliprect ImGui.TableSetupDrawChannels(table_) -- [Part 10] Hit testing on borders if band(table_.Flags, ImGuiTableFlags.Resizable) ~= 0 then ImGui.TableUpdateBorders(table_) end table_instance.LastTopHeadersRowHeight = 0.0 table_.IsLayoutLocked = true table_.IsUsingHeaders = false -- Highlight header table_.HighlightColumnHeader = -1 if table_.IsContextPopupOpen and table_.ContextPopupColumn ~= -1 and table_.InstanceInteracted == table_.InstanceCurrent then table_.HighlightColumnHeader = table_.ContextPopupColumn elseif band(table_.Flags, ImGuiTableFlags.HighlightHoveredColumn) ~= 0 and table_.HoveredColumnBody ~= -1 and table_.HoveredColumnBody ~= columns_count and table_.HoveredColumnBorder == -1 then if g.ActiveId == 0 or (table_.IsActiveIdInTable or g.DragDropActive) then table_.HighlightColumnHeader = table_.HoveredColumnBody end end -- [Part 11] Default context menu if table_.DisableDefaultContextMenu == false and ImGui.TableBeginContextMenuPopup(table_) then ImGui.TableDrawDefaultContextMenu(table_, table_.Flags) ImGui.EndPopup() end -- [Part 12] Sanitize and build sort specs before we have a chance to use them for display. if table_.IsSortSpecsDirty and band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 then ImGui.TableSortSpecsBuild(table_) end -- [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) if table_.FreezeColumnsRequest > 0 then table_.InnerWindow.DecoInnerSizeX1 = table_.Columns[table_.DisplayOrderToIndex[table_.FreezeColumnsRequest - 1]].MaxX - table_.OuterRect.Min.x -- FIXME-FROZEN end if table_.FreezeRowsRequest > 0 then table_.InnerWindow.DecoInnerSizeY1 = table_instance.LastFrozenHeight end table_instance.LastFrozenHeight = 0.0 local inner_window = table_.InnerWindow local bs = g.BoxSelectState if bs and bs.Window == inner_window and bs.UnclipMode then ImGui.TableApplyExternalUnclipRect(table_, bs.UnclipRect) end -- Initial state if band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0 then table_.DrawSplitter:SetCurrentChannel(inner_window.DrawList, TABLE_DRAW_CHANNEL_NOCLIP) else inner_window.DrawList:PushClipRect(inner_window.InnerClipRect.Min, inner_window.InnerClipRect.Max, false) -- FIXME: use table->InnerClipRect? end end -- When starting a BeginMultiSelect() after table has been layout we update IsRequestOutput fields. function ImGui.TableApplyExternalUnclipRect(table_, rect) if rect:IsInverted() then return end for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if not column.IsRequestOutput then if rect:Overlaps(ImRect(column.MinX, table_.WorkRect.Min.y, column.MaxX, FLT_MAX)) then column.IsRequestOutput = true end end end end -- Process hit-testing on resizing borders. Actual size change will be applied in EndTable() function ImGui.TableUpdateBorders(table_) local g = GImGui IM_ASSERT(band(table_.Flags, ImGuiTableFlags.Resizable) ~= 0) local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) local hit_half_width = ImTrunc(TABLE_RESIZE_SEPARATOR_HALF_THICKNESS * g.CurrentDpiScale) local hit_y1 = ((table_.FreezeRowsCount >= 1) and table_.OuterRect.Min.y or table_.WorkRect.Min.y) + table_.AngledHeadersHeight local hit_y2_body = ImMax(table_.OuterRect.Max.y, hit_y1 + table_instance.LastOuterHeight - table_.AngledHeadersHeight) local hit_y2_head = hit_y1 + table_instance.LastTopHeadersRowHeight for order_n = 0, table_.ColumnsCount - 1 do repeat if not BitTest(table_.EnabledMaskByDisplayOrder, order_n) then break end local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] if band(column.Flags, bor(ImGuiTableColumnFlags.NoResize, ImGuiTableColumnFlags.NoDirectResize_)) ~= 0 then break end -- ImGuiTableFlags_NoBordersInBodyUntilResize will be honored in TableDrawBorders() local border_y2_hit = (band(table_.Flags, ImGuiTableFlags.NoBordersInBody) ~= 0) and hit_y2_head or hit_y2_body if band(table_.Flags, ImGuiTableFlags.NoBordersInBody) ~= 0 and table_.IsUsingHeaders == false then break end if not column.IsVisibleX and table_.LastResizedColumn ~= column_n then break end local column_id = ImGui.TableGetColumnResizeID(table_, column_n, table_.InstanceCurrent) local hit_rect = ImRect(column.MaxX - hit_half_width, hit_y1, column.MaxX + hit_half_width, border_y2_hit) ImGui.ItemAdd(hit_rect, column_id, nil, ImGuiItemFlags.NoNav) local pressed, hovered, held = ImGui.ButtonBehavior(hit_rect, column_id, bor(ImGuiButtonFlags.FlattenChildren, ImGuiButtonFlags.PressedOnClick, ImGuiButtonFlags.PressedOnDoubleClick, ImGuiButtonFlags.NoNavFocus)) if pressed and ImGui.IsMouseDoubleClicked(0) then ImGui.TableSetColumnWidthAutoSingle(table_, column_n) ImGui.ClearActiveID() held = false end if held then if table_.LastResizedColumn == -1 then table_.ResizeLockMinContentsX2 = (table_.RightMostEnabledColumn ~= -1) and table_.Columns[table_.RightMostEnabledColumn].MaxX or -FLT_MAX end table_.ResizedColumn = column_n table_.InstanceInteracted = table_.InstanceCurrent end if (hovered and g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) or held then table_.HoveredColumnBorder = column_n ImGui.SetMouseCursor(ImGuiMouseCursor.ResizeEW) end until true end end function ImGui.EndTable() local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "EndTable() call should only be done while in BeginTable() scope!") -- If the user never got to call TableNextRow() or TableNextColumn(), we call layout ourselves. if not table_.IsLayoutLocked then ImGui.TableUpdateLayout(table_) end local flags = table_.Flags local inner_window = table_.InnerWindow local outer_window = table_.OuterWindow local temp_data = table_.TempData IM_ASSERT(inner_window == g.CurrentWindow and inner_window.ID == temp_data.WindowID) IM_ASSERT(outer_window == inner_window or outer_window == inner_window.ParentWindow) if table_.IsInsideRow then ImGui.TableEndRow(table_) end -- Context menu in columns body if band(flags, ImGuiTableFlags.ContextMenuInBody) ~= 0 then if table_.HoveredColumnBody ~= -1 and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(ImGuiMouseButton.Right) then ImGui.TableOpenContextMenu(table_.HoveredColumnBody) end end -- Finalize table height local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) ImVec2_Copy(inner_window.DC.PrevLineSize, temp_data.HostBackupPrevLineSize) ImVec2_Copy(inner_window.DC.CurrLineSize, temp_data.HostBackupCurrLineSize) ImVec2_Copy(inner_window.DC.CursorMaxPos, temp_data.HostBackupCursorMaxPos) local inner_content_max_y = ImCeil(table_.RowPosY2) -- Rounding final position is important as we currently don't round row height IM_ASSERT(table_.RowPosY2 == inner_window.DC.CursorPos.y) if inner_window ~= outer_window then inner_window.DC.CursorMaxPos.y = inner_content_max_y elseif band(flags, ImGuiTableFlags.NoHostExtendY) == 0 then local v = ImMax(table_.OuterRect.Max.y, inner_content_max_y) -- Patch OuterRect/InnerRect height table_.OuterRect.Max.y = v; table_.InnerRect.Max.y = v end table_.WorkRect.Max.y = ImMax(table_.WorkRect.Max.y, table_.OuterRect.Max.y) table_instance.LastOuterHeight = table_.OuterRect:GetHeight() -- Setup inner scrolling range if band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0 then local outer_padding_for_border = (band(table_.Flags, ImGuiTableFlags.BordersOuterV) ~= 0) and TABLE_BORDER_SIZE or 0.0 local max_pos_x = inner_window.DC.CursorMaxPos.x if table_.RightMostEnabledColumn ~= -1 then max_pos_x = ImMax(max_pos_x, table_.Columns[table_.RightMostEnabledColumn].WorkMaxX + table_.CellPaddingX + table_.OuterPaddingX - outer_padding_for_border) end if table_.ResizedColumn ~= -1 then max_pos_x = ImMax(max_pos_x, table_.ResizeLockMinContentsX2) end inner_window.DC.CursorMaxPos.x = max_pos_x + table_.TempData.AngledHeadersExtraWidth end -- Pop clipping rect if band(flags, ImGuiTableFlags.NoClip) == 0 then inner_window.DrawList:PopClipRect() end ImRect_CopyFromV4(inner_window.ClipRect, inner_window.DrawList._ClipRectStack:back()) -- Draw borders if band(flags, ImGuiTableFlags.Borders) ~= 0 then ImGui.TableDrawBorders(table_) end -- Flatten channels and merge draw calls local splitter = table_.DrawSplitter splitter:SetCurrentChannel(inner_window.DrawList, 0) if band(table_.Flags, ImGuiTableFlags.NoClip) == 0 then ImGui.TableMergeDrawChannels(table_) end splitter:Merge(inner_window.DrawList) -- Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable() local auto_fit_width_for_fixed = 0.0 local auto_fit_width_for_stretched = 0.0 local auto_fit_width_for_stretched_min = 0.0 for column_n = 0, table_.ColumnsCount - 1 do if BitTest(table_.EnabledMaskByIndex, column_n) then local column = table_.Columns[column_n] local column_width_request if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoResize) == 0 then column_width_request = column.WidthRequest else column_width_request = ImGui.TableGetColumnWidthAuto(table_, column) end if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 then auto_fit_width_for_fixed = auto_fit_width_for_fixed + column_width_request else auto_fit_width_for_stretched = auto_fit_width_for_stretched + column_width_request end if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoResize) ~= 0 then auto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column.StretchWeight / table_.ColumnsStretchSumWeights)) end end end local width_spacings = (table_.OuterPaddingX * 2.0) + (table_.CellSpacingX1 + table_.CellSpacingX2) * (table_.ColumnsEnabledCount - 1) table_.ColumnsAutoFitWidth = width_spacings + (table_.CellPaddingX * 2.0) * table_.ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min) -- Update scroll if band(table_.Flags, ImGuiTableFlags.ScrollX) == 0 and inner_window ~= outer_window then inner_window.Scroll.x = 0.0 elseif table_.LastResizedColumn ~= -1 and table_.ResizedColumn == -1 and inner_window.ScrollbarX and table_.InstanceInteracted == table_.InstanceCurrent then -- When releasing a column being resized, scroll to keep the resulting column in sight local neighbor_width_to_keep_visible = table_.MinColumnWidth + table_.CellPaddingX * 2.0 local column = table_.Columns[table_.LastResizedColumn] if column.MaxX < table_.InnerClipRect.Min.x then ImGui.SetScrollFromPosX(inner_window, column.MaxX - inner_window.Pos.x - neighbor_width_to_keep_visible, 1.0) elseif column.MaxX > table_.InnerClipRect.Max.x then ImGui.SetScrollFromPosX(inner_window, column.MaxX - inner_window.Pos.x + neighbor_width_to_keep_visible, 1.0) end end -- Apply resizing/dragging at the end of the frame if table_.ResizedColumn ~= -1 and table_.InstanceCurrent == table_.InstanceInteracted then local column = table_.Columns[table_.ResizedColumn] local new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + ImTrunc(TABLE_RESIZE_SEPARATOR_HALF_THICKNESS * g.CurrentDpiScale)) local new_width = ImTrunc(new_x2 - column.MinX - table_.CellSpacingX1 - table_.CellPaddingX * 2.0) table_.ResizedColumnNextWidth = new_width end table_.IsActiveIdInTable = (g.ActiveIdIsAlive ~= 0 and table_.IsActiveIdAliveBeforeTable == false) -- Pop from id stack IM_ASSERT_USER_ERROR(inner_window.IDStack:back() == table_instance.TableInstanceID, "Mismatching PushID/PopID!") IM_ASSERT_USER_ERROR(outer_window.DC.ItemWidthStack.Size >= temp_data.HostBackupItemWidthStackSize, "Too many PopItemWidth!") if table_.InstanceCurrent > 0 then ImGui.PopID() end ImGui.PopID() -- Restore window data that we modified local backup_outer_max_pos = V2(outer_window.DC.CursorMaxPos) ImRect_Copy(inner_window.WorkRect, temp_data.HostBackupWorkRect) ImRect_Copy(inner_window.ParentWorkRect, temp_data.HostBackupParentWorkRect) inner_window.SkipItems = table_.HostSkipItems ImVec2_Copy(outer_window.DC.CursorPos, table_.OuterRect.Min) outer_window.DC.ItemWidth = temp_data.HostBackupItemWidth outer_window.DC.ItemWidthStack:resize(temp_data.HostBackupItemWidthStackSize) outer_window.DC.ColumnsOffset.x = temp_data.HostBackupColumnsOffset -- Layout in outer window if inner_window ~= outer_window then local backup_nav_layers_active_mask = inner_window.DC.NavLayersActiveMask inner_window.DC.NavLayersActiveMask = bor(inner_window.DC.NavLayersActiveMask, lshift(1, table_.NavLayer)) -- So empty table don't appear to navigate differently. g.CurrentTable = nil -- To avoid error recovery recursing ImGui.EndChild() g.CurrentTable = table_ inner_window.DC.NavLayersActiveMask = backup_nav_layers_active_mask else inner_window.DC.TreeDepth = inner_window.DC.TreeDepth - 1 ImGui.ItemSize(table_.OuterRect:GetSize()) ImGui.ItemAdd(table_.OuterRect, 0) end -- Override declared contents width/height to enable auto-resize while not needlessly adding a scrollbar if band(table_.Flags, ImGuiTableFlags.NoHostExtendX) ~= 0 then IM_ASSERT(band(table_.Flags, ImGuiTableFlags.ScrollX) == 0) outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table_.OuterRect.Min.x + table_.ColumnsAutoFitWidth) elseif temp_data.UserOuterSize.x <= 0.0 then local outer_content_max_x = table_.OuterRect.Min.x + table_.ColumnsAutoFitWidth local decoration_size = table_.TempData.AngledHeadersExtraWidth + ((inner_window ~= outer_window) and inner_window.ScrollbarSizes.x or 0.0) outer_window.DC.IdealMaxPos.x = ImMax(outer_window.DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data.UserOuterSize.x) outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table_.OuterRect.Max.x, outer_content_max_x + decoration_size)) else outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table_.OuterRect.Max.x) end if temp_data.UserOuterSize.y <= 0.0 then local outer_content_size_y = (inner_window == outer_window) and (inner_content_max_y - table_.InnerRect.Min.y) or (inner_content_max_y - inner_window.DC.CursorStartPos.y) local outer_content_max_y = table_.OuterRect.Min.y + outer_content_size_y local decoration_size = (inner_window ~= outer_window) and inner_window.ScrollbarSizes.y or 0.0 outer_window.DC.IdealMaxPos.y = ImMax(outer_window.DC.IdealMaxPos.y, outer_content_max_y + decoration_size - temp_data.UserOuterSize.y) outer_window.DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table_.OuterRect.Max.y, outer_content_max_y + decoration_size)) else -- OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags_NoHostExtendY is set) outer_window.DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table_.OuterRect.Max.y) end -- Save settings if table_.IsSettingsDirty then ImGui.TableSaveSettings(table_) end table_.IsInitializing = false -- Clear or restore current table, if any IM_ASSERT(g.CurrentWindow == outer_window and g.CurrentTable == table_) IM_ASSERT(g.TablesTempDataStacked > 0) g.TablesTempDataStacked = g.TablesTempDataStacked - 1 temp_data = (g.TablesTempDataStacked > 0) and g.TablesTempData.Data[g.TablesTempDataStacked] or nil g.CurrentTable = (temp_data and (temp_data.WindowID == outer_window.ID)) and g.Tables:GetByIndex(temp_data.TableIndex) or nil if g.CurrentTable then g.CurrentTable.TempData = temp_data g.CurrentTable.DrawSplitter = temp_data.DrawSplitter end outer_window.DC.CurrentTableIdx = g.CurrentTable and g.Tables:GetIndex(g.CurrentTable) or -1 ImGui.NavUpdateCurrentWindowIsScrollPushableX() end -- Called in TableUpdateLayout() when initializing/after loading settings. -- 'init_mask' specify which fields to initialize. --- @param column_n int # index of `column` (C++: Columns.index_from_ptr(column)) function ImGui.TableInitColumnDefaults(table_, column, column_n, init_mask) local flags = column.Flags if band(init_mask, ImGuiTableFlags.Resizable) ~= 0 then local init_width_or_weight = column.InitStretchWeightOrWidth column.WidthRequest = (band(flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 and init_width_or_weight > 0.0) and init_width_or_weight or -1.0 column.StretchWeight = (init_width_or_weight > 0.0 and band(flags, ImGuiTableColumnFlags.WidthStretch) ~= 0) and init_width_or_weight or -1.0 if init_width_or_weight > 0.0 then -- Disable auto-fit if an explicit width/weight has been specified column.AutoFitQueue = 0x00 end end if band(init_mask, ImGuiTableFlags.Reorderable) ~= 0 then column.DisplayOrder = (band(table_.Flags, ImGuiTableFlags.Reorderable) ~= 0) and -1 or column_n end if band(init_mask, ImGuiTableFlags.Hideable) ~= 0 then local v = band(flags, ImGuiTableColumnFlags.DefaultHide) == 0 column.IsUserEnabled = v; column.IsUserEnabledNextFrame = v end if band(init_mask, ImGuiTableFlags.Sortable) ~= 0 then -- Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. column.SortOrder = (band(flags, ImGuiTableColumnFlags.DefaultSort) ~= 0) and 0 or -1 if band(flags, ImGuiTableColumnFlags.DefaultSort) ~= 0 then column.SortDirection = (band(flags, ImGuiTableColumnFlags.PreferSortDescending) ~= 0) and ImGuiSortDirection.Descending or ImGuiSortDirection.Ascending else column.SortDirection = ImGuiSortDirection.None end end end -- See "COLUMNS SIZING POLICIES" comments at the top of this file -- If (init_width_or_weight <= 0.0f) it is ignored local function TableSetupColumnApply(table_, idx, id, name_offset, flags, init_width_or_weight, user_data) local column = table_.Columns[idx] -- Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. if table_.IsDefaultSizingPolicy and band(flags, ImGuiTableColumnFlags.WidthMask_) == 0 and band(flags, ImGuiTableFlags.ScrollX) == 0 then IM_ASSERT_USER_ERROR_RET(init_width_or_weight <= 0.0, "TableSetupColumn(): can only specify width/weight if sizing policy is set explicitly in either Table or Column.") end -- When passing a width automatically enforce WidthFixed policy if band(flags, ImGuiTableColumnFlags.WidthMask_) == 0 and init_width_or_weight > 0.0 then if band(table_.Flags, ImGuiTableFlags.SizingMask_) == ImGuiTableFlags.SizingFixedFit or band(table_.Flags, ImGuiTableFlags.SizingMask_) == ImGuiTableFlags.SizingFixedSame then flags = bor(flags, ImGuiTableColumnFlags.WidthFixed) end end if band(flags, ImGuiTableColumnFlags.AngledHeader) ~= 0 then flags = bor(flags, ImGuiTableColumnFlags.NoHeaderLabel) table_.AngledHeadersCount = table_.AngledHeadersCount + 1 end TableSetupColumnFlags(table_, column, idx, flags) column.ID = id column.UserData = user_data column.NameOffset = name_offset column.InitStretchWeightOrWidth = init_width_or_weight end --- @param label string? --- @param flags? ImGuiTableColumnFlags --- @param init_width_or_weight? float --- @param user_data? ImGuiID function ImGui.TableSetupColumn(label, flags, init_width_or_weight, user_data) if flags == nil then flags = 0 end if init_width_or_weight == nil then init_width_or_weight = 0.0 end if user_data == nil then user_data = 0 end local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT_USER_ERROR_RET(table_.DeclColumnsCount < table_.ColumnsCount, "TableSetupColumn(): called too many times!") IM_ASSERT_USER_ERROR_RET(table_.IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!") IM_ASSERT(band(flags, ImGuiTableColumnFlags.StatusMask_) == 0, "Illegal to pass StatusMask values to TableSetupColumn()") -- Store name local name_offset = -1 if label ~= nil and label ~= "" then name_offset = #table_.ColumnsNames table_.ColumnsNames[name_offset + 1] = label end local column_id = (label ~= nil and label ~= "") and ImHashStr(label) or 0 -- When ID changed or a column moved: defer the request until layout where we will process full reconcile. local column_idx = table_.DeclColumnsCount table_.DeclColumnsCount = table_.DeclColumnsCount + 1 local column = table_.Columns[column_idx] -- If topology change goes into reconcile mode if table_.IsReconcileMode == false and column.ID ~= column_id and not table_.IsNewTable then table_.IsReconcileMode = true end -- Fast/common path if table_.IsReconcileMode == false then TableSetupColumnApply(table_, column_idx, column_id, name_offset, flags, init_width_or_weight, user_data) column.IsNeedReconcileSrc = false; column.IsNeedReconcileDst = false local old = table_.TempData.OldColumnsData if old and column_idx < table_.TempData.OldColumnsDataSize then old[column_idx].IsNeedReconcileSrc = false end return end -- Reconcile path: defer applying data to TableUpdateLayout() -> TableReconcileMovedColumns() -> TableSetupColumnApply(). local reconcile_data = { ID = column_id, NameOffset = name_offset, Flags = flags, InitWidthOrWeight = init_width_or_weight, UserData = user_data, ColumnNewIdx = column_idx, ColumnOldIdx = -1, ColumnOldData = ImGuiTableColumn(), } table_.TempData.ReconcileColumnsRequests:push_back(reconcile_data) column.NameOffset = name_offset -- Allow TableGetColumnName() to work before layout column.IsNeedReconcileSrc = true; column.IsNeedReconcileDst = true end -- NB: This was written to be similar to the logic in TableLoadSettingsForColumns(). function ImGui.TableReconcileColumns(table_) local temp_data = table_.TempData IMGUI_DEBUG_LOG_TABLE("[table] Reconcile columns for table 0x%08X\n", table_.ID) local dst_columns = table_.Columns local src_columns, src_count if temp_data.OldColumnsData == nil then src_columns, src_count = table_.Columns, table_.ColumnsSize else src_columns, src_count = temp_data.OldColumnsData, temp_data.OldColumnsDataSize end -- Find matches for named columns. local matches = 0 local reconcile_requests = temp_data.ReconcileColumnsRequests for _, reconcile_data in reconcile_requests:iter() do if reconcile_data.ID ~= 0 then for src_n = 0, src_count - 1 do local src_column = src_columns[src_n] if src_column.ID == reconcile_data.ID and src_column.IsNeedReconcileSrc then local dst_column = dst_columns[reconcile_data.ColumnNewIdx] IM_ASSERT(src_column.IsNeedReconcileSrc and dst_column.IsNeedReconcileDst) src_column.IsNeedReconcileSrc = false; dst_column.IsNeedReconcileDst = false reconcile_data.ColumnOldIdx = src_n reconcile_data.ColumnOldData = TableColumnClone(src_column) matches = matches + 1 break end end end end -- Remaining entries are matched sequentially. local dst_idx = 1 -- index in reconcile array (1-based) if matches ~= reconcile_requests.Size then for src_n = 0, src_count - 1 do local src_column = src_columns[src_n] if src_column.IsNeedReconcileSrc then while dst_idx <= reconcile_requests.Size and reconcile_requests.Data[dst_idx].ColumnOldIdx ~= -1 do dst_idx = dst_idx + 1 end if dst_idx > reconcile_requests.Size then break end local reconcile_data = reconcile_requests.Data[dst_idx] local dst_column = dst_columns[reconcile_data.ColumnNewIdx] IM_ASSERT(src_column.IsNeedReconcileSrc and dst_column.IsNeedReconcileDst) src_column.IsNeedReconcileSrc = false; dst_column.IsNeedReconcileDst = false reconcile_data.ColumnOldIdx = src_n reconcile_data.ColumnOldData = TableColumnClone(src_column) end end end -- Apply in the final pass. Because it is possible that src_columns == table->Columns we went through a temporary copy. for _, reconcile_data in reconcile_requests:iter() do TableColumnCopy(table_.Columns[reconcile_data.ColumnNewIdx], reconcile_data.ColumnOldData) TableSetupColumnApply(table_, reconcile_data.ColumnNewIdx, reconcile_data.ID, reconcile_data.NameOffset, reconcile_data.Flags, reconcile_data.InitWidthOrWeight, reconcile_data.UserData) end ImGui.TableFixDisplayOrder(table_) table_.IsSettingsDirty = true -- FIXME-RECONCILE: Necessary? table_.IsReconcileMode = false reconcile_requests:resize(0) -- GC-ed once in NewFrame() end -- [Public] function ImGui.TableSetupScrollFreeze(columns, rows) local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT(table_.IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!") IM_ASSERT(columns >= 0 and columns < IMGUI_TABLE_MAX_COLUMNS) IM_ASSERT(rows >= 0 and rows < 128) -- Arbitrary limit table_.FreezeColumnsRequest = (band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0) and ImMin(columns, table_.ColumnsCount) or 0 table_.FreezeColumnsCount = (table_.InnerWindow.Scroll.x ~= 0.0) and table_.FreezeColumnsRequest or 0 table_.FreezeRowsRequest = (band(table_.Flags, ImGuiTableFlags.ScrollY) ~= 0) and rows or 0 table_.FreezeRowsCount = (table_.InnerWindow.Scroll.y ~= 0.0) and table_.FreezeRowsRequest or 0 table_.IsUnfrozenRows = (table_.FreezeRowsCount == 0) -- Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it. end ---------------------------------------------------------------- -- [SECTION] Tables: Simple accessors ---------------------------------------------------------------- function ImGui.SetWindowClipRectBeforeSetChannel(window, clip_rect) local clip_rect_vec4 = clip_rect:ToVec4() ImRect_Copy(window.ClipRect, clip_rect) ImVec4_Copy(window.DrawList._CmdHeader.ClipRect, clip_rect_vec4) window.DrawList._ClipRectStack.Data[window.DrawList._ClipRectStack.Size] = clip_rect_vec4 end function ImGui.TableGetColumnCount() local g = GImGui local table_ = g.CurrentTable return table_ and table_.ColumnsCount or 0 end -- Overloads: TableGetColumnName(column_n?) / TableGetColumnName(table, column_n) function ImGui.TableGetColumnName(a, b) local table_, column_n if type(a) == "table" then table_, column_n = a, b else local g = GImGui table_ = g.CurrentTable if not table_ then return nil end column_n = a or -1 if column_n < 0 then column_n = table_.CurrentColumn end end if table_.IsLayoutLocked == false and column_n >= table_.DeclColumnsCount then return "" -- NameOffset is invalid at this point end local column = table_.Columns[column_n] if column.NameOffset == -1 then return "" end return table_.ColumnsNames[column.NameOffset + 1] end -- Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view) function ImGui.TableSetColumnEnabled(column_n, enabled) local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT(band(table_.Flags, ImGuiTableFlags.Hideable) ~= 0) -- See comments above if column_n < 0 then column_n = table_.CurrentColumn end IM_ASSERT(column_n >= 0 and column_n < table_.ColumnsCount) local column = table_.Columns[column_n] column.IsUserEnabledNextFrame = enabled end -- We allow querying for an extra column in order to poll the IsHovered state of the right-most section function ImGui.TableGetColumnFlags(column_n) if column_n == nil then column_n = -1 end local g = GImGui local table_ = g.CurrentTable if not table_ then return ImGuiTableColumnFlags.None end if column_n < 0 then column_n = table_.CurrentColumn end if column_n == table_.ColumnsCount then return (table_.HoveredColumnBody == column_n) and ImGuiTableColumnFlags.IsHovered or ImGuiTableColumnFlags.None end return table_.Columns[column_n].Flags end -- Return the cell rectangle based on currently known height. function ImGui.TableGetCellBgRect(table_, column_n) local column = table_.Columns[column_n] local x1 = column.MinX local x2 = column.MaxX x1 = ImMax(x1, table_.WorkRect.Min.x) x2 = ImMin(x2, table_.WorkRect.Max.x) return ImRect(x1, table_.RowPosY1, x2, table_.RowPosY2) end -- Return the resizing ID for the right-side of the given column. function ImGui.TableGetColumnResizeID(table_, column_n, instance_no) if instance_no == nil then instance_no = 0 end IM_ASSERT(column_n >= 0 and column_n < table_.ColumnsCount) local instance_id = ImGui.TableGetInstanceID(table_, instance_no) return band(instance_id + 1 + column_n, 0xFFFFFFFF) -- FIXME: #6140: still not ideal end -- Return -1 when table is not hovered. return columns_count if hovering the unused space at the right of the right-most visible column. function ImGui.TableGetHoveredColumn() local g = GImGui local table_ = g.CurrentTable if not table_ then return -1 end return table_.HoveredColumnBody end -- Return -1 when table is not hovered. Return maxrow+1 if in table but below last submitted row. function ImGui.TableGetHoveredRow() local g = GImGui local table_ = g.CurrentTable if not table_ then return -1 end local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) return table_instance.HoveredRowLast end function ImGui.TableSetBgColor(target, color, column_n) if column_n == nil then column_n = -1 end local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT(target ~= ImGuiTableBgTarget.None) if color == IM_COL32_DISABLE then color = 0 end -- We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. if target == ImGuiTableBgTarget.CellBg then if table_.RowPosY1 > table_.InnerClipRect.Max.y then -- Discard return end if column_n == -1 then column_n = table_.CurrentColumn end if not BitTest(table_.VisibleMaskByIndex, column_n) then return end if table_.RowCellDataCurrent < 0 or table_.RowCellData[table_.RowCellDataCurrent].Column ~= column_n then table_.RowCellDataCurrent = table_.RowCellDataCurrent + 1 end local cell_data = table_.RowCellData[table_.RowCellDataCurrent] cell_data.BgColor = color cell_data.Column = column_n elseif target == ImGuiTableBgTarget.RowBg0 or target == ImGuiTableBgTarget.RowBg1 then if table_.RowPosY1 > table_.InnerClipRect.Max.y then -- Discard return end IM_ASSERT(column_n == -1) local bg_idx = (target == ImGuiTableBgTarget.RowBg1) and 1 or 0 table_.RowBgColor[bg_idx] = color else IM_ASSERT(false) end end ---------------------------------------------------------------- -- [SECTION] Tables: Row changes ---------------------------------------------------------------- -- [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows function ImGui.TableGetRowIndex() local g = GImGui local table_ = g.CurrentTable if not table_ then return 0 end return table_.CurrentRow end -- [Public] Starts into the first cell of a new row --- @param row_flags? ImGuiTableRowFlags --- @param row_min_height? float function ImGui.TableNextRow(row_flags, row_min_height) if row_flags == nil then row_flags = 0 end if row_min_height == nil then row_min_height = 0.0 end local g = GImGui local table_ = g.CurrentTable if not table_.IsLayoutLocked then ImGui.TableUpdateLayout(table_) end if table_.IsInsideRow then ImGui.TableEndRow(table_) end table_.LastRowFlags = table_.RowFlags table_.RowFlags = row_flags table_.RowCellPaddingY = g.Style.CellPadding.y table_.RowMinHeight = row_min_height ImGui.TableBeginRow(table_) -- We honor min_row_height requested by user, but cannot guarantee per-row maximum height, -- because that would essentially require a unique clipping rectangle per-cell. table_.RowPosY2 = table_.RowPosY2 + table_.RowCellPaddingY * 2.0 table_.RowPosY2 = ImMax(table_.RowPosY2, table_.RowPosY1 + row_min_height) -- Disable output until user calls TableNextColumn() table_.InnerWindow.SkipItems = true end -- [Internal] Only called by TableNextRow() function ImGui.TableBeginRow(table_) local window = table_.InnerWindow IM_ASSERT(not table_.IsInsideRow) -- New row table_.CurrentRow = table_.CurrentRow + 1 table_.CurrentColumn = -1 table_.RowBgColor[0] = IM_COL32_DISABLE; table_.RowBgColor[1] = IM_COL32_DISABLE table_.RowCellDataCurrent = -1 table_.IsInsideRow = true -- Begin frozen rows local next_y1 = table_.RowPosY2 if table_.CurrentRow == 0 and table_.FreezeRowsCount > 0 then next_y1 = table_.OuterRect.Min.y window.DC.CursorPos.y = next_y1 end table_.RowPosY1 = next_y1; table_.RowPosY2 = next_y1 table_.RowTextBaseline = 0.0 table_.RowIndentOffsetX = window.DC.Indent.x - table_.HostIndentX -- Lock indent window.DC.PrevLineTextBaseOffset = 0.0 window.DC.CursorPosPrevLine.x = window.DC.CursorPos.x window.DC.CursorPosPrevLine.y = window.DC.CursorPos.y + table_.RowCellPaddingY -- This allows users to call SameLine() to share LineSize between columns. window.DC.PrevLineSize.x = 0.0; window.DC.PrevLineSize.y = 0.0 window.DC.CurrLineSize.x = 0.0; window.DC.CurrLineSize.y = 0.0 window.DC.IsSameLine = false; window.DC.IsSetPos = false window.DC.CursorMaxPos.y = next_y1 -- Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging. if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 then ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(ImGuiCol.TableHeaderBg)) if table_.CurrentRow == 0 then table_.IsUsingHeaders = true end end end -- [Internal] Called by TableNextRow() function ImGui.TableEndRow(table_) local g = GImGui local window = g.CurrentWindow IM_ASSERT(window == table_.InnerWindow) IM_ASSERT(table_.IsInsideRow) if table_.CurrentColumn ~= -1 then ImGui.TableEndCell(table_) table_.CurrentColumn = -1 end -- Logging if g.LogEnabled then ImGui.LogRenderedText(nil, "|") end -- Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. window.DC.CursorPos.y = table_.RowPosY2 -- Row background fill local bg_y1 = table_.RowPosY1 local bg_y2 = table_.RowPosY2 local unfreeze_rows_actual = (table_.CurrentRow + 1 == table_.FreezeRowsCount) local unfreeze_rows_request = (table_.CurrentRow + 1 == table_.FreezeRowsRequest) local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 and (table_.CurrentRow == 0 or band(table_.LastRowFlags, ImGuiTableRowFlags.Headers) ~= 0) then table_instance.LastTopHeadersRowHeight = table_instance.LastTopHeadersRowHeight + bg_y2 - bg_y1 end local is_visible = (bg_y2 >= table_.InnerClipRect.Min.y and bg_y1 <= table_.InnerClipRect.Max.y) if is_visible then -- Update data for TableGetHoveredRow() if table_.HoveredColumnBody ~= -1 and g.IO.MousePos.y >= bg_y1 and g.IO.MousePos.y < bg_y2 and table_instance.HoveredRowNext < 0 then table_instance.HoveredRowNext = table_.CurrentRow end -- Decide of background color for the row local bg_col0 = 0 local bg_col1 = 0 if table_.RowBgColor[0] ~= IM_COL32_DISABLE then bg_col0 = table_.RowBgColor[0] elseif band(table_.Flags, ImGuiTableFlags.RowBg) ~= 0 then bg_col0 = ImGui.GetColorU32((band(table_.RowBgColorCounter, 1) ~= 0) and ImGuiCol.TableRowBgAlt or ImGuiCol.TableRowBg) end if table_.RowBgColor[1] ~= IM_COL32_DISABLE then bg_col1 = table_.RowBgColor[1] end -- Decide of top border color local top_border_col = 0 local border_size = TABLE_BORDER_SIZE if table_.CurrentRow > 0 and band(table_.Flags, ImGuiTableFlags.BordersInnerH) ~= 0 then top_border_col = (band(table_.LastRowFlags, ImGuiTableRowFlags.Headers) ~= 0) and table_.BorderColorStrong or table_.BorderColorLight end local draw_cell_bg_color = table_.RowCellDataCurrent >= 0 local draw_strong_bottom_border = unfreeze_rows_actual if bor(bg_col0, bg_col1, top_border_col) ~= 0 or draw_strong_bottom_border or draw_cell_bg_color then -- In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is -- always followed by a change of clipping rectangle we perform the smallest overwrite possible here. if band(table_.Flags, ImGuiTableFlags.NoClip) == 0 then ImVec4_Copy(window.DrawList._CmdHeader.ClipRect, table_.Bg0ClipRectForDrawCmd:ToVec4()) end table_.DrawSplitter:SetCurrentChannel(window.DrawList, TABLE_DRAW_CHANNEL_BG0) end -- Draw row background -- We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle if bg_col0 ~= 0 or bg_col1 ~= 0 then local row_rect = ImRect(table_.WorkRect.Min.x, bg_y1, table_.WorkRect.Max.x, bg_y2) row_rect:ClipWith(table_.BgClipRect) if bg_col0 ~= 0 and row_rect.Min.y < row_rect.Max.y then window.DrawList:AddRectFilled(row_rect.Min, row_rect.Max, bg_col0) end if bg_col1 ~= 0 and row_rect.Min.y < row_rect.Max.y then window.DrawList:AddRectFilled(row_rect.Min, row_rect.Max, bg_col1) end end -- Draw cell background color if draw_cell_bg_color then for cell_n = 0, table_.RowCellDataCurrent do local cell_data = table_.RowCellData[cell_n] -- As we render the BG here we need to clip things (for layout we would not) local column = table_.Columns[cell_data.Column] local cell_bg_rect = ImGui.TableGetCellBgRect(table_, cell_data.Column) cell_bg_rect:ClipWith(table_.BgClipRect) cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column.ClipRect.Min.x) -- So that first column after frozen one gets clipped when scrolling cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column.MaxX) if cell_bg_rect.Min.y < cell_bg_rect.Max.y then window.DrawList:AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data.BgColor) end end end -- Draw top border if top_border_col ~= 0 and bg_y1 >= table_.BgClipRect.Min.y and bg_y1 < table_.BgClipRect.Max.y then window.DrawList:AddLineH(table_.BorderX1, table_.BorderX2, bg_y1, top_border_col, border_size) end -- Draw bottom border at the row unfreezing mark (always strong) if draw_strong_bottom_border and bg_y2 >= table_.BgClipRect.Min.y and bg_y2 < table_.BgClipRect.Max.y then window.DrawList:AddLineH(table_.BorderX1, table_.BorderX2, bg_y2, table_.BorderColorStrong, border_size) end end -- End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle) if unfreeze_rows_request then IM_ASSERT(table_.FreezeRowsRequest > 0) for column_n = 0, table_.ColumnsCount - 1 do table_.Columns[column_n].NavLayerCurrent = table_.NavLayer end local y0 = ImMax(table_.RowPosY2 + 1, table_.InnerClipRect.Min.y) table_instance.LastFrozenHeight = y0 - table_.OuterRect.Min.y if unfreeze_rows_actual then IM_ASSERT(table_.IsUnfrozenRows == false) table_.IsUnfrozenRows = true -- BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect local min_y = ImMin(y0, table_.InnerClipRect.Max.y) table_.BgClipRect.Min.y = min_y; table_.Bg2ClipRectForDrawCmd.Min.y = min_y table_.BgClipRect.Max.y = table_.InnerClipRect.Max.y; table_.Bg2ClipRectForDrawCmd.Max.y = table_.InnerClipRect.Max.y table_.Bg2DrawChannelCurrent = table_.Bg2DrawChannelUnfrozen IM_ASSERT(table_.Bg2ClipRectForDrawCmd.Min.y <= table_.Bg2ClipRectForDrawCmd.Max.y) local row_height = table_.RowPosY2 - table_.RowPosY1 table_.RowPosY2 = table_.WorkRect.Min.y + table_.RowPosY2 - table_.OuterRect.Min.y window.DC.CursorPos.y = table_.RowPosY2 table_.RowPosY1 = table_.RowPosY2 - row_height for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] column.DrawChannelCurrent = column.DrawChannelUnfrozen column.ClipRect.Min.y = table_.Bg2ClipRectForDrawCmd.Min.y end -- Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y ImGui.SetWindowClipRectBeforeSetChannel(window, table_.Columns[0].ClipRect) table_.DrawSplitter:SetCurrentChannel(window.DrawList, table_.Columns[0].DrawChannelCurrent) end end if band(table_.RowFlags, ImGuiTableRowFlags.Headers) == 0 then table_.RowBgColorCounter = table_.RowBgColorCounter + 1 end table_.IsInsideRow = false end ---------------------------------------------------------------- -- [SECTION] Tables: Columns changes ---------------------------------------------------------------- function ImGui.TableGetColumnIndex() local g = GImGui local table_ = g.CurrentTable if not table_ then return 0 end return table_.CurrentColumn end -- [Public] Append into a specific column function ImGui.TableSetColumnIndex(column_n) local g = GImGui local table_ = g.CurrentTable if not table_ then return false end if table_.CurrentColumn ~= column_n then if table_.CurrentColumn ~= -1 then ImGui.TableEndCell(table_) end if not (column_n >= 0 and column_n < table_.ColumnsCount) then IM_ASSERT_USER_ERROR(false, "TableSetColumnIndex() invalid column index!") return false end ImGui.TableBeginCell(table_, column_n) end -- Return whether the column is visible. User may choose to skip submitting items based on this return value, -- however they shouldn't skip submitting for columns that may have the tallest contribution to row height. return table_.Columns[column_n].IsRequestOutput end -- [Public] Append into the next column, wrap and create a new row when already on last column function ImGui.TableNextColumn() local g = GImGui local table_ = g.CurrentTable if not table_ then return false end if table_.IsInsideRow and table_.CurrentColumn + 1 < table_.ColumnsCount then if table_.CurrentColumn ~= -1 then ImGui.TableEndCell(table_) end ImGui.TableBeginCell(table_, table_.CurrentColumn + 1) else ImGui.TableNextRow() ImGui.TableBeginCell(table_, 0) end -- Return whether the column is visible. User may choose to skip submitting items based on this return value, -- however they shouldn't skip submitting for columns that may have the tallest contribution to row height. return table_.Columns[table_.CurrentColumn].IsRequestOutput end -- [Internal] Called by TableSetColumnIndex()/TableNextColumn() -- This is called very frequently, so we need to be mindful of unnecessary overhead. function ImGui.TableBeginCell(table_, column_n) local g = GImGui local column = table_.Columns[column_n] local window = table_.InnerWindow table_.CurrentColumn = column_n -- Start position is roughly ~~ CellRect.Min + CellPadding + Indent local start_x = column.WorkMinX if band(column.Flags, ImGuiTableColumnFlags.IndentEnable) ~= 0 then start_x = start_x + table_.RowIndentOffsetX -- ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row. end window.DC.CursorPos.x = start_x window.DC.CursorPos.y = table_.RowPosY1 + table_.RowCellPaddingY window.DC.CursorMaxPos.x = window.DC.CursorPos.x window.DC.ColumnsOffset.x = start_x - window.Pos.x - window.DC.Indent.x -- FIXME-WORKRECT window.DC.CursorPosPrevLine.x = window.DC.CursorPos.x -- PrevLine.y is preserved. This allows users to call SameLine() to share LineSize between columns. window.DC.CurrLineTextBaseOffset = table_.RowTextBaseline window.DC.NavLayerCurrent = column.NavLayerCurrent -- Note how WorkRect.Max.y is only set once during layout window.WorkRect.Min.y = window.DC.CursorPos.y window.WorkRect.Min.x = column.WorkMinX window.WorkRect.Max.x = column.WorkMaxX window.DC.ItemWidth = column.ItemWidth window.SkipItems = column.IsSkipItems if column.IsSkipItems then g.LastItemData.ID = 0 g.LastItemData.StatusFlags = 0 end -- Also see TablePushColumnChannel() if band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0 then -- FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. table_.DrawSplitter:SetCurrentChannel(window.DrawList, TABLE_DRAW_CHANNEL_NOCLIP) else -- FIXME-TABLE: Could avoid this if draw channel is dummy channel? ImGui.SetWindowClipRectBeforeSetChannel(window, column.ClipRect) table_.DrawSplitter:SetCurrentChannel(window.DrawList, column.DrawChannelCurrent) end -- Logging if g.LogEnabled and not column.IsSkipItems then ImGui.LogRenderedText(window.DC.CursorPos, "|") g.LogLinePosY = FLT_MAX end end -- [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() function ImGui.TableEndCell(table_) local column = table_.Columns[table_.CurrentColumn] local window = table_.InnerWindow if window.DC.IsSetPos then ImGui.ErrorCheckUsingSetCursorPosToExtendParentBoundaries() end -- Report maximum position so we can infer content size per column. local x = window.DC.CursorMaxPos.x if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 then column.ContentMaxXHeadersUsed = ImMax(column.ContentMaxXHeadersUsed, x) -- Useful in case user submit contents in header row that is not a TableHeader() call elseif table_.IsUnfrozenRows then column.ContentMaxXUnfrozen = ImMax(column.ContentMaxXUnfrozen, x) else column.ContentMaxXFrozen = ImMax(column.ContentMaxXFrozen, x) end if column.IsEnabled then table_.RowPosY2 = ImMax(table_.RowPosY2, window.DC.CursorMaxPos.y + table_.RowCellPaddingY) end column.ItemWidth = window.DC.ItemWidth -- Propagate text baseline for the entire row table_.RowTextBaseline = ImMax(table_.RowTextBaseline, window.DC.PrevLineTextBaseOffset) end ---------------------------------------------------------------- -- [SECTION] Tables: Columns width management ---------------------------------------------------------------- -- Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis. function ImGui.TableCalcMaxColumnWidth(table_, column_n) local column = table_.Columns[column_n] local max_width = FLT_MAX local min_column_distance = table_.MinColumnWidth + table_.CellPaddingX * 2.0 + table_.CellSpacingX1 + table_.CellSpacingX2 if band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0 then -- Frozen columns can't reach beyond visible width else scrolling will naturally break. if column.DisplayOrder < table_.FreezeColumnsRequest then max_width = (table_.InnerClipRect.Max.x - (table_.FreezeColumnsRequest - column.DisplayOrder) * min_column_distance) - column.MinX max_width = max_width - table_.OuterPaddingX - table_.CellPaddingX - table_.CellSpacingX2 end elseif band(table_.Flags, ImGuiTableFlags.NoKeepColumnsVisible) == 0 then -- If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make sure they are all visible. max_width = table_.WorkRect.Max.x - (table_.ColumnsEnabledCount - column.IndexWithinEnabledSet - 1) * min_column_distance - column.MinX max_width = max_width - table_.CellSpacingX2 max_width = max_width - table_.CellPaddingX * 2.0 max_width = max_width - table_.OuterPaddingX end return max_width end -- Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field function ImGui.TableGetColumnWidthAuto(table_, column) local content_width_body = ImMax(column.ContentMaxXFrozen, column.ContentMaxXUnfrozen) - column.WorkMinX local content_width_headers = column.ContentMaxXHeadersIdeal - column.WorkMinX local width_auto = content_width_body if band(column.Flags, ImGuiTableColumnFlags.NoHeaderWidth) == 0 then width_auto = ImMax(width_auto, content_width_headers) end -- Non-resizable fixed columns preserve their requested width if band(column.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 and column.InitStretchWeightOrWidth > 0.0 then if band(table_.Flags, ImGuiTableFlags.Resizable) == 0 or band(column.Flags, ImGuiTableColumnFlags.NoResize) ~= 0 then width_auto = column.InitStretchWeightOrWidth end end return ImMax(width_auto, table_.MinColumnWidth) end -- 'width' = inner column width, without padding function ImGui.TableSetColumnWidth(column_n, width) local g = GImGui local table_ = g.CurrentTable IM_ASSERT(table_ ~= nil and table_.IsLayoutLocked == false) IM_ASSERT(column_n >= 0 and column_n < table_.ColumnsCount) local column_0 = table_.Columns[column_n] local column_0_width = width -- Apply constraints early IM_ASSERT(table_.MinColumnWidth > 0.0) local min_width = table_.MinColumnWidth local max_width = ImMax(min_width, column_0.WidthMax) -- Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933) column_0_width = ImClamp(column_0_width, min_width, max_width) if column_0.WidthGiven == column_0_width or column_0.WidthRequest == column_0_width then return end local column_1 = (column_0.NextEnabledColumn ~= -1) and table_.Columns[column_0.NextEnabledColumn] or nil -- If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize. -- This is the preferred resize path if band(column_0.Flags, ImGuiTableColumnFlags.WidthFixed) ~= 0 then if not column_1 or table_.LeftMostStretchedColumn == -1 or table_.Columns[table_.LeftMostStretchedColumn].DisplayOrder >= column_0.DisplayOrder then column_0.WidthRequest = column_0_width table_.IsSettingsDirty = true return end end -- We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column) if column_1 == nil then column_1 = (column_0.PrevEnabledColumn ~= -1) and table_.Columns[column_0.PrevEnabledColumn] or nil end if column_1 == nil then return end -- Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column. -- (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) local column_1_width = ImMax(column_1.WidthRequest - (column_0_width - column_0.WidthRequest), min_width) column_0_width = column_0.WidthRequest + column_1.WidthRequest - column_1_width IM_ASSERT(column_0_width > 0.0 and column_1_width > 0.0) column_0.WidthRequest = column_0_width column_1.WidthRequest = column_1_width if band(bor(column_0.Flags, column_1.Flags), ImGuiTableColumnFlags.WidthStretch) ~= 0 then ImGui.TableUpdateColumnsWeightFromWidth(table_) end table_.IsSettingsDirty = true end -- Disable clipping then auto-fit, will take 2 frames function ImGui.TableSetColumnWidthAutoSingle(table_, column_n) -- Single auto width uses auto-fit local column = table_.Columns[column_n] if not column.IsEnabled then return end column.CannotSkipItemsQueue = lshift(1, 0) table_.AutoFitSingleColumn = column_n end function ImGui.TableSetColumnWidthAutoAll(table_) for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.IsEnabled or band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then -- Cannot reset weight of hidden stretch column column.CannotSkipItemsQueue = lshift(1, 0) column.AutoFitQueue = lshift(1, 1) end end end function ImGui.TableUpdateColumnsWeightFromWidth(table_) IM_ASSERT(table_.LeftMostStretchedColumn ~= -1 and table_.RightMostStretchedColumn ~= -1) -- Measure existing quantities local visible_weight = 0.0 local visible_width = 0.0 for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.IsEnabled and band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then IM_ASSERT(column.StretchWeight > 0.0) visible_weight = visible_weight + column.StretchWeight visible_width = visible_width + column.WidthRequest end end IM_ASSERT(visible_weight > 0.0 and visible_width > 0.0) -- Apply new weights for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.IsEnabled and band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then column.StretchWeight = (column.WidthRequest / visible_width) * visible_weight IM_ASSERT(column.StretchWeight > 0.0) end end end ---------------------------------------------------------------- -- [SECTION] Tables: Drawing ---------------------------------------------------------------- -- Bg2 is used by Selectable (and possibly other widgets) to render to the background. function ImGui.TablePushBackgroundChannel() local g = GImGui local window = g.CurrentWindow local table_ = g.CurrentTable -- Optimization: avoid SetCurrentChannel() + PushClipRect() ImRect_Copy(table_.HostBackupInnerClipRect, window.ClipRect) ImGui.SetWindowClipRectBeforeSetChannel(window, table_.Bg2ClipRectForDrawCmd) table_.DrawSplitter:SetCurrentChannel(window.DrawList, table_.Bg2DrawChannelCurrent) end function ImGui.TablePopBackgroundChannel() local g = GImGui local window = g.CurrentWindow local table_ = g.CurrentTable -- Optimization: avoid PopClipRect() + SetCurrentChannel() ImGui.SetWindowClipRectBeforeSetChannel(window, table_.HostBackupInnerClipRect) table_.DrawSplitter:SetCurrentChannel(window.DrawList, table_.Columns[table_.CurrentColumn].DrawChannelCurrent) end -- Also see TableBeginCell() function ImGui.TablePushColumnChannel(column_n) local g = GImGui local table_ = g.CurrentTable -- Optimization: avoid SetCurrentChannel() + PushClipRect() if band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0 then return end local window = g.CurrentWindow local column = table_.Columns[column_n] ImGui.SetWindowClipRectBeforeSetChannel(window, column.ClipRect) table_.DrawSplitter:SetCurrentChannel(window.DrawList, column.DrawChannelCurrent) end function ImGui.TablePopColumnChannel() local g = GImGui local table_ = g.CurrentTable -- Optimization: avoid PopClipRect() + SetCurrentChannel() if band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0 or (table_.CurrentColumn == -1) then -- Calling TreePop() after TableNextRow() is supported. return end local window = g.CurrentWindow local column = table_.Columns[table_.CurrentColumn] ImGui.SetWindowClipRectBeforeSetChannel(window, column.ClipRect) table_.DrawSplitter:SetCurrentChannel(window.DrawList, column.DrawChannelCurrent) end -- Allocate draw channels. Called by TableUpdateLayout() function ImGui.TableSetupDrawChannels(table_) local freeze_row_multiplier = (table_.FreezeRowsCount > 0) and 2 or 1 local channels_for_row = (band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0) and 1 or table_.ColumnsEnabledCount local channels_for_bg = 1 + 1 * freeze_row_multiplier local masks_differ = false for n = 0, table_.ColumnsCount - 1 do if (table_.VisibleMaskByIndex[n] == true) ~= (table_.EnabledMaskByIndex[n] == true) then masks_differ = true break end end local channels_for_dummy = (table_.ColumnsEnabledCount < table_.ColumnsCount or masks_differ) and 1 or 0 local channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy table_.DrawSplitter:Split(table_.InnerWindow.DrawList, channels_total) table_.DummyDrawChannel = (channels_for_dummy > 0) and (channels_total - 1) or -1 table_.Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN table_.Bg2DrawChannelUnfrozen = (table_.FreezeRowsCount > 0) and (2 + channels_for_row) or TABLE_DRAW_CHANNEL_BG2_FROZEN local draw_channel_current = 2 for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.IsVisibleX and column.IsVisibleY then column.DrawChannelFrozen = draw_channel_current column.DrawChannelUnfrozen = draw_channel_current + ((table_.FreezeRowsCount > 0) and (channels_for_row + 1) or 0) if band(table_.Flags, ImGuiTableFlags.NoClip) == 0 then draw_channel_current = draw_channel_current + 1 end else column.DrawChannelFrozen = table_.DummyDrawChannel column.DrawChannelUnfrozen = table_.DummyDrawChannel end column.DrawChannelCurrent = column.DrawChannelFrozen end -- Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default. ImRect_Copy(table_.BgClipRect, table_.InnerClipRect) ImRect_Copy(table_.Bg0ClipRectForDrawCmd, table_.OuterWindow.ClipRect) ImRect_Copy(table_.Bg2ClipRectForDrawCmd, table_.HostClipRect) IM_ASSERT(table_.BgClipRect.Min.y <= table_.BgClipRect.Max.y) end -- This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable(). -- (Lua: splitter channel n lives in splitter._Channels.Data[n + 1]; bit arrays are Lua sets) function ImGui.TableMergeDrawChannels(table_) local splitter = table_.DrawSplitter local channels = splitter._Channels.Data local has_freeze_v = (table_.FreezeRowsCount > 0) local has_freeze_h = (table_.FreezeColumnsCount > 0) IM_ASSERT(splitter._Current == 0) -- Track which groups we are going to attempt to merge, and which channels goes into each group. local merge_group_mask = 0x00 local merge_groups = {} for n = 0, 3 do merge_groups[n] = { ClipRect = ImRect(), ChannelsCount = 0, ChannelsMask = {} } end local max_draw_channels = (4 + table_.ColumnsCount * 2) local remaining_mask = {} -- 1. Scan channels and take note of those which can be merged for column_n = 0, table_.ColumnsCount - 1 do if BitTest(table_.VisibleMaskByIndex, column_n) then local column = table_.Columns[column_n] local merge_group_sub_count = has_freeze_v and 2 or 1 for merge_group_sub_n = 0, merge_group_sub_count - 1 do repeat local channel_no = (merge_group_sub_n == 0) and column.DrawChannelFrozen or column.DrawChannelUnfrozen -- Don't attempt to merge if there are multiple draw calls within the column local src_channel = channels[channel_no + 1] local cmds = src_channel._CmdBuffer if cmds.Size > 0 and cmds.Data[cmds.Size].ElemCount == 0 and cmds.Data[cmds.Size].UserCallback == nil then -- Equivalent of PopUnusedDrawCmd() cmds:pop_back() end if cmds.Size ~= 1 then break end -- Find out the width of this merge group and check if it will fit in our column if band(column.Flags, ImGuiTableColumnFlags.NoClip) == 0 then local content_max_x if not has_freeze_v then content_max_x = ImMax(column.ContentMaxXUnfrozen, column.ContentMaxXHeadersUsed) -- No row freeze elseif merge_group_sub_n == 0 then content_max_x = ImMax(column.ContentMaxXFrozen, column.ContentMaxXHeadersUsed) -- Row freeze: use width before freeze else content_max_x = column.ContentMaxXUnfrozen -- Row freeze: use width after freeze end if content_max_x > column.ClipRect.Max.x then break end end local merge_group_n = ((has_freeze_h and column_n < table_.FreezeColumnsCount) and 0 or 1) + ((has_freeze_v and merge_group_sub_n == 0) and 0 or 2) IM_ASSERT(channel_no < max_draw_channels) local merge_group = merge_groups[merge_group_n] if merge_group.ChannelsCount == 0 then merge_group.ClipRect = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX) end merge_group.ChannelsMask[channel_no] = true merge_group.ChannelsCount = merge_group.ChannelsCount + 1 local cr = cmds.Data[1].ClipRect merge_group.ClipRect:Add(ImRect(cr.x, cr.y, cr.z, cr.w)) merge_group_mask = bor(merge_group_mask, lshift(1, merge_group_n)) until true end -- Invalidate current draw channel column.DrawChannelCurrent = -1 end end -- 2. Rewrite channel list in our preferred order if merge_group_mask ~= 0 then -- We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels(). local LEADING_DRAW_CHANNELS = 2 local dst_tmp = {} for n = LEADING_DRAW_CHANNELS, splitter._Count - 1 do remaining_mask[n] = true end remaining_mask[table_.Bg2DrawChannelUnfrozen] = nil IM_ASSERT(has_freeze_v == false or table_.Bg2DrawChannelUnfrozen ~= TABLE_DRAW_CHANNEL_BG2_FROZEN) local remaining_count = splitter._Count - (has_freeze_v and (LEADING_DRAW_CHANNELS + 1) or LEADING_DRAW_CHANNELS) local host_rect = table_.HostClipRect for merge_group_n = 0, 3 do local merge_channels_count = merge_groups[merge_group_n].ChannelsCount if merge_channels_count ~= 0 then local merge_group = merge_groups[merge_group_n] local merge_clip_rect = Rect(merge_group.ClipRect) -- Extend outer-most clip limits to match those of host, so draw calls can be merged even if -- outer-most columns have some outer padding offsetting them from their parent ClipRect. if band(merge_group_n, 1) == 0 or not has_freeze_h then merge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x) end if band(merge_group_n, 2) == 0 or not has_freeze_v then merge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y) end if band(merge_group_n, 1) ~= 0 then merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x) end if band(merge_group_n, 2) ~= 0 and band(table_.Flags, ImGuiTableFlags.NoHostExtendY) == 0 then merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y) end remaining_count = remaining_count - merge_group.ChannelsCount for n in pairs(merge_group.ChannelsMask) do remaining_mask[n] = nil end local n = 0 while n < splitter._Count and merge_channels_count ~= 0 do -- Copy + overwrite new clip rect if merge_group.ChannelsMask[n] then merge_group.ChannelsMask[n] = nil merge_channels_count = merge_channels_count - 1 local channel = channels[n + 1] IM_ASSERT(channel._CmdBuffer.Size == 1) ImVec4_Copy(channel._CmdBuffer.Data[1].ClipRect, merge_clip_rect:ToVec4()) dst_tmp[#dst_tmp + 1] = channel end n = n + 1 end end -- Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1) if merge_group_n == 1 and has_freeze_v then dst_tmp[#dst_tmp + 1] = channels[table_.Bg2DrawChannelUnfrozen + 1] end end -- Append unmergeable channels that we didn't reorder at the end of the list local n = 0 while n < splitter._Count and remaining_count ~= 0 do if remaining_mask[n] then dst_tmp[#dst_tmp + 1] = channels[n + 1] remaining_count = remaining_count - 1 end n = n + 1 end IM_ASSERT(#dst_tmp == splitter._Count - LEADING_DRAW_CHANNELS) for i = 1, #dst_tmp do channels[LEADING_DRAW_CHANNELS + i] = dst_tmp[i] end end end local function TableGetColumnBorderCol(table_, order_n, column_n) local is_hovered = (table_.HoveredColumnBorder == column_n) local is_resized = (table_.ResizedColumn == column_n) and (table_.InstanceInteracted == table_.InstanceCurrent) local is_frozen_separator = (table_.FreezeColumnsCount == order_n + 1) if is_resized or is_hovered then return ImGui.GetColorU32(is_resized and ImGuiCol.SeparatorActive or ImGuiCol.SeparatorHovered) end if is_frozen_separator or band(table_.Flags, bor(ImGuiTableFlags.NoBordersInBody, ImGuiTableFlags.NoBordersInBodyUntilResize)) ~= 0 then return table_.BorderColorStrong end return table_.BorderColorLight end -- FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow) function ImGui.TableDrawBorders(table_) local inner_window = table_.InnerWindow if not table_.OuterWindow.ClipRect:Overlaps(table_.OuterRect) then return end local inner_drawlist = inner_window.DrawList table_.DrawSplitter:SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0) inner_drawlist:PushClipRect(table_.Bg0ClipRectForDrawCmd.Min, table_.Bg0ClipRectForDrawCmd.Max, false) -- Draw inner border and resizing feedback local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) local border_size = TABLE_BORDER_SIZE local draw_y1 = ImMax(table_.InnerRect.Min.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_.AngledHeadersHeight) + ((band(table_.Flags, ImGuiTableFlags.BordersOuterH) ~= 0) and border_size or 0.0) local draw_y2_body = table_.InnerRect.Max.y local draw_y2_head = table_.IsUsingHeaders and ImMin(table_.InnerRect.Max.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_instance.LastTopHeadersRowHeight) or draw_y1 if band(table_.Flags, ImGuiTableFlags.BordersInnerV) ~= 0 then for order_n = 0, table_.ColumnsCount - 1 do repeat if not BitTest(table_.EnabledMaskByDisplayOrder, order_n) then break end local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] local is_hovered = (table_.HoveredColumnBorder == column_n) local is_resized = (table_.ResizedColumn == column_n) and (table_.InstanceInteracted == table_.InstanceCurrent) local is_resizable = band(column.Flags, bor(ImGuiTableColumnFlags.NoResize, ImGuiTableColumnFlags.NoDirectResize_)) == 0 local is_frozen_separator = (table_.FreezeColumnsCount == order_n + 1) if column.MaxX > table_.InnerClipRect.Max.x and not is_resized then break end -- Decide whether right-most column is visible if column.NextEnabledColumn == -1 and not is_resizable then if band(table_.Flags, ImGuiTableFlags.SizingMask_) ~= ImGuiTableFlags.SizingFixedSame or band(table_.Flags, ImGuiTableFlags.NoHostExtendX) ~= 0 then break end end if column.MaxX <= column.ClipRect.Min.x then -- FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. break end -- Draw in outer window so right-most column won't be clipped local draw_y2 = draw_y2_head if is_frozen_separator then draw_y2 = draw_y2_body elseif band(table_.Flags, ImGuiTableFlags.NoBordersInBodyUntilResize) ~= 0 and (is_hovered or is_resized) then draw_y2 = draw_y2_body elseif band(table_.Flags, bor(ImGuiTableFlags.NoBordersInBodyUntilResize, ImGuiTableFlags.NoBordersInBody)) == 0 then draw_y2 = draw_y2_body end if draw_y2 > draw_y1 then inner_drawlist:AddLineV(column.MaxX, draw_y1, draw_y2, TableGetColumnBorderCol(table_, order_n, column_n), border_size) end until true end end -- Draw outer border if band(table_.Flags, ImGuiTableFlags.BordersOuter) ~= 0 then local outer_border = table_.OuterRect local outer_col = table_.BorderColorStrong if band(table_.Flags, ImGuiTableFlags.BordersOuter) == ImGuiTableFlags.BordersOuter then inner_drawlist:AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0, border_size) elseif band(table_.Flags, ImGuiTableFlags.BordersOuterV) ~= 0 then inner_drawlist:AddLineV(outer_border.Min.x, outer_border.Min.y, outer_border.Max.y, outer_col, border_size) inner_drawlist:AddLineV(outer_border.Max.x - border_size, outer_border.Min.y, outer_border.Max.y, outer_col, border_size) elseif band(table_.Flags, ImGuiTableFlags.BordersOuterH) ~= 0 then inner_drawlist:AddLineH(outer_border.Min.x, outer_border.Max.x, outer_border.Min.y, outer_col, border_size) inner_drawlist:AddLineH(outer_border.Min.x, outer_border.Max.x, outer_border.Max.y - border_size, outer_col, border_size) end end if band(table_.Flags, ImGuiTableFlags.BordersInnerH) ~= 0 and table_.RowPosY2 < table_.OuterRect.Max.y then -- Draw bottom-most row border between it is above outer border. local h_inset = (band(table_.Flags, ImGuiTableFlags.BordersOuterV) ~= 0) and border_size or 0.0 local border_y = table_.RowPosY2 if border_y >= table_.BgClipRect.Min.y and border_y < table_.BgClipRect.Max.y then inner_drawlist:AddLineH(table_.BorderX1 + h_inset, table_.BorderX2 - h_inset, border_y, table_.BorderColorLight, border_size) end end inner_drawlist:PopClipRect() end ---------------------------------------------------------------- -- [SECTION] Tables: Sorting ---------------------------------------------------------------- -- Return nil if no sort specs (most often when ImGuiTableFlags_Sortable is not set) -- When 'sort_specs.SpecsDirty == true' you should sort your data. Specs is a 1-based Lua array. function ImGui.TableGetSortSpecs() local g = GImGui local table_ = g.CurrentTable if table_ == nil or band(table_.Flags, ImGuiTableFlags.Sortable) == 0 then return nil end -- Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. if not table_.IsLayoutLocked then ImGui.TableUpdateLayout(table_) end ImGui.TableSortSpecsBuild(table_) return table_.SortSpecs end local function TableGetColumnAvailSortDirection(column, n) IM_ASSERT(n < column.SortDirectionsAvailCount) return band(rshift(column.SortDirectionsAvailList, lshift(n, 1)), 0x03) end -- Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) function ImGui.TableFixColumnSortDirection(table_, column) if column.SortOrder == -1 or band(column.SortDirectionsAvailMask, lshift(1, column.SortDirection)) ~= 0 then return end column.SortDirection = TableGetColumnAvailSortDirection(column, 0) table_.IsSortSpecsDirty = true end -- Calculate next sort direction that would be set after clicking the column function ImGui.TableGetColumnNextSortDirection(column) IM_ASSERT(column.SortDirectionsAvailCount > 0) if column.SortOrder == -1 then return TableGetColumnAvailSortDirection(column, 0) end for n = 0, 2 do if column.SortDirection == TableGetColumnAvailSortDirection(column, n) then return TableGetColumnAvailSortDirection(column, (n + 1) % column.SortDirectionsAvailCount) end end IM_ASSERT(false) return ImGuiSortDirection.None end -- Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert -- the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. function ImGui.TableSetColumnSortDirection(column_n, sort_direction, append_to_sort_specs) local g = GImGui local table_ = g.CurrentTable if band(table_.Flags, ImGuiTableFlags.SortMulti) == 0 then append_to_sort_specs = false end if band(table_.Flags, ImGuiTableFlags.SortTristate) == 0 then IM_ASSERT(sort_direction ~= ImGuiSortDirection.None) end local sort_order_max = 0 if append_to_sort_specs then for other_column_n = 0, table_.ColumnsCount - 1 do sort_order_max = ImMax(sort_order_max, table_.Columns[other_column_n].SortOrder) end end local column = table_.Columns[column_n] column.SortDirection = sort_direction if column.SortDirection == ImGuiSortDirection.None then column.SortOrder = -1 elseif column.SortOrder == -1 or not append_to_sort_specs then column.SortOrder = append_to_sort_specs and (sort_order_max + 1) or 0 end for other_column_n = 0, table_.ColumnsCount - 1 do local other_column = table_.Columns[other_column_n] if other_column ~= column and not append_to_sort_specs then other_column.SortOrder = -1 end ImGui.TableFixColumnSortDirection(table_, other_column) end table_.IsSettingsDirty = true table_.IsSortSpecsDirty = true end function ImGui.TableSortSpecsSanitize(table_) IM_ASSERT(band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0) -- Clear SortOrder from hidden column and verify that there's no gap or duplicate. local sort_order_count = 0 local sort_order_set = {} -- C++: ImU64 sort_order_mask local sort_order_dup = false for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.SortOrder ~= -1 and not column.IsEnabled then column.SortOrder = -1 end if column.SortOrder ~= -1 then sort_order_count = sort_order_count + 1 if sort_order_set[column.SortOrder] then sort_order_dup = true end sort_order_set[column.SortOrder] = true IM_ASSERT(sort_order_count < 64) end end -- need_fix_linearize: (1 << count) != (mask + 1) <=> the set of sort orders isn't exactly {0..count-1} local need_fix_linearize = sort_order_dup for n = 0, sort_order_count - 1 do if not sort_order_set[n] then need_fix_linearize = true end end local need_fix_single_sort_order = (sort_order_count > 1) and band(table_.Flags, ImGuiTableFlags.SortMulti) == 0 if need_fix_linearize or need_fix_single_sort_order then local fixed_mask = {} for sort_n = 0, sort_order_count - 1 do -- Fix: Rewrite sort order fields if needed so they have no gap or duplicate. local column_with_smallest_sort_order = -1 for column_n = 0, table_.ColumnsCount - 1 do if not fixed_mask[column_n] and table_.Columns[column_n].SortOrder ~= -1 then if column_with_smallest_sort_order == -1 or table_.Columns[column_n].SortOrder < table_.Columns[column_with_smallest_sort_order].SortOrder then column_with_smallest_sort_order = column_n end end end IM_ASSERT(column_with_smallest_sort_order ~= -1) fixed_mask[column_with_smallest_sort_order] = true table_.Columns[column_with_smallest_sort_order].SortOrder = sort_n -- Fix: Make sure only one column has a SortOrder if ImGuiTableFlags_MultiSortable is not set. if need_fix_single_sort_order then sort_order_count = 1 for column_n = 0, table_.ColumnsCount - 1 do if column_n ~= column_with_smallest_sort_order then table_.Columns[column_n].SortOrder = -1 end end break end end end -- Fallback default sort order (if no column with the ImGuiTableColumnFlags_DefaultSort flag) if sort_order_count == 0 and band(table_.Flags, ImGuiTableFlags.SortTristate) == 0 then for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.IsEnabled and band(column.Flags, ImGuiTableColumnFlags.NoSort) == 0 then sort_order_count = 1 column.SortOrder = 0 column.SortDirection = TableGetColumnAvailSortDirection(column, 0) break end end end table_.SortSpecsCount = sort_order_count end function ImGui.TableSortSpecsBuild(table_) local dirty = table_.IsSortSpecsDirty if dirty then ImGui.TableSortSpecsSanitize(table_) local multi = table_.SortSpecsMulti local want = (table_.SortSpecsCount <= 1) and 0 or table_.SortSpecsCount for n = #multi + 1, want do multi[n] = ImGuiTableColumnSortSpecs() end for n = #multi, want + 1, -1 do multi[n] = nil end table_.SortSpecs.SpecsDirty = true -- Mark as dirty for user table_.IsSortSpecsDirty = false -- Mark as not dirty for us end -- Write output local sort_specs if table_.SortSpecsCount == 0 then sort_specs = nil elseif table_.SortSpecsCount == 1 then table_.SortSpecsSingleArray = table_.SortSpecsSingleArray or { table_.SortSpecsSingle } sort_specs = table_.SortSpecsSingleArray else sort_specs = table_.SortSpecsMulti end if dirty and sort_specs ~= nil then for column_n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[column_n] if column.SortOrder ~= -1 then IM_ASSERT(column.SortOrder < table_.SortSpecsCount) local sort_spec = sort_specs[column.SortOrder + 1] sort_spec.ColumnUserID = column.UserData sort_spec.ColumnIndex = column_n sort_spec.SortOrder = column.SortOrder sort_spec.SortDirection = column.SortDirection end end end table_.SortSpecs.Specs = sort_specs table_.SortSpecs.SpecsCount = table_.SortSpecsCount end ---------------------------------------------------------------- -- [SECTION] Tables: Headers ---------------------------------------------------------------- function ImGui.TableGetHeaderRowHeight() -- Calculate row height, for the unlikely case that some labels may be taller than others. local g = GImGui local table_ = g.CurrentTable local row_height = g.FontSize for column_n = 0, table_.ColumnsCount - 1 do if BitTest(table_.EnabledMaskByIndex, column_n) then if band(table_.Columns[column_n].Flags, ImGuiTableColumnFlags.NoHeaderLabel) == 0 then row_height = ImMax(row_height, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n)).y) end end end return row_height + g.Style.CellPadding.y * 2.0 end function ImGui.TableGetHeaderAngledMaxLabelWidth() local g = GImGui local table_ = g.CurrentTable local width = 0.0 for column_n = 0, table_.ColumnsCount - 1 do if BitTest(table_.EnabledMaskByIndex, column_n) then if band(table_.Columns[column_n].Flags, ImGuiTableColumnFlags.AngledHeader) ~= 0 then width = ImMax(width, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n), nil, true).x) end end end return width + g.Style.CellPadding.y * 2.0 -- Swap padding end -- [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn(). function ImGui.TableHeadersRow() local g = GImGui local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") -- Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make -- it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this. if not table_.IsLayoutLocked then ImGui.TableUpdateLayout(table_) end -- Open row local row_height = ImGui.TableGetHeaderRowHeight() ImGui.TableNextRow(ImGuiTableRowFlags.Headers, row_height) local row_y1 = ImGui.GetCursorScreenPos().y if table_.HostSkipItems then -- Merely an optimization, you may skip in your own code. return end local columns_count = ImGui.TableGetColumnCount() for column_n = 0, columns_count - 1 do if ImGui.TableSetColumnIndex(column_n) or table_.LastHeldHeaderColumn == column_n then -- Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation) local name = (band(ImGui.TableGetColumnFlags(column_n), ImGuiTableColumnFlags.NoHeaderLabel) ~= 0) and "" or ImGui.TableGetColumnName(column_n) ImGui.PushID(column_n) ImGui.TableHeader(name) ImGui.PopID() end end -- Allow opening popup from the right-most section after the last column. local mouse_pos = ImGui.GetMousePos() if ImGui.IsMouseReleased(1) and ImGui.TableGetHoveredColumn() == columns_count then if mouse_pos.y >= row_y1 and mouse_pos.y < row_y1 + row_height then ImGui.TableOpenContextMenu(columns_count) -- Will open a non-column-specific popup. end end end -- Emit a column header (text + optional sort order) -- We cpu-clip text here so that all columns headers can be merged into a same draw call. function ImGui.TableHeader(label) local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end local table_ = g.CurrentTable IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT(table_.CurrentColumn ~= -1) local column_n = table_.CurrentColumn local column = table_.Columns[column_n] -- Label if label == nil then label = "" end local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local label_pos = V2(window.DC.CursorPos) -- If we already got a row height, there's use that. local cell_r = ImGui.TableGetCellBgRect(table_, column_n) local label_height = ImMax(label_size.y, table_.RowMinHeight - table_.RowCellPaddingY * 2.0) -- Calculate ideal size for sort order arrow local w_arrow = 0.0 local w_sort_text = 0.0 local sort_arrow = false local sort_order_suf = "" local ARROW_SCALE = 0.65 if band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoSort) == 0 then w_arrow = ImTrunc(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x) if column.SortOrder ~= -1 then sort_arrow = true end if column.SortOrder > 0 then sort_order_suf = string.format("%d", column.SortOrder + 1) w_sort_text = g.Style.ItemInnerSpacing.x + ImGui.CalcTextSize(sort_order_suf).x end end -- We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considered for merging. local max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow column.ContentMaxXHeadersUsed = ImMax(column.ContentMaxXHeadersUsed, sort_arrow and cell_r.Max.x or ImMin(max_pos_x, cell_r.Max.x)) column.ContentMaxXHeadersIdeal = ImMax(column.ContentMaxXHeadersIdeal, max_pos_x) -- Keep header highlighted when context menu is open. local id = window:GetID(label) local bb = ImRect(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0)) ImGui.ItemSize(ImVec2(0.0, label_height)) -- Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal if not ImGui.ItemAdd(bb, id) then return end -- Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. local highlight = (table_.HighlightColumnHeader == column_n) local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, ImGuiButtonFlags.AllowOverlap) if held or hovered or highlight then local col = ImGui.GetColorU32(held and ImGuiCol.HeaderActive or (hovered and ImGuiCol.HeaderHovered or ImGuiCol.Header)) ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, col, table_.CurrentColumn) else -- Submit single cell bg color in the case we didn't submit a full header row if band(table_.RowFlags, ImGuiTableRowFlags.Headers) == 0 then ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(ImGuiCol.TableHeaderBg), table_.CurrentColumn) end end ImGui.RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags.Compact, 0.0) if held then table_.HeldHeaderColumn = column_n end window.DC.CursorPos.y = window.DC.CursorPos.y - g.Style.ItemSpacing.y * 0.5 -- Drag and drop to re-order columns. if held and band(table_.Flags, ImGuiTableFlags.Reorderable) ~= 0 and ImGui.IsMouseDragging(0) and not g.DragDropActive then table_.InstanceInteracted = table_.InstanceCurrent if g.IO.MouseDelta.x < 0.0 and g.IO.MousePos.x < cell_r.Min.x then local prev_column = (column.PrevEnabledColumn ~= -1) and table_.Columns[column.PrevEnabledColumn] or nil if prev_column then ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, prev_column.DisplayOrder) end end if g.IO.MouseDelta.x > 0.0 and g.IO.MousePos.x > cell_r.Max.x then local next_column = (column.NextEnabledColumn ~= -1) and table_.Columns[column.NextEnabledColumn] or nil if next_column then ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, next_column.DisplayOrder) end end end -- Sort order arrow local ellipsis_max = ImMax(cell_r.Max.x - (sort_arrow and (w_arrow + w_sort_text) or 0.0), label_pos.x) if band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoSort) == 0 then if column.SortOrder ~= -1 then local x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text) local y = label_pos.y if column.SortOrder > 0 then ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.Text, 0.70)) ImGui.RenderText(ImVec2(x + g.Style.ItemInnerSpacing.x, y), sort_order_suf) ImGui.PopStyleColor() x = x + w_sort_text end ImGui.RenderArrow(window.DrawList, ImVec2(x, y), ImGui.GetColorU32(ImGuiCol.Text), (column.SortDirection == ImGuiSortDirection.Ascending) and ImGuiDir.Up or ImGuiDir.Down, ARROW_SCALE) end -- Handle clicking on column header to adjust Sort Order if pressed and table_.ReorderColumn ~= column_n then local sort_direction = ImGui.TableGetColumnNextSortDirection(column) ImGui.TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift) end end -- Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will -- be merged into a single draw call. ImGui.RenderTextEllipsis(window.DrawList, label_pos, ImVec2(ellipsis_max, bb.Max.y), ellipsis_max, label, label_end, label_size) local text_clipped = label_size.x > (ellipsis_max - label_pos.x) if text_clipped and hovered and g.ActiveId == 0 then ImGui.SetItemTooltip("%s", string.sub(label, 1, label_end - 1)) end -- We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden if ImGui.IsPopupOpenRequestForItem(ImGuiPopupFlags.None, id) then ImGui.TableOpenContextMenu(column_n) end end -- Unlike TableHeadersRow() it is not expected that you can reimplement or customize this with custom widgets. function ImGui.TableAngledHeadersRow() local g = GImGui local table_ = g.CurrentTable local temp_data = table_.TempData temp_data.AngledHeadersRequests:resize(0) -- Which column needs highlight? local row_id = ImGui.GetID("##AngledHeaders") local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) local highlight_column_n = (table_.LastHeldHeaderColumn ~= -1) and table_.LastHeldHeaderColumn or table_.HighlightColumnHeader if highlight_column_n == -1 and table_.HoveredColumnBody ~= -1 then if table_instance.HoveredRowLast == 0 and table_.HoveredColumnBorder == -1 and (g.ActiveId == 0 or g.ActiveId == row_id or (table_.IsActiveIdInTable or g.DragDropActive)) then highlight_column_n = table_.HoveredColumnBody end end -- Build up request local col_header_bg = ImGui.GetColorU32(ImGuiCol.TableHeaderBg) local col_text = ImGui.GetColorU32(ImGuiCol.Text) for order_n = 0, table_.ColumnsCount - 1 do if BitTest(table_.EnabledMaskByDisplayOrder, order_n) then local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] if band(column.Flags, ImGuiTableColumnFlags.AngledHeader) ~= 0 then -- Note: can't rely on ImGuiTableColumnFlags_IsVisible test here. temp_data.AngledHeadersRequests:push_back({ Index = column_n, TextColor = col_text, BgColor0 = col_header_bg, BgColor1 = (column_n == highlight_column_n) and ImGui.GetColorU32(ImGuiCol.Header) or 0 }) end end end -- Render row ImGui.TableAngledHeadersRowEx(row_id, g.Style.TableAngledHeadersAngle, 0.0, temp_data.AngledHeadersRequests.Data, temp_data.AngledHeadersRequests.Size) end local function ImTextCountLines(text, text_begin, text_end) local count = 0 local p = text_begin while p < text_end do local line_end = string.find(text, "\n", p, true) if line_end == nil or line_end >= text_end then p = text_end else p = line_end + 1 end count = count + 1 end return count end -- Important: data must be fed left to right --- @param data ImGuiTableHeaderData[] # 1-based array --- @param data_count int function ImGui.TableAngledHeadersRowEx(row_id, angle, max_label_width, data, data_count) local g = GImGui local table_ = g.CurrentTable local window = g.CurrentWindow local draw_list = window.DrawList IM_ASSERT_USER_ERROR_RET(table_ ~= nil, "Call should only be done while in BeginTable() scope!") IM_ASSERT(table_.CurrentRow == -1, "Must be first row") if max_label_width == 0.0 then max_label_width = ImGui.TableGetHeaderAngledMaxLabelWidth() end -- Angle argument expressed in (-IM_PI/2 .. +IM_PI/2) as it is easier to think about for user. local flip_label = (angle < 0.0) angle = angle - IM_PI * 0.5 local cos_a = ImCos(angle) local sin_a = ImSin(angle) local label_cos_a = flip_label and ImCos(angle + IM_PI) or cos_a local label_sin_a = flip_label and ImSin(angle + IM_PI) or sin_a local unit_right = ImVec2(cos_a, sin_a) -- Calculate our base metrics and set angled headers data _before_ the first call to TableNextRow() local header_height = g.FontSize + g.Style.CellPadding.x * 2.0 local row_height = ImTrunc(ImAbs(ImRotate(ImVec2(max_label_width, flip_label and header_height or -header_height), cos_a, sin_a).y)) table_.AngledHeadersHeight = row_height table_.AngledHeadersSlope = (sin_a ~= 0.0) and (cos_a / sin_a) or 0.0 local header_angled_vector = unit_right * (row_height / -sin_a) -- vector from bottom-left to top-left, and from bottom-right to top-right -- Declare row, override and draw our own background ImGui.TableNextRow(ImGuiTableRowFlags.Headers, row_height) ImGui.TableNextColumn() local row_r = ImRect(table_.WorkRect.Min.x, table_.BgClipRect.Min.y, table_.WorkRect.Max.x, table_.RowPosY2) table_.DrawSplitter:SetCurrentChannel(draw_list, TABLE_DRAW_CHANNEL_BG0) local clip_rect_min_x = table_.BgClipRect.Min.x if table_.FreezeColumnsCount > 0 then clip_rect_min_x = ImMax(clip_rect_min_x, table_.Columns[table_.DisplayOrderToIndex[table_.FreezeColumnsCount - 1]].MaxX) end ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, 0) -- Cancel ImGui.PushClipRect(table_.BgClipRect.Min, table_.BgClipRect.Max, false) -- Span all columns draw_list:AddRectFilled(ImVec2(table_.BgClipRect.Min.x, row_r.Min.y), ImVec2(table_.BgClipRect.Max.x, row_r.Max.y), ImGui.GetColorU32(ImGuiCol.TableHeaderBg, 0.25)) -- FIXME-STYLE: Change row background with an arbitrary color. ImGui.PushClipRect(ImVec2(clip_rect_min_x, table_.BgClipRect.Min.y), table_.BgClipRect.Max, true) -- Span all columns ImGui.ButtonBehavior(row_r, row_id) ImGui.KeepAliveID(row_id) local ascent_scaled = g.FontBaked.Ascent * g.FontBakedScale -- FIXME: Standardize those scaling factors better local line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5, 0.0) / -sin_a) * (flip_label and -1.0 or 1.0) local padding = g.Style.CellPadding -- We will always use swapped component local align = g.Style.TableAngledHeadersTextAlign -- Draw background and labels in first pass, then all borders. local max_x = -FLT_MAX for pass = 0, 1 do for order_n = 0, data_count - 1 do local request = data[order_n + 1] local column_n = request.Index local column = table_.Columns[column_n] local bg_shape = {} bg_shape[0] = ImVec2(column.MaxX, row_r.Max.y) bg_shape[1] = ImVec2(column.MinX, row_r.Max.y) bg_shape[2] = bg_shape[1] + header_angled_vector bg_shape[3] = bg_shape[0] + header_angled_vector if pass == 0 then -- Draw shape draw_list:AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], request.BgColor0) draw_list:AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], request.BgColor1) -- Optional highlight max_x = ImMax(max_x, bg_shape[3].x) -- Draw label local label_name = ImGui.TableGetColumnName(table_, column_n) local label_name_end = ImGui.FindRenderedTextEnd(label_name) local line_off_step_x = (g.FontSize / -sin_a) local label_lines = ImTextCountLines(label_name, 1, label_name_end) -- Left<>Right alignment local line_off_curr_x = flip_label and ((label_lines - 1) * line_off_step_x) or 0.0 local line_off_for_align_x = ImFloor(ImMax((((column.MaxX - column.MinX) - padding.x * 2.0) - (label_lines * line_off_step_x)), 0.0) * align.x) line_off_curr_x = line_off_curr_x + line_off_for_align_x - line_off_for_ascent_x -- Register header width local w = column.WorkMinX + ImCeil(label_lines * line_off_step_x - line_off_for_align_x) column.ContentMaxXHeadersUsed = w; column.ContentMaxXHeadersIdeal = w local p = 1 while p < label_name_end do local label_name_eol = string.find(label_name, "\n", p, true) if label_name_eol == nil or label_name_eol > label_name_end then label_name_eol = label_name_end end local line = string.sub(label_name, p, label_name_eol - 1) -- FIXME: Individual line clipping for right-most column is broken for negative angles. local label_size = ImGui.CalcTextSize(line) local clip_width = max_label_width - padding.y -- Using padding.y*2.0f would be symmetrical but hide more text. local clip_height = ImMin(label_size.y, column.ClipRect.Max.x - column.WorkMinX - line_off_curr_x) local clip_r = ImRect(window.ClipRect.Min, window.ClipRect.Min + ImVec2(clip_width, clip_height)) local vtx_idx_begin = draw_list._VtxCurrentIdx ImGui.PushStyleColor(ImGuiCol.Text, request.TextColor) ImGui.RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, line, #line + 1, label_size) ImGui.PopStyleColor() local vtx_idx_end = draw_list._VtxCurrentIdx -- Up<>Down alignment local available_space = ImMax(clip_width - label_size.x + ImAbs(padding.x * cos_a) * 2.0 - ImAbs(padding.y * sin_a) * 2.0, 0.0) local vertical_offset = available_space * align.y * (flip_label and -1.0 or 1.0) -- Rotate and offset label local pivot_in = ImVec2(window.ClipRect.Min.x - vertical_offset, window.ClipRect.Min.y + label_size.y) local pivot_out = ImVec2(column.WorkMinX, row_r.Max.y) line_off_curr_x = line_off_curr_x + (flip_label and -line_off_step_x or line_off_step_x) pivot_out = pivot_out + unit_right * padding.y if flip_label then pivot_out = pivot_out + unit_right * (clip_width - ImMax(0.0, clip_width - label_size.x)) end pivot_out.x = pivot_out.x + (flip_label and (line_off_curr_x + line_off_step_x) or line_off_curr_x) ImGui.ShadeVertsTransformPos(draw_list, vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out) -- Rotate and offset p = label_name_eol + 1 end end if pass == 1 then -- Draw border local border_size = TABLE_BORDER_SIZE draw_list:AddLine(bg_shape[0] + ImVec2(border_size * 0.5, 0.0), bg_shape[3] + ImVec2(border_size * 0.5, 0.0), TableGetColumnBorderCol(table_, order_n, column_n), border_size) end end end ImGui.PopClipRect() ImGui.PopClipRect() table_.TempData.AngledHeadersExtraWidth = ImMax(0.0, max_x - table_.Columns[table_.RightMostEnabledColumn].MaxX) end ---------------------------------------------------------------- -- [SECTION] Tables: Context Menu ---------------------------------------------------------------- -- Use -1 to open menu not specific to a given column. function ImGui.TableOpenContextMenu(column_n) if column_n == nil then column_n = -1 end local g = GImGui local table_ = g.CurrentTable if column_n == -1 and table_.CurrentColumn ~= -1 then -- When called within a column automatically use this one (for consistency) column_n = table_.CurrentColumn end if column_n == table_.ColumnsCount then -- To facilitate using with TableGetHoveredColumn() column_n = -1 end IM_ASSERT(column_n >= -1 and column_n < table_.ColumnsCount) if band(table_.Flags, bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable)) ~= 0 then table_.IsContextPopupOpen = true table_.ContextPopupColumn = column_n table_.InstanceInteracted = table_.InstanceCurrent local context_menu_id = ImHashStr("##ContextMenu", nil, table_.ID) ImGui.OpenPopupEx(context_menu_id, ImGuiPopupFlags.None) end end function ImGui.TableBeginContextMenuPopup(table_) if not table_.IsContextPopupOpen or table_.InstanceCurrent ~= table_.InstanceInteracted then return false end local context_menu_id = ImHashStr("##ContextMenu", nil, table_.ID) if ImGui.BeginPopupEx(context_menu_id, bor(ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings)) then return true end table_.IsContextPopupOpen = false return false end -- FIXME: Copied from MenuItem() for the purpose of being able to pass _SelectOnRelease (#9312) local function MenuItemForColumnReorder(label, selected, enabled) local g = GImGui local window = g.CurrentWindow local label_size = ImGui.CalcTextSize(label, nil, true) local offsets = window.DC.MenuColumns local checkmark_w = IM_TRUNC(g.FontSize * 1.20) local min_w = offsets:DeclColumns(0.0, label_size.x, 0.0, checkmark_w) -- Feedback for next frame local stretch_w = ImMax(0.0, ImGui.GetContentRegionAvail().x - min_w) local text_pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y + window.DC.CurrLineTextBaseOffset) local id = ImGui.GetID(label) local selectable_flags = bor(ImGuiSelectableFlags.SelectOnRelease, ImGuiSelectableFlags.SpanAvailWidth) if g.ActiveId == id then selectable_flags = bor(selectable_flags, ImGuiSelectableFlags.Highlight) -- Stays highlighted while dragging. end local has_been_moved = (g.ActiveId == id) and g.ActiveIdHasBeenEditedBefore -- But disable toggling once moved. ImGui.BeginDisabled(not enabled) -- Don't use ImGuiSelectableFlags_Disabled so that Check mark is also affected. local ret = ImGui.Selectable(label, false, selectable_flags, ImVec2(min_w, label_size.y)) and not has_been_moved if band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0 and selected then ImGui.RenderCheckMark(window.DrawList, text_pos + ImVec2(offsets.OffsetMark + stretch_w + g.FontSize * 0.40, g.FontSize * 0.134 * 0.5), ImGui.GetColorU32(ImGuiCol.Text), g.FontSize * 0.866) end ImGui.EndDisabled() return ret end -- Output context menu into current window (generally a popup) function ImGui.TableDrawDefaultContextMenu(table_, flags_for_section_to_display) local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end local want_separator = false local context_column_n = (table_.ContextPopupColumn >= 0 and table_.ContextPopupColumn < table_.ColumnsCount) and table_.ContextPopupColumn or -1 local context_column = (context_column_n ~= -1) and table_.Columns[context_column_n] or nil -- Sizing if band(flags_for_section_to_display, ImGuiTableFlags.Resizable) ~= 0 then if context_column ~= nil then local can_resize = band(context_column.Flags, ImGuiTableColumnFlags.NoResize) == 0 and context_column.IsEnabled if ImGui.MenuItem(ImGui.LocalizeGetMsg(ImGuiLocKey.TableSizeOne), nil, false, can_resize) then -- "###SizeOne" ImGui.TableSetColumnWidthAutoSingle(table_, context_column_n) end end local size_all_desc if table_.ColumnsEnabledFixedCount == table_.ColumnsEnabledCount and band(table_.Flags, ImGuiTableFlags.SizingMask_) ~= ImGuiTableFlags.SizingFixedSame then size_all_desc = ImGui.LocalizeGetMsg(ImGuiLocKey.TableSizeAllFit) -- "###SizeAll" All fixed else size_all_desc = ImGui.LocalizeGetMsg(ImGuiLocKey.TableSizeAllDefault) -- "###SizeAll" All stretch or mixed end if ImGui.MenuItem(size_all_desc, nil) then ImGui.TableSetColumnWidthAutoAll(table_) end want_separator = true end -- Reset Order/Visibility etc. if band(flags_for_section_to_display, bor(ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable)) ~= 0 then if ImGui.BeginMenu(ImGui.LocalizeGetMsg(ImGuiLocKey.TableReset)) then if band(flags_for_section_to_display, ImGuiTableFlags.Reorderable) ~= 0 then if ImGui.MenuItem(ImGui.LocalizeGetMsg(ImGuiLocKey.TableResetOrder), nil, false, not table_.IsDefaultDisplayOrder) then -- PS: cannot be hidden because it would mess with drag reordering. table_.IsResetDisplayOrderRequest = true end end if band(flags_for_section_to_display, ImGuiTableFlags.Hideable) ~= 0 then if ImGui.MenuItem(ImGui.LocalizeGetMsg(ImGuiLocKey.TableResetVisibility), nil, false, not table_.IsDefaultVisibility) then table_.IsResetVisibilityRequest = true end end ImGui.EndMenu() end end -- Hiding / Visibility if band(flags_for_section_to_display, ImGuiTableFlags.Hideable) ~= 0 then if want_separator then ImGui.Separator() end want_separator = true -- While reordering: we calculate min/max allowed range once here so we can avoid a O(N log N) in the loop. local is_reordering = (g.ActiveId ~= 0 and g.ActiveIdWindow == g.CurrentWindow and table_.ReorderColumn ~= -1 and g.ActiveIdHasBeenEditedBefore) -- FIXME: This is a bit of a hack. local reorder_src_order = is_reordering and table_.Columns[table_.ReorderColumn].DisplayOrder or -1 local reorder_min_order = is_reordering and TableGetMaxDisplayOrderAllowed(table_, reorder_src_order, 0) or 0 local reorder_max_order = is_reordering and TableGetMaxDisplayOrderAllowed(table_, reorder_src_order, table_.ColumnsCount - 1) or (table_.ColumnsCount - 1) ImGui.PushItemFlag(ImGuiItemFlags.AutoClosePopups, false) for order_n = 0, table_.ColumnsCount - 1 do local column_n = table_.DisplayOrderToIndex[order_n] local column = table_.Columns[column_n] if band(column.Flags, ImGuiTableColumnFlags.Disabled) == 0 then local name = ImGui.TableGetColumnName(table_, column_n) if name == nil or name == "" then name = "" end -- Make sure we can't hide the last active column local menu_item_enabled = band(column.Flags, ImGuiTableColumnFlags.NoHide) == 0 if column.IsUserEnabled and table_.ColumnsEnabledCount <= 1 then menu_item_enabled = false end if is_reordering and (column.DisplayOrder < reorder_min_order or column.DisplayOrder > reorder_max_order) then menu_item_enabled = false end if MenuItemForColumnReorder(name, column.IsUserEnabled, menu_item_enabled) then column.IsUserEnabledNextFrame = not column.IsUserEnabled end -- Drag to reorder if ImGui.IsItemActive() and ImGui.IsMouseDragging(0) and g.ActiveIdSource == ImGuiInputSource.Mouse and band(table_.Flags, ImGuiTableFlags.Reorderable) ~= 0 then g.ActiveIdHasBeenEditedBefore = true -- Disable toggle in MenuItemForColumnReorder() + start dimming to display allowed reorder targets. table_.ReorderColumn = column_n if not ImGui.IsItemHovered() then local reorder_dir = (g.IO.MousePos.y < (g.LastItemData.Rect.Min.y + g.LastItemData.Rect.Max.y) * 0.5) and -1 or 1 local reorder_amount = ((reorder_dir < 0) and (g.LastItemData.Rect.Min.y - g.IO.MousePos.y) or (g.IO.MousePos.y - g.LastItemData.Rect.Max.y)) / g.LastItemData.Rect:GetHeight() local dst_order = column.DisplayOrder + ImTrunc(ImCeil(reorder_amount)) * reorder_dir -- Estimated target order, will be validated and clamped. ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, dst_order) end end end end ImGui.PopItemFlag() end end ---------------------------------------------------------------- -- [SECTION] Tables: Settings (.ini data) ---------------------------------------------------------------- -- Clear and initialize empty settings instance local function TableSettingsInit(settings, id, columns_count, columns_count_max) for k, v in pairs(ImGuiTableSettings()) do settings[k] = v end for n = 0, columns_count_max - 1 do settings.Columns[n] = ImGuiTableColumnSettings() end settings.ID = id settings.ColumnsCount = columns_count settings.ColumnsCountMax = columns_count_max settings.WantApply = true end function ImGui.TableSettingsCreate(id, columns_count) local g = GImGui local settings = ImGui.TableSettingsFindByID(id) if settings then if settings.ColumnsCountMax >= columns_count then TableSettingsInit(settings, id, columns_count, settings.ColumnsCountMax) -- Recycle return settings end settings.ID = 0 -- Invalidate storage, we won't fit because of a count change end settings = ImGuiTableSettings() g.SettingsTables:push_back(settings) TableSettingsInit(settings, id, columns_count, columns_count) return settings end -- Find existing settings function ImGui.TableSettingsFindByID(id) local g = GImGui for _, settings in g.SettingsTables:iter() do if settings.ID == id then return settings end end return nil end local function SettingsTablesOffsetFromPtr(settings) local g = GImGui return g.SettingsTables:find_index(settings) or -1 end -- Get settings for a given table, NULL if none function ImGui.TableGetBoundSettings(table_) if table_.SettingsOffset == -1 then return nil end local g = GImGui local settings = g.SettingsTables.Data[table_.SettingsOffset] IM_ASSERT(settings.ID == table_.ID) return settings end -- Restore initial state of table (with or without saved settings) function ImGui.TableResetSettings(table_) table_.IsInitializing = true; table_.IsSettingsDirty = true table_.IsResetAllRequest = false table_.IsSettingsRequestLoad = false -- Don't reload from ini table_.SettingsLoadedFlags = ImGuiTableFlags.None -- Mark as nothing loaded so our initialized data becomes authoritative end function ImGui.TableSaveSettings(table_) table_.IsSettingsDirty = false if band(table_.Flags, ImGuiTableFlags.NoSavedSettings) ~= 0 then return end -- Bind or create settings data local settings = ImGui.TableGetBoundSettings(table_) if settings ~= nil and table_.ColumnsCount > settings.ColumnsCountMax then settings.ID = 0 -- Invalidate storage, we won't fit because of a count change settings = nil end if settings == nil then settings = ImGui.TableSettingsCreate(table_.ID, table_.ColumnsCount) table_.SettingsOffset = SettingsTablesOffsetFromPtr(settings) end settings.ColumnsCount = table_.ColumnsCount -- Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings IM_ASSERT(settings.ID == table_.ID) IM_ASSERT(settings.ColumnsCount == table_.ColumnsCount and settings.ColumnsCountMax >= settings.ColumnsCount) local save_ref_scale = false settings.SaveFlags = ImGuiTableFlags.None for n = 0, table_.ColumnsCount - 1 do local column = table_.Columns[n] local column_settings = settings.Columns[n] local width_or_weight = (band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0) and column.StretchWeight or column.WidthRequest column_settings.ID = column.ID column_settings.WidthOrWeight = width_or_weight column_settings.Index = n column_settings.DisplayOrder = column.DisplayOrder column_settings.SortOrder = column.SortOrder column_settings.SortDirection = column.SortDirection column_settings.IsEnabled = column.IsUserEnabled and 1 or 0 column_settings.IsStretch = (band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0) and 1 or 0 if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) == 0 then save_ref_scale = true end -- We skip saving some data in the .ini file when they are unnecessary to restore our state. if width_or_weight ~= column.InitStretchWeightOrWidth then settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Resizable) end if column.DisplayOrder ~= n then settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Reorderable) end if column.SortOrder ~= -1 then settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Sortable, ImGuiTableFlags.Reorderable) -- Because SortOrder saving itself is gated, make sure every column is saved (#9519) end if column.IsUserEnabled ~= (band(column.Flags, ImGuiTableColumnFlags.DefaultHide) == 0) then settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Hideable) end end settings.SaveFlags = band(settings.SaveFlags, table_.Flags) settings.RefScale = save_ref_scale and table_.RefScale or 0.0 ImGui.MarkIniSettingsDirty() end function ImGui.TableLoadSettings(table_) if band(table_.Flags, ImGuiTableFlags.NoSavedSettings) ~= 0 then table_.IsSettingsRequestLoad = false -- Done return end -- Bind settings local settings if table_.SettingsOffset == -1 then settings = ImGui.TableSettingsFindByID(table_.ID) if settings == nil then return end if settings.ColumnsCount ~= table_.ColumnsCount then -- Allow settings if columns count changed. We could otherwise decide to return... table_.IsSettingsDirty = true end table_.SettingsOffset = SettingsTablesOffsetFromPtr(settings) else settings = ImGui.TableGetBoundSettings(table_) end table_.SettingsLoadedFlags = settings.SaveFlags table_.RefScale = settings.RefScale -- TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data. end -- NB: This was written to be similar to the logic in TableReconcileColumns(). function ImGui.TableLoadSettingsForColumns(table_) for n = 0, table_.ColumnsSize - 1 do table_.Columns[n].IsLoadedSettings = false end local settings = ImGui.TableGetBoundSettings(table_) if settings == nil then return end table_.SettingsLoadedFlags = bor(table_.SettingsLoadedFlags, ImGuiTableFlags.Reorderable) -- We handle above in code above. -- Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn local column_settings = settings.Columns -- Fast path local matches = 0 for n = 0, table_.ColumnsCount - 1 do if n >= settings.ColumnsCount or column_settings[n].ID ~= table_.Columns[n].ID then break end ImGui.TableLoadSettingsForColumn(table_.Columns[n], column_settings[n], settings.SaveFlags) matches = matches + 1 end if matches == settings.ColumnsCount then return end local settings_start_n = matches -- Small optimization for n = settings_start_n, settings.ColumnsCount - 1 do column_settings[n].IsLoaded = false end -- Find matches for named columns for c = 0, table_.ColumnsSize - 1 do local column = table_.Columns[c] if column.ID ~= 0 and not column.IsLoadedSettings then for n = settings_start_n, settings.ColumnsCount - 1 do if column_settings[n].ID == column.ID and not column_settings[n].IsLoaded then ImGui.TableLoadSettingsForColumn(column, column_settings[n], settings.SaveFlags) matches = matches + 1 break end end end end -- Remaining entries are matched sequentially local dst_idx = 0 for n = settings_start_n, settings.ColumnsCount - 1 do if not column_settings[n].IsLoaded then while dst_idx < table_.ColumnsCount and table_.Columns[dst_idx].IsLoadedSettings do dst_idx = dst_idx + 1 end if dst_idx >= table_.ColumnsCount then break end ImGui.TableLoadSettingsForColumn(table_.Columns[dst_idx], column_settings[n], settings.SaveFlags) dst_idx = dst_idx + 1 end end end function ImGui.TableLoadSettingsForColumn(column, column_settings, load_flags) column.IsLoadedSettings = true column_settings.IsLoaded = true if band(load_flags, ImGuiTableFlags.Resizable) ~= 0 then if column_settings.IsStretch ~= 0 then column.StretchWeight = column_settings.WidthOrWeight else column.WidthRequest = column_settings.WidthOrWeight end column.AutoFitQueue = 0x00 end if band(load_flags, ImGuiTableFlags.Reorderable) ~= 0 then column.DisplayOrder = column_settings.DisplayOrder else column.DisplayOrder = column_settings.Index -- Because default depends on previous Index, we need to set that up and cannot rely on TableInitColumnDefaults() end if band(load_flags, ImGuiTableFlags.Hideable) ~= 0 and column_settings.IsEnabled ~= -1 then local v = (column_settings.IsEnabled == 1) column.IsUserEnabled = v; column.IsUserEnabledNextFrame = v end column.SortOrder = column_settings.SortOrder column.SortDirection = column_settings.SortDirection end -- Fix invalid display order data: compact values (0,1,3 -> 0,1,2); preserve relative order (0,3,1 -> 0,2,1); deduplicate (0,4,1,1 -> 0,3,1,2) function ImGui.TableFixDisplayOrder(table_) if band(table_.Flags, ImGuiTableFlags.Reorderable) == 0 then for n = 0, table_.ColumnsCount - 1 do table_.Columns[n].DisplayOrder = n table_.DisplayOrderToIndex[n] = n end return end local fdo_columns = {} for n = 0, table_.ColumnsCount - 1 do fdo_columns[n + 1] = n end -- Sort by DisplayOrder and then Index. -1 (unsigned short 0xFFFF) always sorts after. local function key(idx) local o = table_.Columns[idx].DisplayOrder if o < 0 then o = o + 0x10000 end return o end table.sort(fdo_columns, function(lhs_idx, rhs_idx) local a, b = key(lhs_idx), key(rhs_idx) if a ~= b then return a < b end return lhs_idx < rhs_idx end) for n = 0, table_.ColumnsCount - 1 do table_.Columns[fdo_columns[n + 1]].DisplayOrder = n end for n = 0, table_.ColumnsCount - 1 do table_.DisplayOrderToIndex[table_.Columns[n].DisplayOrder] = n end end local function ForEachTable(g, fn) for i = 0, g.Tables:GetMapSize() - 1 do local t = g.Tables:GetByIndex(i) if t then fn(t) end end end local function TableSettingsHandler_ClearAll(ctx, handler) local g = ctx ForEachTable(g, function(t) t.SettingsOffset = -1 end) g.SettingsTables:clear() end -- Apply to existing windows (if any) local function TableSettingsHandler_ApplyAll(ctx, handler) local g = ctx ForEachTable(g, function(t) t.IsSettingsRequestLoad = true t.SettingsOffset = -1 end) end local function TableSettingsHandler_ReadOpen(ctx, handler, name) local id, columns_count = string.match(name, "^0x(%x+),(%-?%d+)") if id == nil then return nil end id = tonumber(id, 16); columns_count = tonumber(columns_count) if columns_count <= 0 or columns_count >= IMGUI_TABLE_MAX_COLUMNS then return nil end return ImGui.TableSettingsCreate(id, columns_count) end local function TableSettingsHandler_ReadLine(ctx, handler, settings, line) -- "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" if settings == nil then return end local f = string.match(line, "^RefScale=([%-%d%.eE+]+)") if f then settings.RefScale = tonumber(f); return end local n = string.match(line, "^LastUsed=(%d+)") if n then settings.LastUsedDate = tonumber(n); return end local column_n, rest = string.match(line, "^Column (%-?%d+)(.*)$") if column_n then column_n = tonumber(column_n) if column_n < 0 or column_n >= settings.ColumnsCount then return end local column = settings.Columns[column_n] column.Index = column_n local function take(pattern) local a, b, r = string.match(rest, "^%s*" .. pattern .. "()") if a == nil then return nil end if r == nil then r = b; b = nil end rest = string.sub(rest, r) return a, b end take("UserID=0x(%x+)") -- FIXME-LEGACY: Removed 2025/11/12, was never properly set. local v = take("Width=(%-?%d+)") if v then column.WidthOrWeight = tonumber(v); column.IsStretch = 0; settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Resizable) end v = take("Weight=([%-%d%.eE+]+)") if v then column.WidthOrWeight = tonumber(v); column.IsStretch = 1; settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Resizable) end v = take("Visible=(%-?%d+)") if v then column.IsEnabled = tonumber(v); settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Hideable) end v = take("Order=(%-?%d+)") if v then column.DisplayOrder = tonumber(v); settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Reorderable) end local c v, c = take("Sort=(%-?%d+)(.)") if v then column.SortOrder = tonumber(v); column.SortDirection = (c == "^") and ImGuiSortDirection.Descending or ImGuiSortDirection.Ascending; settings.SaveFlags = bor(settings.SaveFlags, ImGuiTableFlags.Sortable) end v = take("ID=0x(%x+)") if v then column.ID = tonumber(v, 16) end end end local function TableSettingsHandler_WriteAll(ctx, handler, buf) local g = ctx for _, settings in g.SettingsTables:iter() do if settings.ID ~= 0 then -- Skip ditched settings local save_size = band(settings.SaveFlags, ImGuiTableFlags.Resizable) ~= 0 local save_visible = band(settings.SaveFlags, ImGuiTableFlags.Hideable) ~= 0 local save_order = band(settings.SaveFlags, ImGuiTableFlags.Reorderable) ~= 0 local save_sort = band(settings.SaveFlags, ImGuiTableFlags.Sortable) ~= 0 -- We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings". buf:appendf("[%s][0x%08X,%d]\n", handler.TypeName, settings.ID, settings.ColumnsCount) if settings.RefScale ~= 0.0 then buf:appendf("RefScale=%g\n", settings.RefScale) end for column_n = 0, settings.ColumnsCount - 1 do local column = settings.Columns[column_n] local save_column = save_size or save_visible or save_order or (save_sort and column.SortOrder ~= -1) if save_column then buf:appendf("Column %-2d", column_n) if save_size and column.IsStretch ~= 0 then buf:appendf(" Weight=%.4f", column.WidthOrWeight) end if save_size and column.IsStretch == 0 then buf:appendf(" Width=%d", ImTrunc(column.WidthOrWeight)) end if save_visible then buf:appendf(" Visible=%d", column.IsEnabled) end if save_order then buf:appendf(" Order=%d", column.DisplayOrder) end if save_sort and column.SortOrder ~= -1 then buf:appendf(" Sort=%d%s", column.SortOrder, (column.SortDirection == ImGuiSortDirection.Ascending) and "v" or "^") end if column.ID ~= 0 then buf:appendf(" ID=0x%08X", column.ID) end buf:append("\n") end end if g.IO.ConfigIniSettingsSaveLastUsedDate and settings.LastUsedDate ~= 0 then buf:appendf("LastUsed=%08d\n", settings.LastUsedDate) end buf:append("\n") end end end function ImGui.TableSettingsAddSettingsHandler() local ini_handler = ImGuiSettingsHandler() ini_handler.TypeName = "Table" ini_handler.TypeHash = ImHashStr("Table") ini_handler.ClearAllFn = TableSettingsHandler_ClearAll ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen ini_handler.ReadLineFn = TableSettingsHandler_ReadLine ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll ini_handler.WriteAllFn = TableSettingsHandler_WriteAll ImGui.AddSettingsHandler(ini_handler) end ---------------------------------------------------------------- -- [SECTION] Tables: Garbage Collection ---------------------------------------------------------------- -- Remove Table data (currently only used by TestEngine) function ImGui.TableRemove(table_) local g = GImGui local table_idx = g.Tables:GetIndex(table_) g.Tables:Remove(table_.ID, table_) g.TablesLastTimeActive.Data[table_idx + 1] = -1.0 end -- Free up/compact internal Table buffers for when it gets unused -- Overloads: (ImGuiTable) / (ImGuiTableTempData) function ImGui.TableGcCompactTransientBuffers(t) if not t then return end if t.TableIndex ~= nil then -- ImGuiTableTempData t.AngledHeadersRequests:clear() t.DrawSplitter:ClearFreeMemory() t.LastTimeActive = -1.0 return end local g = GImGui local table_ = t IM_ASSERT(table_.MemoryCompacted == false) table_.SortSpecs.Specs = nil table.clear(table_.SortSpecsMulti) table_.IsSortSpecsDirty = true -- FIXME: In theory shouldn't have to leak into user performing a sort on resume. table.clear(table_.ColumnsNames) table_.MemoryCompacted = true for n = 0, table_.ColumnsCount - 1 do table_.Columns[n].NameOffset = -1 end g.TablesLastTimeActive.Data[g.Tables:GetIndex(table_) + 1] = -1.0 end -- Compact and remove unused or resize settings data function ImGui.TableGcCompactSettings() local g = GImGui local has_dead = false for _, settings in g.SettingsTables:iter() do if settings.ID == 0 then has_dead = true end end if not has_dead then return end local new_list = ImVector() for _, settings in g.SettingsTables:iter() do if settings.ID ~= 0 then new_list:push_back(settings) end end g.SettingsTables = new_list ForEachTable(g, function(t) t.SettingsOffset = -1 end) end ---------------------------------------------------------------- -- [SECTION] Columns, BeginColumns, EndColumns, etc. -- (This is a legacy API, prefer using BeginTable/EndTable!) ---------------------------------------------------------------- -- (Lua: columns.Columns is an ImVector, column n lives in .Data[n + 1]) function ImGui.GetColumnIndex() local window = ImGui.GetCurrentWindowRead() return window.DC.CurrentColumns and window.DC.CurrentColumns.Current or 0 end function ImGui.GetColumnsCount() local window = ImGui.GetCurrentWindowRead() return window.DC.CurrentColumns and window.DC.CurrentColumns.Count or 1 end function ImGui.GetColumnOffsetFromNorm(columns, offset_norm) return offset_norm * (columns.OffMaxX - columns.OffMinX) end function ImGui.GetColumnNormFromOffset(columns, offset) return offset / (columns.OffMaxX - columns.OffMinX) end local COLUMNS_HIT_RECT_HALF_THICKNESS = 4.0 local function GetDraggedColumnOffset(columns, column_index) -- Active (dragged) column always follow mouse. local g = GImGui local window = g.CurrentWindow IM_ASSERT(column_index > 0) -- We are not supposed to drag column 0. IM_ASSERT(g.ActiveId == band(columns.ID + column_index, 0xFFFFFFFF)) local x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + ImTrunc(COLUMNS_HIT_RECT_HALF_THICKNESS * g.CurrentDpiScale) - window.Pos.x x = ImMax(x, ImGui.GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing) if band(columns.Flags, ImGuiOldColumnFlags.NoPreserveWidths) ~= 0 then x = ImMin(x, ImGui.GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing) end return x end function ImGui.GetColumnOffset(column_index) if column_index == nil then column_index = -1 end local window = ImGui.GetCurrentWindowRead() local columns = window.DC.CurrentColumns if columns == nil then return 0.0 end if column_index < 0 then column_index = columns.Current end IM_ASSERT(column_index < columns.Columns.Size) local t = columns.Columns.Data[column_index + 1].OffsetNorm local x_offset = ImLerp(columns.OffMinX, columns.OffMaxX, t) return x_offset end local function GetColumnWidthEx(columns, column_index, before_resize) if column_index < 0 then column_index = columns.Current end local d = columns.Columns.Data local offset_norm if before_resize then offset_norm = d[column_index + 2].OffsetNormBeforeResize - d[column_index + 1].OffsetNormBeforeResize else offset_norm = d[column_index + 2].OffsetNorm - d[column_index + 1].OffsetNorm end return ImGui.GetColumnOffsetFromNorm(columns, offset_norm) end function ImGui.GetColumnWidth(column_index) if column_index == nil then column_index = -1 end local g = GImGui local window = g.CurrentWindow local columns = window.DC.CurrentColumns if columns == nil then return ImGui.GetContentRegionAvail().x end if column_index < 0 then column_index = columns.Current end local d = columns.Columns.Data return ImGui.GetColumnOffsetFromNorm(columns, d[column_index + 2].OffsetNorm - d[column_index + 1].OffsetNorm) end function ImGui.SetColumnOffset(column_index, offset) local g = GImGui local window = g.CurrentWindow local columns = window.DC.CurrentColumns IM_ASSERT(columns ~= nil) if column_index < 0 then column_index = columns.Current end IM_ASSERT(column_index < columns.Columns.Size) local preserve_width = band(columns.Flags, ImGuiOldColumnFlags.NoPreserveWidths) == 0 and (column_index < columns.Count - 1) local width = preserve_width and GetColumnWidthEx(columns, column_index, columns.IsBeingResized) or 0.0 if band(columns.Flags, ImGuiOldColumnFlags.NoForceWithinWindow) == 0 then offset = ImMin(offset, columns.OffMaxX - g.Style.ColumnsMinSpacing * (columns.Count - column_index)) end columns.Columns.Data[column_index + 1].OffsetNorm = ImGui.GetColumnNormFromOffset(columns, offset - columns.OffMinX) if preserve_width then ImGui.SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)) end end function ImGui.SetColumnWidth(column_index, width) local window = ImGui.GetCurrentWindowRead() local columns = window.DC.CurrentColumns IM_ASSERT(columns ~= nil) if column_index < 0 then column_index = columns.Current end ImGui.SetColumnOffset(column_index + 1, ImGui.GetColumnOffset(column_index) + width) end function ImGui.PushColumnClipRect(column_index) local window = ImGui.GetCurrentWindowRead() local columns = window.DC.CurrentColumns if column_index < 0 then column_index = columns.Current end local column = columns.Columns.Data[column_index + 1] ImGui.PushClipRect(column.ClipRect.Min, column.ClipRect.Max, false) end -- Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) function ImGui.PushColumnsBackground() local window = ImGui.GetCurrentWindowRead() local columns = window.DC.CurrentColumns if columns.Count == 1 then return end -- Optimization: avoid SetCurrentChannel() + PushClipRect() ImRect_Copy(columns.HostBackupClipRect, window.ClipRect) ImGui.SetWindowClipRectBeforeSetChannel(window, columns.HostInitialClipRect) columns.Splitter:SetCurrentChannel(window.DrawList, 0) end function ImGui.PopColumnsBackground() local window = ImGui.GetCurrentWindowRead() local columns = window.DC.CurrentColumns if columns.Count == 1 then return end -- Optimization: avoid PopClipRect() + SetCurrentChannel() ImGui.SetWindowClipRectBeforeSetChannel(window, columns.HostBackupClipRect) columns.Splitter:SetCurrentChannel(window.DrawList, columns.Current + 1) end function ImGui.FindOrCreateColumns(window, id) -- We have few columns per window so for now we don't need bother much with turning this into a faster lookup. for _, c in window.ColumnsStorage:iter() do if c.ID == id then return c end end local columns = ImGuiOldColumns() window.ColumnsStorage:push_back(columns) columns.ID = id return columns end function ImGui.GetColumnsID(str_id, columns_count) local window = ImGui.GetCurrentWindow() -- Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. ImGui.PushID(0x11223347 + (str_id and 0 or columns_count)) local id = window:GetID(str_id or "columns") ImGui.PopID() return id end function ImGui.BeginColumns(str_id, columns_count, flags) if flags == nil then flags = 0 end local g = GImGui local window = ImGui.GetCurrentWindow() IM_ASSERT(columns_count >= 1) IM_ASSERT(window.DC.CurrentColumns == nil) -- Nested columns are currently not supported -- Acquire storage for the columns set local id = ImGui.GetColumnsID(str_id, columns_count) local columns = ImGui.FindOrCreateColumns(window, id) IM_ASSERT(columns.ID == id) columns.Current = 0 columns.Count = columns_count columns.Flags = flags window.DC.CurrentColumns = columns window.DC.NavIsScrollPushableX = false -- Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); columns.HostCursorPosY = window.DC.CursorPos.y columns.HostCursorMaxPosX = window.DC.CursorMaxPos.x ImRect_Copy(columns.HostInitialClipRect, window.ClipRect) ImRect_Copy(columns.HostBackupParentWorkRect, window.ParentWorkRect) ImRect_Copy(window.ParentWorkRect, window.WorkRect) -- Set state for first column local column_padding = g.Style.ItemSpacing.x local half_clip_extend_x = ImTrunc(ImMax(window.WindowPadding.x * 0.5, window.WindowBorderSize)) local max_1 = window.WorkRect.Max.x + column_padding - ImMax(column_padding - window.WindowPadding.x, 0.0) local max_2 = window.WorkRect.Max.x + half_clip_extend_x columns.OffMinX = window.DC.Indent.x - column_padding + ImMax(column_padding - window.WindowPadding.x, 0.0) columns.OffMaxX = ImMax(ImMin(max_1, max_2) - window.Pos.x, columns.OffMinX + 1.0) columns.LineMinY = window.DC.CursorPos.y; columns.LineMaxY = window.DC.CursorPos.y -- Clear data if columns count changed if columns.Columns.Size ~= 0 and columns.Columns.Size ~= columns_count + 1 then columns.Columns:resize(0) end -- Initialize default widths columns.IsFirstFrame = (columns.Columns.Size == 0) if columns.Columns.Size == 0 then for n = 0, columns_count do local column = ImGuiOldColumnData() column.OffsetNorm = n / columns_count columns.Columns:push_back(column) end end for n = 0, columns_count - 1 do -- Compute clipping rectangle local column = columns.Columns.Data[n + 1] local clip_x1 = IM_ROUND(window.Pos.x + ImGui.GetColumnOffset(n)) local clip_x2 = IM_ROUND(window.Pos.x + ImGui.GetColumnOffset(n + 1) - 1.0) column.ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, FLT_MAX) column.ClipRect:ClipWithFull(window.ClipRect) end if columns.Count > 1 then columns.Splitter:Split(window.DrawList, 1 + columns.Count) columns.Splitter:SetCurrentChannel(window.DrawList, 1) ImGui.PushColumnClipRect(0) end -- We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. local offset_0 = ImGui.GetColumnOffset(columns.Current) local offset_1 = ImGui.GetColumnOffset(columns.Current + 1) local width = offset_1 - offset_0 ImGui.PushItemWidth(width * 0.65) window.DC.ColumnsOffset.x = ImMax(column_padding - window.WindowPadding.x, 0.0) window.DC.CursorPos.x = IM_TRUNC(window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x) window.WorkRect.Max.x = window.Pos.x + offset_1 - column_padding window.WorkRect.Max.y = window.ContentRegionRect.Max.y end function ImGui.NextColumn() local window = ImGui.GetCurrentWindow() if window.SkipItems or window.DC.CurrentColumns == nil then return end local g = GImGui local columns = window.DC.CurrentColumns if columns.Count == 1 then window.DC.CursorPos.x = IM_TRUNC(window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x) IM_ASSERT(columns.Current == 0) return end -- Next column columns.Current = columns.Current + 1 if columns.Current == columns.Count then columns.Current = 0 end ImGui.PopItemWidth() -- Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() local column = columns.Columns.Data[columns.Current + 1] ImGui.SetWindowClipRectBeforeSetChannel(window, column.ClipRect) columns.Splitter:SetCurrentChannel(window.DrawList, columns.Current + 1) local column_padding = g.Style.ItemSpacing.x columns.LineMaxY = ImMax(columns.LineMaxY, window.DC.CursorPos.y) if columns.Current > 0 then -- Columns 1+ ignore IndentX (by canceling it out) window.DC.ColumnsOffset.x = ImGui.GetColumnOffset(columns.Current) - window.DC.Indent.x + column_padding else -- New row/line: column 0 honor IndentX. window.DC.ColumnsOffset.x = ImMax(column_padding - window.WindowPadding.x, 0.0) window.DC.IsSameLine = false columns.LineMinY = columns.LineMaxY end window.DC.CursorPos.x = IM_TRUNC(window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x) window.DC.CursorPos.y = columns.LineMinY window.DC.CurrLineSize.x = 0.0; window.DC.CurrLineSize.y = 0.0 window.DC.CurrLineTextBaseOffset = 0.0 local offset_0 = ImGui.GetColumnOffset(columns.Current) local offset_1 = ImGui.GetColumnOffset(columns.Current + 1) local width = offset_1 - offset_0 ImGui.PushItemWidth(width * 0.65) window.WorkRect.Max.x = window.Pos.x + offset_1 - column_padding end function ImGui.EndColumns() local g = GImGui local window = ImGui.GetCurrentWindow() local columns = window.DC.CurrentColumns IM_ASSERT(columns ~= nil) ImGui.PopItemWidth() if columns.Count > 1 then ImGui.PopClipRect() columns.Splitter:Merge(window.DrawList) end local flags = columns.Flags columns.LineMaxY = ImMax(columns.LineMaxY, window.DC.CursorPos.y) window.DC.CursorPos.y = columns.LineMaxY if band(flags, ImGuiOldColumnFlags.GrowParentContentsSize) == 0 then window.DC.CursorMaxPos.x = columns.HostCursorMaxPosX -- Restore cursor max pos, as columns don't grow parent end -- Draw columns borders and handle resize local is_being_resized = false if band(flags, ImGuiOldColumnFlags.NoBorder) == 0 and not window.SkipItems then -- We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. local y1 = ImMax(columns.HostCursorPosY, window.ClipRect.Min.y) local y2 = ImMin(window.DC.CursorPos.y, window.ClipRect.Max.y) local dragging_column = -1 for n = 1, columns.Count - 1 do local column = columns.Columns.Data[n + 1] local x = window.Pos.x + ImGui.GetColumnOffset(n) local column_id = band(columns.ID + n, 0xFFFFFFFF) local column_hit_hw = ImTrunc(COLUMNS_HIT_RECT_HALF_THICKNESS * g.CurrentDpiScale) local column_hit_rect = ImRect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)) if ImGui.ItemAdd(column_hit_rect, column_id, nil, ImGuiItemFlags.NoNav) then local hovered, held = false, false if band(flags, ImGuiOldColumnFlags.NoResize) == 0 then local _ _, hovered, held = ImGui.ButtonBehavior(column_hit_rect, column_id) if hovered or held then ImGui.SetMouseCursor(ImGuiMouseCursor.ResizeEW) end if held and band(column.Flags, ImGuiOldColumnFlags.NoResize) == 0 then dragging_column = n end end -- Draw column local col = ImGui.GetColorU32(held and ImGuiCol.SeparatorActive or (hovered and ImGuiCol.SeparatorHovered or ImGuiCol.Separator)) local xi = IM_TRUNC(x) window.DrawList:AddLineV(xi, y1 + 1.0, y2, col) end end -- Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. if dragging_column ~= -1 then if not columns.IsBeingResized then for n = 0, columns.Count do local c = columns.Columns.Data[n + 1] c.OffsetNormBeforeResize = c.OffsetNorm end end columns.IsBeingResized = true; is_being_resized = true local x = GetDraggedColumnOffset(columns, dragging_column) ImGui.SetColumnOffset(dragging_column, x) end end columns.IsBeingResized = is_being_resized ImRect_Copy(window.WorkRect, window.ParentWorkRect) ImRect_Copy(window.ParentWorkRect, columns.HostBackupParentWorkRect) window.DC.CurrentColumns = nil window.DC.ColumnsOffset.x = 0.0 window.DC.CursorPos.x = IM_TRUNC(window.Pos.x + window.DC.Indent.x + window.DC.ColumnsOffset.x) ImGui.NavUpdateCurrentWindowIsScrollPushableX() end --- @param columns_count? int --- @param id? string --- @param borders? bool function ImGui.Columns(columns_count, id, borders) if columns_count == nil then columns_count = 1 end if borders == nil then borders = true end local window = ImGui.GetCurrentWindow() IM_ASSERT(columns_count >= 1) local flags = borders and 0 or ImGuiOldColumnFlags.NoBorder local columns = window.DC.CurrentColumns if columns ~= nil and columns.Count == columns_count and columns.Flags == flags then return end if columns ~= nil then ImGui.EndColumns() end if columns_count ~= 1 then ImGui.BeginColumns(id, columns_count, flags) end end return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imgui_widgets.lua'] = function() --- Dear ImGui WIP -- (Widgets Code) --- @type ImGuiContext? local GImGui -- Sets local `GImGui` in this file(imgui_widgets.lua). -- This is currently only used in main code `ImGui.SetCurrentContext()` --- @param ctx ImGuiContext? function ImGui._SetCurrentContext_Widgets(ctx) GImGui = ctx end local DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70 -- Time for drag-hold to activate items accepting the ImGuiButtonFlags.PressedOnDragDropHold button behavior local DRAG_MOUSE_THRESHOLD_FACTOR = 0.50 -- Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags local IM_S8_MIN = -128 local IM_S8_MAX = 127 local IM_U8_MIN = 0 local IM_U8_MAX = 0xFF local IM_S16_MIN = -32768 local IM_S16_MAX = 32767 local IM_U16_MIN = 0 local IM_U16_MAX = 0xFFFF local IM_S32_MIN = INT_MIN local IM_S32_MAX = INT_MAX local IM_U32_MIN = 0 local IM_U32_MAX = UINT_MAX ---------------------------------------------------------------- -- [SECTION] TEXT ---------------------------------------------------------------- --- @param text string --- @param text_end? int --- @param flags? ImGuiTextFlags @native function ImGui.TextEx(text, text_end, flags) if not flags then flags = 0 end local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end if not text or text == "" then text = "" text_end = 1 end if text_end == nil then text_end = #text + 1 end local text_pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y + window.DC.CurrLineTextBaseOffset) local wrap_pos_x = window.DC.TextWrapPos local wrap_enabled = (wrap_pos_x >= 0.0) if (text_end - 1 <= 2000) or wrap_enabled then local wrap_width = wrap_enabled and ImGui.CalcWrapWidthForPos(window.DC.CursorPos, wrap_pos_x) or 0.0 local text_size = ImGui.CalcTextSize(text, text_end, false, wrap_width) local bb = ImRect(text_pos, text_pos + text_size) ImGui.ItemSize(text_size, 0.0) if not ImGui.ItemAdd(bb, 0) then return end ImGui.RenderTextWrapped(bb.Min, text, text_end, wrap_width) else local line = 1 local line_height = ImGui.GetTextLineHeight() local text_size = ImVec2(0, 0) local pos = ImVec2(text_pos.x, text_pos.y) if not g.LogEnabled then local lines_skippable = ImFloor((window.ClipRect.Min.y - text_pos.y) / line_height) if lines_skippable > 0 then local lines_skipped = 0 while line < text_end and lines_skipped < lines_skippable do local line_end = ImMemchr(text, "\n", line) if not line_end then line_end = text_end end if bit32.band(flags, ImGuiTextFlags.NoWidthForLargeClippedText) == 0 then local line_size = ImGui.CalcTextSizeEx(text, line, line_end) text_size.x = ImMax(text_size.x, line_size.x) end line = line_end + 1 lines_skipped = lines_skipped + 1 end pos.y = pos.y + lines_skipped * line_height end end if line < text_end then local line_rect = ImRect(pos, pos + ImVec2(FLT_MAX, line_height)) while line < text_end do if ImGui.IsClippedEx(line_rect, 0) then break end local line_end = ImMemchr(text, "\n", line) if not line_end then line_end = text_end end local line_size = ImGui.CalcTextSizeEx(text, line, line_end) text_size.x = ImMax(text_size.x, line_size.x) ImGui.RenderText(pos, text, line, nil, false) line = line_end + 1 line_rect.Min.y = line_rect.Min.y + line_height line_rect.Max.y = line_rect.Max.y + line_height pos.y = pos.y + line_height end local lines_skipped = 0 while line < text_end do local line_end = ImMemchr(text, "\n", line) if not line_end then line_end = text_end end if bit32.band(flags, ImGuiTextFlags.NoWidthForLargeClippedText) == 0 then local line_size = ImGui.CalcTextSizeEx(text, line, line_end) text_size.x = ImMax(text_size.x, line_size.x) end line = line_end + 1 lines_skipped = lines_skipped + 1 end pos.y = pos.y + lines_skipped * line_height end text_size.y = pos.y - text_pos.y local bb = ImRect(text_pos, text_pos + text_size) ImGui.ItemSize(text_size, 0.0) ImGui.ItemAdd(bb, 0) end end --- @param text string --- @param text_end? int function ImGui.TextUnformatted(text, text_end) ImGui.TextEx(text, text_end, ImGuiTextFlags.NoWidthForLargeClippedText) end --- @param fmt string --- @param ... any @native function ImGui.TextV(fmt, ...) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local text = ImFormatString(fmt, ...) ImGui.TextEx(text, nil, ImGuiTextFlags.NoWidthForLargeClippedText) end --- @param fmt string --- @param ... any @native function ImGui.Text(fmt, ...) if select('#', ...) > 0 then ImGui.TextV(fmt, ...) else ImGui.TextEx(fmt) end end --- @param col ImVec4 --- @param fmt string --- @param ... any function ImGui.TextColored(col, fmt, ...) ImGui.PushStyleColor(ImGuiCol.Text, col) ImGui.TextV(fmt, ...) ImGui.PopStyleColor() end --- @param fmt string --- @param ... any function ImGui.TextDisabled(fmt, ...) local g = GImGui ImGui.PushStyleColor(ImGuiCol.Text, g.Style.Colors[ImGuiCol.TextDisabled]) ImGui.TextV(fmt, ...) ImGui.PopStyleColor() end --- @param fmt string --- @param ... any function ImGui.TextWrapped(fmt, ...) local g = GImGui local need_backup = (g.CurrentWindow.DC.TextWrapPos < 0.0) if need_backup then ImGui.PushTextWrapPos(0.0) end ImGui.TextV(fmt, ...) if need_backup then ImGui.PopTextWrapPos() end end -- align_x: 0.0f = left, 0.5f = center, 1.0f = right. -- size_x : 0.0f = shortcut for GetContentRegionAvail().x -- FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) --- @param align_x float --- @param size_x float --- @param fmt string --- @param ... any function ImGui.TextAligned(align_x, size_x, fmt, ...) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local text = ImFormatString(fmt, ...) local text_end = #text + 1 local text_size = ImGui.CalcTextSize(text, text_end) size_x = ImGui.CalcItemSize(ImVec2(size_x, 0.0), 0.0, text_size.y).x local pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y + window.DC.CurrLineTextBaseOffset) local pos_max = ImVec2(pos.x + size_x, window.ClipRect.Max.y) local size = ImVec2(ImMin(size_x, text_size.x), text_size.y) window.DC.CursorMaxPos.x = ImMax(window.DC.CursorMaxPos.x, pos.x + text_size.x) window.DC.IdealMaxPos.x = ImMax(window.DC.IdealMaxPos.x, pos.x + text_size.x) if align_x > 0.0 and text_size.x < size_x then pos.x = pos.x + ImTrunc((size_x - text_size.x) * align_x) end ImGui.RenderTextEllipsis(window.DrawList, pos, pos_max, pos_max.x, text, text_end, text_size) local backup_max_pos = ImVec2() ImVec2_Copy(backup_max_pos, window.DC.CursorMaxPos) ImGui.ItemSize(size) ImGui.ItemAdd(ImRect(pos, pos + size), 0) window.DC.CursorMaxPos.x = backup_max_pos.x -- Cancel out extending content size because right-aligned text would otherwise mess it up if size_x < text_size.x and ImGui.IsItemHovered(bit32.bor(ImGuiHoveredFlags.NoNavOverride, ImGuiHoveredFlags.AllowWhenDisabled, ImGuiHoveredFlags.ForTooltip)) then ImGui.SetTooltip("%.*s", text_end - 1, text) end end -- Add a label+text combo aligned to other label+value widgets --- @param label string --- @param fmt string --- @param ... any function ImGui.LabelText(label, fmt, ...) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local style = g.Style local w = ImGui.CalcItemWidth() local value_text = ImFormatString(fmt, ...) local value_text_end = #value_text + 1 local value_size = ImGui.CalcTextSize(value_text, value_text_end, false) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local value_bb = ImRect(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2)) local total_bb = ImRect(pos, pos + ImVec2(w + ((label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2)) ImGui.ItemSize(total_bb, style.FramePadding.y) if not ImGui.ItemAdd(total_bb, 0) then return end -- Render ImGui.RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text, value_text_end, value_size, ImVec2(0.0, 0.0)) if label_size.x > 0.0 then ImGui.RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end end --- @param fmt string --- @param ... any function ImGui.BulletText(fmt, ...) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local style = g.Style local text = ImFormatString(fmt, ...) local text_end = #text + 1 local label_size = ImGui.CalcTextSize(text, text_end, false) local total_size = ImVec2(g.FontSize + ((label_size.x > 0.0) and (label_size.x + style.FramePadding.x * 2) or 0.0), label_size.y) -- Empty text doesn't add padding local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) pos.y = pos.y + window.DC.CurrLineTextBaseOffset ImGui.ItemSize(total_size, 0.0) local bb = ImRect(pos, pos + total_size) if not ImGui.ItemAdd(bb, 0) then return end -- Render local text_col = ImGui.GetColorU32(ImGuiCol.Text) ImGui.RenderBullet(window.DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5, g.FontSize * 0.5), text_col) ImGui.RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0), text, 1, text_end, false) end -- va_list variants: identical to the varargs versions in Lua ImGui.TextColoredV = ImGui.TextColored ImGui.TextDisabledV = ImGui.TextDisabled ImGui.TextWrappedV = ImGui.TextWrapped ImGui.TextAlignedV = ImGui.TextAligned ImGui.LabelTextV = ImGui.LabelText ImGui.BulletTextV = ImGui.BulletText -- Value(prefix, b) / Value(prefix, int) / Value(prefix, float, float_format) -- Lua can't tell int from float: integers without float_format print as %d, otherwise %.3f function ImGui.Value(prefix, v, float_format) if type(v) == "boolean" then ImGui.Text("%s: %s", prefix, v and "true" or "false") elseif float_format then ImGui.Text("%s: " .. float_format, prefix, v) elseif math.floor(v) == v then ImGui.Text("%s: %d", prefix, v) else ImGui.Text("%s: %.3f", prefix, v) end end ---------------------------------------------------------------- -- [SECTION] MAIN: BUTTONS, SCROLLBARS, ... ---------------------------------------------------------------- --- @param bb ImRect --- @param id ImGuiID --- @param flags? ImGuiButtonFlags @native function ImGui.ButtonBehavior(bb, id, flags) if flags == nil then flags = 0 end local g = GImGui local window = g.CurrentWindow local item_flags = (g.LastItemData.ID == id) and g.LastItemData.ItemFlags or g.CurrentItemFlags if bit32.band(flags, ImGuiButtonFlags.AllowOverlap) ~= 0 then item_flags = bit32.bor(item_flags, ImGuiItemFlags.AllowOverlap) end if bit32.band(item_flags, ImGuiItemFlags.NoFocus) ~= 0 then flags = bit32.bor(flags, ImGuiButtonFlags.NoFocus, ImGuiButtonFlags.NoNavFocus) end -- Default only reacts to left mouse button if bit32.band(flags, ImGuiButtonFlags.MouseButtonMask_) == 0 then flags = bit32.bor(flags, ImGuiButtonFlags.MouseButtonLeft) end -- Default behavior requires click + release inside bounding box if bit32.band(flags, ImGuiButtonFlags.PressedOnMask_) == 0 then flags = bit32.bor(flags, (bit32.band(item_flags, ImGuiItemFlags.ButtonRepeat) ~= 0) and ImGuiButtonFlags.PressedOnClick or ImGuiButtonFlags.PressedOnDefault_) end local backup_hovered_window = g.HoveredWindow local flatten_hovered_children = (bit32.band(flags, ImGuiButtonFlags.FlattenChildren) ~= 0) and g.HoveredWindow and g.HoveredWindow.RootWindowDockTree == window.RootWindowDockTree if flatten_hovered_children then g.HoveredWindow = window end local pressed = false local hovered = ImGui.ItemHoverable(bb, id, item_flags) if g.DragDropActive then if (bit32.band(flags, ImGuiButtonFlags.PressedOnDragDropHold) ~= 0) and (bit32.band(g.DragDropSourceFlags, ImGuiDragDropFlags.SourceNoHoldToOpenOthers) == 0) and ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) then hovered = true ImGui.SetHoveredID(id) if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER) and (g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) then pressed = true g.DragDropHoldJustPressedId = id ImGui.FocusWindow(window) end end if (g.DragDropAcceptIdPrev == id) and (bit32.band(g.DragDropAcceptFlagsPrev, ImGuiDragDropFlags.AcceptDrawAsHovered) ~= 0) then hovered = true end end if (flatten_hovered_children) then g.HoveredWindow = backup_hovered_window end local test_owner_id = (bit32.band(flags, ImGuiButtonFlags.NoTestKeyOwner) ~= 0) and ImGuiKeyOwner_Any or id if hovered then IM_ASSERT(id ~= 0) local mouse_button_clicked = -1 local mouse_button_released = -1 for button = 0, 2 do if bit32.band(flags, bit32.lshift(ImGuiButtonFlags.MouseButtonLeft, button)) ~= 0 then -- Handle ImGuiButtonFlags.MouseButtonRight and ImGuiButtonFlags.MouseButtonMiddle here. if (ImGui.IsMouseClickedEx(button, ImGuiInputFlags.None, test_owner_id) and mouse_button_clicked == -1) then mouse_button_clicked = button end if (ImGui.IsMouseReleased(button, test_owner_id) and mouse_button_released == -1) then mouse_button_released = button end end end local mods_ok = (bit32.band(flags, ImGuiButtonFlags.NoKeyModsAllowed) == 0) or (not g.IO.KeyCtrl and not g.IO.KeyShift and not g.IO.KeyAlt) if mods_ok then if mouse_button_clicked ~= -1 and g.ActiveId ~= id then --- @cast mouse_button_clicked ImGuiMouseButton if bit32.band(flags, ImGuiButtonFlags.NoSetKeyOwner) == 0 then ImGui.SetKeyOwner(ImGui.MouseButtonToKey(mouse_button_clicked), id) end if bit32.band(flags, bit32.bor(ImGuiButtonFlags.PressedOnClickRelease, ImGuiButtonFlags.PressedOnClickReleaseAnywhere)) ~= 0 then ImGui.SetActiveID(id, window) g.ActiveIdMouseButton = mouse_button_clicked if bit32.band(flags, ImGuiButtonFlags.NoNavFocus) == 0 then ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) elseif bit32.band(flags, ImGuiButtonFlags.NoFocus) == 0 then ImGui.FocusWindow(window, ImGuiFocusRequestFlags.RestoreFocusedChild) end end if (bit32.band(flags, ImGuiButtonFlags.PressedOnClick) ~= 0) or ((bit32.band(flags, ImGuiButtonFlags.PressedOnDoubleClick) ~= 0) and g.IO.MouseClickedCount[mouse_button_clicked] == 2) then pressed = true if bit32.band(flags, ImGuiButtonFlags.NoHoldingActiveId) ~= 0 then ImGui.ClearActiveID() else ImGui.SetActiveID(id, window) end g.ActiveIdMouseButton = mouse_button_clicked if bit32.band(flags, ImGuiButtonFlags.NoNavFocus) == 0 then ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) elseif bit32.band(flags, ImGuiButtonFlags.NoFocus) == 0 then ImGui.FocusWindow(window, ImGuiFocusRequestFlags.RestoreFocusedChild) end end if bit32.band(flags, ImGuiButtonFlags.PressedOnRelease) ~= 0 then -- FIXME: Traditionally ImGuiButtonFlags.PressedOnRelease never took ActiveId. Adding it in 2026-03-20 since ImGuiButtonFlags_NoHoldingActiveId can always be added. -- We don't yet perform an explicit ClearActiveID() to reduce scope of change, but this possibility could be investigated. if bit32.band(flags, ImGuiButtonFlags.NoHoldingActiveId) == 0 then ImGui.SetActiveID(id, window) -- Hold on ID end g.ActiveIdMouseButton = mouse_button_clicked end end if bit32.band(flags, ImGuiButtonFlags.PressedOnRelease) ~= 0 then if mouse_button_released ~= -1 then local has_repeated_at_least_once = (bit32.band(item_flags, ImGuiItemFlags.ButtonRepeat) ~= 0) and g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay if not has_repeated_at_least_once then pressed = true end if bit32.band(flags, ImGuiButtonFlags.NoNavFocus) == 0 then ImGui.SetFocusID(id, window) -- FIXME: Lack of FocusWindow() call here is inconsistent with other paths. Research why. end ImGui.ClearActiveID() end end -- 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). -- Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. if g.ActiveId == id and (bit32.band(item_flags, ImGuiItemFlags.ButtonRepeat) ~= 0) then if g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0 and ImGui.IsMouseClickedEx(g.ActiveIdMouseButton, ImGuiInputFlags.Repeat, test_owner_id) then pressed = true end end end if pressed and g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = false end end -- Keyboard/Gamepad navigation handling -- We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse if bit32.band(item_flags, ImGuiItemFlags.Disabled) == 0 then if g.NavId == id and g.NavCursorVisible and g.NavHighlightItemUnderNav then if bit32.band(flags, ImGuiButtonFlags.NoHoveredOnFocus) == 0 then hovered = true end end if g.NavActivateDownId == id then local nav_activated_by_code = (g.NavActivateId == id) local nav_activated_by_inputs = (g.NavActivatePressedId == id) if not nav_activated_by_inputs and bit32.band(item_flags, ImGuiItemFlags.ButtonRepeat) ~= 0 then -- Avoid pressing multiple keys from triggering excessive amount of repeat events local key1 = ImGui.GetKeyData(g, ImGuiKey.Space) local key2 = ImGui.GetKeyData(g, ImGuiKey.Enter) local key3 = ImGui.GetKeyData(g, ImGuiKey.NavGamepadActivate) local t1 = ImMax(ImMax(key1.DownDuration, key2.DownDuration), key3.DownDuration) nav_activated_by_inputs = ImGui.CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0 end if nav_activated_by_code or nav_activated_by_inputs then -- Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. pressed = true ImGui.SetActiveID(id, window) g.ActiveIdSource = g.NavInputSource if bit32.band(flags, ImGuiButtonFlags.NoNavFocus) == 0 and bit32.band(g.NavActivateFlags, ImGuiActivateFlags.FromShortcut) == 0 then ImGui.SetFocusID(id, window) end if bit32.band(g.NavActivateFlags, ImGuiActivateFlags.FromShortcut) ~= 0 then g.ActiveIdFromShortcut = true end end end end local held = false if g.ActiveId == id then if g.ActiveIdSource == ImGuiInputSource.Mouse then if g.ActiveIdIsJustActivated then g.ActiveIdClickOffset = g.IO.MousePos - bb.Min end local mouse_button = g.ActiveIdMouseButton if mouse_button == -1 then -- Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304). ImGui.ClearActiveID() elseif ImGui.IsMouseDown(mouse_button, test_owner_id) then held = true else local release_in = hovered and (bit32.band(flags, ImGuiButtonFlags.PressedOnClickRelease) ~= 0) local release_anywhere = (bit32.band(flags, ImGuiButtonFlags.PressedOnClickReleaseAnywhere) ~= 0) if (release_in or release_anywhere) and not g.DragDropActive then -- Report as pressed when releasing the mouse (this is the most common path) local is_double_click_release = (bit32.band(flags, ImGuiButtonFlags.PressedOnDoubleClick) ~= 0) and g.IO.MouseReleased[mouse_button] and g.IO.MouseClickedLastCount[mouse_button] == 2 local is_repeating_already = (bit32.band(item_flags, ImGuiItemFlags.ButtonRepeat) ~= 0) and g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay local is_button_avail_or_owned = ImGui.TestKeyOwner(ImGui.MouseButtonToKey(mouse_button), test_owner_id) if not is_double_click_release and not is_repeating_already and is_button_avail_or_owned then pressed = true end end ImGui.ClearActiveID() end if bit32.band(flags, ImGuiButtonFlags.NoNavFocus) == 0 and g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = false end elseif g.ActiveIdSource == ImGuiInputSource.Keyboard or g.ActiveIdSource == ImGuiInputSource.Gamepad then -- When activated using Nav, we hold on the ActiveID until activation button is released if g.NavActivateDownId == id then held = true -- hovered == true not true as we are already likely hovered on direct activation. else ImGui.ClearActiveID() end end if pressed then g.ActiveIdHasBeenPressedBefore = true end end if g.NavHighlightActivatedId == id and (bit32.band(item_flags, ImGuiItemFlags.Disabled) == 0) then hovered = true end return pressed, hovered, held end --- @param label string --- @param size_arg? ImVec2 --- @param flags? ImGuiButtonFlags --- @return bool @native function ImGui.ButtonEx(label, size_arg, flags) if size_arg == nil then size_arg = ImVec2(0, 0) end if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local pos = ImVec2() -- Don't modify the cursor! ImVec2_Copy(pos, window.DC.CursorPos) if bit32.band(flags, ImGuiButtonFlags.AlignTextBaseLine) ~= 0 and style.FramePadding.y < window.DC.CurrLineTextBaseOffset then pos.y = pos.y + window.DC.CurrLineTextBaseOffset - style.FramePadding.y end local size = ImGui.CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0, label_size.y + style.FramePadding.y * 2.0) local bb = ImRect(pos, pos + size) ImGui.ItemSize(size, style.FramePadding.y) if not ImGui.ItemAdd(bb, id) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, flags) local col if held and hovered then col = ImGui.GetColorU32(ImGuiCol.ButtonActive) elseif hovered then col = ImGui.GetColorU32(ImGuiCol.ButtonHovered) else col = ImGui.GetColorU32(ImGuiCol.Button) end ImGui.RenderNavCursor(bb, id) ImGui.RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding) -- if (g.LogEnabled) -- LogSetNextTextDecoration("[", "]"); ImGui.RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, label_end, label_size, style.ButtonTextAlign, bb) -- Automatically close popups --if (pressed && !(flags & ImGuiButtonFlags.DontClosePopups) && (window->Flags & ImGuiWindowFlags.Popup)) -- CloseCurrentPopup(); -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return pressed end --- @param label string --- @param size_arg? ImVec2 --- @return bool function ImGui.Button(label, size_arg) return ImGui.ButtonEx(label, size_arg, ImGuiButtonFlags.None) end --- @param label string --- @return bool function ImGui.SmallButton(label) local g = GImGui local backup_padding_y = g.Style.FramePadding.y g.Style.FramePadding.y = 0.0 local pressed = ImGui.ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags.AlignTextBaseLine) g.Style.FramePadding.y = backup_padding_y return pressed end --- @param str_id string --- @param size_arg ImVec2 --- @param flags? ImGuiButtonFlags function ImGui.InvisibleButton(str_id, size_arg, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end -- Ensure zero-size fits to contents local size = ImGui.CalcItemSize(ImVec2(size_arg.x ~= 0.0 and size_arg.x or -FLT_MIN, size_arg.y ~= 0.0 and size_arg.y or -FLT_MIN), 0.0, 0.0) local id = window:GetID(str_id) local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + size) ImGui.ItemSize(size) local item_flags = (bit32.band(flags, ImGuiButtonFlags.EnableNav) ~= 0) and ImGuiItemFlags.None or ImGuiItemFlags.NoNav if not ImGui.ItemAdd(bb, id, nil, item_flags) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, flags) ImGui.RenderNavCursor(bb, id) -- IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags) return pressed end --- @param str_id string --- @param dir ImGuiDir --- @param size ImVec2 --- @param flags? ImGuiButtonFlags function ImGui.ArrowButtonEx(str_id, dir, size, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local id = window:GetID(str_id) local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + size) local default_size = ImGui.GetFrameHeight() ImGui.ItemSize(size, (size.y >= default_size) and g.Style.FramePadding.y or -1.0) if not ImGui.ItemAdd(bb, id) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, flags) -- Render local bg_col = ImGui.GetColorU32((held and hovered) and ImGuiCol.ButtonActive or hovered and ImGuiCol.ButtonHovered or ImGuiCol.Button) local text_col = ImGui.GetColorU32(ImGuiCol.Text) ImGui.RenderNavCursor(bb, id) ImGui.RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding) ImGui.RenderArrow(window.DrawList, bb.Min + ImVec2(ImMax(0.0, (size.x - g.FontSize) * 0.5), ImMax(0.0, (size.y - g.FontSize) * 0.5)), text_col, dir) -- IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags) return pressed end --- @param str_id string --- @param dir ImGuiDir function ImGui.ArrowButton(str_id, dir) local sz = ImGui.GetFrameHeight() return ImGui.ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags.None) end --- @param id ImGuiID --- @param pos ImVec2 --- @return bool function ImGui.CloseButton(id, pos) local g = GImGui local window = g.CurrentWindow local bb = ImRect(pos, pos + ImVec2(g.FontSize, g.FontSize)) local bb_interact = ImRect() ImRect_Copy(bb_interact, bb) local area_to_visible_ratio = window.OuterRectClipped:GetArea() / bb:GetArea() if area_to_visible_ratio < 1.5 then bb_interact:Expand(ImTrunc(bb_interact:GetSize() * -0.25)) end local is_clipped = not ImGui.ItemAdd(bb_interact, id) local pressed, hovered, held = ImGui.ButtonBehavior(bb, id) if is_clipped then return pressed end local bg_col if held then bg_col = ImGui.GetColorU32(ImGuiCol.ButtonActive) else bg_col = ImGui.GetColorU32(ImGuiCol.ButtonHovered) end if hovered then window.DrawList:AddRectFilled(bb.Min, bb.Max, bg_col) end local cross_center = bb:GetCenter() - ImVec2(0.5, 0.5) local cross_extent = g.FontSize * 0.5 * 0.7071 - 1 local cross_col = ImGui.GetColorU32(ImGuiCol.Text) local cross_thickness = 1.0 -- FIXME-DPI window.DrawList:AddLine(cross_center + ImVec2(cross_extent, cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness) window.DrawList:AddLine(cross_center + ImVec2(cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, cross_extent), cross_col, cross_thickness) return pressed end --- @return bool function ImGui.CollapseButton(id, pos) local g = GImGui local window = g.CurrentWindow local bb = ImRect(pos, pos + ImVec2(g.FontSize, g.FontSize)) local is_clipped = not ImGui.ItemAdd(bb, id) local pressed, hovered = ImGui.ButtonBehavior(bb, id) if hovered then window.DrawList:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.ButtonHovered)) end if window.Collapsed then ImGui.RenderArrow(window.DrawList, bb.Min, ImGui.GetColorU32(ImGuiCol.Text), ImGuiDir.Right, 1) else ImGui.RenderArrow(window.DrawList, bb.Min, ImGui.GetColorU32(ImGuiCol.Text), ImGuiDir.Down, 1) end return pressed end --- @param window ImGuiWindow --- @param axis ImGuiAxis --- @return ImGuiID function ImGui.GetWindowScrollbarID(window, axis) if axis == ImGuiAxis.X then return window:GetID("#SCROLLX") else return window:GetID("#SCROLLY") end end --- @param window ImGuiWindow --- @param axis ImGuiAxis --- @return ImRect --- @nodiscard function ImGui.GetWindowScrollbarRect(window, axis) local g = GImGui local outer_rect = window:Rect() local inner_rect = window.InnerRect -- (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) local scrollbar_size = window.ScrollbarSizes[axis == ImGuiAxis.X and ImGuiAxis.Y or ImGuiAxis.X] IM_ASSERT(scrollbar_size >= 0.0) local border_size = IM_ROUND(window.WindowBorderSize * 0.5) local border_top = (bit32.band(window.Flags, ImGuiWindowFlags.MenuBar) ~= 0) and IM_ROUND(g.Style.FrameBorderSize * 0.5) or (bit32.band(window.Flags, ImGuiWindowFlags.NoTitleBar) ~= 0 and border_size or 0) if axis == ImGuiAxis.X then return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size) else return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size) end end --- @param window ImGuiWindow --- @param bb ImRect --- @param threshold float --- @param axis ImGuiAxis function ImGui.ExtendHitBoxWhenNearViewportEdge(window, bb, threshold, axis) local window_rect = window.RootWindow:Rect() local viewport_rect = window.Viewport:GetMainRect() if window_rect.Min[axis] == viewport_rect.Min[axis] and bb.Min[axis] > window_rect.Min[axis] and bb.Min[axis] - threshold <= window_rect.Min[axis] then bb.Min[axis] = window_rect.Min[axis] end if window_rect.Max[axis] == viewport_rect.Max[axis] and bb.Max[axis] < window_rect.Max[axis] and bb.Max[axis] + threshold >= window_rect.Max[axis] then bb.Max[axis] = window_rect.Max[axis] end end --- @param bb_frame ImRect --- @param id ImGuiID --- @param axis ImGuiAxis --- @param p_scroll_v number --- @param size_visible_v number --- @param size_contents_v number --- @param draw_rounding_flags ImDrawFlags --- @return bool is_held --- @return number scroll_v # Updated p_scroll_v function ImGui.ScrollbarEx(bb_frame, id, axis, p_scroll_v, size_visible_v, size_contents_v, draw_rounding_flags) local g = GImGui local window = g.CurrentWindow if window.SkipItems then return false, p_scroll_v end local bb_frame_width = bb_frame:GetWidth() local bb_frame_height = bb_frame:GetHeight() if bb_frame_width <= 0.0 or bb_frame_height <= 0.0 then return false, p_scroll_v end local alpha = 1.0 if axis == ImGuiAxis.Y and bb_frame_height < bb_frame_width then alpha = ImSaturate(bb_frame_height / ImMax(bb_frame_width * 2.0, 1.0)) end if alpha <= 0.0 then return false, p_scroll_v end local style = g.Style local allow_interaction = (alpha >= 1.0) local bb = ImRect() ImRect_Copy(bb, bb_frame) local padding = IM_TRUNC(ImMin(style.ScrollbarPadding, ImMin(bb_frame_width, bb_frame_height) * 0.5)) bb:Expand(-padding) -- V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) local scrollbar_size_v if axis == ImGuiAxis.X then scrollbar_size_v = bb:GetWidth() else scrollbar_size_v = bb:GetHeight() end if scrollbar_size_v < 1.0 then return false, p_scroll_v end IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0) local win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), 1) local grab_h_minsize = ImMin(bb:GetSize()[axis], style.GrabMinSize) local grab_h_pixels = ImTrunc(ImClamp(scrollbar_size_v * (size_visible_v / win_size_v), grab_h_minsize, scrollbar_size_v)) local grab_h_norm = grab_h_pixels / scrollbar_size_v -- As a special thing, we allow scrollbar near the edge of a screen/viewport to be reachable with mouse at the extreme edge (#9276) local bb_hit = ImRect() ImRect_Copy(bb_hit, bb_frame) ImGui.ExtendHitBoxWhenNearViewportEdge(window, bb_hit, g.Style.WindowBorderSize, ImGuiAxis.X + ImGuiAxis.Y - axis) -- swap axis here ImGui.ItemAdd(bb_frame, id, nil, ImGuiItemFlags.NoNav) local pressed, hovered, held = ImGui.ButtonBehavior(bb_hit, id, ImGuiButtonFlags.NoNavFocus) local scroll_max = ImMax(1, size_contents_v - size_visible_v) local scroll_ratio = ImSaturate(p_scroll_v / scroll_max) local grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v if held and allow_interaction and grab_h_norm < 1.0 then local scrollbar_pos_v = bb.Min[axis] local mouse_pos_v = g.IO.MousePos[axis] local clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v) local held_dir if clicked_v_norm < grab_v_norm then held_dir = -1 elseif clicked_v_norm > grab_v_norm + grab_h_norm then held_dir = 1 else held_dir = 0 end if g.ActiveIdIsJustActivated then local scroll_to_clicked_location = (g.IO.ConfigScrollbarScrollByPage == false) or g.IO.KeyShift or held_dir == 0 if scroll_to_clicked_location then g.ScrollbarSeekMode = 0 else g.ScrollbarSeekMode = held_dir end if held_dir == 0 and not g.IO.KeyShift then g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5 else g.ScrollbarClickDeltaToGrabCenter = 0.0 end end if g.ScrollbarSeekMode == 0 then scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5) / (1.0 - grab_h_norm)) p_scroll_v = scroll_v_norm * scroll_max else if ImGui.IsMouseClickedEx(ImGuiMouseButton.Left, ImGuiInputFlags.Repeat) and held_dir == g.ScrollbarSeekMode then local page_dir if g.ScrollbarSeekMode > 0.0 then page_dir = 1.0 else page_dir = -1.0 end p_scroll_v = ImClamp(p_scroll_v + page_dir * size_visible_v, 0, scroll_max) end end scroll_ratio = ImSaturate(p_scroll_v / scroll_max) grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v end local bg_col = ImGui.GetColorU32(ImGuiCol.ScrollbarBg) local grab_col if held then grab_col = ImGui.GetColorU32(ImGuiCol.ScrollbarGrabActive, alpha) elseif hovered then grab_col = ImGui.GetColorU32(ImGuiCol.ScrollbarGrabHovered, alpha) else grab_col = ImGui.GetColorU32(ImGuiCol.ScrollbarGrab, alpha) end window.DrawList:AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window.WindowRounding, draw_rounding_flags) local grab_rect if axis == ImGuiAxis.X then local x1 = ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) grab_rect = ImRect(x1, bb.Min.y, x1 + grab_h_pixels, bb.Max.y) else local y1 = ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) grab_rect = ImRect(bb.Min.x, y1, bb.Max.x, y1 + grab_h_pixels) end window.DrawList:AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding) return held, p_scroll_v end --- @param axis ImGuiAxis function ImGui.Scrollbar(axis) local g = GImGui local window = g.CurrentWindow local id = ImGui.GetWindowScrollbarID(window, axis) -- Calculate scrollbar bounding box local bb = ImGui.GetWindowScrollbarRect(window, axis) local rounding_corners = ImGui.CalcRoundingFlagsForRectInRect(bb, window:Rect(), g.Style.WindowBorderSize) local size_visible = window.InnerRect.Max[axis] - window.InnerRect.Min[axis] local size_contents = window.ContentSize[axis] + window.WindowPadding[axis] * 2.0 local scroll = window.Scroll[axis] local held held, scroll = ImGui.ScrollbarEx(bb, id, axis, scroll, size_visible, size_contents, rounding_corners) window.Scroll[axis] = scroll end -- - `uv0` and `uv1` are texture coordinates --- @param tex_ref ImTextureRef --- @param image_size ImVec2 --- @param uv0? ImVec2 --- @param uv1? ImVec2 --- @param bg_col? ImVec4 --- @param tint_col? ImVec4 function ImGui.ImageWithBg(tex_ref, image_size, uv0, uv1, bg_col, tint_col) if uv0 == nil then uv0 = ImVec2(0, 0) end if uv1 == nil then uv1 = ImVec2(1, 1) end if bg_col == nil then bg_col = ImVec4(0, 0, 0, 0) end if tint_col == nil then tint_col = ImVec4(1, 1, 1, 1) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local padding = ImVec2(g.Style.ImageBorderSize, g.Style.ImageBorderSize) local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + image_size + padding * 2.0) ImGui.ItemSize(bb) if not ImGui.ItemAdd(bb, 0) then return end -- Render local rounding = g.Style.ImageRounding if bg_col.w > 0.0 then window.DrawList:AddRectFilled(bb.Min + padding, bb.Max - padding, ImGui.GetColorU32(bg_col), rounding) end if rounding > 0.0 then window.DrawList:AddImageRounded(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, ImGui.GetColorU32(tint_col), rounding) else window.DrawList:AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, ImGui.GetColorU32(tint_col)) end if g.Style.ImageBorderSize > 0.0 then window.DrawList:AddRect(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Border), rounding, g.Style.ImageBorderSize, ImDrawFlags.None) end end --- @param tex_ref ImTextureRef --- @param image_size ImVec2 --- @param uv0? ImVec2 --- @param uv1? ImVec2 function ImGui.Image(tex_ref, image_size, uv0, uv1) ImGui.ImageWithBg(tex_ref, image_size, uv0, uv1) end --- @param id ImGuiID --- @param tex_ref ImTextureRef --- @param image_size ImVec2 --- @param uv0 ImVec2 --- @param uv1 ImVec2 --- @param bg_col ImVec4 --- @param tint_col ImVec4 --- @param flags? ImGuiButtonFlags function ImGui.ImageButtonEx(id, tex_ref, image_size, uv0, uv1, bg_col, tint_col, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local padding = g.Style.FramePadding local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + image_size + padding * 2.0) ImGui.ItemSize(bb) if not ImGui.ItemAdd(bb, id) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, flags) -- Render local col = ImGui.GetColorU32((held and hovered) and ImGuiCol.ButtonActive or hovered and ImGuiCol.ButtonHovered or ImGuiCol.Button) ImGui.RenderNavCursor(bb, id) ImGui.RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding) if bg_col.w > 0.0 then window.DrawList:AddRectFilled(bb.Min + padding, bb.Max - padding, ImGui.GetColorU32(bg_col)) end local image_rounding = ImMax(g.Style.FrameRounding - ImMax(padding.x, padding.y), g.Style.ImageRounding) if image_rounding > 0.0 then window.DrawList:AddImageRounded(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, ImGui.GetColorU32(tint_col), image_rounding) else window.DrawList:AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, ImGui.GetColorU32(tint_col)) end return pressed end -- - ImageButton() adds style.FramePadding*2.0 to provided size. This is in order to facilitate fitting an image in a button. -- - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. (#8165) -- FIXME: Maybe that's not the best design? --- @param str_id string --- @param tex_ref ImTextureRef --- @param image_size ImVec2 --- @param uv0 ImVec2 --- @param uv1 ImVec2 --- @param bg_col ImVec4 --- @param tint_col ImVec4 function ImGui.ImageButton(str_id, tex_ref, image_size, uv0, uv1, bg_col, tint_col) local g = GImGui local window = g.CurrentWindow if window.SkipItems then return false end return ImGui.ImageButtonEx(window:GetID(str_id), tex_ref, image_size, uv0, uv1, bg_col, tint_col) end --- @param label string --- @param v bool --- @return bool is_pressed --- @return bool is_checked # The updated `v` passed in @native function ImGui.Checkbox(label, v) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false, v end local g = GImGui local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local square_sz = ImGui.GetFrameHeight() local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local total_width if label_size.x > 0.0 then total_width = square_sz + style.ItemInnerSpacing.x + label_size.x else total_width = square_sz end local total_bb = ImRect(pos, pos + ImVec2(total_width, label_size.y + style.FramePadding.y * 2.0)) ImGui.ItemSize(total_bb, style.FramePadding.y) local is_visible = ImGui.ItemAdd(total_bb, id) local is_multi_select = (bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.IsMultiSelect) ~= 0) if not is_visible then if not is_multi_select or not g.BoxSelectState.UnclipMode or not g.BoxSelectState.UnclipRect:Overlaps(total_bb) then -- Extra layer of "no logic clip" for box-select support -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)) return false, v end end local checked = v if is_multi_select then -- TODO: MultiSelectItemHeader() end local pressed, hovered, held = ImGui.ButtonBehavior(total_bb, id) if is_multi_select then -- TODO: MultiSelectItemFooter() elseif pressed then checked = not checked end if v ~= checked then v = checked pressed = true ImGui.MarkItemEdited(id) end local check_bb = ImRect(pos, pos + ImVec2(square_sz, square_sz)) local mixed_value = (bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.MixedValue) ~= 0) if is_visible then ImGui.RenderNavCursor(total_bb, id) local bg_col = ImGui.GetColorU32((held and hovered) and ImGuiCol.FrameBgActive or (hovered and ImGuiCol.FrameBgHovered or ((mixed_value or checked) and ImGuiCol.CheckboxSelectedBg or ImGuiCol.FrameBg))) local check_col = ImGui.GetColorU32(ImGuiCol.CheckMark) ImGui.RenderFrame(check_bb.Min, check_bb.Max, bg_col, true, style.FrameRounding) if mixed_value then -- Undocumented tristate/mixed/indeterminate checkbox (#2644) -- This may seem awkwardly designed because the aim is to make ImGuiItemFlags.MixedValue supported by all widgets (not just checkbox) local pad_val = ImMax(1.0, IM_TRUNC(square_sz / 3.6)) local pad = ImVec2(pad_val, pad_val) window.DrawList:AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding) elseif v then local pad = ImMax(1.0, IM_TRUNC(square_sz / 6.0)) ImGui.RenderCheckMark(window.DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0) end end local label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y) if g.LogEnabled then -- ImGui.LogRenderedText(label_pos, mixed_value and "[~]" or (v and "[x]" or "[ ]")) end if is_visible and label_size.x > 0.0 then ImGui.RenderText(label_pos, label, 1, label_end, false) end -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)) return pressed, v end --- @param label string --- @param flags int --- @param flags_value int --- @return bool is_pressed --- @return int flags_new # Updated `flags` function ImGui.CheckboxFlags(label, flags, flags_value) local all_on = bit32.band(flags, flags_value) == flags_value local any_on = bit32.band(flags, flags_value) ~= 0 local pressed if not all_on and any_on then local g = GImGui g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.MixedValue) pressed, all_on = ImGui.Checkbox(label, all_on) else pressed, all_on = ImGui.Checkbox(label, all_on) end if pressed then if all_on then flags = bit32.bor(flags, flags_value) else flags = bit32.band(flags, bit32.bnot(flags_value)) end end return pressed, flags end ImGui.CheckboxFlagsT = ImGui.CheckboxFlags --- @param label string --- @param active bool --- @return bool is_pressed function ImGui.RadioButtonEx(label, active) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local square_sz = ImGui.GetFrameHeight() local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local check_bb = ImRect(pos, pos + ImVec2(square_sz, square_sz)) local total_bb = ImRect(pos, pos + ImVec2(square_sz + (label_size.x > 0.0 and style.ItemInnerSpacing.x + label_size.x or 0.0), label_size.y + style.FramePadding.y * 2.0)) ImGui.ItemSize(total_bb, style.FramePadding.y) if not ImGui.ItemAdd(total_bb, id) then return false end local center = check_bb:GetCenter() center.x = IM_ROUND(center.x) center.y = IM_ROUND(center.y) local radius = (square_sz - 1.0) * 0.5 local pressed, hovered, held = ImGui.ButtonBehavior(total_bb, id) if (pressed) then ImGui.MarkItemEdited(id) end ImGui.RenderNavCursor(total_bb, id) local num_segment = window.DrawList:_CalcCircleAutoSegmentCount(radius) local col if held and hovered then col = ImGui.GetColorU32(ImGuiCol.FrameBgActive) else if hovered then col = ImGui.GetColorU32(ImGuiCol.FrameBgHovered) else col = ImGui.GetColorU32(ImGuiCol.FrameBg) end end window.DrawList:AddCircleFilled(center, radius, col, num_segment) if active then local pad = ImMax(1.0, IM_TRUNC(square_sz / 6.0)) window.DrawList:AddCircleFilled(center, radius - pad, ImGui.GetColorU32(ImGuiCol.CheckMark)) end if style.FrameBorderSize > 0.0 then window.DrawList:AddCircle(center + ImVec2(1, 1), radius, ImGui.GetColorU32(ImGuiCol.BorderShadow), num_segment, style.FrameBorderSize) window.DrawList:AddCircle(center, radius, ImGui.GetColorU32(ImGuiCol.Border), num_segment, style.FrameBorderSize) end local label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y) if g.LogEnabled then -- ImGui.LogRenderedText(label_pos, active and "(x)" or "( )") end if label_size.x > 0.0 then ImGui.RenderText(label_pos, label, 1, label_end, false) end return pressed end -- `rawequal` is used here to check if v == v_button --- @param label string --- @param v any --- @param v_button any --- @return bool is_pressed --- @return any v # Updated v function ImGui.RadioButton(label, v, v_button) local pressed = ImGui.RadioButtonEx(label, rawequal(v, v_button)) if pressed then v = v_button end return pressed, v end -- size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size --- @param fraction float --- @param size_arg? ImVec2 --- @param overlay? string function ImGui.ProgressBar(fraction, size_arg, overlay) if size_arg == nil then size_arg = ImVec2(-FLT_MIN, 0) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local style = g.Style local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local size = ImGui.CalcItemSize(size_arg, ImGui.CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0) local bb = ImRect(pos, pos + size) ImGui.ItemSize(size, style.FramePadding.y) if not ImGui.ItemAdd(bb, 0) then return end -- Fraction < 0.0 will display an indeterminate progress bar animation -- The value must be animated along with time, so e.g. passing '-1.0 * ImGui.GetTime()' as fraction works local is_indeterminate = (fraction < 0.0) if not is_indeterminate then fraction = ImSaturate(fraction) end -- Out of courtesy we accept a NaN fraction without crashing local fill_n0 = 0.0 local fill_n1 = (fraction == fraction) and fraction or 0.0 if is_indeterminate then local fill_width_n = 0.2 fill_n0 = ImFmod(-fraction, 1.0) * (1.0 + fill_width_n) - fill_width_n fill_n1 = ImSaturate(fill_n0 + fill_width_n) fill_n0 = ImSaturate(fill_n0) end -- Render ImGui.RenderFrame(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.FrameBg), true, style.FrameRounding) bb:Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)) local fill_x0 = ImLerp(bb.Min.x, bb.Max.x, fill_n0) local fill_x1 = ImLerp(bb.Min.x, bb.Max.x, fill_n1) if fill_x0 < fill_x1 then ImGui.RenderRectFilledInRangeH(window.DrawList, bb, ImGui.GetColorU32(ImGuiCol.PlotHistogram), fill_x0, fill_x1, style.FrameRounding) end -- Default displaying the fraction as percentage string, but user can override it -- Don't display text for indeterminate bars by default if not is_indeterminate or overlay ~= nil then if overlay == nil then overlay = ImFormatString("%.0f%%", fraction * 100 + 0.01) end local overlay_size = ImGui.CalcTextSize(overlay, nil) if overlay_size.x > 0.0 then local text_x = is_indeterminate and ((bb.Min.x + bb.Max.x - overlay_size.x) * 0.5) or (fill_x1 + style.ItemSpacing.x) ImGui.RenderTextClipped(ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, nil, overlay_size, ImVec2(0.0, 0.5), bb) end end end function ImGui.Bullet() local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local style = g.Style local line_height = ImMax(ImMin(window.DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize) local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + ImVec2(g.FontSize, line_height)) ImGui.ItemSize(bb) if not ImGui.ItemAdd(bb, 0) then ImGui.SameLine(0, style.FramePadding.x * 2) return end -- Render and stay on same line local text_col = ImGui.GetColorU32(ImGuiCol.Text) ImGui.RenderBullet(window.DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5, line_height * 0.5), text_col) ImGui.SameLine(0, style.FramePadding.x * 2.0) end --- @param label string function ImGui.TextLink(label) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y + window.DC.CurrLineTextBaseOffset) local size = ImGui.CalcTextSize(label, label_end, false) local bb = ImRect(pos, pos + size) ImGui.ItemSize(size, 0.0) if not ImGui.ItemAdd(bb, id) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id) ImGui.RenderNavCursor(bb, id) if hovered then ImGui.SetMouseCursor(ImGuiMouseCursor.Hand) end local text_colf = ImVec4() ImVec4_Copy(text_colf, g.Style.Colors[ImGuiCol.TextLink]) local line_colf = ImVec4() ImVec4_Copy(line_colf, text_colf) do -- FIXME-STYLE: Read comments above. This widget is NOT written in the same style as some earlier widgets, -- as we are currently experimenting/planning a different styling system. local h, s, v = ImGui.ColorConvertRGBtoHSV(text_colf.x, text_colf.y, text_colf.z) if held or hovered then v = ImSaturate(v + (held and 0.4 or 0.3)) h = ImFmod(h + 0.02, 1.0) end text_colf.x, text_colf.y, text_colf.z = ImGui.ColorConvertHSVtoRGB(h, s, v) v = ImSaturate(v - 0.20) line_colf.x, line_colf.y, line_colf.z = ImGui.ColorConvertHSVtoRGB(h, s, v) end local line_y = bb.Max.y + ImFloor(g.FontBaked.Descent * g.FontBakedScale * 0.20) window.DrawList:AddLineH(bb.Min.x, bb.Max.x, line_y, ImGui.GetColorU32(line_colf), 1.0 * ImTrunc(g.Style._MainScale)) -- FIXME-DPI ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(text_colf)) ImGui.RenderText(bb.Min, label, 1, label_end, false) ImGui.PopStyleColor() -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags) return pressed end --- @param label string --- @param url string function ImGui.TextLinkOpenURL(label, url) local g = GImGui if url == nil then url = label end local pressed = ImGui.TextLink(label) if pressed and g.PlatformIO.Platform_OpenInShellFn ~= nil then g.PlatformIO.Platform_OpenInShellFn(g, url) end ImGui.SetItemTooltip(ImGui.LocalizeGetMsg(ImGuiLocKey.OpenLink_s), url) if ImGui.BeginPopupContextItem() then if ImGui.MenuItem(ImGui.LocalizeGetMsg(ImGuiLocKey.CopyLink)) then ImGui.SetClipboardText(url) end ImGui.EndPopup() end return pressed end ---------------------------------------------------------------- -- [SECTION] Low-level Layout helpers ---------------------------------------------------------------- function ImGui.Spacing() local window = ImGui.GetCurrentWindow() if window.SkipItems then return end ImGui.ItemSize(ImVec2(0, 0)) end --- @param size ImVec2 function ImGui.Dummy(size) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + size) ImGui.ItemSize(size) ImGui.ItemAdd(bb, 0) end function ImGui.NewLine() local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui local backup_layout_type = window.DC.LayoutType window.DC.LayoutType = ImGuiLayoutType.Vertical window.DC.IsSameLine = false if window.DC.CurrLineSize.y > 0.0 then -- In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. ImGui.ItemSize(ImVec2(0, 0)) else ImGui.ItemSize(ImVec2(0.0, g.FontSize)) end window.DC.LayoutType = backup_layout_type end function ImGui.AlignTextToFramePadding() local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui window.DC.CurrLineSize.y = ImMax(window.DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2) window.DC.CurrLineTextBaseOffset = ImMax(window.DC.CurrLineTextBaseOffset, g.Style.FramePadding.y) end --- @param flags ImGuiSeparatorFlags --- @param thickness float function ImGui.SeparatorEx(flags, thickness) if thickness == nil then thickness = 1.0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return end local g = GImGui IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, bit32.bor(ImGuiSeparatorFlags.Horizontal, ImGuiSeparatorFlags.Vertical)))) -- Check that only 1 option is selected IM_ASSERT(thickness > 0.0) if bit32.band(flags, ImGuiSeparatorFlags.Vertical) ~= 0 then -- Vertical separator, for menu bars (use current line height). local y1 = window.DC.CursorPos.y local y2 = window.DC.CursorPos.y + window.DC.CurrLineSize.y local bb = ImRect(ImVec2(window.DC.CursorPos.x, y1), ImVec2(window.DC.CursorPos.x + thickness, y2)) ImGui.ItemSize(ImVec2(thickness, 0.0)) if not ImGui.ItemAdd(bb, 0) then return end -- Draw window.DrawList:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Separator)) if g.LogEnabled then ImGui.LogText(" |") end elseif bit32.band(flags, ImGuiSeparatorFlags.Horizontal) ~= 0 then -- Horizontal Separator local x1 = window.DC.CursorPos.x local x2 = window.WorkRect.Max.x -- Preserve legacy behavior inside Columns() -- Before Tables API happened, we relied on Separator() to span all columns of a Columns() set. -- We currently don't need to provide the same feature for tables because tables naturally have border features. local columns = (bit32.band(flags, ImGuiSeparatorFlags.SpanAllColumns) ~= 0) and window.DC.CurrentColumns or nil if columns then x1 = window.Pos.x + window.DC.Indent.x -- Used to be Pos.x before 2023/10/03 x2 = window.Pos.x + window.Size.x ImGui.PushColumnsBackground() end -- We don't provide our width to the layout so that it doesn't get feed back into AutoFit -- FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) local bb = ImRect(ImVec2(x1, window.DC.CursorPos.y), ImVec2(x2, window.DC.CursorPos.y + thickness)) ImGui.ItemSize(ImVec2(0.0, thickness)) if ImGui.ItemAdd(bb, 0) then -- Draw window.DrawList:AddRectFilled(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.Separator)) if g.LogEnabled then ImGui.LogRenderedText(bb.Min, "--------------------------------") end end if columns then ImGui.PopColumnsBackground() columns.LineMinY = window.DC.CursorPos.y end end end function ImGui.Separator() local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end -- Those flags should eventually be configurable by the user local flags if window.DC.LayoutType == ImGuiLayoutType.Horizontal then flags = ImGuiSeparatorFlags.Vertical else flags = ImGuiSeparatorFlags.Horizontal end -- Only applies to legacy Columns() api as they relied on Separator() a lot. if window.DC.CurrentColumns then flags = bit32.bor(flags, ImGuiSeparatorFlags.SpanAllColumns) end ImGui.SeparatorEx(flags, ImMax(g.Style.SeparatorSize, 1.0)) end --- @param id ImGuiID --- @param label string --- @param label_end? int --- @param extra_w float function ImGui.SeparatorTextEx(id, label, label_end, extra_w) local g = GImGui local window = g.CurrentWindow local style = g.Style local label_size = ImGui.CalcTextSize(label, label_end, false) local pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y) local padding = style.SeparatorTextPadding local separator_thickness = style.SeparatorTextBorderSize local min_size = ImVec2(label_size.x + extra_w + padding.x * 2.0, ImMax(label_size.y + padding.y * 2.0, separator_thickness)) local bb = ImRect(pos, ImVec2(window.WorkRect.Max.x, pos.y + min_size.y)) local text_baseline_y = ImTrunc((bb:GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.999) -- ImMax(padding.y, ImTrunc((style.SeparatorTextSize - label_size.y) * 0.5f)) ImGui.ItemSize(min_size, text_baseline_y) if not ImGui.ItemAdd(bb, id) then return end local sep1_x1 = pos.x local sep2_x2 = bb.Max.x local seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5 + 0.999) local label_avail_w = ImMax(0.0, sep2_x2 - sep1_x1 - padding.x * 2.0) local label_pos = ImVec2(pos.x + padding.x + ImMax(0.0, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y) -- FIXME-ALIGN -- This allows using SameLine() to position something in the 'extra_w' window.DC.CursorPosPrevLine.x = label_pos.x + label_size.x local separator_col = ImGui.GetColorU32(ImGuiCol.Separator) if label_size.x > 0.0 then local sep1_x2 = label_pos.x - style.ItemSpacing.x local sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x if sep1_x2 > sep1_x1 and separator_thickness > 0.0 then window.DrawList:AddLineH(sep1_x1, sep1_x2, seps_y, separator_col, separator_thickness) end if sep2_x2 > sep2_x1 and separator_thickness > 0.0 then window.DrawList:AddLineH(sep2_x1, sep2_x2, seps_y, separator_col, separator_thickness) end if g.LogEnabled then ImGui.LogSetNextTextDecoration("---", nil) end ImGui.RenderTextEllipsis(window.DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, label_size) else if g.LogEnabled then ImGui.LogText("---") end if separator_thickness > 0.0 then window.DrawList:AddLineH(sep1_x1, sep2_x2, seps_y, separator_col, separator_thickness) end end end --- @param label string function ImGui.SeparatorText(label) local window = ImGui.GetCurrentWindow() if window.SkipItems then return end ImGui.SeparatorTextEx(0, label, ImGui.FindRenderedTextEnd(label), 0.0) end ---------------------------------------------------------------- -- [SECTION] COMBO BOX ---------------------------------------------------------------- --- @param items_count float --- @return float local function CalcMaxPopupHeightFromItemCount(items_count) local g = GImGui if items_count <= 0 then return FLT_MAX end return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2) end --- @param label string --- @param preview_value? string --- @param flags? ImGuiComboFlags function ImGui.BeginCombo(label, preview_value, flags) if flags == nil then flags = 0 end local g = GImGui local window = ImGui.GetCurrentWindow() local backup_next_window_data_flags = g.NextWindowData.HasFlags g.NextWindowData:ClearFlags() if window.SkipItems then return false end local style = g.Style local id = window:GetID(label) IM_ASSERT(bit32.band(flags, bit32.bor(ImGuiComboFlags.NoArrowButton, ImGuiComboFlags.NoPreview)) ~= bit32.bor(ImGuiComboFlags.NoArrowButton, ImGuiComboFlags.NoPreview)) -- Can't use both flags together if bit32.band(flags, ImGuiComboFlags.WidthFitPreview) ~= 0 then IM_ASSERT(bit32.band(flags, bit32.bor(ImGuiComboFlags.NoPreview, ImGuiComboFlags.CustomPreview)) == 0) end local arrow_size if (bit32.band(flags, ImGuiComboFlags.NoArrowButton) ~= 0) then arrow_size = 0.0 else arrow_size = ImGui.GetFrameHeight() end local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local preview_width if ((bit32.band(flags, ImGuiComboFlags.WidthFitPreview) ~= 0) and (preview_value ~= nil)) then preview_width = ImGui.CalcTextSize(preview_value, nil, false).x else preview_width = 0.0 end local w if bit32.band(flags, ImGuiComboFlags.NoPreview) ~= 0 then w = arrow_size elseif bit32.band(flags, ImGuiComboFlags.WidthFitPreview) ~= 0 then w = arrow_size + preview_width + style.FramePadding.x * 2.0 else w = ImGui.CalcItemWidth() end local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0)) local label_offset = (label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0 local total_bb = ImRect(bb.Min, bb.Max + ImVec2(label_offset, 0.0)) ImGui.ItemSize(total_bb, style.FramePadding.y) if not ImGui.ItemAdd(total_bb, id, bb) then return false end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id) local popup_id = ImHashStr("##ComboPopup", nil, id) local popup_open = ImGui.IsPopupOpen(popup_id, ImGuiPopupFlags.None) if pressed and not popup_open then ImGui.OpenPopupEx(popup_id, ImGuiPopupFlags.None) popup_open = true end -- Render shape local frame_col = ImGui.GetColorU32(hovered and ImGuiCol.FrameBgHovered or ImGuiCol.FrameBg) local value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size) ImGui.RenderNavCursor(bb, id) if bit32.band(flags, ImGuiComboFlags.NoPreview) == 0 then window.DrawList:AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (bit32.band(flags, ImGuiComboFlags.NoArrowButton) ~= 0) and ImDrawFlags.RoundCornersAll or ImDrawFlags.RoundCornersLeft) end if bit32.band(flags, ImGuiComboFlags.NoArrowButton) == 0 then local bg_col = ImGui.GetColorU32((popup_open or hovered) and ImGuiCol.ButtonHovered or ImGuiCol.Button) local text_col = ImGui.GetColorU32(ImGuiCol.Text) window.DrawList:AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) and ImDrawFlags.RoundCornersAll or ImDrawFlags.RoundCornersRight) if value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x then ImGui.RenderArrow(window.DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir.Down, 1.0) end end ImGui.RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding) -- Custom preview if bit32.band(flags, ImGuiComboFlags.CustomPreview) ~= 0 then g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y) IM_ASSERT(preview_value == nil or preview_value == "") preview_value = nil end -- Render preview and label if preview_value ~= nil and bit32.band(flags, ImGuiComboFlags.NoPreview) == 0 then if g.LogEnabled then ImGui.LogSetNextTextDecoration("{", "}") end ImGui.RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, nil, nil) end if label_size.x > 0 then ImGui.RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end if not popup_open then return false end g.NextWindowData.HasFlags = backup_next_window_data_flags return ImGui.BeginComboPopup(popup_id, bb, flags) end --- @param popup_id ImGuiID --- @param bb ImRect --- @param flags ImGuiComboFlags function ImGui.BeginComboPopup(popup_id, bb, flags) local g = GImGui if not ImGui.IsPopupOpen(popup_id, ImGuiPopupFlags.None) then g.NextWindowData:ClearFlags() return false end local w = bb:GetWidth() if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSizeConstraint) ~= 0 then g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w) else if bit32.band(flags, ImGuiComboFlags.HeightMask_) == 0 then flags = bit32.bor(flags, ImGuiComboFlags.HeightRegular) end IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiComboFlags.HeightMask_))) local popup_max_height_in_items = -1 if bit32.band(flags, ImGuiComboFlags.HeightRegular) ~= 0 then popup_max_height_in_items = 8 elseif bit32.band(flags, ImGuiComboFlags.HeightSmall) ~= 0 then popup_max_height_in_items = 4 elseif bit32.band(flags, ImGuiComboFlags.HeightLarge) ~= 0 then popup_max_height_in_items = 20 end local constraint_min = ImVec2(0.0, 0.0) local constraint_max = ImVec2(FLT_MAX, FLT_MAX) if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) == 0 or g.NextWindowData.SizeVal.x <= 0.0 then constraint_min.x = w end if bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSize) == 0 or g.NextWindowData.SizeVal.y <= 0.0 then constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items) end ImGui.SetNextWindowSizeConstraints(constraint_min, constraint_max) end -- This is essentially a specialized version of BeginPopupEx() local name = ImFormatString("##Combo_%02d", g.BeginComboDepth) -- Set position given a custom constraint (peak into expected window size so we can position it) -- FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? -- FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()? local popup_window = ImGui.FindWindowByName(name) if popup_window then if popup_window.WasActive then -- Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us. local size_expected = ImGui.CalcWindowNextAutoFitSize(popup_window) popup_window.AutoPosLastDirection = (bit32.band(flags, ImGuiComboFlags.PopupAlignLeft) ~= 0) and ImGuiDir.Left or ImGuiDir.Down local r_outer = ImGui.GetPopupAllowedExtentRect(popup_window) local pos pos, popup_window.AutoPosLastDirection = ImGui.FindBestWindowPosForPopupEx(bb:GetBL(), size_expected, popup_window.AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy.ComboBox) ImGui.SetNextWindowPos(pos) end end -- We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() local window_flags = bit32.bor(ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.Popup, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoMove) ImGui.PushStyleVarX(ImGuiStyleVar.WindowPadding, g.Style.FramePadding.x) -- Horizontally align ourselves with the framed text local _, ret = ImGui.Begin(name, nil, window_flags) ImGui.PopStyleVar() if not ret then ImGui.EndPopup() if not g.IO.ConfigDebugBeginReturnValueOnce and not g.IO.ConfigDebugBeginReturnValueLoop then -- Begin may only return false with those debug tools activated. IM_ASSERT(false) -- This should never happen as we tested for IsPopupOpen() above end return false end g.BeginComboDepth = g.BeginComboDepth + 1 return true end function ImGui.EndCombo() local g = GImGui g.BeginComboDepth = g.BeginComboDepth - 1 local name = ImFormatString("##Combo_%02d", g.BeginComboDepth) -- FIXME: Move those to helpers? if g.CurrentWindow.Name ~= name then IM_ASSERT_USER_ERROR_RET(false, "Calling EndCombo() in wrong window!") end ImGui.EndPopup() end -- Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements -- (Experimental, see GitHub issues: #1658, #4168) function ImGui.BeginComboPreview() local g = GImGui local window = g.CurrentWindow local preview_data = g.ComboPreviewData if window.SkipItems or not (bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0) then return false end IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data.PreviewRect.Min.x and g.LastItemData.Rect.Min.y == preview_data.PreviewRect.Min.y) -- Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags.CustomPreview flag? if not window.ClipRect:Overlaps(preview_data.PreviewRect) then -- Narrower test (optional) return false end -- FIXME: This could be contained in a PushWorkRect() api ImVec2_Copy(preview_data.BackupCursorPos, window.DC.CursorPos) ImVec2_Copy(preview_data.BackupCursorMaxPos, window.DC.CursorMaxPos) ImVec2_Copy(preview_data.BackupCursorPosPrevLine, window.DC.CursorPosPrevLine) preview_data.BackupPrevLineTextBaseOffset = window.DC.PrevLineTextBaseOffset preview_data.BackupLayout = window.DC.LayoutType ImVec2_Copy(window.DC.CursorPos, preview_data.PreviewRect.Min + g.Style.FramePadding) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorPos) window.DC.LayoutType = ImGuiLayoutType.Horizontal window.DC.IsSameLine = false ImGui.PushClipRect(preview_data.PreviewRect.Min, preview_data.PreviewRect.Max, true) return true end function ImGui.EndComboPreview() local g = GImGui local window = g.CurrentWindow local preview_data = g.ComboPreviewData local draw_list = window.DrawList if window.DC.CursorMaxPos.x < preview_data.PreviewRect.Max.x and window.DC.CursorMaxPos.y < preview_data.PreviewRect.Max.y then if draw_list.CmdBuffer.Size > 1 then -- Unlikely case that the PushClipRect() didn't create a command ImVec4_Copy(draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].ClipRect, draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size - 1].ClipRect) ImVec4_Copy(draw_list._CmdHeader.ClipRect, draw_list.CmdBuffer.Data[draw_list.CmdBuffer.Size].ClipRect) draw_list:_TryMergeDrawCmds() end end ImGui.PopClipRect() ImVec2_Copy(window.DC.CursorPos, preview_data.BackupCursorPos) ImVec2_Copy(window.DC.CursorMaxPos, ImMax(window.DC.CursorMaxPos, preview_data.BackupCursorMaxPos)) ImVec2_Copy(window.DC.CursorPosPrevLine, preview_data.BackupCursorPosPrevLine) window.DC.PrevLineTextBaseOffset = preview_data.BackupPrevLineTextBaseOffset window.DC.LayoutType = preview_data.BackupLayout window.DC.IsSameLine = false preview_data.PreviewRect = ImRect() end -- Getter for the old Combo() API: Lua array of strings (1-based), `idx` is 0-based local function Items_ArrayGetter(data, idx) return data[idx + 1] end -- Getter for the old Combo() API: "item1\0item2\0item3\0" local function Items_SingleStringGetter(data, idx) local items_count = 0 local p = 1 while p <= #data and string.byte(data, p) ~= 0 do local e = string.find(data, "\0", p, true) or (#data + 1) if idx == items_count then return string.sub(data, p, e - 1) end p = e + 1 items_count = items_count + 1 end return nil end local function Items_SingleStringCount(data) local items_count = 0 local p = 1 while p <= #data and string.byte(data, p) ~= 0 do p = (string.find(data, "\0", p, true) or #data) + 1 items_count = items_count + 1 end return items_count end -- Normalizes the 3 upstream overloads to (getter, user_data, items_count, height) -- - (items: string[], items_count?, height?) -- - (items_separated_by_zeros: string, height?) -- - (getter: fun(user_data, idx): string?, user_data, items_count, height?) local function Items_ResolveArgs(a, b, c, d) if type(a) == "function" then return a, b, c, d elseif type(a) == "string" then return Items_SingleStringGetter, a, Items_SingleStringCount(a), b else return Items_ArrayGetter, a, b or #a, c end end -- Old API, prefer using BeginCombo() nowadays if you can. --- @param label string --- @param current_item int # 0-based --- @return int current_item --- @return bool value_changed function ImGui.Combo(label, current_item, a, b, c, d) local g = GImGui local getter, user_data, items_count, popup_max_height_in_items = Items_ResolveArgs(a, b, c, d) if popup_max_height_in_items == nil then popup_max_height_in_items = -1 end local preview_value = nil if bit32.band(bit32.bor(g.NextItemData.ItemFlagsSet, g.CurrentItemFlags), ImGuiItemFlags.MixedValue) ~= 0 then preview_value = "" elseif current_item >= 0 and current_item < items_count then preview_value = getter(user_data, current_item) end if popup_max_height_in_items ~= -1 and bit32.band(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasSizeConstraint) == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))) end if not ImGui.BeginCombo(label, preview_value, ImGuiComboFlags.None) then return current_item, false end local value_changed = false local clipper = ImGuiListClipper() clipper:Begin(items_count) clipper:IncludeItemByIndex(current_item) while clipper:Step() do for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do local item_text = getter(user_data, i) if item_text == nil then item_text = "*Unknown item*" end ImGui.PushID(i) local item_selected = (i == current_item) if ImGui.Selectable(item_text, item_selected) and current_item ~= i then value_changed = true current_item = i end if item_selected then ImGui.SetItemDefaultFocus() end ImGui.PopID() end end ImGui.EndCombo() if value_changed then ImGui.MarkItemEdited(g.LastItemData.ID) end return current_item, value_changed end ---------------------------------------------------------------- -- [SECTION] DATA TYPE & DATA FORMATTING [Internal] ---------------------------------------------------------------- local function float(val) return val end local function double(val) return val end local GDefaultRgbaColorMarkers = { IM_COL32(240, 20, 20, 255), IM_COL32(20, 240, 20, 255), IM_COL32(20, 20, 240, 255), IM_COL32(140, 140, 140, 255) } --- @param size size_t --- @param name string --- @param print_fmt string --- @param scan_fmt string --- @return ImGuiDataTypeInfo --- @nodiscard --- @package local function ImGuiDataTypeInfo(size, name, print_fmt, scan_fmt) return { Size = size, Name = name, PrintFmt = print_fmt, ScanFmt = scan_fmt } end local GDataTypeInfo = { ImGuiDataTypeInfo(1, "S8", "%d", "%d"), ImGuiDataTypeInfo(1, "U8", "%u", "%u"), ImGuiDataTypeInfo(2, "S16", "%d", "%d"), ImGuiDataTypeInfo(2, "U16", "%u", "%u"), ImGuiDataTypeInfo(4, "S32", "%d", "%d"), ImGuiDataTypeInfo(4, "U32", "%u", "%u"), ImGuiDataTypeInfo(4, "float", "%.3f", "%f"), ImGuiDataTypeInfo(8, "double", "%f", "%lf"), ImGuiDataTypeInfo(1, "bool", "%d", "%d"), ImGuiDataTypeInfo(0, "string", "%s", "%s") } --- @param data_type ImGuiDataType function ImGui.DataTypeGetInfo(data_type) IM_ASSERT(data_type >= 0 and data_type < ImGuiDataType.COUNT) return GDataTypeInfo[data_type + 1] end --- @param buf char[] --- @param buf_size int --- @param data_type ImGuiDataType --- @param data number --- @param format string function ImGui.DataTypeFormatString(buf, buf_size, data_type, data, format) local str if data_type == ImGuiDataType.S32 then str = ImFormatString(format, (ImS32)(data)) elseif data_type == ImGuiDataType.U32 then str = ImFormatString(format, (ImU32)(data)) elseif data_type == ImGuiDataType.Float then str = ImFormatString(format, data) elseif data_type == ImGuiDataType.Double then str = ImFormatString(format, data) elseif data_type == ImGuiDataType.S8 then str = ImFormatString(format, (ImS8)(data)) elseif data_type == ImGuiDataType.U8 then str = ImFormatString(format, (ImU8)(data)) elseif data_type == ImGuiDataType.S16 then str = ImFormatString(format, (ImS16)(data)) elseif data_type == ImGuiDataType.U16 then str = ImFormatString(format, (ImU16)(data)) else IM_ASSERT(false) end ImStd.ImStrncpy(buf, 1, { string.byte(str, 1, #str) }, 1, ImMin(#str + 1, buf_size)) -- TODO: update this when new ImFormatString is implemented end --- @param data_type ImGuiDataType --- @param op int --- @param arg1 number --- @param arg2 number function ImGui.DataTypeApplyOp(data_type, op, arg1, arg2) IM_ASSERT(op == 43 or op == 45) -- '+' or '-' if data_type == ImGuiDataType.S8 then if op == 43 then return ImAddClampOverflow(arg1, arg2, IM_S8_MIN, IM_S8_MAX) elseif op == 45 then return ImSubClampOverflow(arg1, arg2, IM_S8_MIN, IM_S8_MAX) end elseif data_type == ImGuiDataType.U8 then if op == 43 then return ImAddClampOverflow(arg1, arg2, IM_U8_MIN, IM_U8_MAX) elseif op == 45 then return ImSubClampOverflow(arg1, arg2, IM_U8_MIN, IM_U8_MAX) end elseif data_type == ImGuiDataType.S16 then if op == 43 then return ImAddClampOverflow((ImS16)(arg1), (ImS16)(arg2), IM_S16_MIN, IM_S16_MAX) elseif op == 45 then return ImSubClampOverflow((ImS16)(arg1), (ImS16)(arg2), IM_S16_MIN, IM_S16_MAX) end elseif data_type == ImGuiDataType.U16 then if op == 43 then return ImAddClampOverflow((ImU16)(arg1), (ImU16)(arg2), IM_U16_MIN, IM_U16_MAX) elseif op == 45 then return ImSubClampOverflow((ImU16)(arg1), (ImU16)(arg2), IM_U16_MIN, IM_U16_MAX) end elseif data_type == ImGuiDataType.S32 then if op == 43 then return ImAddClampOverflow(arg1, arg2, IM_S32_MIN, IM_S32_MAX) elseif op == 45 then return ImSubClampOverflow(arg1, arg2, IM_S32_MIN, IM_S32_MAX) end elseif data_type == ImGuiDataType.U32 then if op == 43 then return ImAddClampOverflow(arg1, arg2, IM_U32_MIN, IM_U32_MAX) elseif op == 45 then return ImSubClampOverflow(arg1, arg2, IM_U32_MIN, IM_U32_MAX) end elseif data_type == ImGuiDataType.Float then if op == 43 then return arg1 + arg2 elseif op == 45 then return arg1 - arg2 end elseif data_type == ImGuiDataType.Double then if op == 43 then return arg1 + arg2 elseif op == 45 then return arg1 - arg2 end end IM_ASSERT(false) end local ImParseFormatSanitizeForScanning --- @param buf char[] --- @param data_type ImGuiDataType --- @param data number --- @param format string --- @param data_when_empty? number function ImGui.DataTypeApplyFromText(buf, data_type, data, format, data_when_empty) local type_info = ImGui.DataTypeGetInfo(data_type) local data_backup = data local p = 1 while ImCharIsBlankA(buf[p]) do p = p + 1 end if buf[p] == 0 then if data_when_empty ~= nil then data = data_when_empty return data, data_backup ~= data end return data, false end local format_sanitized, format_sanitized_size = {}, 32 if (data_type == ImGuiDataType.Float or data_type == ImGuiDataType.Double) then format = type_info.ScanFmt else format = ImParseFormatSanitizeForScanning(format, format_sanitized, format_sanitized_size) if format[1] == 0 then format = type_info.ScanFmt end end local v32 = 0 local res = {} if ImStd.sscanf(buf, 1, format, res) < 1 then return data, false end if type_info.Size >= 4 then data = res[1] else v32 = res[1] end if type_info.Size < 4 then if data_type == ImGuiDataType.S8 then data = (ImS8)(ImClamp(v32, IM_S8_MIN, IM_S8_MAX)) elseif data_type == ImGuiDataType.U8 then data = (ImU8)(ImClamp(v32, IM_U8_MIN, IM_U8_MAX)) elseif data_type == ImGuiDataType.S16 then data = (ImS16)(ImClamp(v32, IM_S16_MIN, IM_S16_MAX)) elseif data_type == ImGuiDataType.U16 then data = (ImU16)(ImClamp(v32, IM_U16_MIN, IM_U16_MAX)) else IM_ASSERT(false) end end return data, data_backup ~= data end --- @generic T : number --- @param lhs T --- @param rhs T local function DataTypeCompareT(lhs, rhs) if lhs < rhs then return -1 end if lhs > rhs then return 1 end return 0 end --- @param data_type ImGuiDataType --- @param arg1 number --- @param arg2 number function ImGui.DataTypeCompare(data_type, arg1, arg2) if data_type == ImGuiDataType.S8 then return DataTypeCompareT((ImS8)(arg1), (ImS8)(arg2)) elseif data_type == ImGuiDataType.U8 then return DataTypeCompareT((ImU8)(arg1), (ImU8)(arg2)) elseif data_type == ImGuiDataType.S16 then return DataTypeCompareT((ImS16)(arg1), (ImS16)(arg2)) elseif data_type == ImGuiDataType.U16 then return DataTypeCompareT((ImU16)(arg1), (ImU16)(arg2)) elseif data_type == ImGuiDataType.S32 then return DataTypeCompareT((ImS32)(arg1), (ImS32)(arg2)) elseif data_type == ImGuiDataType.U32 then return DataTypeCompareT((ImU32)(arg1), (ImU32)(arg2)) elseif data_type == ImGuiDataType.Float then return DataTypeCompareT(arg1, arg2) elseif data_type == ImGuiDataType.Double then return DataTypeCompareT(arg1, arg2) end IM_ASSERT(false) return 0 end --- @generic T : number --- @param v T --- @param v_min? T --- @param v_max? T --- @return T, boolean local function DataTypeClampT(v, v_min, v_max) if v_min and v < v_min then return v_min, true end if v_max and v > v_max then return v_max, true end return v, false end --- @param data_type ImGuiDataType --- @param data number --- @param min? number --- @param max? number function ImGui.DataTypeClamp(data_type, data, min, max) if data_type == ImGuiDataType.S8 then return DataTypeClampT((ImS8)(data), min and (ImS8)(min), max and (ImS8)(max)) elseif data_type == ImGuiDataType.U8 then return DataTypeClampT((ImU8)(data), min and (ImU8)(min), max and (ImU8)(max)) elseif data_type == ImGuiDataType.S16 then return DataTypeClampT((ImS16)(data), min and (ImS16)(min), max and (ImS16)(max)) elseif data_type == ImGuiDataType.U16 then return DataTypeClampT((ImU16)(data), min and (ImU16)(min), max and (ImU16)(max)) elseif data_type == ImGuiDataType.S32 then return DataTypeClampT((ImS32)(data), min and (ImS32)(min), max and (ImS32)(max)) elseif data_type == ImGuiDataType.U32 then return DataTypeClampT((ImU32)(data), min and (ImU32)(min), max and (ImU32)(max)) elseif data_type == ImGuiDataType.Float then return DataTypeClampT(data, min, max) elseif data_type == ImGuiDataType.Double then return DataTypeClampT(data, min, max) end IM_ASSERT(false) return data, false end --- @param data_type ImGuiDataType --- @param data number function ImGui.DataTypeIsZero(data_type, data) local g = GImGui return ImGui.DataTypeCompare(data_type, data, g.DataTypeZeroValue) == 0 end local GetMinimumStepAtDecimalPrecision do local min_steps = { 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001 } --- @param decimal_precision int --- @return float function GetMinimumStepAtDecimalPrecision(decimal_precision) if decimal_precision < 0 then return FLT_MIN end if decimal_precision < #min_steps then return min_steps[decimal_precision + 1] else return ImPow(10.0, -decimal_precision) end end end local ImParseFormatFindStart --- @param format string --- @param data_type ImGuiDataType --- @param v number function ImGui.RoundScalarWithFormatT(format, data_type, v) -- IM_UNUSED(data_type) IM_ASSERT(data_type == ImGuiDataType.Float or data_type == ImGuiDataType.Double) local fmt_start = ImParseFormatFindStart(format) if string.byte(format, fmt_start) ~= 37 or string.byte(format, fmt_start + 1) == 37 then return v -- Don't apply if the value is not visible in the format string end -- TODO: Sanitize format local str = ImFormatString(format, v) v = ImAtof(str) or v return v end ---------------------------------------------------------------- -- [SECTION] INPUTXXX ---------------------------------------------------------------- --- @param fmt string function ImParseFormatFindStart(fmt) local len = #fmt local i = 1 local c while i < len do c = string.byte(fmt, i) if c == 37 and string.byte(fmt, i + 1) ~= 37 then -- '%' return i elseif c == 37 then i = i + 1 end i = i + 1 end return nil end --- @param fmt string --- @param pos int local function ImParseFormatFindEnd(fmt, pos) -- Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format if string.byte(fmt, pos) ~= 37 then -- '%' return pos end local ignored_uppercase_mask = bit32.bor(bit32.lshift(1, 73 - 65), bit32.lshift(1, 76 - 65)) local ignored_lowercase_mask = bit32.bor(bit32.lshift(1, 104 - 97), bit32.lshift(1, 106 - 97), bit32.lshift(1, 108 - 97), bit32.lshift(1, 116 - 97), bit32.lshift(1, 119 - 97), bit32.lshift(1, 122 - 97)) local len = #fmt local c for i = pos, len do c = string.byte(fmt, i) if c >= 65 and c <= 90 and (bit32.band(bit32.lshift(1, c - 65), ignored_uppercase_mask) == 0) then return i + 1 end if c >= 97 and c <= 122 and (bit32.band(bit32.lshift(1, c - 97), ignored_lowercase_mask) == 0) then return i + 1 end end return len + 1 end -- TODO: temporary patch. does not look good --- @param fmt string local function ImParseFormatTrimDecorations(fmt) local fmt_start = ImParseFormatFindStart(fmt) if string.byte(fmt, fmt_start) ~= 37 then -- '%' return "" end --- @cast fmt_start int local fmt_end = ImParseFormatFindEnd(fmt, fmt_start) if string.byte(fmt, fmt_end) ~= 37 then return string.sub(fmt, fmt_start) end return string.sub(fmt, fmt_start, fmt_end) end --- @param fmt_in string --- @param fmt_out char[] --- @param fmt_out_size size_t function ImParseFormatSanitizeForScanning(fmt_in, fmt_out, fmt_out_size) local fmt_end = ImParseFormatFindEnd(fmt_in, 1) -- IM_UNUSED(fmt_out_size) IM_ASSERT(fmt_end < fmt_out_size) local has_type = false local fmt_in_begin = 1 local fmt_out_begin = 1 while fmt_in_begin < fmt_end do repeat local c = string.byte(fmt_in, fmt_in_begin, fmt_in_begin) fmt_in_begin = fmt_in_begin + 1 if (not has_type and ((c >= 48 and c <= 57) or c == 46 or c == 43 or c == 35)) then break end has_type = has_type or ((c >= 97 and c <= 122) or (c >= 65 and c <= 90)) if c ~= 39 and c ~= 36 and c ~= 95 then fmt_out[fmt_out_begin] = c fmt_out_begin = fmt_out_begin + 1 end until true end -- fmt_out[fmt_out_begin] = 0 return string.char(unpack(fmt_out)) -- FIXME: not ideal end --- @param str string --- @param pos int local function ImAtoi(str, pos) local negative = false if string.byte(str, pos) == 45 then -- '-' negative = true pos = pos + 1 end if string.byte(str, pos) == 43 then -- '+' pos = pos + 1 end local len = #str local v = 0 local c = string.byte(str, pos) while c >= 48 and c <= 57 do v = v * 10 + c - 48 pos = pos + 1 c = string.byte(str, pos) if pos > len then break end end return negative and -v or v, pos end --- @param fmt string --- @param default_precision int local function ImParseFormatPrecision(fmt, default_precision) local pos = ImParseFormatFindStart(fmt) if not pos then return default_precision end pos = pos + 1 local len = #fmt local c = string.byte(fmt, pos) while c >= 48 and c <= 57 do pos = pos + 1 c = string.byte(fmt, pos) if pos > len then break end end local precision = INT_MAX if c == 46 then -- '.' precision, pos = ImAtoi(fmt, pos + 1) if precision < 0 or precision > 99 then precision = default_precision end end c = string.byte(fmt, pos) if c == 101 or c == 69 then -- Maximum precision with scientific notation precision = -1 end if (c == 103 or c == 71) and precision == INT_MAX then precision = -1 end return (precision == INT_MAX) and default_precision or precision end --- @param bb ImRect --- @param id ImGuiID --- @param label string --- @param buf char[] --- @param buf_size int --- @param flags? ImGuiInputTextFlags --- @param callback? ImGuiInputTextCallback --- @param user_data any function ImGui.TempInputText(bb, id, label, buf, buf_size, flags, callback, user_data) if flags == nil then flags = 0 end local g = GImGui local window = g.CurrentWindow local is_deactivated = (g.InputTextDeactivatedState.ID == id) local is_active = (g.TempInputId == id) if (not is_active and not is_deactivated) then ImGui.ClearActiveID() end local backup_pos = ImVec2() ImVec2_Copy(backup_pos, window.DC.CursorPos) ImVec2_Copy(window.DC.CursorPos, bb.Min) g.LastItemData.ItemFlags = bit32.bor(g.LastItemData.ItemFlags, ImGuiItemFlags.AllowDuplicateId) local value_changed = ImGui.InputTextEx(label, nil, buf, buf_size, bb:GetSize(), bit32.bor(flags, ImGuiInputTextFlags.TempInput, ImGuiInputTextFlags.AutoSelectAll), callback, user_data) ImGui.KeepAliveID(id) if (not is_active and not is_deactivated) then IM_ASSERT(g.ActiveId == id) g.TempInputId = g.ActiveId end if is_active and g.ActiveId ~= id then g.TempInputId = 0 end ImVec2_Copy(window.DC.CursorPos, backup_pos) return value_changed end --- @param bb ImRect --- @param id ImGuiID --- @param label string --- @param data_type ImGuiDataType --- @param data number --- @param format string --- @param clamp_min? number --- @param clamp_max? number function ImGui.TempInputScalar(bb, id, label, data_type, data, format, clamp_min, clamp_max) local g = GImGui local type_info = ImGui.DataTypeGetInfo(data_type) local data_buf, data_buf_size = {}, 32 format = ImParseFormatTrimDecorations(format) if format == "" then format = type_info.PrintFmt end ImGui.DataTypeFormatString(data_buf, data_buf_size, data_type, data, format) ImStd.ImStrTrimBlanks(data_buf) local flags = bit32.bor(ImGuiInputTextFlags.AutoSelectAll, ImGuiInputTextFlags.LocalizeDecimalPoint) g.LastItemData.ItemFlags = bit32.bor(g.LastItemData.ItemFlags, ImGuiItemFlags.NoMarkEdited) g.LastItemData.ItemFlags = (bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0) and bit32.bor(g.LastItemData.ItemFlags, ImGuiItemFlags.LiveEditOnInputText) or bit32.band(g.LastItemData.ItemFlags, bit32.bnot(ImGuiItemFlags.LiveEditOnInputText)) if not ImGui.TempInputText(bb, id, label, data_buf, data_buf_size, flags) then return data, false end local data_backup = data data = ImGui.DataTypeApplyFromText(data_buf, data_type, data, format, nil) if clamp_min or clamp_max then if clamp_min and clamp_max and ImGui.DataTypeCompare(data_type, clamp_min, clamp_max) > 0 then clamp_min, clamp_max = clamp_max, clamp_min end data = ImGui.DataTypeClamp(data_type, data, clamp_min, clamp_max) end g.LastItemData.ItemFlags = bit32.band(g.LastItemData.ItemFlags, bit32.bnot(ImGuiItemFlags.NoMarkEdited)) local value_changed = data_backup ~= data if value_changed then ImGui.MarkItemEdited(id) end return data, value_changed end --- @param label string --- @param data_type ImGuiDataType --- @param data number --- @param step? number --- @param step_fast? number --- @param format? string --- @param flags? ImGuiInputTextFlags function ImGui.InputScalar(label, data_type, data, step, step_fast, format, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return data, false end local g = GImGui local style = g.Style if format == nil then format = ImGui.DataTypeGetInfo(data_type).PrintFmt end local data_default = (bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasRefVal) ~= 0) and g.NextItemData.RefVal or g.DataTypeZeroValue local buf, buf_size = {}, 64 -- TODO: IM_COUNTOF() if bit32.band(flags, ImGuiInputTextFlags.DisplayEmptyRefVal) ~= 0 and ImGui.DataTypeCompare(data_type, data, data_default) == 0 then buf[1] = 0 else ImGui.DataTypeFormatString(buf, buf_size, data_type, data, format) end g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.NoMarkEdited) flags = bit32.bor(flags, ImGuiInputTextFlags.AutoSelectAll, ImGuiInputTextFlags.LocalizeDecimalPoint) local has_step_buttons = (step ~= nil) local button_size = has_step_buttons and ImGui.GetFrameHeight() or 0.0 local ret if has_step_buttons then ImGui.BeginGroup() ImGui.PushID(label) ImGui.SetNextItemWidth(ImMax(1.0, ImGui.CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)) ret = ImGui.InputText("", buf, buf_size, flags) -- IMGUI_TEST_ENGINE_ITEM_INFO() else ret = ImGui.InputText(label, buf, buf_size, flags) end local value_changed = false if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0 then local input_edited = bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.EditedInternal) ~= 0 if input_edited then data, value_changed = ImGui.DataTypeApplyFromText(buf, data_type, data, format, bit32.band(flags, ImGuiInputTextFlags.ParseEmptyRefVal) ~= 0 and data_default or nil) end else -- g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_Edited if (g.DeactivatedItemData.ID == g.LastItemData.ID) then -- g.DeactivatedItemData.HasBeenEditedBefore = false; // Will be set below by MarkItemEdited() -- if (IsItemDeactivated()) // Should be unnecessary data, value_changed = ImGui.DataTypeApplyFromText(buf, data_type, data, format, bit32.band(flags, ImGuiInputTextFlags.ParseEmptyRefVal) ~= 0 and data_default or nil) end end if has_step_buttons then local backup_frame_padding = ImVec2() ImVec2_Copy(backup_frame_padding, style.FramePadding) style.FramePadding.x = style.FramePadding.y if bit32.band(flags, ImGuiInputTextFlags.ReadOnly) ~= 0 then ImGui.BeginDisabled() end ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true) ImGui.SameLine(0, style.ItemInnerSpacing.x) --- @cast step number if ImGui.ButtonEx("-", ImVec2(button_size, button_size)) then data = ImGui.DataTypeApplyOp(data_type, 45, data, ((g.IO.KeyCtrl and step_fast) and step_fast or step)) value_changed = true ret = true end ImGui.SameLine(0, style.ItemInnerSpacing.x) if ImGui.ButtonEx("+", ImVec2(button_size, button_size)) then data = ImGui.DataTypeApplyOp(data_type, 43, data, ((g.IO.KeyCtrl and step_fast) and step_fast or step)) value_changed = true ret = true end ImGui.PopItemFlag() if bit32.band(flags, ImGuiInputTextFlags.ReadOnly) ~= 0 then ImGui.EndDisabled() end local label_end = ImGui.FindRenderedTextEnd(label) if label_end ~= 1 then ImGui.SameLine(0, style.ItemInnerSpacing.x) ImGui.TextEx(label, label_end) end ImVec2_Copy(style.FramePadding, backup_frame_padding) ImGui.PopID() ImGui.EndGroup() end g.LastItemData.ItemFlags = bit32.band(g.LastItemData.ItemFlags, bit32.bnot(ImGuiItemFlags.NoMarkEdited)) if value_changed then ImGui.MarkItemEdited(g.LastItemData.ID) end if bit32.band(flags, ImGuiInputTextFlags.EnterReturnsTrue) ~= 0 then return data, ret end return data, value_changed end --- @param label string --- @param data_type ImGuiDataType --- @param data number[] --- @param components int --- @param step? number --- @param step_fast? number --- @param format? string --- @param flags? ImGuiInputTextFlags function ImGui.InputScalarN(label, data_type, data, components, step, step_fast, format, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local value_changed = false ImGui.BeginGroup() ImGui.PushID(label) ImGui.PushMultiItemsWidths(components, ImGui.CalcItemWidth()) for i = 1, components do ImGui.PushID(i - 1) if i > 1 then ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) end local changed data[i], changed = ImGui.InputScalar("", data_type, data[i], step, step_fast, format, flags) if changed then value_changed = true end ImGui.PopID() ImGui.PopItemWidth() end ImGui.PopID() local label_end = ImGui.FindRenderedTextEnd(label) if label_end > 1 then ImGui.SameLine(0.0, g.Style.ItemInnerSpacing.x) ImGui.TextEx(label, label_end) end ImGui.EndGroup() return value_changed end --- @param label string --- @param v [float, float, float] --- @param format? string --- @param flags? ImGuiInputTextFlags function ImGui.InputFloat3(label, v, format, flags) if format == nil then format = "%.3f" end return ImGui.InputScalarN(label, ImGuiDataType.Float, v, 3, nil, nil, format, flags) end function ImGui.InputFloat2(label, v, format, flags) return ImGui.InputScalarN(label, ImGuiDataType.Float, v, 2, nil, nil, format or "%.3f", flags) end function ImGui.InputFloat4(label, v, format, flags) return ImGui.InputScalarN(label, ImGuiDataType.Float, v, 4, nil, nil, format or "%.3f", flags) end function ImGui.InputInt2(label, v, flags) return ImGui.InputScalarN(label, ImGuiDataType.S32, v, 2, nil, nil, "%d", flags) end function ImGui.InputInt3(label, v, flags) return ImGui.InputScalarN(label, ImGuiDataType.S32, v, 3, nil, nil, "%d", flags) end function ImGui.InputInt4(label, v, flags) return ImGui.InputScalarN(label, ImGuiDataType.S32, v, 4, nil, nil, "%d", flags) end --- @param label string --- @param v int --- @param step? int --- @param step_fast? int --- @param flags? ImGuiInputTextFlags function ImGui.InputInt(label, v, step, step_fast, flags) if step == nil then step = 1 end if step_fast == nil then step_fast = 100 end if flags == nil then flags = 0 end local format = (bit32.band(flags, ImGuiInputTextFlags.CharsHexadecimal) ~= 0) and "%08X" or "%d" return ImGui.InputScalar(label, ImGuiDataType.S32, v, (step > 0) and step or nil, (step_fast > 0) and step_fast or nil, format, flags) end --- @param label string --- @param v float --- @param step? float --- @param step_fast? float --- @param format? string --- @param flags? ImGuiInputTextFlags function ImGui.InputFloat(label, v, step, step_fast, format, flags) if step == nil then step = .0 end if step_fast == nil then step_fast = .0 end if format == nil then format = "%.3f" end return ImGui.InputScalar(label, ImGuiDataType.Float, v, (step > 0.0 and step or nil), (step_fast > 0.0 and step_fast or nil), format, flags) end --- @param label string --- @param v double --- @param step? double --- @param step_fast? double --- @param format? string --- @param flags? ImGuiInputTextFlags function ImGui.InputDouble(label, v, step, step_fast, format, flags) if step == nil then step = .0 end if step_fast == nil then step_fast = .0 end if format == nil then format = "%.6f" end return ImGui.InputScalar(label, ImGuiDataType.Double, v, (step > 0.0 and step or nil), (step_fast > 0.0 and step_fast or nil), format, flags) end ---------------------------------------------------------------- -- [SECTION] DRAGXXX ---------------------------------------------------------------- -- This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) --- @generic T : number --- @param TYPE fun(val: number): T --- @param SIGNEDTYPE fun(val: number): T --- @param data_type ImGuiDataType --- @param v T --- @param v_speed float --- @param v_min T --- @param v_max T --- @param format string --- @param flags ImGuiSliderFlags --- @return T new_v # Updated `v` --- @return bool changed function ImGui.DragBehaviorT(TYPE, SIGNEDTYPE, data_type, v, v_speed, v_min, v_max, format, flags) local g = GImGui local axis = (bit32.band(flags, ImGuiSliderFlags.Vertical) ~= 0) and ImGuiAxis.Y or ImGuiAxis.X local is_bounded = (v_min < v_max) or ((v_min == v_max) and (v_min ~= 0.0 or (bit32.band(flags, ImGuiSliderFlags.ClampZeroRange) ~= 0))) local is_wrapped = is_bounded and (bit32.band(flags, ImGuiSliderFlags.WrapAround) ~= 0) local is_logarithmic = bit32.band(flags, ImGuiSliderFlags.Logarithmic) ~= 0 local is_floating_point = (data_type == ImGuiDataType.Float) or (data_type == ImGuiDataType.Double) -- Default tweak speed if v_speed == 0.0 and is_bounded and (v_max - v_min < math.huge) then v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio end -- Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings local adjust_delta = 0.0 if g.ActiveIdSource == ImGuiInputSource.Mouse and ImGui.IsMousePosValid() and ImGui.IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR) then adjust_delta = g.IO.MouseDelta[axis] if g.IO.KeyAlt and bit32.band(flags, ImGuiSliderFlags.NoSpeedTweaks) == 0 then adjust_delta = adjust_delta / 100.0 end if g.IO.KeyShift and bit32.band(flags, ImGuiSliderFlags.NoSpeedTweaks) == 0 then adjust_delta = adjust_delta * 10.0 end elseif g.ActiveIdSource == ImGuiInputSource.Keyboard or g.ActiveIdSource == ImGuiInputSource.Gamepad then local decimal_precision if is_floating_point then decimal_precision = ImParseFormatPrecision(format, 3) else decimal_precision = 0 end local slow_key = (g.NavInputSource == ImGuiInputSource.Gamepad) and ImGuiKey.NavGamepadTweakSlow or ImGuiKey.NavKeyboardTweakSlow local fast_key = (g.NavInputSource == ImGuiInputSource.Gamepad) and ImGuiKey.NavGamepadTweakFast or ImGuiKey.NavKeyboardTweakFast local tweak_factor if bit32.band(flags, ImGuiSliderFlags.NoSpeedTweaks) ~= 0 then tweak_factor = 1.0 elseif ImGui.IsKeyDown(slow_key) then tweak_factor = 1.0 / 10.0 elseif ImGui.IsKeyDown(fast_key) then tweak_factor = 10.0 else tweak_factor = 1.0 end adjust_delta = ImGui.GetNavTweakPressedAmount(axis) * tweak_factor v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)) end adjust_delta = adjust_delta * v_speed -- For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter if axis == ImGuiAxis.Y then adjust_delta = -adjust_delta end -- For logarithmic use our range is effectively 0..1 so scale the delta into that range if is_logarithmic and (v_max - v_min < FLT_MAX) and (v_max - v_min > 0.000001) then -- Epsilon to avoid /0 adjust_delta = adjust_delta / (v_max - v_min) end -- Clear current value on activation -- Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. local is_just_activated = g.ActiveIdIsJustActivated local is_already_past_limits_and_pushing_outward = is_bounded and not is_wrapped and ((v >= v_max and adjust_delta > 0.0) or (v <= v_min and adjust_delta < 0.0)) if is_just_activated or is_already_past_limits_and_pushing_outward then g.DragCurrentAccum = 0.0 g.DragCurrentAccumDirty = false elseif adjust_delta ~= 0.0 then g.DragCurrentAccum = g.DragCurrentAccum + adjust_delta g.DragCurrentAccumDirty = true end if not g.DragCurrentAccumDirty then return v, false end local v_cur = (TYPE)(v) local v_old_ref_for_accum_remainder = 0.0 local logarithmic_zero_epsilon = 0.0 -- Only valid when is_logarithmic is true local zero_deadzone_halfsize = 0.0 -- Drag widgets have no deadzone (as it doesn't make sense) if is_logarithmic then -- When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. local decimal_precision if is_floating_point then decimal_precision = ImParseFormatPrecision(format, 3) else decimal_precision = 1 end logarithmic_zero_epsilon = ImPow(0.1, decimal_precision) -- Convert to parametric space, apply delta, convert back local v_old_parametric = ImGui.ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) local v_new_parametric = v_old_parametric + g.DragCurrentAccum v_cur = ImGui.ScaleValueFromRatioT(TYPE, SIGNEDTYPE, data_type, v_new_parametric, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) v_old_ref_for_accum_remainder = v_old_parametric else v_cur = (TYPE)(v_cur + (SIGNEDTYPE)(g.DragCurrentAccum)) end -- Round to user desired precision based on format string if is_floating_point and bit32.band(flags, ImGuiSliderFlags.NoRoundToFormat) == 0 then v_cur = ImGui.RoundScalarWithFormatT(format, data_type, v_cur) end -- Preserve remainder after rounding has been applied. This also allow slow tweaking of values g.DragCurrentAccumDirty = false if is_logarithmic then -- Convert to parametric space, apply delta, convert back local v_new_parametric = ImGui.ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) g.DragCurrentAccum = g.DragCurrentAccum - (v_new_parametric - v_old_ref_for_accum_remainder) else g.DragCurrentAccum = g.DragCurrentAccum - ((SIGNEDTYPE)(v_cur) - (SIGNEDTYPE)(v)) end -- This does nothing if v_cur == (TYPE)(-0) then v_cur = (TYPE)(0) end if v ~= v_cur and is_bounded then if is_wrapped then -- Wrap values if v_cur < v_min then v_cur = (TYPE)(v_cur + (TYPE)((TYPE)(v_max - v_min) + (is_floating_point and 0 or 1))) end if v_cur > v_max then v_cur = (TYPE)(v_cur - (TYPE)((TYPE)(v_max - v_min) - (is_floating_point and 0 or 1))) end else -- Clamp values + handle overflow/wrap-around for integer types if v_cur < v_min or (v_cur > v and adjust_delta < 0.0 and not is_floating_point) then v_cur = (TYPE)(v_min) end if v_cur > v_max or (v_cur < v and adjust_delta > 0.0 and not is_floating_point) then v_cur = (TYPE)(v_max) end end end -- Apply result if v == v_cur then return v, false end v = v_cur return v, true end --- @param id ImGuiID --- @param data_type ImGuiDataType --- @param v number --- @param v_speed float --- @param min number --- @param max number --- @param format string --- @param flags ImGuiSliderFlags @native function ImGui.DragBehavior(id, data_type, v, v_speed, min, max, format, flags) IM_ASSERT((flags == 1 or bit32.band(flags, ImGuiSliderFlags.InvalidMask_) == 0), "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.") local g = GImGui if g.ActiveId == id then if g.ActiveIdSource == ImGuiInputSource.Mouse and not g.IO.MouseDown[0] then ImGui.ClearActiveID() elseif (g.ActiveIdSource == ImGuiInputSource.Keyboard or g.ActiveIdSource == ImGuiInputSource.Gamepad) and g.NavActivatePressedId == id and not g.ActiveIdIsJustActivated then ImGui.ClearActiveID() end end if g.ActiveId ~= id then return v, false end if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.ReadOnly) ~= 0 or bit32.band(flags, ImGuiSliderFlags.ReadOnly) ~= 0 then return v, false end if data_type == ImGuiDataType.S8 then return ImGui.DragBehaviorT(ImS32, ImS32, ImGuiDataType.S32, v, v_speed, min and min or IM_S8_MIN, max and max or IM_S8_MAX, format, flags) elseif data_type == ImGuiDataType.U8 then return ImGui.DragBehaviorT(ImU32, ImS32, ImGuiDataType.U32, v, v_speed, min and min or IM_U8_MIN, max and max or IM_U8_MAX, format, flags) elseif data_type == ImGuiDataType.S16 then return ImGui.DragBehaviorT(ImS32, ImS32, ImGuiDataType.S32, v, v_speed, min and min or IM_S16_MIN, max and max or IM_S16_MAX, format, flags) elseif data_type == ImGuiDataType.U16 then return ImGui.DragBehaviorT(ImU32, ImS32, ImGuiDataType.U32, v, v_speed, min and min or IM_U16_MIN, max and max or IM_U16_MAX, format, flags) elseif data_type == ImGuiDataType.S32 then return ImGui.DragBehaviorT(ImS32, ImS32, data_type, v, v_speed, min and min or IM_S32_MIN, max and max or IM_S32_MAX, format, flags) elseif data_type == ImGuiDataType.U32 then return ImGui.DragBehaviorT(ImU32, ImS32, data_type, v, v_speed, min and min or IM_U32_MIN, max and max or IM_U32_MAX, format, flags) elseif data_type == ImGuiDataType.Float then return ImGui.DragBehaviorT(float, float, data_type, v, v_speed, min and min or -FLT_MAX, max and max or FLT_MAX, format, flags) elseif data_type == ImGuiDataType.Double then return ImGui.DragBehaviorT(double, double, data_type, v, v_speed, min and min or -DBL_MAX, max and max or DBL_MAX, format, flags) end IM_ASSERT(false) return v, false end --- @param flags ImGuiSliderFlags --- @param data_type ImGuiDataType --- @param min number --- @param max number local function TempInputIsClampEnabled(flags, data_type, min, max) if bit32.band(flags, ImGuiSliderFlags.ClampOnInput) ~= 0 and (min ~= nil or max ~= nil) then local clamp_range_dir = 0 if min ~= nil and max ~= nil then clamp_range_dir = ImGui.DataTypeCompare(data_type, min, max) end if min == nil or max == nil or clamp_range_dir < 0 then return true end if clamp_range_dir == 0 then return ImGui.DataTypeIsZero(data_type, min) and (bit32.band(flags, ImGuiSliderFlags.ClampZeroRange) ~= 0) or true end end return false end --- @param label string --- @param data_type ImGuiDataType --- @param data number --- @param v_speed float --- @param min number --- @param max number --- @param format string --- @param flags ImGuiSliderFlags -- [Luau] memo of string.format(format, value) for drag/slider value text (same values are redrawn every frame). -- ponytail: whole-memo reset at 4096 entries, LRU if values churn local fmt_memo, fmt_memo_n = {}, 0 local DRAG_TEXT_ALIGN = ImVec2(0.5, 0.5) function FormatCached(format, v) local m = fmt_memo[format] if m == nil then m = {}; fmt_memo[format] = m end local r = m[v] if r == nil then if fmt_memo_n >= 4096 then table.clear(fmt_memo); m = {}; fmt_memo[format] = m; fmt_memo_n = 0 end r = ImFormatString(format, v); m[v] = r; fmt_memo_n += 1 end return r end @native function ImGui.DragScalar(label, data_type, data, v_speed, min, max, format, flags) if v_speed == nil then v_speed = 1.0 end if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return data, false end local g = GImGui local style = g.Style local id = window:GetID(label) local w = ImGui.CalcItemWidth() local color_marker = (bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasColorMarker) ~= 0) and g.NextItemData.ColorMarker or 0 local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0)) local total_bb = ImRect(frame_bb.Min, frame_bb.Max + ImVec2((label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0, 0.0)) local temp_input_allowed = (bit32.band(flags, ImGuiSliderFlags.NoInput) == 0) ImGui.ItemSize(total_bb, style.FramePadding.y) if not ImGui.ItemAdd(total_bb, id, frame_bb, temp_input_allowed and ImGuiItemFlags.Inputable or 0) then return data, false end -- Default format string when passing NULL if format == nil then format = ImGui.DataTypeGetInfo(data_type).PrintFmt end local hovered = ImGui.ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags) local temp_input_is_active = temp_input_allowed and ImGui.TempInputIsActive(id) if not temp_input_is_active then local clicked = hovered and ImGui.IsMouseClickedEx(0, ImGuiInputFlags.None, id) local double_clicked = (hovered and g.IO.MouseClickedCount[0] == 2 and ImGui.TestKeyOwner(ImGuiKey.MouseLeft, id)) local make_active = (clicked or double_clicked or g.NavActivateId == id) if make_active and (clicked or double_clicked) then ImGui.SetKeyOwner(ImGuiKey.MouseLeft, id) end if make_active and temp_input_allowed then if (clicked and g.IO.KeyCtrl) or double_clicked or (g.NavActivateId == id and bit32.band(g.NavActivateFlags, ImGuiActivateFlags.PreferInput) ~= 0) then temp_input_is_active = true end end -- (Optional) simple click (without moving) turns Drag into an InputText if g.IO.ConfigDragClickToInputText and temp_input_allowed and not temp_input_is_active then if g.ActiveId == id and hovered and g.IO.MouseReleased[0] and not ImGui.IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR) then g.NavActivateId = id g.NavActivateFlags = ImGuiActivateFlags.PreferInput temp_input_is_active = true end end -- Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) if make_active then g.ActiveIdValueOnActivation = data end if make_active and not temp_input_is_active then ImGui.SetActiveID(id, window) ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) g.ActiveIdUsingNavDirMask = bit32.bor(bit32.lshift(1, ImGuiDir.Left), bit32.lshift(1, ImGuiDir.Right)) end end if temp_input_is_active then local clamp_enabled = TempInputIsClampEnabled(flags, data_type, min, max) return ImGui.TempInputScalar(frame_bb, id, label, data_type, data, format, clamp_enabled and min or nil, clamp_enabled and max or nil) end -- Draw frame local frame_col = ImGui.GetColorU32(g.ActiveId == id and ImGuiCol.FrameBgActive or hovered and ImGuiCol.FrameBgHovered or ImGuiCol.FrameBg) ImGui.RenderNavCursor(frame_bb, id) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, false, style.FrameRounding) if color_marker ~= 0 and style.ColorMarkerSize > 0.0 then ImGui.RenderColorComponentMarker(frame_bb, ImGui.GetColorU32(color_marker, nil, true), style.FrameRounding) end ImGui.RenderFrameBorder(frame_bb.Min, frame_bb.Max, g.Style.FrameRounding) -- Drag behavior local value_changed data, value_changed = ImGui.DragBehavior(id, data_type, data, v_speed, min, max, format, flags) if value_changed then ImGui.MarkItemEdited(id) end -- TODO: ImGui.DataTypeFormatString() should be used here instead of ImFormatString() -- Display value using user-provided display format so user can add prefix/suffix/decorations to the value ImGui.RenderTextClipped(frame_bb.Min, frame_bb.Max, FormatCached(format, data), nil, nil, DRAG_TEXT_ALIGN) if label_size.x > 0.0 then ImGui.RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end return data, value_changed end --- @param label string --- @param v float --- @param v_speed? float --- @param v_min? float --- @param v_max? float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.DragFloat(label, v, v_speed, v_min, v_max, format, flags) if v_speed == nil then v_speed = 1.0 end if v_min == nil then v_min = 0.0 end if v_max == nil then v_max = 0.0 end if format == nil then format = "%.3f" end if flags == nil then flags = 0 end return ImGui.DragScalar(label, ImGuiDataType.Float, v, v_speed, v_min, v_max, format, flags) end --- @param label string --- @param v int --- @param v_speed? float --- @param v_min? int --- @param v_max? int --- @param format? string --- @param flags? ImGuiSliderFlags @native function ImGui.DragInt(label, v, v_speed, v_min, v_max, format, flags) if v_speed == nil then v_speed = 1.0 end if v_min == nil then v_min = 0 end if v_max == nil then v_max = 0 end if format == nil then format = "%d" end if flags == nil then flags = 0 end return ImGui.DragScalar(label, ImGuiDataType.S32, v, v_speed, v_min, v_max, format, flags) end -- `v` is mutated in place (1-based), returns value_changed function ImGui.DragScalarN(label, data_type, v, components, v_speed, v_min, v_max, format, flags) if v_speed == nil then v_speed = 1.0 end if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local value_changed = false ImGui.BeginGroup() ImGui.PushID(label) ImGui.PushMultiItemsWidths(components, ImGui.CalcItemWidth()) for i = 1, components do ImGui.PushID(i - 1) if i > 1 then ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) end if bit32.band(flags, ImGuiSliderFlags.ColorMarkers) ~= 0 then ImGui.SetNextItemColorMarker(GDefaultRgbaColorMarkers[i]) end local changed v[i], changed = ImGui.DragScalar("", data_type, v[i], v_speed, v_min, v_max, format, flags) value_changed = value_changed or changed ImGui.PopID() ImGui.PopItemWidth() end ImGui.PopID() local label_end = ImGui.FindRenderedTextEnd(label) if label_end > 1 then ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) ImGui.TextEx(label, label_end) end ImGui.EndGroup() return value_changed end local function DragFloatN(n) return function(label, v, v_speed, v_min, v_max, format, flags) return ImGui.DragScalarN(label, ImGuiDataType.Float, v, n, v_speed or 1.0, v_min or 0.0, v_max or 0.0, format or "%.3f", flags or 0) end end local function DragIntN(n) return function(label, v, v_speed, v_min, v_max, format, flags) return ImGui.DragScalarN(label, ImGuiDataType.S32, v, n, v_speed or 1.0, v_min or 0, v_max or 0, format or "%d", flags or 0) end end ImGui.DragFloat2 = DragFloatN(2) ImGui.DragFloat3 = DragFloatN(3) ImGui.DragFloat4 = DragFloatN(4) ImGui.DragInt2 = DragIntN(2) ImGui.DragInt3 = DragIntN(3) ImGui.DragInt4 = DragIntN(4) -- NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. --- @return float v_current_min --- @return float v_current_max --- @return bool value_changed local function DragRange2(data_type, label, v_current_min, v_current_max, v_speed, v_min, v_max, format, format_max, flags) local window = ImGui.GetCurrentWindow() if window.SkipItems then return v_current_min, v_current_max, false end local g = GImGui local lo = (data_type == ImGuiDataType.Float) and -FLT_MAX or INT_MIN local hi = (data_type == ImGuiDataType.Float) and FLT_MAX or INT_MAX ImGui.PushID(label) ImGui.BeginGroup() ImGui.PushMultiItemsWidths(2, ImGui.CalcItemWidth()) local min_min = (v_min >= v_max) and lo or v_min local min_max = (v_min >= v_max) and v_current_max or ImMin(v_max, v_current_max) local min_flags = bit32.bor(flags, (min_min == min_max) and ImGuiSliderFlags.ReadOnly or 0) local value_changed, changed v_current_min, value_changed = ImGui.DragScalar("##min", data_type, v_current_min, v_speed, min_min, min_max, format, min_flags) ImGui.PopItemWidth() ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) local max_min = (v_min >= v_max) and v_current_min or ImMax(v_min, v_current_min) local max_max = (v_min >= v_max) and hi or v_max local max_flags = bit32.bor(flags, (max_min == max_max) and ImGuiSliderFlags.ReadOnly or 0) v_current_max, changed = ImGui.DragScalar("##max", data_type, v_current_max, v_speed, max_min, max_max, format_max or format, max_flags) value_changed = value_changed or changed ImGui.PopItemWidth() ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) ImGui.TextEx(label, ImGui.FindRenderedTextEnd(label)) ImGui.EndGroup() ImGui.PopID() return v_current_min, v_current_max, value_changed end function ImGui.DragFloatRange2(label, v_current_min, v_current_max, v_speed, v_min, v_max, format, format_max, flags) return DragRange2(ImGuiDataType.Float, label, v_current_min, v_current_max, v_speed or 1.0, v_min or 0.0, v_max or 0.0, format or "%.3f", format_max, flags or 0) end function ImGui.DragIntRange2(label, v_current_min, v_current_max, v_speed, v_min, v_max, format, format_max, flags) return DragRange2(ImGuiDataType.S32, label, v_current_min, v_current_max, v_speed or 1.0, v_min or 0, v_max or 0, format or "%d", format_max, flags or 0) end ---------------------------------------------------------------- -- [SECTION] SLIDERXXX ---------------------------------------------------------------- -- Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) --- @param data_type ImGuiDataType --- @param v number --- @param v_min number --- @param v_max number --- @param logarithmic_zero_epsilon float --- @param zero_deadzone_halfsize float function ImGui.ScaleRatioFromValueT(data_type, v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if v_min == v_max then return 0.0 end -- IM_UNUSED(data_type) local v_clamped if v_min < v_max then v_clamped = ImClamp(v, v_min, v_max) else v_clamped = ImClamp(v, v_max, v_min) end if logarithmic_zero_epsilon > 0.0 then -- == is_logarithmic from caller local flipped = v_max < v_min if flipped then -- Handle the case where the range is backwards v_min, v_max = v_max, v_min end -- Fudge min/max to avoid getting close to log(0) local v_min_fudged if ImAbs(v_min) < logarithmic_zero_epsilon then v_min_fudged = (v_min < 0.0) and -logarithmic_zero_epsilon or logarithmic_zero_epsilon else v_min_fudged = v_min end local v_max_fudged if ImAbs(v_max) < logarithmic_zero_epsilon then v_max_fudged = (v_max < 0.0) and -logarithmic_zero_epsilon or logarithmic_zero_epsilon else v_max_fudged = v_max end -- Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) if v_min == 0.0 and v_max < 0.0 then v_min_fudged = -logarithmic_zero_epsilon elseif v_max == 0.0 and v_min < 0.0 then v_max_fudged = -logarithmic_zero_epsilon end local result if v_clamped <= v_min_fudged then result = 0.0 -- Workaround for values that are in-range but below our fudge elseif v_clamped >= v_max_fudged then result = 1.0 -- Workaround for values that are in-range but above our fudge elseif v_min * v_max < 0.0 then -- Range crosses zero, so split into two portions local zero_point_center = (-v_min) / (v_max - v_min) -- The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) local zero_point_snap_L = zero_point_center - zero_deadzone_halfsize local zero_point_snap_R = zero_point_center + zero_deadzone_halfsize if v == 0.0 then result = zero_point_center -- Special case for exactly zero elseif v < 0.0 then result = (1.0 - (ImLog(-v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L else result = zero_point_snap_R + ((ImLog(v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0 - zero_point_snap_R)) end elseif v_min < 0.0 or v_max < 0.0 then -- Entirely negative slider result = 1.0 - (ImLog(-v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)) else result = ImLog(v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged) end return flipped and (1.0 - result) or result else -- Linear slider return (v_clamped - v_min) / (v_max - v_min) end end -- Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) --- @param TYPE fun(val: number): number --- @param SIGNEDTYPE fun(val: number): number --- @param data_type ImGuiDataType --- @param t float --- @param v_min number --- @param v_max number --- @param logarithmic_zero_epsilon float --- @param zero_deadzone_halfsize float function ImGui.ScaleValueFromRatioT(TYPE, SIGNEDTYPE, data_type, t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) -- We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" -- but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. if t <= 0.0 or v_min == v_max then return v_min end if t >= 1.0 then return v_max end local result = 0 if logarithmic_zero_epsilon > 0.0 then -- == is_logarithmic from caller -- Fudge min/max to avoid getting silly results close to zero local v_min_fudged if ImAbs(v_min) < logarithmic_zero_epsilon then v_min_fudged = (v_min < 0.0) and -logarithmic_zero_epsilon or logarithmic_zero_epsilon else v_min_fudged = v_min end local v_max_fudged if ImAbs(v_max) < logarithmic_zero_epsilon then v_max_fudged = (v_max < 0.0) and -logarithmic_zero_epsilon or logarithmic_zero_epsilon else v_max_fudged = v_max end local flipped = v_max < v_min -- Check if range is "backwards" if flipped then v_min_fudged, v_max_fudged = v_max_fudged, v_min_fudged end -- Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) if v_max == 0.0 and v_min < 0.0 then v_max_fudged = -logarithmic_zero_epsilon end local t_with_flip = flipped and (1.0 - t) or t -- t, but flipped if necessary to account for us flipping the range if v_min * v_max < 0.0 then -- Range crosses zero, so we have to do this in two parts local zero_point_center = (-ImMin(v_min, v_max)) / ImAbs(v_max - v_min) -- The zero point in parametric space local zero_point_snap_L = zero_point_center - zero_deadzone_halfsize local zero_point_snap_R = zero_point_center + zero_deadzone_halfsize if t_with_flip >= zero_point_snap_L and t_with_flip <= zero_point_snap_R then result = (TYPE)(0.0) -- Special case to make getting exactly zero possible (the epsilon prevents it otherwise) elseif t_with_flip < zero_point_center then result = (TYPE)(-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, 1.0 - (t_with_flip / zero_point_snap_L)))) else result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (t_with_flip - zero_point_snap_R) / (1.0 - zero_point_snap_R))) end elseif v_min < 0.0 or v_max < 0.0 then -- Entirely negative slider result = (TYPE)(-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, 1.0 - t_with_flip))) else result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, t_with_flip)) end else -- Linear slider local is_floating_point = (data_type == ImGuiDataType.Float) or (data_type == ImGuiDataType.Double) if is_floating_point then result = ImLerp(v_min, v_max, t) elseif t < 1.0 then local v_new_off_f = (SIGNEDTYPE)((v_max - v_min)) * t result = (TYPE)((SIGNEDTYPE)(v_min) + (SIGNEDTYPE)(v_new_off_f + 0)) -- LUA: + 0 instead of + ((v_min > v_max) and -0.5 or 0.5) end end return result end --- @generic T : number --- @param TYPE fun(val: number): T --- @param SIGNEDTYPE fun(val: number): T --- @param bb ImRect --- @param id ImGuiID --- @param data_type ImGuiDataType --- @param v T --- @param v_min T --- @param v_max T --- @param format string --- @param flags ImGuiSliderFlags --- @param out_grab_bb ImRect --- @return T v # updated `v` passed in --- @return bool value_changed function ImGui.SliderBehaviorT(TYPE, SIGNEDTYPE, bb, id, data_type, v, v_min, v_max, format, flags, out_grab_bb) local g = GImGui local style = g.Style local axis = (bit32.band(flags, ImGuiSliderFlags.Vertical) ~= 0) and ImGuiAxis.Y or ImGuiAxis.X local is_logarithmic = bit32.band(flags, ImGuiSliderFlags.Logarithmic) ~= 0 local is_floating_point = (data_type == ImGuiDataType.Float) or (data_type == ImGuiDataType.Double) local v_range_f = (v_min < v_max) and (v_max - v_min) or (v_min - v_max) local grab_padding = 2.0 local slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0 local grab_sz = style.GrabMinSize if not is_floating_point and v_range_f >= 0.0 then grab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize) end grab_sz = ImMin(grab_sz, slider_sz) local slider_usable_sz = slider_sz - grab_sz local slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5 local slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5 local logarithmic_zero_epsilon = 0.0 local zero_deadzone_halfsize = 0.0 if is_logarithmic then local decimal_precision = is_floating_point and ImParseFormatPrecision(format, 3) or 1 logarithmic_zero_epsilon = ImPow(0.1, decimal_precision) zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5) / ImMax(slider_usable_sz, 1.0) end local value_changed = false if g.ActiveId == id then local set_new_value = false local clicked_t = 0.0 if g.ActiveIdSource == ImGuiInputSource.Mouse then if not g.IO.MouseDown[0] then ImGui.ClearActiveID() else local mouse_abs_pos = g.IO.MousePos[axis] if g.ActiveIdIsJustActivated then local grab_t = ImGui.ScaleRatioFromValueT(data_type, v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if axis == ImGuiAxis.Y then grab_t = 1.0 - grab_t end local grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t) local clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5 - 1.0) and (mouse_abs_pos <= grab_pos + grab_sz * 0.5 + 1.0) g.SliderGrabClickOffset = (clicked_around_grab and is_floating_point) and (mouse_abs_pos - grab_pos) or 0.0 end if slider_usable_sz > 0.0 then clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz) end if axis == ImGuiAxis.Y then clicked_t = 1.0 - clicked_t end set_new_value = true end elseif g.ActiveIdSource == ImGuiInputSource.Keyboard or g.ActiveIdSource == ImGuiInputSource.Gamepad then if g.ActiveIdIsJustActivated then g.SliderCurrentAccum = 0.0 g.SliderCurrentAccumDirty = false end local input_delta = (axis == ImGuiAxis.X) and ImGui.GetNavTweakPressedAmount(axis) or -ImGui.GetNavTweakPressedAmount(axis) if input_delta ~= 0.0 then local tweak_slow = ImGui.IsKeyDown((g.NavInputSource == ImGuiInputSource.Gamepad) and ImGuiKey.NavGamepadTweakSlow or ImGuiKey.NavKeyboardTweakSlow) local tweak_fast = ImGui.IsKeyDown((g.NavInputSource == ImGuiInputSource.Gamepad) and ImGuiKey.NavGamepadTweakFast or ImGuiKey.NavKeyboardTweakFast) local decimal_precision = is_floating_point and ImParseFormatPrecision(format, 3) or 0 if decimal_precision > 0 then input_delta = input_delta / 100.0 if tweak_slow then input_delta = input_delta / 10.0 end else if (v_range_f >= -100.0 and v_range_f <= 100.0 and v_range_f ~= 0.0) or tweak_slow then input_delta = ((input_delta < 0.0) and -1.0 or 1.0) / v_range_f else input_delta = input_delta / 100.0 end end if tweak_fast then input_delta = input_delta * 10.0 end g.SliderCurrentAccum = g.SliderCurrentAccum + input_delta g.SliderCurrentAccumDirty = true end local delta = g.SliderCurrentAccum if g.NavActivatePressedId == id and not g.ActiveIdIsJustActivated then ImGui.ClearActiveID() elseif g.SliderCurrentAccumDirty then clicked_t = ImGui.ScaleRatioFromValueT(data_type, v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if (clicked_t >= 1.0 and delta > 0.0) or (clicked_t <= 0.0 and delta < 0.0) then set_new_value = false g.SliderCurrentAccum = 0.0 else set_new_value = true local old_clicked_t = clicked_t clicked_t = ImSaturate(clicked_t + delta) local v_new = ImGui.ScaleValueFromRatioT(TYPE, SIGNEDTYPE, data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if is_floating_point and bit32.band(flags, ImGuiSliderFlags.NoRoundToFormat) == 0 then v_new = ImGui.RoundScalarWithFormatT(format, data_type, v_new) end local new_clicked_t = ImGui.ScaleRatioFromValueT(data_type, v_new, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if delta > 0 then g.SliderCurrentAccum = g.SliderCurrentAccum - ImMin(new_clicked_t - old_clicked_t, delta) else g.SliderCurrentAccum = g.SliderCurrentAccum - ImMax(new_clicked_t - old_clicked_t, delta) end end g.SliderCurrentAccumDirty = false end end if set_new_value then if (bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.ReadOnly) ~= 0) or (bit32.band(flags, ImGuiSliderFlags.ReadOnly) ~= 0) then set_new_value = false end end if set_new_value then local v_new = ImGui.ScaleValueFromRatioT(TYPE, SIGNEDTYPE, data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if is_floating_point and bit32.band(flags, ImGuiSliderFlags.NoRoundToFormat) == 0 then v_new = ImGui.RoundScalarWithFormatT(format, data_type, v_new) end if v ~= v_new then v = v_new value_changed = true end end end if slider_sz < 1.0 then ImRect_Copy(out_grab_bb, ImRect(bb.Min, bb.Min)) else local grab_t = ImGui.ScaleRatioFromValueT(data_type, v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize) if axis == ImGuiAxis.Y then grab_t = 1.0 - grab_t end local grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t) if axis == ImGuiAxis.X then ImRect_Copy(out_grab_bb, ImRect(grab_pos - grab_sz * 0.5, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5, bb.Max.y - grab_padding)) else ImRect_Copy(out_grab_bb, ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5)) end end return v, value_changed end --- @generic T : number --- @param bb ImRect --- @param id ImGuiID --- @param data_type ImGuiDataType --- @param v T --- @param min T --- @param max T --- @param format string --- @param flags ImGuiSliderFlags --- @param out_grab_bb ImRect --- @return T v --- @return bool value_changed function ImGui.SliderBehavior(bb, id, data_type, v, min, max, format, flags, out_grab_bb) IM_ASSERT((flags == 1 or bit32.band(flags, ImGuiSliderFlags.InvalidMask_) == 0), "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.") IM_ASSERT(bit32.band(flags, ImGuiSliderFlags.WrapAround) == 0) if data_type == ImGuiDataType.S8 then local v32 = (ImS32)((ImS8)(v)); local r v32, r = ImGui.SliderBehaviorT(ImS32, ImS32, bb, id, ImGuiDataType.S32, v32, min, max, format, flags, out_grab_bb) if r then v = (ImS8)(v32) end return v, r elseif data_type == ImGuiDataType.U8 then local v32 = (ImU32)((ImU8)(v)); local r v32, r = ImGui.SliderBehaviorT(ImU32, ImS32, bb, id, ImGuiDataType.U32, v32, min, max, format, flags, out_grab_bb) if r then v = (ImU8)(v32) end return v, r elseif data_type == ImGuiDataType.S16 then local v32 = (ImS32)((ImS16)(v)); local r v32, r = ImGui.SliderBehaviorT(ImS32, ImS32, bb, id, ImGuiDataType.S32, v32, min, max, format, flags, out_grab_bb) if r then v = (ImS16)(v32) end return v, r elseif data_type == ImGuiDataType.U16 then local v32 = (ImU32)((ImU16)(v)); local r v32, r = ImGui.SliderBehaviorT(ImU32, ImS32, bb, id, ImGuiDataType.U32, v32, min, max, format, flags, out_grab_bb) if r then v = (ImU16)(v32) end return v, r elseif data_type == ImGuiDataType.S32 then IM_ASSERT(min >= math.floor(IM_S32_MIN / 2) and max <= math.floor(IM_S32_MAX / 2)) return ImGui.SliderBehaviorT(ImS32, ImS32, bb, id, data_type, v, min, max, format, flags, out_grab_bb) elseif data_type == ImGuiDataType.U32 then IM_ASSERT(max <= math.floor(IM_U32_MAX / 2)) return ImGui.SliderBehaviorT(ImU32, ImS32, bb, id, data_type, v, min, max, format, flags, out_grab_bb) elseif data_type == ImGuiDataType.Float then IM_ASSERT(min >= -FLT_MAX / 2.0 and max <= FLT_MAX / 2.0) return ImGui.SliderBehaviorT(float, float, bb, id, data_type, v, min, max, format, flags, out_grab_bb) elseif data_type == ImGuiDataType.Double then IM_ASSERT(min >= -DBL_MAX / 2.0 and max <= DBL_MAX / 2.0) return ImGui.SliderBehaviorT(double, double, bb, id, data_type, v, min, max, format, flags, out_grab_bb) end IM_ASSERT(false) return v, false end --- @generic T : number --- @param label string --- @param data_type ImGuiDataType --- @param data T --- @param min T --- @param max T --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderScalar(label, data_type, data, min, max, format, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return data, false end local g = GImGui local style = g.Style local id = window:GetID(label) local w = ImGui.CalcItemWidth() local color_marker = (bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasColorMarker) ~= 0) and g.NextItemData.ColorMarker or 0 local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0)) local total_bb_x = frame_bb.Max.x + ((label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0) local total_bb = ImRect(frame_bb.Min, ImVec2(total_bb_x, frame_bb.Max.y)) local temp_input_allowed = bit32.band(flags, ImGuiSliderFlags.NoInput) == 0 ImGui.ItemSize(total_bb, style.FramePadding.y) local item_flags = temp_input_allowed and ImGuiItemFlags.Inputable or 0 if not ImGui.ItemAdd(total_bb, id, frame_bb, item_flags) then return data, false end if format == nil then format = ImGui.DataTypeGetInfo(data_type).PrintFmt end local hovered = ImGui.ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags) local temp_input_is_active = temp_input_allowed and ImGui.TempInputIsActive(id) if not temp_input_is_active then local clicked = hovered and ImGui.IsMouseClickedEx(0, ImGuiInputFlags.None, id) local make_active = clicked or g.NavActivateId == id if make_active and clicked then ImGui.SetKeyOwner(ImGuiKey.MouseLeft, id) end if make_active and temp_input_allowed then if (clicked and g.IO.KeyCtrl) or (g.NavActivateId == id and bit32.band(g.NavActivateFlags, ImGuiActivateFlags.PreferInput) ~= 0) then temp_input_is_active = true end end if make_active then g.ActiveIdValueOnActivation = data end if make_active and not temp_input_is_active then ImGui.SetActiveID(id, window) ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) g.ActiveIdUsingNavDirMask = bit32.bor(g.ActiveIdUsingNavDirMask, bit32.lshift(1, ImGuiDir.Left), bit32.lshift(1, ImGuiDir.Right)) end end if temp_input_is_active then local clamp_enabled = bit32.band(flags, ImGuiSliderFlags.ClampOnInput) ~= 0 return ImGui.TempInputScalar(frame_bb, id, label, data_type, data, format, clamp_enabled and min or nil, clamp_enabled and max or nil) end local frame_col = ImGui.GetColorU32((g.ActiveId == id) and ImGuiCol.FrameBgActive or (hovered and ImGuiCol.FrameBgHovered or ImGuiCol.FrameBg)) ImGui.RenderNavCursor(frame_bb, id) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, false, style.FrameRounding) if color_marker ~= 0 and style.ColorMarkerSize > 0.0 then ImGui.RenderColorComponentMarker(frame_bb, ImGui.GetColorU32(color_marker, nil, true), style.FrameRounding) end ImGui.RenderFrameBorder(frame_bb.Min, frame_bb.Max, g.Style.FrameRounding) local grab_bb = ImRect() local value_changed data, value_changed = ImGui.SliderBehavior(frame_bb, id, data_type, data, min, max, format, flags, grab_bb) if value_changed then ImGui.MarkItemEdited(id) end if grab_bb.Max.x > grab_bb.Min.x then window.DrawList:AddRectFilled(grab_bb.Min, grab_bb.Max, ImGui.GetColorU32((g.ActiveId == id) and ImGuiCol.SliderGrabActive or ImGuiCol.SliderGrab), style.GrabRounding) end -- TODO: ImGui.DataTypeFormatString() should be used here instead of ImFormatString() -- if g.LogEnabled then -- ImGui.LogSetNextTextDecoration("{", "}") -- end ImGui.RenderTextClipped(frame_bb.Min, frame_bb.Max, FormatCached(format, data), nil, nil, DRAG_TEXT_ALIGN) if label_size.x > 0.0 then ImGui.RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end -- IMGUI_TEST_ENGINE_ITEM_INFO() return data, value_changed end --- @param label string --- @param data_type ImGuiDataType --- @param v table --- @param components int --- @param v_min number --- @param v_max number --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderScalarN(label, data_type, v, components, v_min, v_max, format, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local value_changed = false ImGui.BeginGroup() ImGui.PushID(label) ImGui.PushMultiItemsWidths(components, ImGui.CalcItemWidth()) for i = 1, components do ImGui.PushID(i - 1) if i > 1 then ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) end if bit32.band(flags, ImGuiSliderFlags.ColorMarkers) ~= 0 then ImGui.SetNextItemColorMarker(GDefaultRgbaColorMarkers[i]) end local changed v[i], changed = ImGui.SliderScalar("", data_type, v[i], v_min, v_max, format, flags) value_changed = value_changed or changed ImGui.PopID() ImGui.PopItemWidth() end ImGui.PopID() local label_end = ImGui.FindRenderedTextEnd(label) if label_end > 1 then ImGui.SameLine(0, g.Style.ItemInnerSpacing.x) ImGui.TextEx(label, label_end) end ImGui.EndGroup() return value_changed end --- @param label string --- @param v [float, float] --- @param v_min float --- @param v_max float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderFloat2(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.Float, v, 2, v_min, v_max, format, flags) end --- @param label string --- @param v [float, float, float] --- @param v_min float --- @param v_max float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderFloat3(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.Float, v, 3, v_min, v_max, format, flags) end --- @param label string --- @param v [float, float, float, float] --- @param v_min float --- @param v_max float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderFloat4(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.Float, v, 4, v_min, v_max, format, flags) end --- @param label string --- @param v float --- @param v_min float --- @param v_max float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderFloat(label, v, v_min, v_max, format, flags) if format == nil then format = "%.3f" end if flags == nil then flags = 0 end return ImGui.SliderScalar(label, ImGuiDataType.Float, v, v_min, v_max, format, flags) end --- @param label string --- @param v_rad float --- @param v_degrees_min? float --- @param v_degrees_max? float --- @param format? string --- @param flags? ImGuiSliderFlags --- @return float v_rad # updated `v_rad` --- @return bool value_changed function ImGui.SliderAngle(label, v_rad, v_degrees_min, v_degrees_max, format, flags) if v_degrees_min == nil then v_degrees_min = -360.0 end if v_degrees_max == nil then v_degrees_max = 360.0 end if format == nil then format = "%.0f deg" end if flags == nil then flags = 0 end local v_deg = v_rad * 360.0 / (2 * IM_PI) local value_changed v_deg, value_changed = ImGui.SliderFloat(label, v_deg, v_degrees_min, v_degrees_max, format, flags) if value_changed then v_rad = v_deg * (2 * IM_PI) / 360.0 end return v_rad, value_changed end --- @param label string --- @param v int --- @param v_min int --- @param v_max int --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.SliderInt(label, v, v_min, v_max, format, flags) if format == nil then format = "%d" end if flags == nil then flags = 0 end return ImGui.SliderScalar(label, ImGuiDataType.S32, v, v_min, v_max, format, flags) end function ImGui.SliderInt2(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.S32, v, 2, v_min, v_max, format or "%d", flags) end function ImGui.SliderInt3(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.S32, v, 3, v_min, v_max, format or "%d", flags) end function ImGui.SliderInt4(label, v, v_min, v_max, format, flags) return ImGui.SliderScalarN(label, ImGuiDataType.S32, v, 4, v_min, v_max, format or "%d", flags) end --- @param label string --- @param size ImVec2 --- @param data_type ImGuiDataType --- @param data number --- @param min number --- @param max number --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.VSliderScalar(label, size, data_type, data, min, max, format, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return data, false end local g = GImGui local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + size) local bb = ImRect(frame_bb.Min, ImVec2(frame_bb.Max.x + (label_size.x > 0.0 and (style.ItemInnerSpacing.x + label_size.x) or 0.0), frame_bb.Max.y)) ImGui.ItemSize(bb, style.FramePadding.y) if not ImGui.ItemAdd(frame_bb, id) then return data, false end if format == nil then format = ImGui.DataTypeGetInfo(data_type).PrintFmt end local hovered = ImGui.ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags) local clicked = hovered and ImGui.IsMouseClickedEx(0, ImGuiInputFlags.None, id) if clicked or g.NavActivateId == id then if clicked then ImGui.SetKeyOwner(ImGuiKey.MouseLeft, id) end ImGui.SetActiveID(id, window) ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) g.ActiveIdUsingNavDirMask = bit32.bor(g.ActiveIdUsingNavDirMask, bit32.lshift(1, ImGuiDir.Up), bit32.lshift(1, ImGuiDir.Down)) end local frame_col = ImGui.GetColorU32((g.ActiveId == id) and ImGuiCol.FrameBgActive or (hovered and ImGuiCol.FrameBgHovered or ImGuiCol.FrameBg)) ImGui.RenderNavCursor(frame_bb, id) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding) local grab_bb = ImRect() local value_changed data, value_changed = ImGui.SliderBehavior(frame_bb, id, data_type, data, min, max, format, bit32.bor(flags or 0, ImGuiSliderFlags.Vertical), grab_bb) if value_changed then ImGui.MarkItemEdited(id) end if grab_bb.Max.y > grab_bb.Min.y then window.DrawList:AddRectFilled(grab_bb.Min, grab_bb.Max, ImGui.GetColorU32((g.ActiveId == id) and ImGuiCol.SliderGrabActive or ImGuiCol.SliderGrab), style.GrabRounding) end -- local value_buf, value_buf_size = {}, 64 -- TODO: ImGui.DataTypeFormatString() ImGui.RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, ImFormatString(format, data), nil, nil, ImVec2(0.5, 0.0)) if label_size.x > 0.0 then ImGui.RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end -- IMGUI_TEST_ENGINE_ITEM_INFO() return data, value_changed end --- @param label string --- @param size ImVec2 --- @param v float --- @param v_min float --- @param v_max float --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.VSliderFloat(label, size, v, v_min, v_max, format, flags) if format == nil then format = "%.3f" end return ImGui.VSliderScalar(label, size, ImGuiDataType.Float, v, v_min, v_max, format, flags) end --- @param label string --- @param size ImVec2 --- @param v int --- @param v_min int --- @param v_max int --- @param format? string --- @param flags? ImGuiSliderFlags function ImGui.VSliderInt(label, size, v, v_min, v_max, format, flags) if format == nil then format = "%d" end return ImGui.VSliderScalar(label, size, ImGuiDataType.S32, v, v_min, v_max, format, flags) end ---------------------------------------------------------------- -- [SECTION] INPUT TEXT ---------------------------------------------------------------- --- @param label string --- @param buf char[] --- @param buf_size int --- @param flags? ImGuiInputTextFlags --- @param callback? ImGuiInputTextCallback --- @param user_data any function ImGui.InputText(label, buf, buf_size, flags, callback, user_data) if flags == nil then flags = 0 end IM_ASSERT(bit32.band(flags, ImGuiInputTextFlags.Multiline) == 0) return ImGui.InputTextEx(label, nil, buf, buf_size, ImVec2(0, 0), flags, callback, user_data) end --- @param size? ImVec2 function ImGui.InputTextMultiline(label, buf, buf_size, size, flags, callback, user_data) return ImGui.InputTextEx(label, nil, buf, buf_size, size or ImVec2(0, 0), bit32.bor(flags or 0, ImGuiInputTextFlags.Multiline), callback, user_data) end ImStb = {} --- @module "imstb_textedit" local stbte local IMSTB_TEXTEDIT_GETWIDTH_NEWLINE = -1.0 ImStb.TEXTEDIT_memmove = ImStd.memmove --- @param ctx ImGuiContext --- @param text char[] --- @param text_begin int --- @param text_end_display int --- @param text_end int --- @param out_offset? ImVec2 --- @param flags? ImDrawTextFlags local function InputTextCalcTextSize(ctx, text, text_begin, text_end_display, text_end, out_offset, flags) if flags == nil then flags = 0 end local g = ctx local obj = g.InputTextState IM_ASSERT(text_end_display >= text_begin and text_end_display <= text_end) return ImFontCalcTextSizeEx(g.Font, g.FontSize, FLT_MAX, obj.WrapWidth, text, text_begin, text_end_display, text_end, out_offset, flags) end --- @param obj ImGuiInputTextState --- @return int function ImStb.TEXTEDIT_STRINGLEN(obj) return obj.TextLen end --- @param obj ImGuiInputTextState --- @param idx int # 1-based function ImStb.TEXTEDIT_GETCHAR(obj, idx) IM_ASSERT(idx >= 1 and idx <= obj.TextLen + 1); return obj.TextSrc[idx] end --- @param obj ImGuiInputTextState --- @param line_start_idx int # 1-based --- @param char_idx int # 1-based --- @return float function ImStb.TEXTEDIT_GETWIDTH(obj, line_start_idx, char_idx) local _, c = ImStd.ImTextCharFromUtf8(obj.TextSrc, line_start_idx + char_idx - 1, obj.TextLen + 1); if c == 10 then return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE end; local g = obj.Ctx; return g.FontBaked:GetCharAdvance(c) * g.FontBakedScale end --- @param r StbTexteditRow --- @param obj ImGuiInputTextState --- @param line_start_idx int # 1-based function ImStb.TEXTEDIT_LAYOUTROW(r, obj, line_start_idx) local text = obj.TextSrc local size, text_remaining = InputTextCalcTextSize(obj.Ctx, text, line_start_idx, obj.TextLen + 1, obj.TextLen + 1, nil, bit32.bor(ImDrawTextFlags.StopOnNewLine, ImDrawTextFlags.WrapKeepBlanks)) r.x0 = 0.0 r.x1 = size.x r.baseline_y_delta = size.y r.ymin = 0.0 r.ymax = size.y r.num_chars = text_remaining - line_start_idx end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, idx) if idx >= obj.TextLen then return obj.TextLen + 1 end return idx + ImStd.ImTextCharFromUtf8(obj.TextSrc, idx, obj.TextLen + 1) end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.TEXTEDIT_GETPREVCHARINDEX(obj, idx) if idx <= 1 then return -1 end local p = ImStd.ImTextFindPreviousUtf8Codepoint(obj.TextSrc, 1, idx) return p end local ImCharIsSeparatorW do local separator_list = { 44, 0x3001, 46, 0x3002, 59, 0xFF1B, 40, 0xFF08, 41, 0xFF09, 123, 0xFF5B, 125, 0xFF5D, 91, 0x300C, 93, 0x300D, 124, 0xFF5C, 33, 0xFF01, 92, 0xFFE5, 47, 0x30FB, 0xFF0F, 10, 13 } --- @param c unsigned_int function ImCharIsSeparatorW(c) for i = 1, #separator_list do if c == separator_list[i] then return true end end return false end end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.is_word_boundary_from_right(obj, idx) -- When ImGuiInputTextFlags.Password is set, we don't want actions such as Ctrl+Arrow to leak the fact that underlying data are blanks or separators if bit32.band(obj.Flags, ImGuiInputTextFlags.Password) ~= 0 or idx <= 1 then return false end local prev = ImStd.ImTextFindPreviousUtf8Codepoint(obj.TextSrc, 1, idx) local _, curr_c = ImStd.ImTextCharFromUtf8(obj.TextSrc, idx, obj.TextLen + 1) local _, prev_c = ImStd.ImTextCharFromUtf8(obj.TextSrc, prev, obj.TextLen + 1) local prev_white = ImCharIsBlankW(prev_c) local prev_separ = ImCharIsSeparatorW(prev_c) local curr_white = ImCharIsBlankW(curr_c) local curr_separ = ImCharIsSeparatorW(curr_c) return ((prev_white or prev_separ) and not (curr_separ or curr_white)) or (curr_separ and not prev_separ) end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.is_word_boundary_from_left(obj, idx) if bit32.band(obj.Flags, ImGuiInputTextFlags.Password) ~= 0 or idx <= 1 then return false end local prev = ImStd.ImTextFindPreviousUtf8Codepoint(obj.TextSrc, 1, idx) local _, prev_c = ImStd.ImTextCharFromUtf8(obj.TextSrc, idx, obj.TextLen + 1) local _, curr_c = ImStd.ImTextCharFromUtf8(obj.TextSrc, prev, obj.TextLen + 1) local prev_white = ImCharIsBlankW(prev_c) local prev_separ = ImCharIsSeparatorW(prev_c) local curr_white = ImCharIsBlankW(curr_c) local curr_separ = ImCharIsSeparatorW(curr_c) return (prev_white and not (curr_separ or curr_white)) or (curr_separ and not prev_separ) end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.TEXTEDIT_MOVEWORDLEFT(obj, idx) idx = ImStb.TEXTEDIT_GETPREVCHARINDEX(obj, idx) while idx >= 1 and not ImStb.is_word_boundary_from_right(obj, idx) do idx = ImStb.TEXTEDIT_GETPREVCHARINDEX(obj, idx) end return (idx < 1) and 1 or idx end --- @param obj ImGuiInputTextState --- @param idx int local function STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx) local len = obj.TextLen idx = ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, idx) while idx <= len and not ImStb.is_word_boundary_from_left(obj, idx) do idx = ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, idx) end return (idx > len + 1) and len + 1 or idx end --- @param obj ImGuiInputTextState --- @param idx int local function STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx) idx = ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, idx) local len = obj.TextLen while idx <= len and not ImStb.is_word_boundary_from_right(obj, idx) do idx = ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, idx) end return (idx > len + 1) and len + 1 or idx end --- @param obj ImGuiInputTextState --- @param idx int function ImStb.TEXTEDIT_MOVEWORDRIGHT(obj, idx) local g = obj.Ctx if g.IO.ConfigMacOSXBehaviors then return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx) else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx) end end -- Reimplementation of stb_textedit_move_line_start()/stb_textedit_move_line_end() which supports word-wrapping --- @param obj ImGuiInputTextState --- @param state STB_TexteditState --- @param cursor int function ImStb.TEXTEDIT_MOVELINESTART(obj, state, cursor) if state.single_line then return 1 end if obj.WrapWidth > 0.0 then local g = obj.Ctx local bol = ImStd.ImStrbol(obj.TextSrc, cursor, 1) local p = bol local text_end = obj.TextLen + 1 -- End of line would be enough while p >= bol do local eol = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, obj.TextSrc, p, text_end, obj.WrapWidth, ImDrawTextFlags.WrapKeepBlanks) if p == cursor then -- If we are already on a visible beginning-of-line, return real beginning-of-line (would be same as regular handler below) return bol end if eol == cursor and obj.TextA[cursor] ~= 10 and obj.LastMoveDirectionLR == ImGuiDir.Left then return bol end if eol >= cursor then return p end p = (obj.TextSrc[eol] == 10) and eol + 1 or eol end end -- Regular handler, same as stb_textedit_move_line_start() while cursor > 1 do local prev_cursor = ImStb.TEXTEDIT_GETPREVCHARINDEX(obj, cursor) if (ImStb.TEXTEDIT_GETCHAR(obj, prev_cursor) == STB_TEXTEDIT_NEWLINE) then break end cursor = prev_cursor end return cursor end --- @param obj ImGuiInputTextState --- @param state STB_TexteditState --- @param cursor int function ImStb.TEXTEDIT_MOVELINEEND(obj, state, cursor) local n = ImStb.TEXTEDIT_STRINGLEN(obj) if state.single_line then return n + 1 end if obj.WrapWidth > 0.0 then local g = obj.Ctx local p = ImStd.ImStrbol(obj.TextSrc, cursor, 1) local text_end = obj.TextLen + 1 -- End of line would be enough while p < text_end do local eol = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, obj.TextSrc, p, text_end, obj.WrapWidth, ImDrawTextFlags.WrapKeepBlanks) cursor = eol if eol == cursor and obj.LastMoveDirectionLR ~= ImGuiDir.Left then -- If we are already on a visible end-of-line, switch to regular handle break end if eol > cursor then return cursor end p = (obj.TextSrc[eol] == 10) and eol + 1 or eol end end -- Regular handler, same as stb_textedit_move_line_end() while (cursor < n and ImStb.TEXTEDIT_GETCHAR(obj, cursor) ~= STB_TEXTEDIT_NEWLINE) do cursor = ImStb.TEXTEDIT_GETNEXTCHARINDEX(obj, cursor) end return cursor end --- @param obj ImGuiInputTextState --- @param pos int --- @param n int function ImStb.TEXTEDIT_DELETECHARS(obj, pos, n) IM_ASSERT(obj.TextSrc == obj.TextA.Data) ImStd.memmove(obj.TextA.Data, pos, obj.TextA.Data, pos + n, obj.TextLen - n - pos + 2) obj.EditedBefore = true obj.EditedThisFrame = true obj.TextLen = obj.TextLen - n end --- @param obj ImGuiInputTextState --- @param pos int --- @param new_text ImStringBuffer --- @param new_text_pos int --- @param new_text_len int function ImStb.TEXTEDIT_INSERTCHARS(obj, pos, new_text, new_text_pos, new_text_len) local is_resizable = bit32.band(obj.Flags, ImGuiInputTextFlags.CallbackResize) ~= 0 local text_len = obj.TextLen IM_ASSERT(pos <= text_len + 1) -- We support partial insertion (with a mod in stb_textedit) local avail = obj.BufCapacity - 1 - obj.TextLen if not is_resizable and new_text_len > avail then new_text_len = math.floor(ImStd.ImTextFindValidUtf8CodepointEnd(new_text, new_text_pos, new_text_len + 1, avail) - new_text_pos) -- Truncate to closest UTF-8 codepoint. Alternative: return 0 to cancel insertion end if new_text_len == 0 then return 0 end -- Grow internal buffer if needed IM_ASSERT(obj.TextSrc == obj.TextA.Data) if text_len + new_text_len + 1 > obj.TextA.Size and is_resizable then obj.TextA:resize(text_len + ImClamp(new_text_len, 32, ImMax(256, new_text_len)) + 1) obj.TextSrc = obj.TextA.Data end local text = obj.TextA.Data if pos ~= text_len + 1 then ImStd.memmove(text, pos + new_text_len, text, pos, text_len - pos + 1) end ImStd.memmove(text, pos, new_text, new_text_pos, new_text_len) obj.EditedBefore = true obj.EditedThisFrame = true obj.TextLen = obj.TextLen + new_text_len obj.TextA[obj.TextLen + 1] = 0 return new_text_len end stbte = IM_INCLUDE"imstb_textedit.lua" --- @param str ImGuiInputTextState --- @param state STB_TexteditState --- @param text IMSTB_TEXTEDIT_CHARTYPE[] --- @param text_len int function ImStb.stb_textedit_replace(str, state, text, text_len) stbte.makeundo_replace(str, state, 1, str.TextLen, text_len) ImStb.TEXTEDIT_DELETECHARS(str, 1, str.TextLen) state.cursor = 1 state.select_start = 1 state.select_end = 1 if text_len <= 0 then return end local text_len_inserted = ImStb.TEXTEDIT_INSERTCHARS(str, 1, text, 1, text_len) if text_len_inserted > 0 then state.cursor = text_len + 1 state.select_start = text_len + 1 state.select_end = text_len + 1 state.has_preferred_x = false return end IM_ASSERT(false) -- Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() end local MT = ImGui.GetMetatables() do --- @param key int function MT.ImGuiInputTextState:OnKeyPressed(key) stbte.key(self, self.Stb, key) self.CursorFollow = true self:CursorAnimReset() local key_u = bit32.band(key, bit32.bnot(STB_TEXTEDIT_K_SHIFT)) if key_u == STB_TEXTEDIT_K_LEFT or key_u == STB_TEXTEDIT_K_LINESTART or key_u == STB_TEXTEDIT_K_TEXTSTART or key_u == STB_TEXTEDIT_K_BACKSPACE or key_u == STB_TEXTEDIT_K_WORDLEFT then self.LastMoveDirectionLR = ImGuiDir.Left elseif key_u == STB_TEXTEDIT_K_RIGHT or key_u == STB_TEXTEDIT_K_LINEEND or key_u == STB_TEXTEDIT_K_TEXTEND or key_u == STB_TEXTEDIT_K_DELETE or key_u == STB_TEXTEDIT_K_WORDRIGHT then self.LastMoveDirectionLR = ImGuiDir.Right end end local utf8 = {0, 0, 0, 0, 0} --- @param c unsigned_int function MT.ImGuiInputTextState:OnCharPressed(c) for i = 1, 5 do utf8[i] = 0 end -- Convert the key to a UTF8 byte sequence. -- The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great. ImStd.ImTextCharToUtf8(utf8, c) stbte.text(self, self.Stb, utf8, ImStd.ImStrlen(utf8)) self.CursorFollow = true self:CursorAnimReset() end -- After a user-input the cursor stays on for a while without blinking function MT.ImGuiInputTextState:CursorAnimReset() self.CursorAnim = -0.30 end function MT.ImGuiInputTextState:CursorClamp() self.Stb.cursor = ImMin(self.Stb.cursor, self.TextLen + 1) self.Stb.select_start = ImMin(self.Stb.select_start, self.TextLen + 1) self.Stb.select_end = ImMin(self.Stb.select_end, self.TextLen + 1) end function MT.ImGuiInputTextState:HasSelection() return self.Stb.select_start ~= self.Stb.select_end end function MT.ImGuiInputTextState:SelectAll() self.Stb.select_start = 1 self.Stb.cursor = self.TextLen + 1 self.Stb.select_end = self.TextLen + 1 self.Stb.has_preferred_x = false end end function ImGui.PushPasswordFont() local g = GImGui local backup = g.InputTextPasswordFontBackupBaked IM_ASSERT(backup.IndexAdvanceX.Size == 0 and backup.IndexLookup.Size == 0) local glyph = g.FontBaked:FindGlyph(42) -- '*' g.InputTextPasswordFontBackupFlags = g.Font.Flags backup.FallbackGlyphIndex = g.FontBaked.FallbackGlyphIndex backup.FallbackAdvanceX = g.FontBaked.FallbackAdvanceX backup.IndexLookup:swap(g.FontBaked.IndexLookup) backup.IndexAdvanceX:swap(g.FontBaked.IndexAdvanceX) g.Font.Flags = bit32.bor(g.Font.Flags, ImFontFlags.NoLoadGlyphs) g.FontBaked.FallbackGlyphIndex = g.FontBaked.Glyphs:index_from_ptr(glyph) + 1 g.FontBaked.FallbackAdvanceX = glyph.AdvanceX end function ImGui.PopPasswordFont() local g = GImGui local backup = g.InputTextPasswordFontBackupBaked g.Font.Flags = g.InputTextPasswordFontBackupFlags g.FontBaked.FallbackGlyphIndex = backup.FallbackGlyphIndex g.FontBaked.FallbackAdvanceX = backup.FallbackAdvanceX g.FontBaked.IndexLookup:swap(backup.IndexLookup) g.FontBaked.IndexAdvanceX:swap(backup.IndexAdvanceX) IM_ASSERT(backup.IndexAdvanceX.Size == 0 and backup.IndexLookup.Size == 0) end --- @param ctx ImGuiContext --- @param state ImGuiInputTextState --- @param char unsigned_int --- @param callback? ImGuiInputTextCallback --- @param user_data any --- @param input_source_is_clipboard? bool --- @return unsigned_int out_char --- @return bool local function InputTextFilterCharacter(ctx, state, char, callback, user_data, input_source_is_clipboard) if input_source_is_clipboard == nil then input_source_is_clipboard = false end IM_ASSERT(state ~= nil) local c = char local flags = state.Flags -- Filter non-printable (NB: isprint is unreliable! see #2467) local apply_named_filters = true if c < 0x20 then local pass = false pass = pass or (c == 10) and (bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0) -- Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) if c == 10 and input_source_is_clipboard and (bit32.band(flags, ImGuiInputTextFlags.Multiline) == 0) then -- In single line mode, replace \n with a space char = 32 c = 32 pass = true end pass = pass or (c == 10) and (bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0) pass = pass or (c == 9) and (bit32.band(flags, ImGuiInputTextFlags.AllowTabInput) ~= 0) -- tab if not pass then return char, false end apply_named_filters = false -- Override named filters below so newline and tabs can still be inserted. end if not input_source_is_clipboard then -- We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) if c == 127 then return char, false end -- Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) if c >= 0xE000 and c <= 0xF8FF then return char, false end end -- Filter Unicode ranges we are not handling in this build if c > IM_UNICODE_CODEPOINT_MAX then return char, false end -- Generic named filters if apply_named_filters and (bit32.band(flags, bit32.bor(ImGuiInputTextFlags.CharsDecimal, ImGuiInputTextFlags.CharsHexadecimal, ImGuiInputTextFlags.CharsUppercase, ImGuiInputTextFlags.CharsNoBlank, ImGuiInputTextFlags.CharsScientific, ImGuiInputTextFlags.LocalizeDecimalPoint))) ~= 0 then -- The standard mandate that programs starts in the "C" locale where the decimal point is '.'. -- We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. -- Change the default decimal_point with: -- ImGui::GetPlatformIO()->Platform_LocaleDecimalPoint = *localeconv()->decimal_point; -- Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. local g = ctx local c_decimal_point = g.PlatformIO.Platform_LocaleDecimalPoint if bit32.band(flags, bit32.bor(ImGuiInputTextFlags.CharsDecimal, ImGuiInputTextFlags.CharsScientific, ImGuiInputTextFlags.LocalizeDecimalPoint)) ~= 0 then if c == 46 or c == 44 then -- '.' or ',' c = c_decimal_point end end -- Full-width -> half-width conversion for numeric fields: https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) -- While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may -- scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font. if bit32.band(flags, bit32.bor(ImGuiInputTextFlags.CharsDecimal, ImGuiInputTextFlags.CharsScientific, ImGuiInputTextFlags.CharsHexadecimal)) ~= 0 then if c >= 0xFF01 and c <= 0xFF5E then c = c - 0xFF01 + 0x21 end end -- Allow 0-9 . - + * / if bit32.band(flags, ImGuiInputTextFlags.CharsDecimal) ~= 0 then if not (c >= 48 and c <= 57) and (c ~= c_decimal_point) and (c ~= 45) and (c ~= 43) and (c ~= 42) and (c ~= 47) then -- 0-9 . - + * / return char, false end end -- Allow 0-9 . - + * / e E if bit32.band(flags, ImGuiInputTextFlags.CharsScientific) ~= 0 then if not (c >= 48 and c <= 57) and (c ~= c_decimal_point) and (c ~= 45) and (c ~= 43) and (c ~= 42) and (c ~= 47) and (c ~= 101) and (c ~= 69) then -- 0-9 . - + * / e E return char, false end end -- Allow 0-9 a-F A-F if bit32.band(flags, ImGuiInputTextFlags.CharsHexadecimal) ~= 0 then if not (c >= 48 and c <= 57) and not (c >= 97 and c <= 102) and not (c >= 65 and c <= 70) then -- 0-9 a-f A-F return char, false end end -- Turn a-z into A-Z if bit32.band(flags, ImGuiInputTextFlags.CharsUppercase) ~= 0 then if c >= 97 and c <= 122 then -- a-z c = c + (65 - 97) -- 'A' - 'a' end end if bit32.band(flags, ImGuiInputTextFlags.CharsNoBlank) ~= 0 then if ImStd.ImCharIsBlankW(c) then return char, false end end char = c end -- Custom callback filter if bit32.band(flags, ImGuiInputTextFlags.CallbackCharFilter) ~= 0 then local g = GImGui local callback_data = ImGuiInputTextCallbackData() callback_data.Ctx = g callback_data.ID = state.ID callback_data.Flags = flags callback_data.EventFlag = ImGuiInputTextFlags.CallbackCharFilter callback_data.EventChar = c callback_data.EventActivated = (state ~= nil and g.ActiveId == state.ID and g.ActiveIdIsJustActivated) callback_data.CursorPos = state.Stb.cursor callback_data.SelectionStart = state.Stb.select_start callback_data.SelectionEnd = state.Stb.select_end callback_data.UserData = user_data if callback(callback_data) ~= 0 then return char, false end char = callback_data.EventChar if not callback_data.EventChar then return char, false end end return char, true end -- Find the shortest single replacement we can make to get from old_buf to new_buf -- Note that this doesn't directly alter state->TextA, state->TextLen. They are expected to be made valid separately. -- FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly --- @param state ImGuiInputTextState --- @param old_buf ImStringBuffer --- @param old_length int --- @param new_buf ImStringBuffer --- @param new_length int local function InputTextReconcileUndoState(state, old_buf, old_length, new_buf, new_length) local shorter_length = ImMin(old_length, new_length) local first_diff for i = 1, shorter_length do first_diff = i if old_buf[first_diff] ~= new_buf[first_diff] then break end end if first_diff == old_length + 1 and first_diff == new_length + 1 then return end local old_last_diff = old_length local new_last_diff = new_length while old_last_diff >= first_diff and new_last_diff >= first_diff do if old_buf[old_last_diff] ~= new_buf[new_last_diff] then break end old_last_diff = old_last_diff - 1 new_last_diff = new_last_diff - 1 end local insert_len = new_last_diff - first_diff + 1 local delete_len = old_last_diff - first_diff + 1 if insert_len > 0 or delete_len > 0 then local undostate = state.Stb.undostate local p = stbte.createundo(undostate, first_diff, delete_len, insert_len) if p then for i = 0, delete_len - 1 do undostate.undo_char[p + i] = old_buf[first_diff + i] end end end end --- @param id ImGuiID function ImGui.InputTextDeactivateHook(id) local g = GImGui local state = g.InputTextState if id == 0 or state.ID ~= id or g.ActiveId ~= id then return end if not state.EditedBefore then return end -- IMGUI_DEBUG_LOG_ACTIVEID("InputTextDeactivateHook() id = 0x%08X\n", id); g.InputTextDeactivatedState.ID = state.ID g.InputTextDeactivatedState.ElapseFrame = g.FrameCount + 1 if bit32.band(state.Flags, ImGuiInputTextFlags.ReadOnly) ~= 0 then g.InputTextDeactivatedState.TextA:resize(0) -- In theory this data won't be used, but clear to be neat else IM_ASSERT(state.TextA.Data ~= nil) -- IM_ASSERT(state.TextA[state.TextLen + 1] == 0) g.InputTextDeactivatedState.TextA:resize(state.TextLen + 1) ImStd.memmove(g.InputTextDeactivatedState.TextA.Data, 1, state.TextA.Data, 1, state.TextLen) -- state.TextLen + 1 end end --- @param flags ImGuiInputTextFlags --- @param line_index ImGuiTextIndex --- @param buf char[] --- @param buf_end int --- @param wrap_width float --- @param max_output_buffer_size int --- @return int size --- @return int? out_buf_end local function InputTextLineIndexBuild(flags, line_index, buf, buf_end, wrap_width, max_output_buffer_size) local g = GImGui local size = 0 local s = 1 local trailing_line_already_counted = false if bit32.band(flags, ImGuiInputTextFlags.WordWrap) ~= 0 then while s < buf_end do if size <= max_output_buffer_size then line_index.Offsets:push_back(s - 1) end size = size + 1 s = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, buf, s, buf_end, wrap_width, ImDrawTextFlags.WrapKeepBlanks) if buf[s] == 10 then s = s + 1 end end elseif buf_end ~= nil then while s < buf_end do if size <= max_output_buffer_size then line_index.Offsets:push_back(s - 1) end size = size + 1 s = ImMemchr(buf, 10, s) --[[@as int]] -- FIXME: if s then s = s + 1 else s = buf_end end end else -- Inactive path: we don't know buf_end ahead of time. local s_eol s = 1 while true do if size <= max_output_buffer_size then line_index.Offsets:push_back(s - 1) end size = size + 1 s_eol = ImMemchr(buf, 10, s) if s_eol == nil then s = s + ImStd.ImStrlen(buf) - s -- FIXME: trailing_line_already_counted = true break end s = s_eol + 1 end end local out_buf_end if out_buf_end ~= nil then out_buf_end = s buf_end = s end if size == 0 then line_index.Offsets:push_back(0) size = size + 1 end if s > 1 and buf[s - 1] == 10 and not trailing_line_already_counted then local old_size = size size = size + 1 if old_size <= max_output_buffer_size then line_index.Offsets:push_back(s - 1) end end return size, out_buf_end end --- @param t table --- @param in_begin int --- @param in_end int --- @param v int local function ImLowerBound(t, in_begin, in_end, v) local in_p = in_begin local count = in_end - in_begin local floor = math.floor local rshift = bit32.rshift while count > 0 do local count2 = floor(rshift(count, 1)) local mid = in_p + count2 if t[mid] < v then in_p = mid + 1 count = count - count2 - 1 else count = count2 end end return in_p end --- @param g ImGuiContext --- @param state ImGuiInputTextState --- @param line_index ImGuiTextIndex --- @param buf char[] --- @param buf_end int --- @param cursor_n int --- @return ImVec2 local function InputTextLineIndexGetPosOffset(g, state, line_index, buf, buf_end, cursor_n) local cursor_ptr = cursor_n local it = ImLowerBound(line_index.Offsets, 1, line_index.Offsets.Size + 1, cursor_ptr) if it > 1 then if it > line_index.Offsets.Size or line_index.Offsets[it] ~= cursor_ptr or (state ~= nil and state.WrapWidth > 0.0 and state.LastMoveDirectionLR == ImGuiDir.Right and buf[cursor_ptr - 1] ~= 10 and buf[cursor_ptr - 1] ~= 0) then it = it - 1 end end local line_no = it local line_start = (line_no == 1) and 1 or line_index.Offsets[line_no] + 1 local offset = ImVec2() offset.x = InputTextCalcTextSize(g, buf, line_start, cursor_ptr, buf_end, nil, ImDrawTextFlags.WrapKeepBlanks).x offset.y = line_no * g.FontSize return offset end -- Edit a string of text --- @param label string --- @param hint? char[] --- @param buf char[] --- @param buf_size int --- @param size_arg ImVec2 --- @param flags ImGuiInputTextFlags --- @param callback? ImGuiInputTextCallback --- @param callback_user_data any local HintBufCache = setmetatable({}, { __mode = "k" }) local function HintToBuf(hint) local t = HintBufCache[hint] if t == nil then t = {} for i = 1, #hint do t[i] = string.byte(hint, i) end t[#hint + 1] = 0 HintBufCache[hint] = t end return t end function ImGui.InputTextEx(label, hint, buf, buf_size, size_arg, flags, callback, callback_user_data) if type(hint) == "string" then hint = HintToBuf(hint) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end IM_ASSERT(buf ~= nil and buf_size >= 0) IM_ASSERT(not (bit32.band(flags, ImGuiInputTextFlags.CallbackHistory) ~= 0 and bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0)) -- Can't use both together (they both use up/down keys) IM_ASSERT(not (bit32.band(flags, ImGuiInputTextFlags.CallbackCompletion) ~= 0 and bit32.band(flags, ImGuiInputTextFlags.AllowTabInput) ~= 0)) -- Can't use both together (they both use tab key) IM_ASSERT(not (bit32.band(flags, ImGuiInputTextFlags.ElideLeft) ~= 0 and bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0)) -- Multiline does not not work with left-trimming IM_ASSERT(bit32.band(flags, ImGuiInputTextFlags.WordWrap) == 0 or bit32.band(flags, ImGuiInputTextFlags.Password) == 0) -- WordWrap does not work with Password mode IM_ASSERT(bit32.band(flags, ImGuiInputTextFlags.WordWrap) == 0 or bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0) -- WordWrap does not work in single-line mode local g = GImGui --[[@as ImGuiContext]] local io = g.IO local style = g.Style local RENDER_SELECTION_WHEN_INACTIVE = false local is_multiline = bit32.band(flags, ImGuiInputTextFlags.Multiline) ~= 0 if is_multiline then -- Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) ImGui.BeginGroup() end local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local frame_size = ImGui.CalcItemSize(size_arg, ImGui.CalcItemWidth(), (is_multiline and g.FontSize * 8.0 or label_size.y) + style.FramePadding.y * 2.0) -- Arbitrary default of 8 lines high for multi-line local total_size = ImVec2(frame_size.x + ((label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0), frame_size.y) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + frame_size) local total_bb = ImRect(frame_bb.Min, frame_bb.Min + total_size) local draw_window = window local inner_size = ImVec2() ImVec2_Copy(inner_size, frame_size) local item_data_backup = ImGuiLastItemData() if is_multiline then local backup_pos = ImVec2() ImVec2_Copy(backup_pos, window.DC.CursorPos) ImGui.ItemSize(total_bb, style.FramePadding.y) local no_clip = (g.InputTextDeactivatedState.ID == id) or (g.ActiveId == id) or (id == g.NavActivateId) -- Mimic some of ItemAdd() logic + add InputTextDeactivatedState.ID check. if not ImGui.ItemAdd(total_bb, id, frame_bb, ImGuiItemFlags.Inputable) and not no_clip then ImGui.EndGroup() return false end ImGuiLastItemData_Copy(item_data_backup, g.LastItemData) ImVec2_Copy(window.DC.CursorPos, backup_pos) -- Prevent NavActivation from explicit Tabbing when our widget accepts Tab inputs: this allows cycling through widgets without stopping if g.NavActivateId == id and (bit32.band(g.NavActivateFlags, ImGuiActivateFlags.FromTabbing) ~= 0) and (bit32.band(g.NavActivateFlags, ImGuiActivateFlags.FromFocusApi) == 0) and (bit32.band(flags, ImGuiInputTextFlags.AllowTabInput) ~= 0) then g.NavActivateId = 0 end -- Prevent NavActivate reactivating in BeginChild() when we are already active local backup_activate_id = g.NavActivateId if g.ActiveId == id then -- Prevent reactivation g.NavActivateId = 0 end -- We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug ImGui.PushStyleColor(ImGuiCol.ChildBg, style.Colors[ImGuiCol.FrameBg]) ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, style.FrameRounding) ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, style.FrameBorderSize) ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Ensure no clip rect so mouse hover can reach FramePadding edges local child_visible = ImGui.BeginChildEx(label, id, frame_bb:GetSize(), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) g.NavActivateId = backup_activate_id ImGui.PopStyleVar(3) ImGui.PopStyleColor() if not child_visible and not no_clip then ImGui.EndChild() ImGui.EndGroup() return false end draw_window = g.CurrentWindow -- Child window draw_window.DC.NavLayersActiveMaskNext = bit32.bor(draw_window.DC.NavLayersActiveMaskNext, bit32.lshift(1, draw_window.DC.NavLayerCurrent)) -- This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it ImVec2_Copy(draw_window.DC.CursorPos, draw_window.DC.CursorPos + style.FramePadding) inner_size.x = inner_size.x - draw_window.ScrollbarSizes.x -- FIXME: Could this be a ImGuiChildFlags to affect the SetLastItemDataForWindow() call? g.LastItemData.ID = id g.LastItemData.ItemFlags = item_data_backup.ItemFlags g.LastItemData.StatusFlags = item_data_backup.StatusFlags else ImGui.ItemSize(total_bb, style.FramePadding.y) if bit32.band(flags, ImGuiInputTextFlags.TempInput) == 0 then if not ImGui.ItemAdd(total_bb, id, frame_bb, ImGuiItemFlags.Inputable) then return false end end end -- Ensure mouse cursor is set even after switching to keyboard/gamepad mode. May generalize further? (#6417) local hovered = ImGui.ItemHoverable(frame_bb, id, bit32.bor(g.LastItemData.ItemFlags, ImGuiItemFlags.NoNavDisableMouseHover)) if hovered then ImGui.SetMouseCursor(ImGuiMouseCursor.TextInput) end if hovered and g.NavHighlightItemUnderNav then hovered = false end -- We are only allowed to access the state if we are already the active widget local state = ImGui.GetInputTextState(id) if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.ReadOnly) ~= 0 then flags = bit32.bor(flags, ImGuiInputTextFlags.ReadOnly) end local is_readonly = bit32.band(flags, ImGuiInputTextFlags.ReadOnly) ~= 0 local is_password = bit32.band(flags, ImGuiInputTextFlags.Password) ~= 0 local is_undoable = bit32.band(flags, ImGuiInputTextFlags.NoUndoRedo) == 0 local is_resizable = bit32.band(flags, ImGuiInputTextFlags.CallbackResize) ~= 0 if is_resizable then IM_ASSERT(callback ~= nil) -- Must provide a callback if you set the ImGuiInputTextFlags.CallbackResize flag! end -- Word-wrapping: enforcing a fixed width not altered by vertical scrollbar makes things easier, notably to track cursor reliably and avoid one-frame glitches. -- Instead of using ImGuiWindowFlags_AlwaysVerticalScrollbar we account for that space if the scrollbar is not visible. local is_wordwrap = bit32.band(flags, ImGuiInputTextFlags.WordWrap) ~= 0 local wrap_width = 0.0 if is_wordwrap then wrap_width = ImMax(1.0, ImGui.GetContentRegionAvail().x + (draw_window.ScrollbarY and 0.0 or -g.Style.ScrollbarSize)) end local user_clicked = hovered and io.MouseClicked[0] local input_requested_by_nav = (g.ActiveId ~= id) and (g.NavActivateId == id) and ((bit32.band(g.NavActivateFlags, ImGuiActivateFlags.PreferInput) ~= 0) or (g.NavInputSource == ImGuiInputSource.Keyboard)) local input_requested_by_reactivate = (g.InputTextReactivateId == id) -- for io.ConfigInputTextEnterKeepActive local input_requested_by_user = (user_clicked) or (g.ActiveId == 0 and bit32.band(flags, ImGuiInputTextFlags.TempInput) ~= 0 and g.InputTextDeactivatedState.ID ~= id) local scrollbar_id = (is_multiline and state ~= nil) and ImGui.GetWindowScrollbarID(draw_window, ImGuiAxis.Y) or 0 local user_scroll_finish = is_multiline and state ~= nil and g.ActiveId == 0 and g.ActiveIdPreviousFrame == scrollbar_id local user_scroll_active = is_multiline and state ~= nil and g.ActiveId == scrollbar_id local clear_active_id = false local select_all = false local scroll_y = is_multiline and draw_window.Scroll.y or FLT_MAX local init_reload_from_user_buf = (state ~= nil and state.WantReloadUserBuf) local init_changed_specs_multiline = (state ~= nil and (state.Stb.single_line ~= (not is_multiline))) local init_changed_specs_readonly = (state ~= nil and (bit32.band(bit32.bxor(state.Flags, flags), ImGuiInputTextFlags.ReadOnly) ~= 0)) -- state ~= nil means it's our state local init_make_active = (input_requested_by_user or input_requested_by_nav or input_requested_by_reactivate or user_scroll_finish) if init_reload_from_user_buf then local new_len = ImStd.ImStrlen(buf) IM_ASSERT(new_len + 1 <= buf_size, "Is your input buffer properly zero-terminated?") state.WantReloadUserBuf = false --- @cast state ImGuiInputTextState InputTextReconcileUndoState(state, state.TextA.Data, state.TextLen, buf, new_len) state.TextA:resize(buf_size + 1) state.TextLen = new_len ImStd.memmove(state.TextA.Data, 1, buf, 1, state.TextLen + 1) state.Stb.select_start = state.ReloadSelectionStart state.Stb.cursor = state.ReloadSelectionEnd state.Stb.select_end = state.ReloadSelectionEnd -- will be clamped to bounds below elseif (init_make_active and g.ActiveId ~= id) or init_changed_specs_multiline or init_changed_specs_readonly then -- Access state even if we don't own it yet state = g.InputTextState state:CursorAnimReset() -- Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) if (state.ID ~= id and state.ID == g.ActiveId and (init_make_active and g.ActiveId ~= id)) then ImGui.InputTextDeactivateHook(state.ID) -- <-- this is essentially an earlier call to what SetActiveID() would do below. end -- Take a copy of the initial buffer value. -- From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) local buf_len = ImStd.ImStrlen(buf) IM_ASSERT(((buf_len + 1 <= buf_size) or (buf_len == 0 and buf_size == 0)), "Is your input buffer properly zero-terminated?") if not user_scroll_finish then state.TextToRevertTo:resize(buf_len + 1) ImStd.memmove(state.TextToRevertTo.Data, 1, buf, 1, buf_len + 1) end -- Preserve cursor position and undo/redo stack if we come back to same widget -- FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? local recycle_state = (state.ID == id and not init_changed_specs_multiline) if (recycle_state and not init_changed_specs_readonly and (state.TextLen ~= buf_len or (state.TextA.Data == nil or ImStd.strncmp(state.TextA.Data, buf, buf_len) ~= 0))) then recycle_state = false end -- Start edition state.ID = id state.TextLen = buf_len state.EditedBefore = false if not is_readonly then state.TextA:resize(buf_size + 1) ImStd.memmove(state.TextA.Data, 1, buf, 1, state.TextLen + 1) end -- Find initial scroll position for right alignment ImVec2_Copy(state.Scroll, ImVec2(0.0, 0.0)) if bit32.band(flags, ImGuiInputTextFlags.ElideLeft) ~= 0 then state.Scroll.x = state.Scroll.x + ImMax(0.0, ImGui.CalcTextSize(table.concat(buf)).x - frame_size.x + style.FramePadding.x * 2.0) -- FIXME: no table.concat here end -- Recycle existing cursor/selection/undo stack but clamp position -- Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler if not recycle_state then stbte.initialize_state(state.Stb, not is_multiline) end if not is_multiline then if bit32.band(flags, ImGuiInputTextFlags.AutoSelectAll) ~= 0 then select_all = true end if input_requested_by_nav and (not recycle_state or (bit32.band(g.NavActivateFlags, ImGuiActivateFlags.TryToPreserveState) == 0)) then select_all = true end if user_clicked and io.KeyCtrl then select_all = true end end if bit32.band(flags, ImGuiInputTextFlags.AlwaysOverwrite) ~= 0 then state.Stb.insert_mode = true -- stb field name is indeed incorrect (see #2863) end end local is_osx = io.ConfigMacOSXBehaviors if init_make_active and g.ActiveId ~= id then IM_ASSERT(state ~= nil and state.ID == id) ImGui.SetActiveID(id, window) ImGui.SetFocusID(id, window) ImGui.FocusWindow(window) if input_requested_by_nav then ImGui.SetNavCursorVisibleAfterMove() end end if g.ActiveId == id then -- Declare some inputs, the other are registered and polled via Shortcut() routing system -- FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all mods combination into individual shortcuts local always_owned_keys = { ImGuiKey.LeftArrow, ImGuiKey.RightArrow, ImGuiKey.Delete, ImGuiKey.Backspace, ImGuiKey.Home, ImGuiKey.End } for _, key in ipairs(always_owned_keys) do ImGui.SetKeyOwner(key, id) end if user_clicked then ImGui.SetKeyOwner(ImGuiKey.MouseLeft, id) end g.ActiveIdUsingNavDirMask = bit32.bor(g.ActiveIdUsingNavDirMask, bit32.lshift(1, ImGuiDir.Left), bit32.lshift(1, ImGuiDir.Right)) if is_multiline or (bit32.band(flags, ImGuiInputTextFlags.CallbackHistory) ~= 0) then g.ActiveIdUsingNavDirMask = bit32.bor(g.ActiveIdUsingNavDirMask, bit32.lshift(1, ImGuiDir.Up), bit32.lshift(1, ImGuiDir.Down)) ImGui.SetKeyOwner(ImGuiKey.UpArrow, id) ImGui.SetKeyOwner(ImGuiKey.DownArrow, id) end if is_multiline then ImGui.SetKeyOwner(ImGuiKey.PageUp, id) ImGui.SetKeyOwner(ImGuiKey.PageDown, id) end -- FIXME: May be a problem to always steal Alt on OSX, would ideally still allow an uninterrupted Alt down-up to toggle menu if is_osx then ImGui.SetKeyOwner(ImGuiMod_Alt, id) end -- Expose scroll in a manner that is agnostic to us using a child window if is_multiline and state ~= nil then state.Scroll.y = draw_window.Scroll.y end -- Read-only mode always ever read from source buffer. Refresh TextLen when active. if is_readonly and state ~= nil then state.TextLen = ImStd.ImStrlen(buf) end if state ~= nil then state:CursorClamp() end -- if is_readonly and state ~= nil then -- state.TextA:clear() -- Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation. -- end end if state ~= nil then state.TextSrc = is_readonly and buf or state.TextA.Data end -- We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) if g.ActiveId == id and state == nil then ImGui.ClearActiveID() end -- Release focus when we click outside if g.ActiveId == id and io.MouseClicked[0] and not init_make_active then clear_active_id = true end -- Lock the decision of whether we are going to take the path displaying the cursor or selection local render_cursor = (g.ActiveId == id) or (state and user_scroll_active) --[[@as bool]] local render_selection = state and (state:HasSelection() or select_all) and (RENDER_SELECTION_WHEN_INACTIVE or render_cursor) local value_changed = false local validated = false -- Select the buffer to render local buf_display_from_state = (render_cursor or render_selection or g.ActiveId == id) and not is_readonly and state ~= nil local is_displaying_hint = (hint ~= nil and (buf_display_from_state and state.TextA.Data or buf)[1] == 0) -- Password pushes a temporary font with only a fallback glyph if is_password and not is_displaying_hint then ImGui.PushPasswordFont() end if state ~= nil and state.ID == id then state.Flags = flags -- Word-wrapping: attempt to keep cursor in view while resizing frame/parent (FIXME-WORDWRAP: would be better to preserve same relative offset) if is_wordwrap and state.WrapWidth ~= wrap_width then state.CursorCenterY = true state.WrapWidth = wrap_width render_cursor = true end end -- Process mouse inputs and character inputs if g.ActiveId == id then --- @cast state ImGuiInputTextState IM_ASSERT(state ~= nil) state.EditedThisFrame = false state.BufCapacity = buf_size state.WrapWidth = wrap_width -- Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. -- Down the line we should have a cleaner library-wide concept of Selected vs Active g.ActiveIdAllowOverlap = not io.MouseDown[0] -- Edit in progress local mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state.Scroll.x local mouse_y = (is_multiline and (io.MousePos.y - draw_window.DC.CursorPos.y) or (g.FontSize * 0.5)) if select_all then state:SelectAll() state.SelectedAllMouseLock = true elseif hovered and io.MouseClickedCount[0] >= 2 and not io.KeyShift then stbte.click(state, state.Stb, mouse_x, mouse_y) local multiclick_count = (io.MouseClickedCount[0] - 2) if multiclick_count % 2 == 0 then -- Double-click: Select word -- We always use the "Mac" word advance for double-click select vs Ctrl+Right which use the platform dependent variant: -- FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) local is_bol = (state.Stb.cursor == 1) or ImStb.TEXTEDIT_GETCHAR(state, state.Stb.cursor - 1) == 10 if stbte.HAS_SELECTION(state.Stb) or not is_bol then state:OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT) end -- state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_WORDRIGHT, STB_TEXTEDIT_K_SHIFT)) if not stbte.HAS_SELECTION(state.Stb) then stbte.prep_selection_at_cursor(state.Stb) end state.Stb.cursor = STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state.Stb.cursor) state.Stb.select_end = state.Stb.cursor stbte.clamp(state, state.Stb) else -- Triple-click: Select line local is_eol = ImStb.TEXTEDIT_GETCHAR(state, state.Stb.cursor) == 10 state.WrapWidth = 0.0 -- Temporarily disable wrapping so we use real line start state:OnKeyPressed(STB_TEXTEDIT_K_LINESTART) state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_SHIFT)) state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT)) state.WrapWidth = wrap_width if not is_eol and is_multiline then state.Stb.select_start, state.Stb.select_end = state.Stb.select_end, state.Stb.select_start state.Stb.cursor = state.Stb.select_end end state.CursorFollow = false end state:CursorAnimReset() elseif io.MouseClicked[0] and not state.SelectedAllMouseLock then if hovered then if io.KeyShift then stbte.drag(state, state.Stb, mouse_x, mouse_y) else stbte.click(state, state.Stb, mouse_x, mouse_y) end state:CursorAnimReset() end elseif io.MouseDown[0] and not state.SelectedAllMouseLock and (io.MouseDelta.x ~= 0.0 or io.MouseDelta.y ~= 0.0) then stbte.drag(state, state.Stb, mouse_x, mouse_y) state:CursorAnimReset() state.CursorFollow = true end if state.SelectedAllMouseLock and not io.MouseDown[0] then state.SelectedAllMouseLock = false end if bit32.band(flags, ImGuiInputTextFlags.AllowTabInput) ~= 0 and not is_readonly then if ImGui.Shortcut(ImGuiKey.Tab, ImGuiInputFlags.Repeat, id) then local c = 9 -- Insert TAB local ret2 c, ret2 = InputTextFilterCharacter(g, state, c, callback, callback_user_data) if ret2 then state:OnCharPressed(c) end end -- FIXME: Implement Shift+Tab end -- Process regular text input local ignore_char_inputs = io.KeyCtrl and not io.KeyAlt if io.InputQueueCharacters.Size > 0 then if not ignore_char_inputs and not is_readonly and not input_requested_by_nav then for n = 1, io.InputQueueCharacters.Size do repeat -- Insert character if they pass filtering local c = io.InputQueueCharacters[n] if c == 9 then -- Skip Tab, see above break end local ret2 c, ret2 = InputTextFilterCharacter(g, state, c, callback, callback_user_data) if ret2 then state:OnCharPressed(c) end until true end end -- Consume characters io.InputQueueCharacters:resize(0) end end -- Process other shortcuts/key-presses local revert_edit = false if g.ActiveId == id and not g.ActiveIdIsJustActivated and not clear_active_id then IM_ASSERT(state ~= nil) --- @cast state ImGuiInputTextState local row_count_per_page = ImMax(ImTrunc((inner_size.y - style.FramePadding.y) / g.FontSize), 1) state.Stb.row_count_per_page = row_count_per_page local k_mask = (io.KeyShift and STB_TEXTEDIT_K_SHIFT or 0) local is_wordmove_key_down = is_osx and io.KeyAlt or io.KeyCtrl local is_startend_key_down = is_osx and io.KeyCtrl and not io.KeySuper and not io.KeyAlt local f_repeat = ImGuiInputFlags.Repeat local is_cut = (ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.X), f_repeat, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Shift, ImGuiKey.Delete), f_repeat, id)) and not is_readonly and not is_password and (not is_multiline or state:HasSelection()) local is_copy = (ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.C), 0, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.Insert), 0, id)) and not is_password and (not is_multiline or state:HasSelection()) local is_paste = (ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.V), f_repeat, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Shift, ImGuiKey.Insert), f_repeat, id)) and not is_readonly local is_undo = (ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.Z), f_repeat, id)) and not is_readonly and is_undoable local is_redo = (ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.Y), f_repeat, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey.Z), f_repeat, id)) and not is_readonly and is_undoable local is_select_all = ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.A), 0, id) local nav_gamepad_active = (bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0) and (bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0) local is_enter = ImGui.Shortcut(ImGuiKey.Enter, f_repeat, id) or ImGui.Shortcut(ImGuiKey.KeypadEnter, f_repeat, id) local is_ctrl_enter = ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.Enter), f_repeat, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.KeypadEnter), f_repeat, id) local is_shift_enter = ImGui.Shortcut(bit32.bor(ImGuiMod_Shift, ImGuiKey.Enter), f_repeat, id) or ImGui.Shortcut(bit32.bor(ImGuiMod_Shift, ImGuiKey.KeypadEnter), f_repeat, id) local is_gamepad_validate = nav_gamepad_active and ImGui.IsKeyPressed(ImGuiKey.NavGamepadActivate, false) local is_cancel = ImGui.Shortcut(ImGuiKey.Escape, f_repeat, id) or (nav_gamepad_active and ImGui.Shortcut(ImGuiKey.NavGamepadCancel, f_repeat, id)) if ImGui.IsKeyPressed(ImGuiKey.LeftArrow) then state:OnKeyPressed(bit32.bor(is_startend_key_down and STB_TEXTEDIT_K_LINESTART or (is_wordmove_key_down and STB_TEXTEDIT_K_WORDLEFT or STB_TEXTEDIT_K_LEFT), k_mask)) elseif ImGui.IsKeyPressed(ImGuiKey.RightArrow) then state:OnKeyPressed(bit32.bor(is_startend_key_down and STB_TEXTEDIT_K_LINEEND or (is_wordmove_key_down and STB_TEXTEDIT_K_WORDRIGHT or STB_TEXTEDIT_K_RIGHT), k_mask)) elseif ImGui.IsKeyPressed(ImGuiKey.UpArrow) and is_multiline then if io.KeyCtrl then ImGui.SetScrollY(draw_window, ImMax(draw_window.Scroll.y - g.FontSize, 0.0)) else state:OnKeyPressed(bit32.bor(is_startend_key_down and STB_TEXTEDIT_K_TEXTSTART or STB_TEXTEDIT_K_UP, k_mask)) end elseif ImGui.IsKeyPressed(ImGuiKey.DownArrow) and is_multiline then if io.KeyCtrl then ImGui.SetScrollY(draw_window, ImMin(draw_window.Scroll.y + g.FontSize, ImGui.GetScrollMaxY())) else state:OnKeyPressed(bit32.bor(is_startend_key_down and STB_TEXTEDIT_K_TEXTEND or STB_TEXTEDIT_K_DOWN, k_mask)) end elseif ImGui.IsKeyPressed(ImGuiKey.PageUp) and is_multiline then state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_PGUP, k_mask)) scroll_y = scroll_y - row_count_per_page * g.FontSize elseif ImGui.IsKeyPressed(ImGuiKey.PageDown) and is_multiline then state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_PGDOWN, k_mask)) scroll_y = scroll_y + row_count_per_page * g.FontSize elseif ImGui.IsKeyPressed(ImGuiKey.Home) then state:OnKeyPressed(io.KeyCtrl and bit32.bor(STB_TEXTEDIT_K_TEXTSTART, k_mask) or bit32.bor(STB_TEXTEDIT_K_LINESTART, k_mask)) elseif ImGui.IsKeyPressed(ImGuiKey.End) then state:OnKeyPressed(io.KeyCtrl and bit32.bor(STB_TEXTEDIT_K_TEXTEND, k_mask) or bit32.bor(STB_TEXTEDIT_K_LINEEND, k_mask)) elseif ImGui.IsKeyPressed(ImGuiKey.Delete) and not is_readonly and not is_cut then if not state:HasSelection() then if is_wordmove_key_down then state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_WORDRIGHT, STB_TEXTEDIT_K_SHIFT)) end end state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_DELETE, k_mask)) elseif ImGui.IsKeyPressed(ImGuiKey.Backspace) and not is_readonly then if not state:HasSelection() then if is_wordmove_key_down then state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_WORDLEFT, STB_TEXTEDIT_K_SHIFT)) elseif is_osx and io.KeyCtrl and not io.KeyAlt and not io.KeySuper then state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_SHIFT)) end end state:OnKeyPressed(bit32.bor(STB_TEXTEDIT_K_BACKSPACE, k_mask)) elseif is_enter or is_ctrl_enter or is_shift_enter or is_gamepad_validate then local ctrl_enter_for_new_line = bit32.band(flags, ImGuiInputTextFlags.CtrlEnterForNewLine) ~= 0 local is_new_line = is_multiline and not is_gamepad_validate and (is_shift_enter or (is_enter and not ctrl_enter_for_new_line) or (is_ctrl_enter and ctrl_enter_for_new_line)) if not is_new_line then validated = true clear_active_id = true if io.ConfigInputTextEnterKeepActive and not is_multiline and not is_ctrl_enter and not is_shift_enter then state:SelectAll() g.InputTextReactivateId = id end elseif not is_readonly then local c = 10 -- Insert new line local ret2 c, ret2 = InputTextFilterCharacter(g, state, c, callback, callback_user_data) if ret2 then state:OnCharPressed(c) end end elseif is_cancel then if bit32.band(flags, ImGuiInputTextFlags.EscapeClearsAll) ~= 0 then if state.TextA.Data[1] ~= 0 then revert_edit = true else render_cursor = false render_selection = false clear_active_id = true end else clear_active_id = true revert_edit = true render_cursor = false render_selection = false end elseif is_undo or is_redo then state:OnKeyPressed(is_undo and STB_TEXTEDIT_K_UNDO or STB_TEXTEDIT_K_REDO) state:ClearSelection() elseif is_select_all then state:SelectAll() state.CursorFollow = true elseif is_cut or is_copy then if g.PlatformIO.Platform_SetClipboardTextFn ~= nil then local ib = state:HasSelection() and ImMin(state.Stb.select_start, state.Stb.select_end) or 1 local ie = state:HasSelection() and ImMax(state.Stb.select_start, state.Stb.select_end) or state.TextLen + 1 g.TempBuffer:reserve(ie - ib + 1) ImStd.memmove(g.TempBuffer.Data, 1, state.TextSrc, ib, ie - ib) g.TempBuffer.Data[ie - ib + 1] = 0 ImGui.SetClipboardText(ImGui._ByteArrayToString(g.TempBuffer.Data, 1, ie - ib + 1)) end if is_cut then if not state:HasSelection() then state:SelectAll() end state.CursorFollow = true stbte.cut(state, state.Stb) end elseif is_paste then local clipboard = ImGui.GetClipboardText() if clipboard then local clipboard_len = #clipboard local clipboard_end = clipboard_len + 1 local clipboard_filtered = ImVector() clipboard_filtered:reserve(clipboard_len + 1) local s local i = 1 while i <= clipboard_len do repeat s = string.byte(clipboard, i) local c, ret2 local in_len in_len, c = ImStd.ImTextCharFromUtf8(clipboard, i, clipboard_end) i = i + in_len c, ret2 = InputTextFilterCharacter(g, state, c, callback, callback_user_data, true) if ret2 then break end local c_utf8 = {0, 0, 0, 0, 0} ImStd.ImTextCharToUtf8(c_utf8, c) local out_len = ImStd.ImStrlen(c_utf8) clipboard_filtered:resize(clipboard_filtered.Size + out_len) ImStd.memmove(clipboard_filtered.Data, clipboard_filtered.Size - out_len, c_utf8, 1, out_len) until true end if clipboard_filtered.Size > 0 then clipboard_filtered:push_back(0) stbte.paste(state, state.Stb, clipboard_filtered.Data, clipboard_filtered.Size - 1) state.CursorFollow = true end end end render_selection = render_selection or (state:HasSelection() and (RENDER_SELECTION_WHEN_INACTIVE or render_cursor)) end -- Process revert and user callbacks local apply_new_text = nil local apply_new_text_length = 0 if g.ActiveId == id then IM_ASSERT(state ~= nil) --- @cast state ImGuiInputTextState if revert_edit and not is_readonly then if bit32.band(flags, ImGuiInputTextFlags.EscapeClearsAll) ~= 0 then IM_ASSERT(state.TextA.Data[1] ~= 0) apply_new_text = {0} apply_new_text_length = 0 value_changed = true local empty_string = {0} ImStb.stb_textedit_replace(state, state.Stb, empty_string, 0) elseif ImStd.strcmp(state.TextA.Data, state.TextToRevertTo.Data) ~= 0 then apply_new_text = state.TextToRevertTo.Data apply_new_text_length = state.TextToRevertTo.Size - 1 value_changed = true ImStb.stb_textedit_replace(state, state.Stb, state.TextToRevertTo.Data, state.TextToRevertTo.Size - 1) end end if bit32.band(flags, bit32.bor(ImGuiInputTextFlags.CallbackCompletion, ImGuiInputTextFlags.CallbackHistory, ImGuiInputTextFlags.CallbackEdit, ImGuiInputTextFlags.CallbackAlways)) ~= 0 then IM_ASSERT(callback ~= nil) local event_flag = 0 local event_key = ImGuiKey.None if bit32.band(flags, ImGuiInputTextFlags.CallbackCompletion) ~= 0 and ImGui.Shortcut(ImGuiKey.Tab, 0, id) then event_flag = ImGuiInputTextFlags.CallbackCompletion event_key = ImGuiKey.Tab elseif bit32.band(flags, ImGuiInputTextFlags.CallbackHistory) ~= 0 and ImGui.IsKeyPressed(ImGuiKey.UpArrow) then event_flag = ImGuiInputTextFlags.CallbackHistory event_key = ImGuiKey.UpArrow elseif bit32.band(flags, ImGuiInputTextFlags.CallbackHistory) ~= 0 and ImGui.IsKeyPressed(ImGuiKey.DownArrow) then event_flag = ImGuiInputTextFlags.CallbackHistory event_key = ImGuiKey.DownArrow elseif bit32.band(flags, ImGuiInputTextFlags.CallbackEdit) ~= 0 and state.EditedThisFrame then event_flag = ImGuiInputTextFlags.CallbackEdit elseif bit32.band(flags, ImGuiInputTextFlags.CallbackAlways) ~= 0 then event_flag = ImGuiInputTextFlags.CallbackAlways end if event_flag ~= 0 then local callback_data = ImGuiInputTextCallbackData() callback_data.Ctx = g callback_data.ID = id callback_data.Flags = flags callback_data.EventFlag = event_flag callback_data.EventActivated = (g.ActiveId == state.ID and g.ActiveIdIsJustActivated) callback_data.UserData = callback_user_data local callback_buf = is_readonly and buf or state.TextA.Data IM_ASSERT(callback_buf == state.TextSrc) state.CallbackTextBackup:resize(state.TextLen + 1) ImStd.memmove(state.CallbackTextBackup.Data, 1, callback_buf, 1, state.TextLen + 1) callback_data.EventKey = event_key callback_data.Buf = callback_buf callback_data.BufTextLen = state.TextLen callback_data.BufSize = state.BufCapacity callback_data.BufDirty = false callback_data.CursorPos = state.Stb.cursor callback_data.SelectionStart = state.Stb.select_start callback_data.SelectionEnd = state.Stb.select_end callback(callback_data) callback_buf = is_readonly and buf or state.TextA.Data IM_ASSERT(callback_data.Buf == callback_buf) IM_ASSERT(callback_data.BufSize == state.BufCapacity) IM_ASSERT(callback_data.Flags == flags) if callback_data.BufDirty or callback_data.CursorPos ~= state.Stb.cursor then state.CursorFollow = true end state.Stb.cursor = ImClamp(callback_data.CursorPos, 0, callback_data.BufTextLen) state.Stb.select_start = ImClamp(callback_data.SelectionStart, 0, callback_data.BufTextLen) state.Stb.select_end = ImClamp(callback_data.SelectionEnd, 0, callback_data.BufTextLen) if callback_data.BufDirty then IM_ASSERT(callback_data.BufTextLen == ImStd.ImStrlen(callback_data.Buf)) InputTextReconcileUndoState(state, state.CallbackTextBackup.Data, state.CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen) state.TextLen = callback_data.BufTextLen state.EditedBefore = true; state.EditedThisFrame = true state:CursorAnimReset() end end end if not is_readonly then if bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0 then -- Apply when modified if (ImStd.strcmp(state.TextSrc, buf) ~= 0) then apply_new_text = state.TextSrc apply_new_text_length = state.TextLen value_changed = true end else -- Apply on validation/deactivation, otherwise cancel out previous apply attempts (e.g. revert) value_changed = ((validated or clear_active_id or revert_edit) and ImStd.strcmp(state.TextSrc, buf) ~= 0) apply_new_text = value_changed and state.TextSrc or NULL apply_new_text_length = value_changed and state.TextLen or 0 end end end if g.InputTextDeactivatedState.ID == id then -- The state only exists after an Edit. IsItemDeactivatedAfterEdit() is not valid in every code path (see "widgets_inputtext_status_noliveedit" test). if ((g.ActiveId ~= id and ImGui.IsItemDeactivated()) or (g.ActiveId == id and bit32.band(flags, ImGuiInputTextFlags.TempInput) ~= 0)) then if (not is_readonly and ImStd.strcmp(g.InputTextDeactivatedState.TextA.Data, buf) ~= 0) then apply_new_text = g.InputTextDeactivatedState.TextA.Data apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1 value_changed = true -- IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text); end end g.InputTextDeactivatedState.ID = 0 end if apply_new_text ~= nil then IM_ASSERT(apply_new_text_length >= 0) if is_resizable then local callback_data = ImGuiInputTextCallbackData() callback_data.Ctx = g callback_data.ID = id callback_data.Flags = flags callback_data.EventFlag = ImGuiInputTextFlags.CallbackResize callback_data.EventActivated = (g.ActiveId == state.ID and g.ActiveIdIsJustActivated) callback_data.Buf = buf callback_data.BufTextLen = apply_new_text_length callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1) callback_data.UserData = callback_user_data callback(callback_data) buf = callback_data.Buf buf_size = callback_data.BufSize apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1) IM_ASSERT(apply_new_text_length <= buf_size) end ImStd.ImStrncpy(buf, 1, apply_new_text, 1, ImMin(apply_new_text_length + 1, buf_size)) end -- Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) -- Otherwise request text input ahead for next frame. if g.ActiveId == id and clear_active_id then state.ID = 0 ImGui.ClearActiveID() state.ID = id end -- Render frame if not is_multiline then ImGui.RenderNavCursor(frame_bb, id) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, ImGui.GetColorU32(ImGuiCol.FrameBg), true, style.FrameRounding) end local draw_pos = ImVec2() ImVec2_Copy(draw_pos, is_multiline and draw_window.DC.CursorPos or (frame_bb.Min + style.FramePadding)) local clip_rect = ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y) -- Not using frame_bb.Max because we have adjusted size if is_multiline then clip_rect:ClipWith(draw_window.ClipRect) end -- Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line -- without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. -- Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. local buf_display_max_length = 2 * 1024 * 1024 local buf_display = buf_display_from_state and state.TextA.Data or buf local buf_display_end = nil -- We have specialized paths below for setting the length -- Display hint when contents is empty -- At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368) local new_is_displaying_hint = (hint ~= nil and (buf_display_from_state and state.TextA.Data or buf)[1] == 0) if new_is_displaying_hint ~= is_displaying_hint then if is_password and not is_displaying_hint then ImGui.PopPasswordFont() end is_displaying_hint = new_is_displaying_hint if is_password and not is_displaying_hint then ImGui.PushPasswordFont() end end if is_displaying_hint then --- @cast hint char[] buf_display = hint buf_display_end = ImStd.ImStrlen(hint) + 1 else if render_cursor or render_selection or g.ActiveId == id then buf_display_end = state.TextLen + 1 elseif is_multiline and not is_wordwrap then buf_display_end = nil -- Inactive multi-line: end of buffer will be output by InputTextLineIndexBuild() special strchr() path else buf_display_end = ImStd.ImStrlen(buf_display) + 1 end end -- Calculate visibility local line_visible_n0, line_visible_n1 = 1, 2 if is_multiline then line_visible_n0, line_visible_n1 = ImGui.CalcClipRectVisibleItemsY(clip_rect, draw_pos, g.FontSize) end local line_index = g.InputTextLineIndex line_index.Offsets:resize(0) local line_count = 1 if is_multiline then local will_scroll_y = state and ((state.CursorFollow and render_cursor) or (state.CursorCenterY and (render_cursor or render_selection))) --- @cast buf_display_end int local out_buf_end line_count, out_buf_end = InputTextLineIndexBuild(flags, line_index, buf_display, buf_display_end, wrap_width, will_scroll_y and INT_MAX or (line_visible_n1 + 1)) if buf_display_end then buf_display_end = out_buf_end end end line_index.EndOffset = buf_display_end - 1 line_visible_n1 = ImMin(line_visible_n1, line_count + 1) local text_size_y = line_count * g.FontSize --- @cast buf_display_end int local cursor_offset = (render_cursor and state) and InputTextLineIndexGetPosOffset(g, state, line_index, buf_display, buf_display_end, state.Stb.cursor) or ImVec2(0.0, 0.0) local draw_scroll = ImVec2() local text_col = ImGui.GetColorU32(is_displaying_hint and ImGuiCol.TextDisabled or ImGuiCol.Text) if render_cursor or render_selection then IM_ASSERT(state ~= nil) state.LineCount = line_count local new_scroll_y = scroll_y if render_cursor and state.CursorFollow then if bit32.band(flags, ImGuiInputTextFlags.NoHorizontalScroll) == 0 then local scroll_increment_x = inner_size.x * 0.25 local visible_width = inner_size.x - style.FramePadding.x if cursor_offset.x < state.Scroll.x then state.Scroll.x = IM_TRUNC(ImMax(0.0, cursor_offset.x - scroll_increment_x)) elseif cursor_offset.x - visible_width >= state.Scroll.x then state.Scroll.x = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x) end else state.Scroll.x = 0.0 end if is_multiline then if cursor_offset.y - g.FontSize < scroll_y then new_scroll_y = ImMax(0.0, cursor_offset.y - g.FontSize) elseif cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0) >= scroll_y then new_scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0 end end state.CursorFollow = false end if state.CursorCenterY then if is_multiline then new_scroll_y = cursor_offset.y - g.FontSize - (inner_size.y * 0.5 - style.FramePadding.y) end state.CursorCenterY = false render_cursor = false end if new_scroll_y ~= scroll_y then local scroll_max_y = ImMax((text_size_y + style.FramePadding.y * 2.0) - inner_size.y, 0.0) scroll_y = ImClamp(new_scroll_y, 0.0, scroll_max_y) draw_pos.y = draw_pos.y + (draw_window.Scroll.y - scroll_y) draw_window.Scroll.y = scroll_y line_visible_n0, line_visible_n1 = ImGui.CalcClipRectVisibleItemsY(clip_rect, draw_pos, g.FontSize) line_visible_n1 = ImMin(line_visible_n1, line_count) end draw_scroll.x = state.Scroll.x if render_selection then local bg_color = ImGui.GetColorU32(ImGuiCol.TextSelectedBg, render_cursor and 1.0 or 0.6) local bg_offy_up = is_multiline and 0.0 or -1.0 local bg_offy_dn = is_multiline and 0.0 or 2.0 local bg_eol_width = IM_TRUNC(g.FontBaked:GetCharAdvance(32) * 0.50) local text_selected_begin = ImMin(state.Stb.select_start, state.Stb.select_end) local text_selected_end = ImMax(state.Stb.select_start, state.Stb.select_end) for line_n = line_visible_n0, line_visible_n1 - 1 do repeat local p = line_index:get_line_begin(1, line_n) local p_eol = line_index:get_line_end(1, line_n) local p_eol_is_wrap = (p_eol < buf_display_end and buf_display[p_eol] ~= 10) if p_eol_is_wrap then p_eol = p_eol + 1 end local line_selected_begin = (text_selected_begin > p) and text_selected_begin or p local line_selected_end = (text_selected_end < p_eol) and text_selected_end or p_eol local rect_width = 0.0 if line_selected_begin < line_selected_end then rect_width = rect_width + ImGui.CalcTextSizeEx(buf_display, line_selected_begin, line_selected_end).x end if text_selected_begin <= p_eol and text_selected_end > p_eol and not p_eol_is_wrap then rect_width = rect_width + bg_eol_width end if rect_width == 0.0 then break end local rect = ImRect() rect.Min.x = draw_pos.x - draw_scroll.x + ImGui.CalcTextSizeEx(buf_display, p, line_selected_begin).x rect.Min.y = draw_pos.y - draw_scroll.y + (line_n - 1) * g.FontSize rect.Max.x = rect.Min.x + rect_width rect.Max.y = rect.Min.y + bg_offy_dn + g.FontSize rect.Min.y = rect.Min.y + bg_offy_up rect:ClipWith(clip_rect) draw_window.DrawList:AddRectFilled(rect.Min, rect.Max, bg_color) until true end end end if g.ActiveId ~= id and bit32.band(flags, ImGuiInputTextFlags.ElideLeft) ~= 0 and not render_cursor and not render_selection then draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - ImGui.CalcTextSize(buf_display, nil).x - style.FramePadding.x) end if (is_multiline or (buf_display_end - 1) < buf_display_max_length) and bit32.band(text_col, IM_COL32_A_MASK) ~= 0 and line_visible_n0 < line_visible_n1 then g.Font:RenderText(draw_window.DrawList, g.FontSize, draw_pos - draw_scroll + ImVec2(0.0, (line_visible_n0 - 1) * g.FontSize), text_col, clip_rect:AsVec4(), buf_display, line_index:get_line_begin(1, line_visible_n0), line_index:get_line_end(1, line_visible_n1 - 1), wrap_width, bit32.bor(ImDrawTextFlags.WrapKeepBlanks, ImDrawTextFlags.CpuFineClip)) end if render_cursor then state.CursorAnim = state.CursorAnim + io.DeltaTime local cursor_is_visible = (not g.IO.ConfigInputTextCursorBlink) or (state.CursorAnim <= 0.0) or (ImFmod(state.CursorAnim, 1.20) <= 0.80) local cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll) local cursor_screen_rect = ImRect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5, cursor_screen_pos.x + 1.0, cursor_screen_pos.y - 1.5) if cursor_is_visible and cursor_screen_rect:Overlaps(clip_rect) then draw_window.DrawList:AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, ImGui.GetColorU32(ImGuiCol.InputTextCursor), style.InputTextCursorSize) end if not is_readonly and g.ActiveId == id then local ime_data = g.PlatformImeData ime_data.WantVisible = true ime_data.WantTextInput = true ImVec2_Copy(ime_data.InputPos, ImVec2(cursor_screen_pos.x - 1.0, cursor_screen_pos.y - g.FontSize)) ime_data.InputLineHeight = g.FontSize ime_data.ViewportId = window.Viewport.ID end end if is_password and not is_displaying_hint then ImGui.PopPasswordFont() end if is_multiline then -- For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags.Inputable (see #4761, #7870)... ImGui.Dummy(ImVec2(0.0, text_size_y + style.FramePadding.y)) g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.Inputable, ImGuiItemFlags.NoTabStop) ImGui.EndChild() item_data_backup.StatusFlags = bit32.bor(item_data_backup.StatusFlags, bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow)) -- ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... -- FIXME: This quite messy/tricky, should attempt to get rid of the child window. ImGui.EndGroup() if g.LastItemData.ID == 0 or g.LastItemData.ID ~= ImGui.GetWindowScrollbarID(draw_window, ImGuiAxis.Y) then g.LastItemData.ID = id g.LastItemData.ItemFlags = item_data_backup.ItemFlags g.LastItemData.StatusFlags = item_data_backup.StatusFlags end end if state and is_readonly then state.TextSrc = nil end if label_size.x > 0.0 then ImGui.RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, 1, label_end, false) end if value_changed then ImGui.MarkItemEdited(id) end if bit32.band(flags, ImGuiInputTextFlags.EnterReturnsTrue) ~= 0 then return validated else return value_changed end end --- @param label string --- @param hint char[] --- @param buf char[] --- @param buf_size size_t --- @param flags? ImGuiInputTextFlags --- @param callback? ImGuiInputTextCallback --- @param user_data? any function ImGui.InputTextWithHint(label, hint, buf, buf_size, flags, callback, user_data) if flags == nil then flags = 0 end IM_ASSERT(bit32.band(flags, ImGuiInputTextFlags.Multiline) == 0) return ImGui.InputTextEx(label, hint, buf, buf_size, ImVec2(0, 0), flags, callback, user_data) end ---------------------------------------------------------------- -- [SECTION] COLOR EDIT / PICKER ---------------------------------------------------------------- --- @param col float[] --- @param H float --- @return float local function ColorEditRestoreH(col, H) local g = GImGui IM_ASSERT(g.ColorEditCurrentID ~= 0) if g.ColorEditSavedID ~= g.ColorEditCurrentID or g.ColorEditSavedColor ~= ImGui.ColorConvertFloat4ToU32(ImVec4(col[1], col[2], col[3], 0)) then return H end H = g.ColorEditSavedHue return H end --- @param col float[] --- @param H float --- @param S float --- @param V float --- @return float, float, float local function ColorEditRestoreHS(col, H, S, V) local g = GImGui IM_ASSERT(g.ColorEditCurrentID ~= 0) if g.ColorEditSavedID ~= g.ColorEditCurrentID or g.ColorEditSavedColor ~= ImGui.ColorConvertFloat4ToU32(ImVec4(col[1], col[2], col[3], 0)) then return H, S, V end -- When S == 0, H is undefined. -- When H == 1 it wraps around to 0. if S == 0.0 or (H == 0.0 and g.ColorEditSavedHue == 1) then H = g.ColorEditSavedHue end -- When V == 0, S is undefined. if V == 0.0 then S = g.ColorEditSavedSat end return H, S, V end do --[[ColorEdit4]] local ids = { "##X", "##Y", "##Z", "##W" } local fmt_table_int = { { "%3d", "%3d", "%3d", "%3d" }, -- Short display { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, -- Long display for RGBA { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } -- Long display for HSVA } local fmt_table_float = { { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, -- Short display { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, -- Long display for RGBA { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } -- Long display for HSVA } --- @param label string --- @param col float[] --- @param flags ImGuiColorEditFlags @native function ImGui.ColorEdit4(label, col, flags) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local square_sz = ImGui.GetFrameHeight() local label_display_end = ImGui.FindRenderedTextEnd(label) local w_full = ImGui.CalcItemWidth() g.NextItemData:ClearFlags() -- [Luau] Fast path for a row that is entirely clipped (e.g. long lists such as Style Editor > Colors): nothing -- inside would draw, be hovered or receive input, so only reproduce the layout (same group size, baseline and -- last item rect as the full path). Not taken while anything could depend on the inner items: an active item -- or popup, keyboard navigation, logging, or the ID debug hook. if label_display_end == 1 and bit32.band(flags, bit32.bor(ImGuiColorEditFlags.NoInputs, ImGuiColorEditFlags.NoSmallPreview)) == 0 and g.ActiveId == 0 and g.OpenPopupStack.Size == 0 and not g.NavCursorVisible and not g.NavAnyRequest and not g.LogEnabled and g.DebugHookIdInfoId == 0 then local w_button = square_sz + style.ItemInnerSpacing.x local w = ImMax(w_full - w_button, 1.0) + w_button local p = window.DC.CursorPos local cr = window.ClipRect if p.y + square_sz < cr.Min.y or p.y > cr.Max.y or p.x + w < cr.Min.x or p.x > cr.Max.x then ImGui.BeginGroup() local bb = ImRect(p.x, p.y, p.x + w, p.y + square_sz) ImGui.ItemSize(ImVec2(w, square_sz), style.FramePadding.y) ImGui.ItemAdd(bb, 0) ImGui.EndGroup() return false end end ImGui.BeginGroup() ImGui.PushID(label) local set_current_color_edit_id = (g.ColorEditCurrentID == 0) if set_current_color_edit_id then g.ColorEditCurrentID = window.IDStack:back() end -- If we're not showing any slider there's no point in doing any HSV conversions local flags_untouched = flags if bit32.band(flags, ImGuiColorEditFlags.NoInputs) ~= 0 then flags = bit32.bor(bit32.band(flags, bit32.bnot(ImGuiColorEditFlags.DisplayMask_)), ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.NoOptions) end -- Context menu: display and modify options (before defaults are applied) if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.ColorEditOptionsPopup(col, flags) end -- Read stored options if bit32.band(flags, ImGuiColorEditFlags.DisplayMask_) == 0 then flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.DisplayMask_)) end if bit32.band(flags, ImGuiColorEditFlags.DataTypeMask_) == 0 then flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.DataTypeMask_)) end if bit32.band(flags, ImGuiColorEditFlags.PickerMask_) == 0 then flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.PickerMask_)) end if bit32.band(flags, ImGuiColorEditFlags.InputMask_) == 0 then flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.InputMask_)) end flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, bit32.bnot(bit32.bor(ImGuiColorEditFlags.DisplayMask_, ImGuiColorEditFlags.DataTypeMask_, ImGuiColorEditFlags.PickerMask_, ImGuiColorEditFlags.InputMask_)))) IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiColorEditFlags.DisplayMask_))) -- Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiColorEditFlags.InputMask_))) -- Check that only 1 is selected local alpha = bit32.band(flags, ImGuiColorEditFlags.NoAlpha) == 0 local hdr = bit32.band(flags, ImGuiColorEditFlags.HDR) ~= 0 local components = alpha and 4 or 3 local w_button = (bit32.band(flags, ImGuiColorEditFlags.NoSmallPreview) ~= 0) and 0.0 or (square_sz + style.ItemInnerSpacing.x) local w_inputs = ImMax(w_full - w_button, 1.0) w_full = w_inputs + w_button -- Convert to the formats we need local f = { col[1], col[2], col[3], alpha and col[4] or 1.0 } if bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.DisplayRGB) ~= 0 then f[1], f[2], f[3] = ImGui.ColorConvertHSVtoRGB(f[1], f[2], f[3]) elseif bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.DisplayHSV) ~= 0 then -- Hue is lost when converting from grayscale rgb (saturation=0). Restore it. f[1], f[2], f[3] = ImGui.ColorConvertRGBtoHSV(f[1], f[2], f[3]) f[1], f[2], f[3] = ColorEditRestoreHS(col, f[1], f[2], f[3]) end local i = { IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]), IM_F32_TO_INT8_UNBOUND(f[4]) } local value_changed = false local value_changed_as_float = false local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local inputs_offset_x = (style.ColorButtonPosition == ImGuiDir.Left) and w_button or 0.0 window.DC.CursorPos.x = pos.x + inputs_offset_x if bit32.band(flags, bit32.bor(ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.DisplayHSV)) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.NoInputs) == 0 then local w_items = w_inputs - style.ItemInnerSpacing.x * (components - 1) local w_per_component = IM_TRUNC(w_items / components) local draw_color_marker = bit32.band(flags, bit32.bor(ImGuiColorEditFlags.DisplayHSV, ImGuiColorEditFlags.NoColorMarkers)) == 0 local hide_prefix = draw_color_marker or (w_per_component <= ImGui.CalcTextSize((bit32.band(flags, ImGuiColorEditFlags.Float) ~= 0) and "M:0.000" or "M:000").x) local fmt_idx if hide_prefix then fmt_idx = 1 elseif bit32.band(flags, ImGuiColorEditFlags.DisplayHSV) ~= 0 then fmt_idx = 3 else fmt_idx = 2 end local drag_flags = draw_color_marker and ImGuiSliderFlags.ColorMarkers or ImGuiSliderFlags.None local prev_split = 0.0 for n = 1, components do if n > 1 then ImGui.SameLine(0, style.ItemInnerSpacing.x) end local next_split = IM_TRUNC(w_items * n / components) ImGui.SetNextItemWidth(ImMax(next_split - prev_split, 1.0)) prev_split = next_split if draw_color_marker then ImGui.SetNextItemColorMarker(GDefaultRgbaColorMarkers[n]) end -- FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0 if bit32.band(flags, ImGuiColorEditFlags.Float) ~= 0 then local changed f[n], changed = ImGui.DragFloat(ids[n], f[n], 1.0 / 255.0, 0.0, hdr and 0.0 or 1.0, fmt_table_float[fmt_idx][n], drag_flags) value_changed = value_changed or changed value_changed_as_float = value_changed_as_float or value_changed else local changed i[n], changed = ImGui.DragInt(ids[n], i[n], 1.0, 0, hdr and 0 or 255, fmt_table_int[fmt_idx][n], drag_flags) value_changed = value_changed or changed end if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) end end elseif bit32.band(flags, ImGuiColorEditFlags.DisplayHex) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.NoInputs) == 0 then -- RGB Hexadecimal Input -- TODO: resolve sprintf, sscanf requirement. currently this section creates a lot of temp tables and strings... local buf, buf_size = nil, 64 if alpha then local str = ImFormatString("#%02X%02X%02X%02X", ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255), ImClamp(i[4], 0, 255)) buf = { string.byte(str, 1, #str) } buf[#buf + 1] = 0 else local str = ImFormatString("#%02X%02X%02X", ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)) buf = { string.byte(str, 1, #str) } buf[#buf + 1] = 0 end ImGui.SetNextItemWidth(w_inputs) if ImGui.InputText("##Text", buf, buf_size, ImGuiInputTextFlags.CharsUppercase) then value_changed = true local p = 1 while buf[p] == 35 or ImCharIsBlankA(buf[p]) do p = p + 1 end i[1], i[2], i[3] = 0, 0, 0 i[4] = 0xFF local r if alpha then r = ImStd.sscanf(buf, p, "%02X%02X%02X%02X", i) else r = ImStd.sscanf(buf, p, "%02X%02X%02X", i) end -- IM_UNUSED(r) end if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) end end local picker_active_window = nil if bit32.band(flags, ImGuiColorEditFlags.NoSmallPreview) == 0 then local button_offset_x = (bit32.band(flags, ImGuiColorEditFlags.NoInputs) ~= 0 or style.ColorButtonPosition == ImGuiDir.Left) and 0.0 or (w_inputs + style.ItemInnerSpacing.x) ImVec2_Copy(window.DC.CursorPos, ImVec2(pos.x + button_offset_x, pos.y)) local col_v4 = ImVec4(col[1], col[2], col[3], alpha and col[4] or 1.0) if ImGui.ColorButton("##ColorButton", col_v4, flags) then if bit32.band(flags, ImGuiColorEditFlags.NoPicker) == 0 then -- Store current color and open a picker ImVec4_Copy(g.ColorPickerRef, col_v4) ImGui.OpenPopup("picker") ImGui.SetNextWindowPos(g.LastItemData.Rect:GetBL() + ImVec2(0.0, style.ItemSpacing.y)) end end if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) end if ImGui.BeginPopup("picker") then if g.CurrentWindow.BeginCount == 1 then picker_active_window = g.CurrentWindow if label ~= "" and label_display_end > 1 then ImGui.TextEx(label, label_display_end) ImGui.Spacing() end local picker_flags_to_forward = bit32.bor(ImGuiColorEditFlags.DataTypeMask_, ImGuiColorEditFlags.PickerMask_, ImGuiColorEditFlags.InputMask_, ImGuiColorEditFlags.HDR, ImGuiColorEditFlags.NoAlpha, ImGuiColorEditFlags.AlphaBar) local picker_flags = bit32.bor(bit32.band(flags_untouched, picker_flags_to_forward), ImGuiColorEditFlags.DisplayMask_, ImGuiColorEditFlags.NoLabel, ImGuiColorEditFlags.AlphaPreviewHalf) ImGui.SetNextItemWidth(square_sz * 12.0) -- Use 256 + bar sizes? value_changed = value_changed or ImGui.ColorPicker4("##picker", col, picker_flags, g.ColorPickerRef) end ImGui.EndPopup() end end if label ~= "" and label_display_end > 1 and bit32.band(flags, ImGuiColorEditFlags.NoLabel) == 0 then -- Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left), -- but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this ImGui.SameLine(0.0, style.ItemInnerSpacing.x) window.DC.CursorPos.x = pos.x + ((bit32.band(flags, ImGuiColorEditFlags.NoInputs) ~= 0) and w_button or (w_full + style.ItemInnerSpacing.x)) ImGui.TextEx(label, label_display_end) end -- Convert back if value_changed and picker_active_window == nil then if not value_changed_as_float then for n = 1, 4 do f[n] = i[n] / 255.0 end end if bit32.band(flags, ImGuiColorEditFlags.DisplayHSV) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 then g.ColorEditSavedHue = f[1] g.ColorEditSavedSat = f[2] f[1], f[2], f[3] = ImGui.ColorConvertHSVtoRGB(f[1], f[2], f[3]) g.ColorEditSavedID = g.ColorEditCurrentID g.ColorEditSavedColor = ImGui.ColorConvertFloat4ToU32(ImVec4(f[1], f[2], f[3], 0)) end if bit32.band(flags, ImGuiColorEditFlags.DisplayRGB) ~= 0 and bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then f[1], f[2], f[3] = ImGui.ColorConvertRGBtoHSV(f[1], f[2], f[3]) end col[1] = f[1] col[2] = f[2] col[3] = f[3] if alpha then col[4] = f[4] end end if set_current_color_edit_id then g.ColorEditCurrentID = 0 end ImGui.PopID() ImGui.EndGroup() -- Drag and Drop Target -- TODO: -- When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4() if picker_active_window and g.ActiveId ~= 0 and g.ActiveIdWindow == picker_active_window then g.LastItemData.ID = g.ActiveId end if value_changed and g.LastItemData.ID ~= 0 then -- In case of ID collision, the second EndGroup() won't catch g.ActiveId ImGui.MarkItemEdited(g.LastItemData.ID) end return value_changed end end --- @param label string --- @param col [float, float, float] --- @param flags? ImGuiColorEditFlags function ImGui.ColorEdit3(label, col, flags) if flags == nil then flags = 0 end if flags == nil then flags = 0 end return ImGui.ColorEdit4(label, col, bit32.bor(flags, ImGuiColorEditFlags.NoAlpha)) end -- `col` mutated in place, returns value_changed function ImGui.ColorPicker3(label, col, flags) if flags == nil then flags = 0 end local col4 = { col[1], col[2], col[3], 1.0 } if not ImGui.ColorPicker4(label, col4, bit32.bor(flags or 0, ImGuiColorEditFlags.NoAlpha)) then return false end col[1] = col4[1]; col[2] = col4[2]; col[3] = col4[3] return true end function ImGui.SetColorEditOptions(flags) local g = GImGui local def = ImGuiColorEditFlags.DefaultOptions_ for _, mask in ipairs({ ImGuiColorEditFlags.DisplayMask_, ImGuiColorEditFlags.DataTypeMask_, ImGuiColorEditFlags.PickerMask_, ImGuiColorEditFlags.InputMask_ }) do if bit32.band(flags, mask) == 0 then flags = bit32.bor(flags, bit32.band(def, mask)) end end g.IO.ConfigColorEditFlags = flags end -- Helper for ColorPicker4() --- @param draw_list ImDrawList --- @param pos ImVec2 --- @param half_sz ImVec2 --- @param bar_w float --- @param alpha float local function RenderArrowsForVerticalBar(draw_list, pos, half_sz, bar_w, alpha) local alpha8 = IM_F32_TO_INT8_SAT(alpha) ImGui.RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir.Right, IM_COL32(0, 0, 0, alpha8)) ImGui.RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir.Right, IM_COL32(255, 255, 255, alpha8)) ImGui.RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir.Left, IM_COL32(0, 0, 0, alpha8)) ImGui.RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir.Left, IM_COL32(255, 255, 255, alpha8)) end do --[[ColorPicker4]] local backup_initial_col = {0, 0, 0, 0} --- @param label string --- @param col float[] --- @param flags ImGuiColorEditFlags --- @param ref_col? float[] function ImGui.ColorPicker4(label, col, flags, ref_col) if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local draw_list = window.DrawList local g = GImGui local style = g.Style local io = g.IO local width = ImGui.CalcItemWidth() local is_readonly = bit32.band(bit32.bor(g.NextItemData.ItemFlagsSet, g.CurrentItemFlags), ImGuiItemFlags.ReadOnly) ~= 0 g.NextItemData:ClearFlags() ImGui.PushID(label) local set_current_color_edit_id = (g.ColorEditCurrentID == 0) if set_current_color_edit_id then g.ColorEditCurrentID = window.IDStack:back() end ImGui.BeginGroup() if bit32.band(flags, ImGuiColorEditFlags.NoSidePreview) == 0 then flags = bit32.bor(flags, ImGuiColorEditFlags.NoSmallPreview) end -- Context menu: display and store options. if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.ColorPickerOptionsPopup(col, flags) end -- Read stored options if bit32.band(flags, ImGuiColorEditFlags.PickerMask_) == 0 then local picker_flags = bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.PickerMask_) if picker_flags ~= 0 then flags = bit32.bor(flags, picker_flags) else flags = bit32.bor(flags, bit32.band(ImGuiColorEditFlags.DefaultOptions_, ImGuiColorEditFlags.PickerMask_)) end end if bit32.band(flags, ImGuiColorEditFlags.InputMask_) == 0 then local input_flags = bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.InputMask_) if input_flags ~= 0 then flags = bit32.bor(flags, input_flags) else flags = bit32.bor(flags, bit32.band(ImGuiColorEditFlags.DefaultOptions_, ImGuiColorEditFlags.InputMask_)) end end IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiColorEditFlags.PickerMask_))) -- Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(bit32.band(flags, ImGuiColorEditFlags.InputMask_))) -- Check that only 1 is selected if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then flags = bit32.bor(flags, bit32.band(g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.AlphaBar)) end -- Setup local components = (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 3 or 4 local alpha_bar = (bit32.band(flags, ImGuiColorEditFlags.AlphaBar) ~= 0) and (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) == 0) local picker_pos = ImVec2() ImVec2_Copy(picker_pos, window.DC.CursorPos) local square_sz = ImGui.GetFrameHeight() local bars_width = square_sz -- Arbitrary smallish width of Hue/Alpha picking bars local sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar and 2 or 1) * (bars_width + style.ItemInnerSpacing.x)) -- Saturation/Value picking box local bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x local bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x local bars_triangles_half_sz = IM_TRUNC(bars_width * 0.20) backup_initial_col[1], backup_initial_col[2], backup_initial_col[3], backup_initial_col[4] = col[1], col[2], col[3], col[4] local wheel_thickness = sv_picker_size * 0.08 local wheel_r_outer = sv_picker_size * 0.50 local wheel_r_inner = wheel_r_outer - wheel_thickness local wheel_center = ImVec2(picker_pos.x + (sv_picker_size + bars_width) * 0.5, picker_pos.y + sv_picker_size * 0.5) -- Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. local triangle_rotate = bit32.band(flags, ImGuiColorEditFlags.PickerNoRotate) == 0 local triangle_r = wheel_r_inner - math.floor(sv_picker_size * 0.027) local triangle_pa, triangle_pb, triangle_pc if triangle_rotate then triangle_pa = ImVec2( triangle_r, 0.0) else triangle_pa = ImVec2( triangle_r * 0.866, triangle_r * 0.5) end -- Hue point if triangle_rotate then triangle_pb = ImVec2(triangle_r * -0.5, triangle_r * -0.866) else triangle_pb = ImVec2( 0.0, -triangle_r) end -- Black point if triangle_rotate then triangle_pc = ImVec2(triangle_r * -0.5, triangle_r * 0.866) else triangle_pc = ImVec2(triangle_r * -0.866, triangle_r * 0.5) end -- White point local H = col[1]; local S = col[2]; local V = col[3] local R = col[1]; local G = col[2]; local B = col[3] if bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 then -- Hue is lost when converting from grayscale rgb (saturation=0). Restore it. H, S, V = ImGui.ColorConvertRGBtoHSV(R, G, B) H, S, V = ColorEditRestoreHS(col, H, S, V) elseif bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then R, G, B = ImGui.ColorConvertHSVtoRGB(H, S, V) end local value_changed = false; local value_changed_h = false; local value_changed_sv = false ImGui.PushItemFlag(ImGuiItemFlags.NoNav, true) if bit32.band(flags, ImGuiColorEditFlags.PickerHueWheel) ~= 0 then -- Hue wheel + SV triangle logic ImGui.InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)) if ImGui.IsItemActive() and not is_readonly then local initial_off = g.IO.MouseClickedPos[0] - wheel_center local current_off = g.IO.MousePos - wheel_center local initial_dist2 = ImLengthSqr(initial_off) if initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) and initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1) then -- Interactive with Hue wheel H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5 if H < 0.0 then H = H + 1.0 end value_changed = true value_changed_h = true end local cos_hue_angle = triangle_rotate and ImCos(-H * 2.0 * IM_PI) or 1.0 local sin_hue_angle = triangle_rotate and ImSin(-H * 2.0 * IM_PI) or 0.0 if ImStd.ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)) then -- Interacting with SV triangle local current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle) if not ImStd.ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated) then current_off_unrotated = ImStd.ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated) end local uu, vv, ww uu, vv, ww = ImStd.ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated) V = ImClamp(1.0 - vv, 0.0001, 1.0) S = ImClamp(uu / V, 0.0001, 1.0) value_changed = true value_changed_sv = true end end if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) end elseif bit32.band(flags, ImGuiColorEditFlags.PickerHueBar) ~= 0 then -- SV rectangle logic ImGui.InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)) if ImGui.IsItemActive() and not is_readonly then S = ImSaturate((io.MousePos.x - picker_pos.x) / ImMax(sv_picker_size - 1, 0.0001)) V = 1.0 - ImSaturate((io.MousePos.y - picker_pos.y) / ImMax(sv_picker_size - 1, 0.0001)) H = ColorEditRestoreH(col, H) -- Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. value_changed = true value_changed_sv = true end if bit32.band(flags, ImGuiColorEditFlags.NoOptions) == 0 then ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) end -- Hue bar logic ImGui.SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)) ImGui.InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)) if ImGui.IsItemActive() and not is_readonly then H = ImSaturate((io.MousePos.y - picker_pos.y) / ImMax(sv_picker_size - 1, 0.0001)) value_changed = true value_changed_h = true end end -- Alpha bar logic if alpha_bar then ImGui.SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)) ImGui.InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)) if ImGui.IsItemActive() then col[4] = 1.0 - ImSaturate((io.MousePos.y - picker_pos.y) / ImMax(sv_picker_size - 1, 0.0001)) value_changed = true end end ImGui.PopItemFlag() if bit32.band(flags, ImGuiColorEditFlags.NoSidePreview) == 0 then ImGui.SameLine(0, style.ItemInnerSpacing.x) ImGui.BeginGroup() end if bit32.band(flags, ImGuiColorEditFlags.NoLabel) == 0 then local label_display_end = ImGui.FindRenderedTextEnd(label) if label ~= "" and label_display_end > 1 then if bit32.band(flags, ImGuiColorEditFlags.NoSidePreview) ~= 0 then ImGui.SameLine(0, style.ItemInnerSpacing.x) end ImGui.TextEx(label, label_display_end) end end if bit32.band(flags, ImGuiColorEditFlags.NoSidePreview) == 0 then ImGui.PushItemFlag(ImGuiItemFlags.NoNavDefaultFocus, true) local col_v4 = ImVec4(col[1], col[2], col[3], (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 1.0 or col[4]) if bit32.band(flags, ImGuiColorEditFlags.NoLabel) ~= 0 then ImGui.Text("Current") end local sub_flags_to_forward = bit32.bor(ImGuiColorEditFlags.InputMask_, ImGuiColorEditFlags.HDR, ImGuiColorEditFlags.AlphaMask_, ImGuiColorEditFlags.NoTooltip) ImGui.ColorButton("##current", col_v4, bit32.band(flags, sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)) if ref_col ~= nil then ImGui.Text("Original") local ref_col_v4 = ImVec4(ref_col[1], ref_col[2], ref_col[3], (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 1.0 or ref_col[4]) if ImGui.ColorButton("##original", ref_col_v4, bit32.band(flags, sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)) then for i = 1, components do col[i] = ref_col[i] end value_changed = true end end ImGui.PopItemFlag() ImGui.EndGroup() end -- Convert back color to RGB if value_changed_h or value_changed_sv then if bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 then col[1], col[2], col[3] = ImGui.ColorConvertHSVtoRGB(H, S, V) -- Lua 1-based indexing g.ColorEditSavedHue = H g.ColorEditSavedSat = S g.ColorEditSavedID = g.ColorEditCurrentID g.ColorEditSavedColor = ImGui.ColorConvertFloat4ToU32(ImVec4(col[1], col[2], col[3], 0)) elseif bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then col[1] = H col[2] = S col[3] = V end end -- R,G,B and H,S,V slider color editor local value_changed_fix_hue_wrap = false if bit32.band(flags, ImGuiColorEditFlags.NoInputs) == 0 then ImGui.PushItemWidth((alpha_bar and bar1_pos_x or bar0_pos_x) + bars_width - picker_pos.x) local sub_flags_to_forward = bit32.bor(ImGuiColorEditFlags.DataTypeMask_, ImGuiColorEditFlags.InputMask_, ImGuiColorEditFlags.HDR, ImGuiColorEditFlags.AlphaMask_, ImGuiColorEditFlags.NoOptions, ImGuiColorEditFlags.NoTooltip, ImGuiColorEditFlags.NoSmallPreview) local sub_flags = bit32.bor(bit32.band(flags, sub_flags_to_forward), ImGuiColorEditFlags.NoPicker) if bit32.band(flags, ImGuiColorEditFlags.DisplayRGB) ~= 0 or bit32.band(flags, ImGuiColorEditFlags.DisplayMask_) == 0 then if ImGui.ColorEdit4("##rgb", col, bit32.bor(sub_flags, ImGuiColorEditFlags.DisplayRGB)) then -- FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. -- For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) value_changed_fix_hue_wrap = (g.ActiveId ~= 0 and not g.ActiveIdAllowOverlap) value_changed = true end end if bit32.band(flags, ImGuiColorEditFlags.DisplayHSV) ~= 0 or bit32.band(flags, ImGuiColorEditFlags.DisplayMask_) == 0 then if ImGui.ColorEdit4("##hsv", col, bit32.bor(sub_flags, ImGuiColorEditFlags.DisplayHSV)) then value_changed = true end end if bit32.band(flags, ImGuiColorEditFlags.DisplayHex) ~= 0 or bit32.band(flags, ImGuiColorEditFlags.DisplayMask_) == 0 then if ImGui.ColorEdit4("##hex", col, bit32.bor(sub_flags, ImGuiColorEditFlags.DisplayHex)) then value_changed = true end end ImGui.PopItemWidth() end -- Try to cancel hue wrap (after ColorEdit4 call), if any if value_changed_fix_hue_wrap and bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 then local new_H, new_S, new_V = ImGui.ColorConvertRGBtoHSV(col[1], col[2], col[3]) -- Lua 1-based indexing if new_H <= 0 and H > 0 then if new_V <= 0 and V ~= new_V then col[1], col[2], col[3] = ImGui.ColorConvertHSVtoRGB(H, S, (new_V <= 0) and (V * 0.5) or new_V) elseif new_S <= 0 then col[1], col[2], col[3] = ImGui.ColorConvertHSVtoRGB(H, (new_S <= 0) and (S * 0.5) or new_S, new_V) end end end if value_changed then if bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 then R = col[1] G = col[2] B = col[3] H, S, V = ImGui.ColorConvertRGBtoHSV(R, G, B) H, S, V = ColorEditRestoreHS(col, H, S, V) -- Fix local Hue as display below will use it immediately. elseif bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then H = col[1] S = col[2] V = col[3] R, G, B = ImGui.ColorConvertHSVtoRGB(H, S, V) end end local style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha) local col_black = IM_COL32(0, 0, 0, style_alpha8) local col_white = IM_COL32(255, 255, 255, style_alpha8) local col_midgrey = IM_COL32(128, 128, 128, style_alpha8) local col_hues = { IM_COL32(255, 0, 0, style_alpha8), IM_COL32(255, 255, 0, style_alpha8), IM_COL32(0, 255, 0, style_alpha8), IM_COL32(0, 255, 255, style_alpha8), IM_COL32(0, 0, 255, style_alpha8), IM_COL32(255, 0, 255, style_alpha8), IM_COL32(255, 0, 0, style_alpha8) } local hue_color_f = ImVec4(1, 1, 1, style.Alpha) hue_color_f.x, hue_color_f.y, hue_color_f.z = ImGui.ColorConvertHSVtoRGB(H, 1, 1) local hue_color32 = ImGui.ColorConvertFloat4ToU32(hue_color_f) local user_col32_striped_of_alpha = ImGui.ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)) -- Important: this is still including the main rendering/style alpha!! local sv_cursor_pos = ImVec2() if bit32.band(flags, ImGuiColorEditFlags.PickerHueWheel) ~= 0 then -- Render Hue Wheel local aeps = 0.5 / wheel_r_outer -- Half a pixel arc length in radians (2pi cancels out). local segment_per_arc = ImMax(4, math.floor(wheel_r_outer / 12)) for n = 1, 6 do local a0 = (n - 1) / 6.0 * 2.0 * IM_PI - aeps local a1 = n / 6.0 * 2.0 * IM_PI + aeps local vert_start_idx = draw_list.VtxBuffer.Size + 1 draw_list:PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer) * 0.5, a0, a1, segment_per_arc) draw_list:PathStroke(col_white, wheel_thickness) local vert_end_idx = draw_list.VtxBuffer.Size + 1 -- Paint colors over existing vertices local gradient_p0 = ImVec2(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner) local gradient_p1 = ImVec2(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner) ImGui.ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]) end -- Render Cursor + preview on Hue Wheel local cos_hue_angle = ImCos(H * 2.0 * IM_PI) local sin_hue_angle = ImSin(H * 2.0 * IM_PI) local hue_cursor_pos = ImVec2(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5) local hue_cursor_rad = value_changed_h and (wheel_thickness * 0.65) or (wheel_thickness * 0.55) local hue_cursor_segments = draw_list:_CalcCircleAutoSegmentCount(hue_cursor_rad) -- Lock segment count so the +1 one matches others. draw_list:AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments) draw_list:AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments) draw_list:AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments) if triangle_rotate == false then cos_hue_angle = 1.0 sin_hue_angle = 0.0 end -- Render SV triangle (rotated according to hue) local tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle) local trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle) local trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle) local uv_white = ImGui.GetFontTexUvWhitePixel() draw_list:PrimReserve(3, 3) draw_list:PrimVtx(tra, uv_white, hue_color32) draw_list:PrimVtx(trb, uv_white, col_black) draw_list:PrimVtx(trc, uv_white, col_white) draw_list:AddTriangle(tra, trb, trc, col_midgrey, 1.5) sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)) elseif bit32.band(flags, ImGuiColorEditFlags.PickerHueBar) ~= 0 then -- Render SV Square draw_list:AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white) draw_list:AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black) ImGui.RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0) -- Sneakily prevent the circle to stick out too much sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2) sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2) -- Render Hue Bar for i = 1, 6 do draw_list:AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + (i - 1) * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + i * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]) end local bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size) ImGui.RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0) RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0, style.Alpha) end -- Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) local sv_cursor_rad = value_changed_sv and (wheel_thickness * 0.55) or (wheel_thickness * 0.40) local sv_cursor_segments = draw_list:_CalcCircleAutoSegmentCount(sv_cursor_rad) -- Lock segment count so the +1 one matches others. draw_list:AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments) draw_list:AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments) draw_list:AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments) -- Render alpha bar if alpha_bar then local alpha = ImSaturate(col[4]) local bar1_bb = ImRect(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size) ImGui.RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb:GetWidth() / 2.0, ImVec2(0.0, 0.0)) draw_list:AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, bit32.band(user_col32_striped_of_alpha, bit32.bnot(IM_COL32_A_MASK)), bit32.band(user_col32_striped_of_alpha, bit32.bnot(IM_COL32_A_MASK))) local bar1_line_y = IM_ROUND(picker_pos.y + (1.0 - alpha) * sv_picker_size) ImGui.RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0) RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0, style.Alpha) end ImGui.EndGroup() if value_changed then for i = 1, components do if backup_initial_col[i] ~= col[i] then break end if i == components then value_changed = false end end end if value_changed and g.LastItemData.ID ~= 0 then -- In case of ID collision, the second EndGroup() won't catch g.ActiveId ImGui.MarkItemEdited(g.LastItemData.ID) end if set_current_color_edit_id then g.ColorEditCurrentID = 0 end ImGui.PopID() return value_changed end end --- @param desc_id string --- @param col ImVec4 --- @param flags? ImGuiColorEditFlags --- @param size_arg? ImVec2 @native function ImGui.ColorButton(desc_id, col, flags, size_arg) if flags == nil then flags = 0 end if size_arg == nil then size_arg = ImVec2(0, 0) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local id = window:GetID(desc_id) local default_size = ImGui.GetFrameHeight() local size = ImVec2(size_arg.x == 0.0 and default_size or size_arg.x, size_arg.y == 0.0 and default_size or size_arg.y) local bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + size) ImGui.ItemSize(bb, (size.y >= default_size) and g.Style.FramePadding.y or 0.0) if not ImGui.ItemAdd(bb, id) then return false end local pressed, hovered, _ = ImGui.ButtonBehavior(bb, id) if bit32.band(flags, bit32.bor(ImGuiColorEditFlags.NoAlpha, ImGuiColorEditFlags.AlphaOpaque)) ~= 0 then flags = bit32.band(flags, bit32.bnot(bit32.bor(ImGuiColorEditFlags.AlphaNoBg, ImGuiColorEditFlags.AlphaPreviewHalf))) end local col_rgb = ImVec4(col.x, col.y, col.z, col.w) if bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then col_rgb.x, col_rgb.y, col_rgb.z = ImGui.ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z) end local col_rgb_without_alpha = ImVec4(col_rgb.x, col_rgb.y, col_rgb.z, 1.0) local grid_step = ImMin(size.x, size.y) / 2.99 local rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5) local bb_inner = ImRect() ImRect_Copy(bb_inner, bb) local off = 0.0 if bit32.band(flags, ImGuiColorEditFlags.NoBorder) == 0 then off = -0.75 bb_inner:Expand(off) end if bit32.band(flags, ImGuiColorEditFlags.AlphaPreviewHalf) ~= 0 and col_rgb.w < 1.0 then local mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5) if bit32.band(flags, ImGuiColorEditFlags.AlphaNoBg) == 0 then ImGui.RenderColorRectWithAlphaCheckerboard(window.DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, ImGui.GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags.RoundCornersRight) else window.DrawList:AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, ImGui.GetColorU32(col_rgb), rounding, ImDrawFlags.RoundCornersRight) end window.DrawList:AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), ImGui.GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags.RoundCornersLeft) else local col_source = (bit32.band(flags, ImGuiColorEditFlags.AlphaOpaque) ~= 0) and col_rgb_without_alpha or col_rgb if col_source.w < 1.0 and bit32.band(flags, ImGuiColorEditFlags.AlphaNoBg) == 0 then ImGui.RenderColorRectWithAlphaCheckerboard(window.DrawList, bb_inner.Min, bb_inner.Max, ImGui.GetColorU32(col_source), grid_step, ImVec2(off, off), rounding) else window.DrawList:AddRectFilled(bb_inner.Min, bb_inner.Max, ImGui.GetColorU32(col_source), rounding) end end ImGui.RenderNavCursor(bb, id) if bit32.band(flags, ImGuiColorEditFlags.NoBorder) == 0 then if g.Style.FrameBorderSize > 0.0 then ImGui.RenderFrameBorder(bb.Min, bb.Max, rounding) else window.DrawList:AddRect(bb.Min, bb.Max, ImGui.GetColorU32(ImGuiCol.FrameBg), rounding) end end -- Drag and Drop Source -- NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. -- if g.ActiveId == id and bit32.band(flags, ImGuiColorEditFlags.NoDragDrop) == 0 and ImGui.BeginDragDropSource() then -- if bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0 then -- ImGui.SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, col_rgb, ImGuiCond.Once) -- else -- ImGui.SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, col_rgb, ImGuiCond.Once) -- end -- ImGui.ColorButton(desc_id, col, flags) -- ImGui.SameLine() -- ImGui.TextEx("Color") -- ImGui.EndDragDropSource() -- end -- Tooltip if bit32.band(flags, ImGuiColorEditFlags.NoTooltip) == 0 and hovered and ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) then ImGui.ColorTooltip(desc_id, col, bit32.band(flags, bit32.bor(ImGuiColorEditFlags.InputMask_, ImGuiColorEditFlags.AlphaMask_))) end return pressed end --- @param text? string --- @param col ImVec4 --- @param flags ImGuiColorEditFlags function ImGui.ColorTooltip(text, col, flags) local g = GImGui if not ImGui.BeginTooltipEx(ImGuiTooltipFlags.OverridePrevious, ImGuiWindowFlags.None) then return end local text_end = text and ImGui.FindRenderedTextEnd(text, nil) or 1 if text_end > 1 then --- @cast text string ImGui.TextEx(text, text_end) ImGui.Separator() end local sz = ImVec2(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2) local cf = ImVec4(col.x, col.y, col.z, (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 1.0 or col.w) local cr = IM_F32_TO_INT8_SAT(col.x) local cg = IM_F32_TO_INT8_SAT(col.y) local cb = IM_F32_TO_INT8_SAT(col.z) local ca = (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 255 or IM_F32_TO_INT8_SAT(col.w) local flags_to_forward = bit32.bor(ImGuiColorEditFlags.InputMask_, ImGuiColorEditFlags.AlphaMask_) ImGui.ColorButton("##preview", cf, bit32.bor(bit32.band(flags, flags_to_forward), ImGuiColorEditFlags.NoTooltip), sz) ImGui.SameLine() if bit32.band(flags, ImGuiColorEditFlags.InputRGB) ~= 0 or bit32.band(flags, ImGuiColorEditFlags.InputMask_) == 0 then if bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0 then ImGui.Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col.x, col.y, col.z) else ImGui.Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col.x, col.y, col.z, col.w) end elseif bit32.band(flags, ImGuiColorEditFlags.InputHSV) ~= 0 then if bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0 then ImGui.Text("H: %.3f, S: %.3f, V: %.3f", col.x, col.y, col.z) else ImGui.Text("H: %.3f, S: %.3f, V: %.3f, A: %.3f", col.x, col.y, col.z, col.w) end end ImGui.EndTooltip() end --- @param col float[] --- @param flags ImGuiColorEditFlags function ImGui.ColorEditOptionsPopup(col, flags) local allow_opt_inputs = bit32.band(flags, ImGuiColorEditFlags.DisplayMask_) == 0 local allow_opt_datatype = bit32.band(flags, ImGuiColorEditFlags.DataTypeMask_) == 0 if (not allow_opt_inputs and not allow_opt_datatype) or not ImGui.BeginPopup("context") then return end local g = GImGui ImGui.PushItemFlag(ImGuiItemFlags.NoMarkEdited, true) local opts = g.IO.ConfigColorEditFlags if allow_opt_inputs then if ImGui.RadioButtonEx("RGB", bit32.band(opts, ImGuiColorEditFlags.DisplayRGB) ~= 0) then opts = bit32.bor(bit32.band(opts, bit32.bnot(ImGuiColorEditFlags.DisplayMask_)), ImGuiColorEditFlags.DisplayRGB) end if ImGui.RadioButtonEx("HSV", bit32.band(opts, ImGuiColorEditFlags.DisplayHSV) ~= 0) then opts = bit32.bor(bit32.band(opts, bit32.bnot(ImGuiColorEditFlags.DisplayMask_)), ImGuiColorEditFlags.DisplayHSV) end if ImGui.RadioButtonEx("Hex", bit32.band(opts, ImGuiColorEditFlags.DisplayHex) ~= 0) then opts = bit32.bor(bit32.band(opts, bit32.bnot(ImGuiColorEditFlags.DisplayMask_)), ImGuiColorEditFlags.DisplayHex) end end if allow_opt_datatype then if allow_opt_inputs then ImGui.Separator() end if ImGui.RadioButtonEx("0..255", bit32.band(opts, ImGuiColorEditFlags.Uint8) ~= 0) then opts = bit32.bor(bit32.band(opts, bit32.bnot(ImGuiColorEditFlags.DataTypeMask_)), ImGuiColorEditFlags.Uint8) end if ImGui.RadioButtonEx("0.00..1.00", bit32.band(opts, ImGuiColorEditFlags.Float) ~= 0) then opts = bit32.bor(bit32.band(opts, bit32.bnot(ImGuiColorEditFlags.DataTypeMask_)), ImGuiColorEditFlags.Float) end end if allow_opt_inputs or allow_opt_datatype then ImGui.Separator() end if ImGui.Button("Copy as..", ImVec2(-1, 0)) then ImGui.OpenPopup("Copy") end if ImGui.BeginPopup("Copy") then local cr = IM_F32_TO_INT8_SAT(col[1]) local cg = IM_F32_TO_INT8_SAT(col[2]) local cb = IM_F32_TO_INT8_SAT(col[3]) local ca = (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 255 or IM_F32_TO_INT8_SAT(col[4]) local buf1 = ImFormatString("(%.3ff, %.3ff, %.3ff, %.3ff)", col[1], col[2], col[3], (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) ~= 0) and 1.0 or col[4]) if ImGui.Selectable(buf1) then ImGui.SetClipboardText(buf1) end local buf2 = ImFormatString("(%d,%d,%d,%d)", cr, cg, cb, ca) if ImGui.Selectable(buf2) then ImGui.SetClipboardText(buf2) end local buf3 = ImFormatString("#%02X%02X%02X", cr, cg, cb) if ImGui.Selectable(buf3) then ImGui.SetClipboardText(buf3) end if bit32.band(flags, ImGuiColorEditFlags.NoAlpha) == 0 then local buf4 = ImFormatString("#%02X%02X%02X%02X", cr, cg, cb, ca) if ImGui.Selectable(buf4) then ImGui.SetClipboardText(buf4) end end ImGui.EndPopup() end g.IO.ConfigColorEditFlags = opts ImGui.PopItemFlag() ImGui.EndPopup() end --- @param ref_col float[] --- @param flags ImGuiColorEditFlags function ImGui.ColorPickerOptionsPopup(ref_col, flags) local allow_opt_picker = bit32.band(flags, ImGuiColorEditFlags.PickerMask_) == 0 local allow_opt_alpha_bar = (bit32.band(flags, ImGuiColorEditFlags.NoAlpha) == 0) and (bit32.band(flags, ImGuiColorEditFlags.AlphaBar) == 0) if (not allow_opt_picker and not allow_opt_alpha_bar) or not ImGui.BeginPopup("context") then return end local g = GImGui ImGui.PushItemFlag(ImGuiItemFlags.NoMarkEdited, true) if allow_opt_picker then local picker_size = ImVec2(g.FontSize * 8, ImMax(g.FontSize * 8 - (ImGui.GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0)) -- FIXME: Picker size copied from main picker function ImGui.PushItemWidth(picker_size.x) for picker_type = 0, 1 do if picker_type > 0 then ImGui.Separator() end ImGui.PushID(picker_type) local picker_flags = bit32.bor(ImGuiColorEditFlags.NoInputs, ImGuiColorEditFlags.NoOptions, ImGuiColorEditFlags.NoLabel, ImGuiColorEditFlags.NoSidePreview, bit32.band(flags, ImGuiColorEditFlags.NoAlpha)) if picker_type == 0 then picker_flags = bit32.bor(picker_flags, ImGuiColorEditFlags.PickerHueBar) end if picker_type == 1 then picker_flags = bit32.bor(picker_flags, ImGuiColorEditFlags.PickerHueWheel) end local backup_pos = ImGui.GetCursorScreenPos() -- By default, Selectable() is closing popup if ImGui.Selectable("##selectable", false, 0, picker_size) then g.IO.ConfigColorEditFlags = bit32.bor(bit32.band(g.IO.ConfigColorEditFlags, bit32.bnot(ImGuiColorEditFlags.PickerMask_)), bit32.band(picker_flags, ImGuiColorEditFlags.PickerMask_)) end ImGui.SetCursorScreenPos(backup_pos) local previewing_ref_col = ImVec4() for i = 1, (bit32.band(picker_flags, ImGuiColorEditFlags.NoAlpha) ~= 0 and 3 or 4) do previewing_ref_col[i] = ref_col[i] end ImGui.ColorPicker4("##previewing_picker", previewing_ref_col, picker_flags) ImGui.PopID() end ImGui.PopItemWidth() end if allow_opt_alpha_bar then if allow_opt_picker then ImGui.Separator() end _, g.IO.ConfigColorEditFlags = ImGui.CheckboxFlags("Alpha Bar", g.IO.ConfigColorEditFlags, ImGuiColorEditFlags.AlphaBar) end ImGui.PopItemFlag() ImGui.EndPopup() end ---------------------------------------------------------------- -- [SECTION] TREES ---------------------------------------------------------------- -- va_list variants: identical in Lua (varargs) ImGui.TextColoredV = function(...) return ImGui.TextColored(...) end ImGui.TextDisabledV = function(...) return ImGui.TextDisabled(...) end ImGui.TextWrappedV = function(...) return ImGui.TextWrapped(...) end ImGui.TextAlignedV = function(...) return ImGui.TextAligned(...) end ImGui.LabelTextV = function(...) return ImGui.LabelText(...) end ImGui.BulletTextV = function(...) return ImGui.BulletText(...) end --- @param data_type ImGuiDataType --- @param v number function ImGui.SetNextItemRefVal(data_type, v) local g = GImGui g.NextItemData.HasFlags = bit32.bor(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasRefVal) g.NextItemData.RefVal = v end -- Overloads: TreeNode(label) / TreeNode(str_id, fmt, ...) --- @param label string @native function ImGui.TreeNode(label, fmt, ...) if fmt ~= nil then return ImGui.TreeNodeEx(label, 0, fmt, ...) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local id = window:GetID(label) return ImGui.TreeNodeBehavior(id, ImGuiTreeNodeFlags.None, label, nil) end function ImGui.TreeNodeV(str_id, fmt, ...) return ImGui.TreeNodeExV(str_id, 0, fmt, ...) end -- Overloads: TreeNodeEx(label, flags) / TreeNodeEx(str_id, flags, fmt, ...) --- @param label string --- @param flags? ImGuiTreeNodeFlags function ImGui.TreeNodeEx(label, flags, fmt, ...) if flags == nil then flags = 0 end if fmt ~= nil then return ImGui.TreeNodeExV(label, flags, fmt, ...) end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local id = window:GetID(label) return ImGui.TreeNodeBehavior(id, flags, label, nil) end --- @param str_id string|ImGuiID function ImGui.TreeNodeExV(str_id, flags, fmt, ...) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local id = window:GetID(str_id) local label = (select("#", ...) > 0) and string.format(fmt, ...) or fmt return ImGui.TreeNodeBehavior(id, flags, label, #label + 1) end --- @param storage_id ImGuiID function ImGui.TreeNodeGetOpen(storage_id) local g = GImGui local storage = g.CurrentWindow.DC.StateStorage return (storage[storage_id]) and true or false end --- @param storage_id ImGuiID --- @param is_open bool function ImGui.TreeNodeSetOpen(storage_id, is_open) local g = GImGui local storage = g.CurrentWindow.DC.StateStorage storage[storage_id] = is_open end --- @param storage_id ImGuiID --- @param flags ImGuiTreeNodeFlags function ImGui.TreeNodeUpdateNextOpen(storage_id, flags) if bit32.band(flags, ImGuiTreeNodeFlags.Leaf) ~= 0 then return true end local g = GImGui local window = g.CurrentWindow local storage = window.DC.StateStorage local is_open if bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasOpen) ~= 0 then if bit32.band(g.NextItemData.OpenCond, ImGuiCond.Always) ~= 0 then is_open = g.NextItemData.OpenVal ImGui.TreeNodeSetOpen(storage_id, is_open) else local stored_value = storage[storage_id] if stored_value == nil then is_open = g.NextItemData.OpenVal ImGui.TreeNodeSetOpen(storage_id, is_open) else is_open = stored_value and true or false end end else is_open = (storage[storage_id] == nil) and (bit32.band(flags, ImGuiTreeNodeFlags.DefaultOpen) ~= 0) or storage[storage_id] end if g.LogEnabled and bit32.band(flags, ImGuiTreeNodeFlags.NoAutoOpenOnLog) == 0 and (window.DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand then is_open = true end return is_open end --- @param flags ImGuiTreeNodeFlags --- @param x1 float local function TreeNodeStoreStackData(flags, x1) local g = GImGui local window = g.CurrentWindow g.TreeNodeStack:resize(g.TreeNodeStack.Size + 1) local tree_node_data = g.TreeNodeStack.Data[g.TreeNodeStack.Size] tree_node_data.ID = g.LastItemData.ID tree_node_data.TreeFlags = flags tree_node_data.ItemFlags = g.LastItemData.ItemFlags ImRect_Copy(tree_node_data.NavRect, g.LastItemData.NavRect) local draw_lines = bit32.band(flags, bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DrawLinesToNodes)) ~= 0 tree_node_data.DrawLinesX1 = draw_lines and (x1 + g.FontSize * 0.5 + g.Style.FramePadding.x) or FLT_MAX tree_node_data.DrawLinesTableColumn = (draw_lines and g.CurrentTable) and g.CurrentTable.CurrentColumn or -1 tree_node_data.DrawLinesToNodesY2 = -FLT_MAX window.DC.TreeHasStackDataDepthMask = bit32.bor(window.DC.TreeHasStackDataDepthMask, bit32.lshift(1, window.DC.TreeDepth)) if bit32.band(flags, ImGuiTreeNodeFlags.DrawLinesToNodes) ~= 0 then window.DC.TreeRecordsClippedNodesY2Mask = bit32.bor(window.DC.TreeRecordsClippedNodesY2Mask, bit32.lshift(1, window.DC.TreeDepth)) end end --- @param id ImGuiID --- @param flags ImGuiTreeNodeFlags --- @param label string --- @param label_end? int @native function ImGui.TreeNodeBehavior(id, flags, label, label_end) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local display_frame = bit32.band(flags, ImGuiTreeNodeFlags.Framed) ~= 0 local use_frame_padding = display_frame or (bit32.band(flags, ImGuiTreeNodeFlags.FramePadding) ~= 0) local padding if use_frame_padding then padding = style.FramePadding else padding = ImVec2(style.FramePadding.x, ImMin(window.DC.CurrLineTextBaseOffset, style.FramePadding.y)) end if label_end == nil then label_end = ImGui.FindRenderedTextEnd(label) end local label_size = ImGui.CalcTextSize(label, label_end, false) local text_offset_x = g.FontSize + (display_frame and (padding.x * 3) or (padding.x * 2)) local text_offset_y = use_frame_padding and ImMax(style.FramePadding.y, window.DC.CurrLineTextBaseOffset) or window.DC.CurrLineTextBaseOffset local text_width = g.FontSize + label_size.x + padding.x * 2 local frame_height = label_size.y + padding.y * 2 local span_all_columns = bit32.band(flags, ImGuiTreeNodeFlags.SpanAllColumns) ~= 0 and (g.CurrentTable ~= nil) local span_all_columns_label = bit32.band(flags, ImGuiTreeNodeFlags.LabelSpanAllColumns) ~= 0 and (g.CurrentTable ~= nil) local frame_bb = ImRect() frame_bb.Min.x = span_all_columns and window.ParentWorkRect.Min.x or (bit32.band(flags, ImGuiTreeNodeFlags.SpanFullWidth) ~= 0 and window.WorkRect.Min.x or window.DC.CursorPos.x) frame_bb.Min.y = window.DC.CursorPos.y + (text_offset_y - padding.y) frame_bb.Max.x = span_all_columns and window.ParentWorkRect.Max.x or (bit32.band(flags, ImGuiTreeNodeFlags.SpanLabelWidth) ~= 0 and window.DC.CursorPos.x + text_width + padding.x or window.WorkRect.Max.x) frame_bb.Max.y = window.DC.CursorPos.y + (text_offset_y - padding.y) + frame_height if display_frame then local outer_extend = IM_TRUNC(window.WindowPadding.x * 0.5) frame_bb.Min.x = frame_bb.Min.x - outer_extend frame_bb.Max.x = frame_bb.Max.x + outer_extend end local text_pos = ImVec2(window.DC.CursorPos.x + text_offset_x, window.DC.CursorPos.y + text_offset_y) ImGui.ItemSize(ImVec2(text_width, frame_height), padding.y) local interact_bb = ImRect() ImRect_Copy(interact_bb, frame_bb) if bit32.band(flags, bit32.bor(ImGuiTreeNodeFlags.Framed, ImGuiTreeNodeFlags.SpanAvailWidth, ImGuiTreeNodeFlags.SpanFullWidth, ImGuiTreeNodeFlags.SpanLabelWidth, ImGuiTreeNodeFlags.SpanAllColumns)) == 0 then interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0 and (style.ItemSpacing.x * 2.0) or 0.0) end local storage_id = (bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasStorageID) ~= 0) and g.NextItemData.StorageId or id local is_open = ImGui.TreeNodeUpdateNextOpen(storage_id, flags) local is_visible if span_all_columns or span_all_columns_label then local backup_clip_rect_min_x = window.ClipRect.Min.x local backup_clip_rect_max_x = window.ClipRect.Max.x window.ClipRect.Min.x = window.ParentWorkRect.Min.x window.ClipRect.Max.x = window.ParentWorkRect.Max.x is_visible = ImGui.ItemAdd(interact_bb, id) window.ClipRect.Min.x = backup_clip_rect_min_x window.ClipRect.Max.x = backup_clip_rect_max_x else is_visible = ImGui.ItemAdd(interact_bb, id) end g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasDisplayRect) ImRect_Copy(g.LastItemData.DisplayRect, frame_bb) local store_tree_node_stack_data = false if bit32.band(flags, ImGuiTreeNodeFlags.DrawLinesMask_) == 0 then flags = bit32.bor(flags, g.Style.TreeLinesFlags) end local draw_tree_lines = (bit32.band(flags, bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DrawLinesToNodes)) ~= 0) and (frame_bb.Min.y < window.ClipRect.Max.y) and (g.Style.TreeLinesSize > 0.0) if bit32.band(flags, ImGuiTreeNodeFlags.NoTreePushOnOpen) == 0 then store_tree_node_stack_data = draw_tree_lines if bit32.band(flags, ImGuiTreeNodeFlags.NavLeftJumpsToParent) ~= 0 and not g.NavIdIsAlive then if g.NavMoveDir == ImGuiDir.Left and g.NavWindow == window and ImGui.NavMoveRequestButNoResultYet() then store_tree_node_stack_data = true end end end local is_leaf = bit32.band(flags, ImGuiTreeNodeFlags.Leaf) ~= 0 if not is_visible then if bit32.band(flags, ImGuiTreeNodeFlags.DrawLinesToNodes) ~= 0 and bit32.band(window.DC.TreeRecordsClippedNodesY2Mask, bit32.lshift(1, (window.DC.TreeDepth - 1))) ~= 0 then local parent_data = g.TreeNodeStack.Data[g.TreeNodeStack.Size] parent_data.DrawLinesToNodesY2 = ImMax(parent_data.DrawLinesToNodesY2, window.DC.CursorPos.y) if frame_bb.Min.y >= window.ClipRect.Max.y then window.DC.TreeRecordsClippedNodesY2Mask = bit32.band(window.DC.TreeRecordsClippedNodesY2Mask, bit32.bnot(bit32.lshift(1, (window.DC.TreeDepth - 1)))) end end if is_open and store_tree_node_stack_data then TreeNodeStoreStackData(flags, text_pos.x - text_offset_x) end if is_open and bit32.band(flags, ImGuiTreeNodeFlags.NoTreePushOnOpen) == 0 then ImGui.TreePushOverrideID(id) end -- IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)) return is_open end if span_all_columns or span_all_columns_label then ImGui.TablePushBackgroundChannel() g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasClipRect) ImRect_Copy(g.LastItemData.ClipRect, window.ClipRect) end local button_flags = ImGuiTreeNodeFlags.None if bit32.band(flags, ImGuiTreeNodeFlags.AllowOverlap) ~= 0 or bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.AllowOverlap) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.AllowOverlap) end if not is_leaf then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnDragDropHold) end local arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x local arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0) + style.TouchExtraPadding.x local is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 and g.IO.MousePos.x < arrow_hit_x2) local is_multi_select = bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.IsMultiSelect) ~= 0 if is_multi_select then flags = bit32.bor(flags, (bit32.band(flags, ImGuiTreeNodeFlags.OpenOnMask_) == 0) and bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick) or ImGuiTreeNodeFlags.OpenOnArrow) end if is_mouse_x_over_arrow then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClick) elseif bit32.band(flags, ImGuiTreeNodeFlags.OpenOnDoubleClick) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClickRelease, ImGuiButtonFlags.PressedOnDoubleClick) else button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClickRelease) end if bit32.band(flags, ImGuiTreeNodeFlags.NoNavFocus) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.NoNavFocus) end local selected = bit32.band(flags, ImGuiTreeNodeFlags.Selected) ~= 0 local was_selected = selected if is_multi_select then selected, button_flags = ImGui.MultiSelectItemHeader(id, selected, button_flags) if is_mouse_x_over_arrow then button_flags = bit32.band(bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClick), bit32.bnot(ImGuiButtonFlags.PressedOnClickRelease)) end else if window ~= g.HoveredWindow or not is_mouse_x_over_arrow then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.NoKeyModsAllowed) end end local pressed, hovered, held = ImGui.ButtonBehavior(interact_bb, id, button_flags) local toggled = false if not is_leaf then if pressed and g.DragDropHoldJustPressedId ~= id then if bit32.band(flags, ImGuiTreeNodeFlags.OpenOnMask_) == 0 or (g.NavActivateId == id and not is_multi_select) then toggled = true end if bit32.band(flags, ImGuiTreeNodeFlags.OpenOnArrow) ~= 0 then toggled = toggled or (is_mouse_x_over_arrow and not g.NavHighlightItemUnderNav) end if bit32.band(flags, ImGuiTreeNodeFlags.OpenOnDoubleClick) ~= 0 and g.IO.MouseClickedCount[0] == 2 then toggled = true end elseif pressed and g.DragDropHoldJustPressedId == id then IM_ASSERT(bit32.band(button_flags, ImGuiButtonFlags.PressedOnDragDropHold) ~= 0) if not is_open then toggled = true else pressed = false end end if g.NavId == id and g.NavMoveDir == ImGuiDir.Left and is_open then toggled = true ImGui.NavClearPreferredPosForAxis(ImGuiAxis.X) ImGui.NavMoveRequestCancel() end if g.NavId == id and g.NavMoveDir == ImGuiDir.Right and not is_open then toggled = true ImGui.NavClearPreferredPosForAxis(ImGuiAxis.X) ImGui.NavMoveRequestCancel() end if toggled then is_open = not is_open window.DC.StateStorage[storage_id] = is_open g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.ToggledOpen) end end if is_multi_select then local pressed_copy = pressed and not toggled selected, pressed_copy = ImGui.MultiSelectItemFooter(id, selected, pressed_copy) if pressed then ImGui.SetNavID(id, window.DC.NavLayerCurrent, g.CurrentFocusScopeId, interact_bb) end end if selected ~= was_selected then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.ToggledSelection) end -- Render do local text_col = ImGui.GetColorU32(ImGuiCol.Text) local nav_render_cursor_flags = ImGuiNavRenderCursorFlags.Compact if is_multi_select then nav_render_cursor_flags = bit32.bor(nav_render_cursor_flags, ImGuiNavRenderCursorFlags.AlwaysDraw) end if display_frame then local bg_col = ImGui.GetColorU32((held and hovered) and ImGuiCol.HeaderActive or (hovered and ImGuiCol.HeaderHovered or ImGuiCol.Header)) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding) ImGui.RenderNavCursor(frame_bb, id, nav_render_cursor_flags) if span_all_columns and not span_all_columns_label then ImGui.TablePopBackgroundChannel() end if bit32.band(flags, ImGuiTreeNodeFlags.Bullet) ~= 0 then ImGui.RenderBullet(window.DrawList, ImVec2(text_pos.x - text_offset_x * 0.60, text_pos.y + g.FontSize * 0.5), text_col) elseif not is_leaf then ImGui.RenderArrow(window.DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open and ((bit32.band(flags, ImGuiTreeNodeFlags.UpsideDownArrow) ~= 0) and ImGuiDir.Up or ImGuiDir.Down) or ImGuiDir.Right, 1.0) else text_pos.x = text_pos.x - (text_offset_x - padding.x) end if bit32.band(flags, ImGuiTreeNodeFlags.ClipLabelForTrailingButton) ~= 0 then frame_bb.Max.x = frame_bb.Max.x - (g.FontSize + style.FramePadding.x) end -- if g.LogEnabled then -- ImGui.LogSetNextTextDecoration("###", "###") -- end else if hovered or selected then local bg_col = ImGui.GetColorU32((held and hovered) and ImGuiCol.HeaderActive or (hovered and ImGuiCol.HeaderHovered or ImGuiCol.Header)) ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false, 0.0) end ImGui.RenderNavCursor(frame_bb, id, nav_render_cursor_flags, 0.0) if span_all_columns and not span_all_columns_label then ImGui.TablePopBackgroundChannel() end if bit32.band(flags, ImGuiTreeNodeFlags.Bullet) ~= 0 then ImGui.RenderBullet(window.DrawList, ImVec2(text_pos.x - text_offset_x * 0.5, text_pos.y + g.FontSize * 0.5), text_col) elseif not is_leaf then ImGui.RenderArrow(window.DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15), text_col, is_open and ((bit32.band(flags, ImGuiTreeNodeFlags.UpsideDownArrow) ~= 0) and ImGuiDir.Up or ImGuiDir.Down) or ImGuiDir.Right, 0.70) end -- if g.LogEnabled then -- ImGui.LogSetNextTextDecoration(">", nil) -- end end if draw_tree_lines then ImGui.TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.5)) end if display_frame then ImGui.RenderTextClipped(text_pos, frame_bb.Max, label, label_end, label_size) else ImGui.RenderText(text_pos, label, 1, label_end, false) end if span_all_columns_label then ImGui.TablePopBackgroundChannel() end end if is_open and store_tree_node_stack_data then TreeNodeStoreStackData(flags, text_pos.x - text_offset_x) end if is_open and bit32.band(flags, ImGuiTreeNodeFlags.NoTreePushOnOpen) == 0 then ImGui.TreePushOverrideID(id) end -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open end --- @param target_pos ImVec2 function ImGui.TreeNodeDrawLineToChildNode(target_pos) local g = GImGui local window = g.CurrentWindow if window.DC.TreeDepth == 0 or bit32.band(window.DC.TreeHasStackDataDepthMask, bit32.lshift(1, window.DC.TreeDepth - 1)) == 0 then return end local parent_data = g.TreeNodeStack.Data[g.TreeNodeStack.Size] local x1 = ImTrunc(parent_data.DrawLinesX1) local x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x) local y = ImTrunc(target_pos.y) local rounding = (g.Style.TreeLinesRounding > 0.0) and ImMin(x2 - x1, g.Style.TreeLinesRounding) or 0.0 parent_data.DrawLinesToNodesY2 = ImMax(parent_data.DrawLinesToNodesY2, y - rounding) if x1 >= x2 then return end if rounding > 0.0 then x1 = x1 + 0.5 + rounding window.DrawList:PathArcToFast(ImVec2(x1, y - rounding), rounding, 6, 3) if x1 < x2 then window.DrawList:PathLineTo(ImVec2(x2, y)) end window.DrawList:PathStroke(ImGui.GetColorU32(ImGuiCol.TreeLines), g.Style.TreeLinesSize) else window.DrawList:AddLineH(x1, x2, y, ImGui.GetColorU32(ImGuiCol.TreeLines), g.Style.TreeLinesSize) end end --- @param data ImGuiTreeNodeStackData function ImGui.TreeNodeDrawLineToTreePop(data) local g = GImGui local window = g.CurrentWindow local y1 = ImMax(data.NavRect.Max.y, window.ClipRect.Min.y) local y2 = data.DrawLinesToNodesY2 if bit32.band(data.TreeFlags, ImGuiTreeNodeFlags.DrawLinesFull) ~= 0 then local y2_full = window.DC.CursorPos.y if g.CurrentTable then y2_full = ImMax(g.CurrentTable.RowPosY2, y2_full) end y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5) if y2 + (g.Style.ItemSpacing.y + g.Style.TreeLinesRounding) < y2_full then y2 = y2_full end end y2 = ImMin(y2, window.ClipRect.Max.y) if y2 <= y1 then return end local x = ImTrunc(data.DrawLinesX1 - g.Style.TreeLinesSize * 0.5) + g.Style.TreeLinesSize * 0.5 if data.DrawLinesTableColumn ~= -1 then ImGui.TablePushColumnChannel(data.DrawLinesTableColumn) end window.DrawList:AddLine(ImVec2(x, y1), ImVec2(x, y2), ImGui.GetColorU32(ImGuiCol.TreeLines), g.Style.TreeLinesSize) if data.DrawLinesTableColumn ~= -1 then ImGui.TablePopColumnChannel() end end --- @param str_id string|ImGuiID function ImGui.TreePush(str_id) local window = ImGui.GetCurrentWindow() ImGui.Indent() window.DC.TreeDepth = window.DC.TreeDepth + 1 ImGui.PushID(str_id) end --- @param id ImGuiID function ImGui.TreePushOverrideID(id) local g = GImGui local window = g.CurrentWindow ImGui.Indent() window.DC.TreeDepth = window.DC.TreeDepth + 1 ImGui.PushOverrideID(id) end function ImGui.TreePop() local g = GImGui local window = g.CurrentWindow ImGui.Unindent() window.DC.TreeDepth = window.DC.TreeDepth - 1 local tree_depth_mask = bit32.lshift(1, window.DC.TreeDepth) if bit32.band(window.DC.TreeHasStackDataDepthMask, tree_depth_mask) ~= 0 then local data = g.TreeNodeStack.Data[g.TreeNodeStack.Size] IM_ASSERT(data.ID == window.IDStack:back()) if bit32.band(data.TreeFlags, ImGuiTreeNodeFlags.NavLeftJumpsToParent) ~= 0 then if g.NavIdIsAlive and g.NavMoveDir == ImGuiDir.Left and g.NavWindow == window and ImGui.NavMoveRequestButNoResultYet() then ImGui.NavMoveRequestResolveWithPastTreeNode(g.NavMoveResultLocal, data) end end if data.DrawLinesX1 ~= FLT_MAX and window.DC.CursorPos.y >= window.ClipRect.Min.y then ImGui.TreeNodeDrawLineToTreePop(data) end g.TreeNodeStack:pop_back() window.DC.TreeHasStackDataDepthMask = bit32.band(window.DC.TreeHasStackDataDepthMask, bit32.bnot(tree_depth_mask)) window.DC.TreeRecordsClippedNodesY2Mask = bit32.band(window.DC.TreeRecordsClippedNodesY2Mask, bit32.bnot(tree_depth_mask)) end IM_ASSERT(window.IDStack.Size > 1) ImGui.PopID() end --- @param is_open bool --- @param cond? ImGuiCond function ImGui.SetNextItemOpen(is_open, cond) if cond == nil then cond = 0 end local g = GImGui if g.CurrentWindow.SkipItems then return end g.NextItemData.HasFlags = bit32.bor(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasOpen) g.NextItemData.OpenVal = is_open g.NextItemData.OpenCond = (cond ~= 0) and cond or ImGuiCond.Always end -- Horizontal distance preceding label when using TreeNode() or Bullet() function ImGui.GetTreeNodeToLabelSpacing() local g = GImGui return g.FontSize + (g.Style.FramePadding.x * 2.0) end --- @param storage_id ImGuiID function ImGui.SetNextItemStorageID(storage_id) local g = GImGui if g.CurrentWindow.SkipItems then return end g.NextItemData.HasFlags = bit32.bor(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasStorageID) g.NextItemData.StorageId = storage_id end -- Overloads: CollapsingHeader(label, flags?) -> is_open -- CollapsingHeader(label, p_visible: bool, flags?) -> is_open, p_visible --- @param label string @native function ImGui.CollapsingHeader(label, a, b) local p_visible, flags if type(a) == "boolean" then p_visible, flags = a, b else flags = a end if flags == nil then flags = 0 end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false, p_visible end if p_visible == false then return false, p_visible end local id = window:GetID(label) flags = bit32.bor(flags, ImGuiTreeNodeFlags.CollapsingHeader) if p_visible ~= nil then flags = bit32.bor(flags, ImGuiTreeNodeFlags.AllowOverlap, ImGuiTreeNodeFlags.ClipLabelForTrailingButton) end local is_open = ImGui.TreeNodeBehavior(id, flags, label) if p_visible ~= nil then -- Create a small overlapping close button local g = GImGui local last_item_backup = ImGuiLastItemData() ImGuiLastItemData_Copy(last_item_backup, g.LastItemData) local button_size = g.FontSize local button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size) local button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y local close_button_id = ImGui.GetIDWithSeed("#CLOSE", nil, id) if ImGui.CloseButton(close_button_id, ImVec2(button_x, button_y)) then p_visible = false end ImGuiLastItemData_Copy(g.LastItemData, last_item_backup) end return is_open, p_visible end ---------------------------------------------------------------- -- [SECTION] SELECTABLE ---------------------------------------------------------------- -- - Selectable() ---------------------------------------------------------------- -- Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. -- But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. -- With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags. -- FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. --- @param label string --- @param selected? bool --- @param flags? ImGuiSelectableFlags --- @param size_arg? any --- @return bool is_pressed --- @return bool is_selected # Updated `selected` @native function ImGui.Selectable(label, selected, flags, size_arg) if selected == nil then selected = false end if flags == nil then flags = 0 end if size_arg == nil then size_arg = ImVec2(0, 0) end local window = ImGui.GetCurrentWindow() if (window.SkipItems) then return false, selected end local g = GImGui local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local size = ImVec2((size_arg.x ~= 0.0) and size_arg.x or label_size.x, (size_arg.y ~= 0.0) and size_arg.y or label_size.y) local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) pos.y = pos.y + window.DC.CurrLineTextBaseOffset ImGui.ItemSize(size, 0.0) -- Fill horizontal space -- We don't support (size < 0.0) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. local span_all_columns = bit32.band(flags, ImGuiSelectableFlags.SpanAllColumns) ~= 0 local min_x = span_all_columns and window.ParentWorkRect.Min.x or pos.x local max_x = span_all_columns and window.ParentWorkRect.Max.x or window.WorkRect.Max.x if size_arg.x == 0.0 or bit32.band(flags, ImGuiSelectableFlags.SpanAvailWidth) ~= 0 then size.x = ImMax(label_size.x, max_x - min_x) end -- Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. -- FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos. local bb = ImRect(min_x, pos.y, min_x + size.x, pos.y + size.y) if bit32.band(flags, ImGuiSelectableFlags.NoPadWithHalfSpacing) == 0 then local spacing_x = span_all_columns and 0.0 or style.ItemSpacing.x local spacing_y = style.ItemSpacing.y local spacing_L = IM_TRUNC(spacing_x * 0.50) local spacing_U = IM_TRUNC(spacing_y * 0.50) bb.Min.x = bb.Min.x - spacing_L bb.Min.y = bb.Min.y - spacing_U bb.Max.x = bb.Max.x + (spacing_x - spacing_L) bb.Max.y = bb.Max.y + (spacing_y - spacing_U) end local disabled_item = bit32.band(flags, ImGuiSelectableFlags.Disabled) ~= 0 local extra_item_flags = disabled_item and ImGuiItemFlags.Disabled or ImGuiItemFlags.None local is_visible if span_all_columns then -- Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. local backup_clip_rect_min_x = window.ClipRect.Min.x local backup_clip_rect_max_x = window.ClipRect.Max.x window.ClipRect.Min.x = window.ParentWorkRect.Min.x window.ClipRect.Max.x = window.ParentWorkRect.Max.x is_visible = ImGui.ItemAdd(bb, id, nil, extra_item_flags) window.ClipRect.Min.x = backup_clip_rect_min_x window.ClipRect.Max.x = backup_clip_rect_max_x else is_visible = ImGui.ItemAdd(bb, id, nil, extra_item_flags) end local is_multi_select = bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.IsMultiSelect) ~= 0 if not is_visible then if not is_multi_select or not g.BoxSelectState.UnclipMode or not g.BoxSelectState.UnclipRect:Overlaps(bb) then -- Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd) return false, selected end end local disabled_global = bit32.band(g.CurrentItemFlags, ImGuiItemFlags.Disabled) ~= 0 if disabled_item and not disabled_global then -- Only testing this as an optimization ImGui.BeginDisabled() end -- FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, -- which would be advantageous since most selectable are not selected. if span_all_columns then if g.CurrentTable then ImGui.TablePushBackgroundChannel() elseif window.DC.CurrentColumns then ImGui.PushColumnsBackground() end g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HasClipRect) ImRect_Copy(g.LastItemData.ClipRect, window.ClipRect) end -- We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries local button_flags = 0 if bit32.band(flags, ImGuiSelectableFlags.NoHoldingActiveID) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.NoHoldingActiveId) end if bit32.band(flags, ImGuiSelectableFlags.NoSetKeyOwner) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.NoSetKeyOwner) end if bit32.band(flags, ImGuiSelectableFlags.SelectOnClick) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClick) end if bit32.band(flags, ImGuiSelectableFlags.SelectOnRelease) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnRelease) end if bit32.band(flags, ImGuiSelectableFlags.AllowDoubleClick) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnClickRelease, ImGuiButtonFlags.PressedOnDoubleClick) end if bit32.band(flags, ImGuiSelectableFlags.AllowOverlap) ~= 0 or bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.AllowOverlap) ~= 0 then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.AllowOverlap) end -- Multi-selection support (header) local was_selected = selected if is_multi_select then -- Handle multi-select + alter button flags for it -- TODO: selected, button_flags = ImGui.MultiSelectItemHeader(id, selected, button_flags) end local pressed, hovered, held = ImGui.ButtonBehavior(bb, id, button_flags) local auto_selected = false -- Multi-selection support (footer) if is_multi_select then -- TODO: selected, pressed = ImGui.MultiSelectItemFooter(id, selected, pressed) else -- Auto-select when moved into -- - This will be more fully fleshed in the range-select branch -- - This is not exposed as it won't nicely work with some user side handling of shift/control -- - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons -- - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) -- - (2) usage will fail with clipped items -- The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. if bit32.band(flags, ImGuiSelectableFlags.SelectOnNav) ~= 0 and g.NavJustMovedToId ~= 0 and g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId then if g.NavJustMovedToId == id and bit32.band(g.NavJustMovedToKeyMods, ImGuiMod_Ctrl) == 0 then selected = true pressed = true auto_selected = true end end end -- Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with keyboard/gamepad if pressed or (hovered and bit32.band(flags, ImGuiSelectableFlags.SetNavIdOnHover) ~= 0) then if not g.NavHighlightItemUnderNav and g.NavWindow == window and g.NavLayer == window.DC.NavLayerCurrent then ImGui.SetNavID(id, window.DC.NavLayerCurrent, g.CurrentFocusScopeId, ImGui.WindowRectAbsToRel(window, bb)) -- (bb == NavRect) if g.IO.ConfigNavCursorVisibleAuto then g.NavCursorVisible = false end end end if pressed then ImGui.MarkItemEdited(id) end if selected ~= was_selected then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.ToggledSelection) end if g.ActiveId == id and g.ActiveIdIsJustActivated then g.ActiveIdWasSelected = was_selected g.ActiveIdWasSoleSelected = was_selected and (not is_multi_select or g.CurrentMultiSelect.IsSoleOrUnknownSelectionSize) end -- Render if is_visible then local highlighted = hovered or (bit32.band(flags, ImGuiSelectableFlags.Highlight) ~= 0) if highlighted or selected then -- Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106) local col if held and highlighted then col = ImGui.GetColorU32(ImGuiCol.HeaderActive) elseif highlighted then col = ImGui.GetColorU32(ImGuiCol.HeaderHovered) else col = ImGui.GetColorU32(ImGuiCol.Header) end ImGui.RenderFrame(bb.Min, bb.Max, col, false, style.SelectableRounding) end if g.NavId == id then local nav_render_cursor_flags = ImGuiNavRenderCursorFlags.Compact if is_multi_select then nav_render_cursor_flags = bit32.bor(nav_render_cursor_flags, ImGuiNavRenderCursorFlags.AlwaysDraw) -- Always show the nav rectangle end ImGui.RenderNavCursor(bb, id, nav_render_cursor_flags, style.SelectableRounding) end end if span_all_columns then if g.CurrentTable then ImGui.TablePopBackgroundChannel() elseif window.DC.CurrentColumns then ImGui.PopColumnsBackground() end end -- Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns. if is_visible then ImGui.RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window.WorkRect.Max.x), pos.y + size.y), label, label_end, label_size, style.SelectableTextAlign, bb) end -- Automatically close popups if pressed and not auto_selected and bit32.band(window.Flags, ImGuiWindowFlags.Popup) ~= 0 and bit32.band(flags, ImGuiSelectableFlags.NoAutoClosePopups) == 0 and bit32.band(g.LastItemData.ItemFlags, ImGuiItemFlags.AutoClosePopups) ~= 0 then ImGui.CloseCurrentPopup() end if disabled_item and not disabled_global then ImGui.EndDisabled() end -- Users of BeginMultiSelect()/EndMultiSelect() scope: you may call ImGui::IsItemToggledSelection() to retrieve -- selection toggle, only useful if you need that state updated (e.g. for rendering purpose) before reaching EndMultiSelect(). return pressed, selected end ---------------------------------------------------------------- -- [SECTION] LISTBOX ---------------------------------------------------------------- --- @param label string --- @param size_arg? ImVec2 function ImGui.BeginListBox(label, size_arg) if size_arg == nil then size_arg = ImVec2(0, 0) end local g = GImGui local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local style = g.Style local id = ImGui.GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local size = ImTrunc(ImGui.CalcItemSize(size_arg, ImGui.CalcItemWidth(), ImGui.GetTextLineHeightWithSpacing() * 7.25 + style.FramePadding.y * 2.0)) local frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + frame_size) local bb = ImRect(frame_bb.Min, frame_bb.Max + ImVec2((label_size.x > 0.0) and (style.ItemInnerSpacing.x + label_size.x) or 0.0, 0.0)) g.NextItemData:ClearFlags() if not ImGui.IsRectVisible(bb.Min, bb.Max) then ImGui.ItemSize(bb:GetSize(), style.FramePadding.y) ImGui.ItemAdd(bb, 0, frame_bb) g.NextWindowData:ClearFlags() return false end ImGui.BeginGroup() if label_size.x > 0.0 then local label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y) ImGui.RenderText(label_pos, label, 1, label_end, false) ImVec2_Copy(window.DC.CursorMaxPos, ImMax(window.DC.CursorMaxPos, label_pos + label_size)) ImGui.AlignTextToFramePadding() end ImGui.BeginChild(id, frame_bb:GetSize(), ImGuiChildFlags.FrameStyle) return true end function ImGui.EndListBox() local g = GImGui local window = g.CurrentWindow IM_ASSERT(bit32.band(window.Flags, ImGuiWindowFlags.ChildWindow) ~= 0, "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?") ImGui.EndChild() ImGui.EndGroup() end -- Overloads: (label, current_item, items[], items_count?, height_in_items?) or (label, current_item, getter, user_data, items_count, height_in_items?) --- @param current_item int # 0-based --- @return int current_item --- @return bool value_changed function ImGui.ListBox(label, current_item, a, b, c, d) local g = GImGui local getter, user_data, items_count, height_in_items = Items_ResolveArgs(a, b, c, d) if height_in_items == nil then height_in_items = -1 end if height_in_items < 0 then height_in_items = ImMin(items_count, 7) end local height_in_items_f = height_in_items + 0.25 local size = ImVec2(0.0, ImTrunc(ImGui.GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0)) if not ImGui.BeginListBox(label, size) then return current_item, false end local value_changed = false local clipper = ImGuiListClipper() clipper:Begin(items_count, ImGui.GetTextLineHeightWithSpacing()) clipper:IncludeItemByIndex(current_item) while clipper:Step() do for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do local item_text = getter(user_data, i) if item_text == nil then item_text = "*Unknown item*" end ImGui.PushID(i) local item_selected = (i == current_item) if ImGui.Selectable(item_text, item_selected) then current_item = i value_changed = true end if item_selected then ImGui.SetItemDefaultFocus() end ImGui.PopID() end end ImGui.EndListBox() if value_changed then ImGui.MarkItemEdited(g.LastItemData.ID) end return current_item, value_changed end ---------------------------------------------------------------- -- [SECTION] BASIC PLOTTING ---------------------------------------------------------------- --- @param plot_type ImGuiPlotType --- @param label string --- @param values_getter fun(data?: table, idx: int): float --- @param data? table # 1-based table --- @param values_count int --- @param values_offset int --- @param overlay_text? string --- @param scale_min float --- @param scale_max float --- @param size_arg ImVec2 --- @return int function ImGui.PlotEx(plot_type, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, size_arg) local g = GImGui local window = ImGui.GetCurrentWindow() if window.SkipItems then return -1 end local style = g.Style local id = window:GetID(label) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local frame_size = ImGui.CalcItemSize(size_arg, ImGui.CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0) local frame_bb = ImRect(window.DC.CursorPos, window.DC.CursorPos + frame_size) local inner_bb = ImRect(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding) local total_bb = ImRect(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0 and style.ItemInnerSpacing.x + label_size.x or 0.0, 0)) ImGui.ItemSize(total_bb, style.FramePadding.y) if not ImGui.ItemAdd(total_bb, id, frame_bb, ImGuiItemFlags.NoNav) then return -1 end local _, hovered, _ = ImGui.ButtonBehavior(frame_bb, id) if scale_min == FLT_MAX or scale_max == FLT_MAX then local v_min = FLT_MAX local v_max = -FLT_MAX for i = 1, values_count do local v = values_getter(data, i) -- NaN isn't checked here v_min = ImMin(v_min, v) v_max = ImMax(v_max, v) end if scale_min == FLT_MAX then scale_min = v_min end if scale_max == FLT_MAX then scale_max = v_max end end ImGui.RenderFrame(frame_bb.Min, frame_bb.Max, ImGui.GetColorU32(ImGuiCol.FrameBg), true, style.FrameRounding) local values_count_min = (plot_type == ImGuiPlotType.Lines) and 2 or 1 local idx_hovered = -1 if values_count >= values_count_min then local res_w = ImMin(math.floor(frame_size.x), values_count) + ((plot_type == ImGuiPlotType.Lines) and -1 or 0) local item_count = values_count + ((plot_type == ImGuiPlotType.Lines) and -1 or 0) if hovered and inner_bb:Contains(g.IO.MousePos) then local t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0, 0.999) local v_idx = math.floor(t * item_count) + 1 IM_ASSERT(v_idx >= 1 and v_idx <= values_count) local v0 = values_getter(data, (v_idx - 1 + values_offset) % values_count + 1) local v1 = values_getter(data, (v_idx - 1 + 1 + values_offset) % values_count + 1) if plot_type == ImGuiPlotType.Lines then ImGui.SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1) elseif plot_type == ImGuiPlotType.Histogram then ImGui.SetTooltip("%d: %8.4g", v_idx, v0) end idx_hovered = v_idx end local t_step = 1.0 / res_w local inv_scale = (scale_min == scale_max) and 0.0 or (1.0 / (scale_max - scale_min)) local v0 = values_getter(data, (0 + values_offset) % values_count + 1) local t0 = 0.0 local tp0 = ImVec2(t0, 1.0 - ImSaturate((v0 - scale_min) * inv_scale)) local histogram_zero_line_t = (scale_min * scale_max < 0.0) and (1 + scale_min * inv_scale) or (scale_min < 0.0 and 0.0 or 1.0) local col_base = ImGui.GetColorU32((plot_type == ImGuiPlotType.Lines) and ImGuiCol.PlotLines or ImGuiCol.PlotHistogram) local col_hovered = ImGui.GetColorU32((plot_type == ImGuiPlotType.Lines) and ImGuiCol.PlotLinesHovered or ImGuiCol.PlotHistogramHovered) for _ = 0, res_w - 1 do local t1 = t0 + t_step local v1_idx = math.floor(t0 * item_count + 0.5) + 1 IM_ASSERT(v1_idx >= 1 and v1_idx <= values_count) local v1 = values_getter(data, (v1_idx - 1 + values_offset + 1) % values_count + 1) local tp1 = ImVec2(t1, 1.0 - ImSaturate((v1 - scale_min) * inv_scale)) local pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0) local pos1 if plot_type == ImGuiPlotType.Lines then pos1 = ImLerp(inner_bb.Min, inner_bb.Max, tp1) else pos1 = ImLerp(inner_bb.Min, inner_bb.Max, ImVec2(tp1.x, histogram_zero_line_t)) end if plot_type == ImGuiPlotType.Lines then window.DrawList:AddLine(pos0, pos1, idx_hovered == v1_idx and col_hovered or col_base) elseif plot_type == ImGuiPlotType.Histogram then if pos1.x >= pos0.x + 2.0 then pos1.x = pos1.x - 1.0 end window.DrawList:AddRectFilled(pos0, pos1, idx_hovered == v1_idx and col_hovered or col_base) end t0 = t1 tp0 = tp1 end end if overlay_text then ImGui.RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, nil, nil, ImVec2(0.5, 0.0)) end if label_size.x > 0.0 then ImGui.RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label, 1, label_end, false) end return idx_hovered end --- @class ImGuiPlotArrayGetterData --- @field Values float[] --- @field Stride int --- @param values float[] --- @param stride int --- @return ImGuiPlotArrayGetterData --- @nodiscard function ImGuiPlotArrayGetterData(values, stride) return { Values = values, Stride = stride } end --- @param data ImGuiPlotArrayGetterData --- @param idx int --- @return float --- @package local function Plot_ArrayGetter(data, idx) return data.Values[idx * data.Stride] end --- @param label string --- @param values_or_getter table|fun(data:table, i:int) # 1-based table or a function --- @param data? table # 1-based table --- @param values_count int --- @param values_offset? int # Defaults to 0 --- @param overlay_text? string --- @param scale_min? float # Defaults to FLT_MAX --- @param scale_max? float # Defaults to FLT_MAX --- @param graph_size? ImVec2 # Defaults to ImVec2(0, 0) --- @param stride? int # Defaults to 1 function ImGui.PlotLines(label, values_or_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride) if values_offset == nil then values_offset = 0 end if scale_min == nil then scale_min = FLT_MAX end if scale_max == nil then scale_max = FLT_MAX end if graph_size == nil then graph_size = ImVec2(0, 0) end if stride == nil then stride = 1 end if type(values_or_getter) == "function" then ImGui.PlotEx(ImGuiPlotType.Lines, label, values_or_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size) else data = ImGuiPlotArrayGetterData(values_or_getter, stride) ImGui.PlotEx(ImGuiPlotType.Lines, label, Plot_ArrayGetter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size) end end --- @param label string --- @param values_or_getter table|fun(data:table, i:int) # 1-based table or a function --- @param data? table # 1-based table --- @param values_count int --- @param values_offset? int # Defaults to 0 --- @param overlay_text? string --- @param scale_min? float # Defaults to FLT_MAX --- @param scale_max? float # Defaults to FLT_MAX --- @param graph_size? ImVec2 # Defaults to ImVec2(0, 0) --- @param stride? int # Defaults to 1 function ImGui.PlotHistogram(label, values_or_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride) if values_offset == nil then values_offset = 0 end if scale_min == nil then scale_min = FLT_MAX end if scale_max == nil then scale_max = FLT_MAX end if graph_size == nil then graph_size = ImVec2(0, 0) end if stride == nil then stride = 1 end if type(values_or_getter) == "function" then ImGui.PlotEx(ImGuiPlotType.Histogram, label, values_or_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size) else data = ImGuiPlotArrayGetterData(values_or_getter, stride) ImGui.PlotEx(ImGuiPlotType.Histogram, label, Plot_ArrayGetter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size) end end ---------------------------------------------------------------- -- [SECTION] MENU RELATED ---------------------------------------------------------------- --- @param spacing float --- @param window_reappearing bool function MT.ImGuiMenuColumns:Update(spacing, window_reappearing) if window_reappearing then for i = 1, #self.Widths do self.Widths[i] = 0 end end self.Spacing = spacing self:CalcNextTotalWidth(true) for i = 1, #self.Widths do self.Widths[i] = 0 end self.TotalWidth = self.NextTotalWidth self.NextTotalWidth = 0 end --- @param update_offsets bool function MT.ImGuiMenuColumns:CalcNextTotalWidth(update_offsets) local offset = 0 local want_spacing = false for i = 1, #self.Widths do local width = self.Widths[i] if want_spacing and width > 0 then offset = offset + self.Spacing end want_spacing = want_spacing or (width > 0) if update_offsets then if i == 2 then self.OffsetLabel = offset end if i == 3 then self.OffsetShortcut = offset end if i == 4 then self.OffsetMark = offset end end offset = offset + width end self.NextTotalWidth = offset end --- @param w_icon float --- @param w_label float --- @param w_shortcut float --- @param w_mark float function MT.ImGuiMenuColumns:DeclColumns(w_icon, w_label, w_shortcut, w_mark) self.Widths[1] = ImMax(self.Widths[1], (ImU16)(w_icon)) self.Widths[2] = ImMax(self.Widths[2], (ImU16)(w_label)) self.Widths[3] = ImMax(self.Widths[3], (ImU16)(w_shortcut)) self.Widths[4] = ImMax(self.Widths[4], (ImU16)(w_mark)) self:CalcNextTotalWidth(false) return ImMax(self.TotalWidth, self.NextTotalWidth) end -- FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. -- Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. -- Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags.MenuBar will become unnecessary. -- Then later the same system could be used for multiple menu-bars, scrollbars, side-bars. function ImGui.BeginMenuBar() local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end if bit32.band(window.Flags, ImGuiWindowFlags.MenuBar) == 0 then return false end IM_ASSERT(not window.DC.MenuBarAppending) ImGui.BeginGroup() -- FIXME: Misleading to use a group for that backup/restore ImGui.PushID("##MenuBar") -- We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. -- We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. local border_top = ImMax(IM_ROUND(window.WindowBorderSize * 0.5 - window.TitleBarHeight), 0.0) local border_half = IM_ROUND(window.WindowBorderSize * 0.5) local bar_rect = window:MenuBarRect() local clip_rect = ImRect(ImFloor(bar_rect.Min.x + border_half), ImFloor(bar_rect.Min.y + border_top), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window.WindowRounding, border_half))), ImFloor(bar_rect.Max.y)) clip_rect:ClipWith(window.OuterRectClipped) ImGui.PushClipRect(clip_rect.Min, clip_rect.Max, false) -- We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags) ImVec2_Copy(window.DC.CursorPos, ImVec2(bar_rect.Min.x + window.DC.MenuBarOffset.x, bar_rect.Min.y + window.DC.MenuBarOffset.y)) ImVec2_Copy(window.DC.CursorMaxPos, window.DC.CursorPos) window.DC.LayoutType = ImGuiLayoutType.Horizontal window.DC.IsSameLine = false window.DC.NavLayerCurrent = ImGuiNavLayer.Menu window.DC.MenuBarAppending = true ImGui.AlignTextToFramePadding() return true end function ImGui.EndMenuBar() local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui IM_ASSERT(bit32.band(window.Flags, ImGuiWindowFlags.MenuBar) ~= 0) IM_ASSERT(window.DC.MenuBarAppending) -- Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings if ImGui.NavMoveRequestButNoResultYet() and (g.NavMoveDir == ImGuiDir.Left or g.NavMoveDir == ImGuiDir.Right) and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then local nav_earliest_child = g.NavWindow while nav_earliest_child.ParentWindow and bit32.band(nav_earliest_child.ParentWindow.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 do nav_earliest_child = nav_earliest_child.ParentWindow end if nav_earliest_child.ParentWindow == window and nav_earliest_child.DC.ParentLayoutType == ImGuiLayoutType.Horizontal and bit32.band(g.NavMoveFlags, ImGuiNavMoveFlags.Forwarded) == 0 then local layer = ImGuiNavLayer.Menu IM_ASSERT(bit32.band(window.DC.NavLayersActiveMaskNext, bit32.lshift(1, layer)) ~= 0) ImGui.FocusWindow(window) ImGui.SetNavID(window.NavLastIds[layer], layer, 0, window.NavRectRel[layer]) if g.NavCursorVisible then g.NavCursorVisible = false g.NavCursorHideFrames = 2 end g.NavHighlightItemUnderNav = true g.NavMousePosDirty = true ImGui.NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags) end else ImGui.NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags.WrapX) end ImGui.PopClipRect() ImGui.PopID() window.DC.MenuBarOffset.x = window.DC.CursorPos.x - window.Pos.x -- Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos -- FIXME: Extremely confusing, cleanup by (a) working on WorkRect stack system (b) not using a Group confusingly here local group_data = g.GroupStack:back() group_data.EmitItem = false local restore_cursor_max_pos = ImVec2() ImVec2_Copy(restore_cursor_max_pos, group_data.BackupCursorMaxPos) window.DC.IdealMaxPos.x = ImMax(window.DC.IdealMaxPos.x, window.DC.CursorMaxPos.x - window.Scroll.x) -- Convert ideal extents for scrolling layer equivalent ImGui.EndGroup() -- Restore position on layer 0 // FIXME: Misleading to use a group for that backup/restore window.DC.LayoutType = ImGuiLayoutType.Vertical window.DC.IsSameLine = false window.DC.NavLayerCurrent = ImGuiNavLayer.Main window.DC.MenuBarAppending = false ImVec2_Copy(window.DC.CursorMaxPos, restore_cursor_max_pos) end -- Important: calling order matters! --- @param name string --- @param viewport_p? ImGuiViewport --- @param dir ImGuiDir --- @param axis_size float --- @param window_flags ImGuiWindowFlags function ImGui.BeginViewportSideBar(name, viewport_p, dir, axis_size, window_flags) IM_ASSERT(dir ~= ImGuiDir.None) local bar_window = ImGui.FindWindowByName(name) local viewport = viewport_p or ImGui.GetMainViewport() if bar_window == nil or bar_window.BeginCount == 0 then local avail_rect = viewport:GetBuildWorkRect() local axis = (dir == ImGuiDir.Up or dir == ImGuiDir.Down) and ImGuiAxis.Y or ImGuiAxis.X local pos = ImVec2(avail_rect.Min.x, avail_rect.Min.y) if dir == ImGuiDir.Right or dir == ImGuiDir.Down then pos[axis] = avail_rect.Max[axis] - axis_size end local size = avail_rect:GetSize() size[axis] = axis_size ImGui.SetNextWindowPos(pos) ImGui.SetNextWindowSize(size) if dir == ImGuiDir.Up or dir == ImGuiDir.Left then viewport.BuildWorkInsetMin[axis] = viewport.BuildWorkInsetMin[axis] + axis_size elseif dir == ImGuiDir.Down or dir == ImGuiDir.Right then viewport.BuildWorkInsetMax[axis] = viewport.BuildWorkInsetMax[axis] + axis_size end end window_flags = bit32.bor(window_flags or 0, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoDocking) ImGui.SetNextWindowViewport(viewport.ID) ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0) ImGui.PushStyleVar(ImGuiStyleVar.WindowMinSize, ImVec2(0, 0)) local _, is_open = ImGui.Begin(name, nil, window_flags) ImGui.PopStyleVar(2) return is_open end function ImGui.BeginMainMenuBar() local g = GImGui local viewport = ImGui.GetMainViewport() ImGui.SetCurrentViewport(nil, viewport) g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0)) local window_flags = bit32.bor(ImGuiWindowFlags.NoScrollbar, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.MenuBar) local height = ImGui.GetFrameHeight() local is_open = ImGui.BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir.Up, height, window_flags) g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0, 0.0) if not is_open then ImGui.End() return false end g.CurrentWindow.Flags = bit32.band(g.CurrentWindow.Flags, bit32.bnot(ImGuiWindowFlags.NoSavedSettings)) ImGui.BeginMenuBar() return is_open end function ImGui.EndMainMenuBar() local g = GImGui IM_ASSERT_USER_ERROR_RET(g.CurrentWindow.DC.MenuBarAppending, "Calling EndMainMenuBar() not from a menu-bar!") ImGui.EndMenuBar() g.CurrentWindow.Flags = bit32.bor(g.CurrentWindow.Flags, ImGuiWindowFlags.NoSavedSettings) if g.CurrentWindow == g.NavWindow and g.NavLayer == ImGuiNavLayer.Main and not g.NavAnyRequest and g.ActiveId == 0 then ImGui.FocusTopMostWindowUnderOne(g.NavWindow, nil, nil, bit32.bor(ImGuiFocusRequestFlags.UnlessBelowModal, ImGuiFocusRequestFlags.RestoreFocusedChild)) end ImGui.End() end local function IsRootOfOpenMenuSet() local g = GImGui local window = g.CurrentWindow if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) or (bit32.band(window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0) then return false end local upper_popup = g.OpenPopupStack.Data[g.BeginPopupStack.Size + 1] if window.DC.NavLayerCurrent ~= upper_popup.ParentNavLayer then return false end return upper_popup.Window and (bit32.band(upper_popup.Window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0) and ImGui.IsWindowChildOf(upper_popup.Window, window, true, false) end --- @param label string --- @param icon? string --- @param enabled bool function ImGui.BeginMenuEx(label, icon, enabled) local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local id = window:GetID(label) local menu_is_open = ImGui.IsPopupOpen(id, ImGuiPopupFlags.None) local window_flags = bit32.bor(ImGuiWindowFlags.ChildMenu, ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoNavFocus) if bit32.band(window.Flags, ImGuiWindowFlags.ChildMenu) ~= 0 then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.ChildWindow) end if g.MenusIdSubmittedThisFrame:contains(id) then if menu_is_open then menu_is_open = ImGui.BeginPopupMenuEx(id, label, window_flags) else g.NextWindowData:ClearFlags() end return menu_is_open end g.MenusIdSubmittedThisFrame:push_back(id) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local menuset_is_open = IsRootOfOpenMenuSet() if menuset_is_open then g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.NoWindowHoverableCheck) end local popup_pos local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) ImGui.PushID(label) if not enabled then ImGui.BeginDisabled() end local pressed local backup_rounding = style.SelectableRounding style.SelectableRounding = style.MenuItemRounding local selectable_flags = bit32.bor(ImGuiSelectableFlags.SelectOnClick, ImGuiSelectableFlags.NoAutoClosePopups) local offsets = window.DC.MenuColumns if window.DC.LayoutType == ImGuiLayoutType.Horizontal then window.DC.CursorPos.x = window.DC.CursorPos.x + IM_TRUNC(style.ItemSpacing.x * 0.5) ImGui.PushStyleVarX(ImGuiStyleVar.ItemSpacing, style.ItemSpacing.x * 2.0) local text_pos = ImVec2(window.DC.CursorPos.x + offsets.OffsetLabel, pos.y + window.DC.CurrLineTextBaseOffset) pressed = ImGui.Selectable("", menu_is_open, selectable_flags, label_size) -- TODO: ImGui.LogSetNextTextDecoration("[", "]") ImGui.RenderText(text_pos, label, 1, label_end, false) ImGui.PopStyleVar() window.DC.CursorPos.x = window.DC.CursorPos.x + IM_TRUNC(style.ItemSpacing.x * (-1.0 + 0.5)) popup_pos = ImVec2(pos.x - 1.0 - IM_TRUNC(style.ItemSpacing.x * 0.5), text_pos.y - style.FramePadding.y + window.MenuBarHeight) else local icon_w if (icon and icon ~= "") then icon_w = ImGui.CalcTextSize(icon, nil).x else icon_w = 0.0 end local checkmark_w = IM_TRUNC(g.FontSize * 1.20) local min_w = offsets:DeclColumns(icon_w, label_size.x, 0.0, checkmark_w) local extra_w = ImMax(0.0, ImGui.GetContentRegionAvail().x - min_w) local text_pos = ImVec2(window.DC.CursorPos.x, pos.y + window.DC.CurrLineTextBaseOffset) pressed = ImGui.Selectable("", menu_is_open, bit32.bor(selectable_flags, ImGuiSelectableFlags.SpanAvailWidth), ImVec2(min_w, label_size.y)) -- ImGui.LogSetNextTextDecoration("", ">") ImGui.RenderText(ImVec2(text_pos.x + offsets.OffsetLabel, text_pos.y), label, 1, label_end, false) if icon_w > 0.0 then --- @cast icon string ImGui.RenderText(ImVec2(text_pos.x + offsets.OffsetIcon, text_pos.y), icon) end ImGui.RenderArrow(window.DrawList, ImVec2(text_pos.x + offsets.OffsetMark + extra_w + g.FontSize * 0.30, text_pos.y), ImGui.GetColorU32(ImGuiCol.Text), ImGuiDir.Right) popup_pos = ImVec2(pos.x, text_pos.y - style.WindowPadding.y) end style.SelectableRounding = backup_rounding if not enabled then ImGui.EndDisabled() end if g.ActiveId == id and g.HoveredId ~= id and g.ActiveIdSource == ImGuiInputSource.Mouse and ImGui.IsMouseDragging(0) then ImGui.ClearActiveID() ImGui.SetKeyOwner(ImGuiKey.MouseLeft, ImGuiKeyOwner_NoOwner) end local hovered = g.HoveredId == id and enabled and not g.NavHighlightItemUnderNav local want_open = false local want_open_nav_init = false local want_close = false if window.DC.LayoutType == ImGuiLayoutType.Vertical then local moving_toward_child_menu = false local child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) and g.OpenPopupStack[g.BeginPopupStack.Size + 1] or nil local child_menu_window = (child_popup and child_popup.Window and child_popup.Window.ParentWindow == window) and child_popup.Window or nil if g.HoveredWindow == window and child_menu_window ~= nil then local ref_unit = g.FontSize local child_dir = (window.Pos.x < child_menu_window.Pos.x) and 1.0 or -1.0 local next_window_rect = child_menu_window:Rect() local ta = (g.IO.MousePos - g.IO.MouseDelta) local tb local tc if child_dir > 0.0 then tb = next_window_rect:GetTL() tc = next_window_rect:GetBL() else tb = next_window_rect:GetTR() tc = next_window_rect:GetBR() end local pad_farmost_h = ImClamp(ImFabs(ta.x - tb.x) * 0.30, ref_unit * 0.5, ref_unit * 2.5) ta.x = ta.x + child_dir * -0.5 tb.x = tb.x + child_dir * ref_unit tc.x = tc.x + child_dir * ref_unit tb.y = ta.y + ImMax((tb.y - pad_farmost_h) - ta.y, -ref_unit * 8.0) tc.y = ta.y + ImMin((tc.y + pad_farmost_h) - ta.y, ref_unit * 8.0) moving_toward_child_menu = ImStd.ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos) end if menu_is_open and not hovered and g.HoveredWindow == window and not moving_toward_child_menu and not g.NavHighlightItemUnderNav and g.ActiveId == 0 then want_close = true end if not menu_is_open and pressed then want_open = true elseif not menu_is_open and hovered and not moving_toward_child_menu then want_open = true elseif not menu_is_open and hovered and g.HoveredIdTimer >= 0.30 and g.MouseStationaryTimer >= 0.30 then want_open = true end if g.NavId == id and g.NavMoveDir == ImGuiDir.Right then want_open = true want_open_nav_init = true ImGui.NavMoveRequestCancel() ImGui.SetNavCursorVisibleAfterMove() end else if menu_is_open and pressed and menuset_is_open then want_close = true want_open = false menu_is_open = false elseif pressed or (hovered and menuset_is_open and not menu_is_open) then want_open = true elseif g.NavId == id and g.NavMoveDir == ImGuiDir.Down then want_open = true ImGui.NavMoveRequestCancel() end end if not enabled then want_close = true end if want_close and ImGui.IsPopupOpen(id, ImGuiPopupFlags.None) then ImGui.ClosePopupToLevel(g.BeginPopupStack.Size, true) end -- IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)) ImGui.PopID() if g.ActiveId == id and want_open then g.ActiveIdNoClearOnFocusLoss = true end if want_open and not menu_is_open and g.OpenPopupStack.Size > g.BeginPopupStack.Size then ImGui.OpenPopup(label) elseif want_open then menu_is_open = true ImGui.OpenPopup(label, ImGuiPopupFlags.NoReopen) end if menu_is_open then local last_item_in_parent = ImGuiLastItemData() ImGuiLastItemData_Copy(last_item_in_parent, g.LastItemData) ImGui.SetNextWindowPos(popup_pos, ImGuiCond.Always) ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, style.PopupRounding) menu_is_open = ImGui.BeginPopupMenuEx(id, label, window_flags) ImGui.PopStyleVar() if menu_is_open then if want_open and want_open_nav_init and not g.NavInitRequest then ImGui.FocusWindow(g.CurrentWindow, ImGuiFocusRequestFlags.UnlessBelowModal) ImGui.NavInitWindow(g.CurrentWindow, false) end ImGuiLastItemData_Copy(g.LastItemData, last_item_in_parent) if g.HoveredWindow == window then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow) end end else g.NextWindowData:ClearFlags() end return menu_is_open end --- @param label string --- @param enabled? bool function ImGui.BeginMenu(label, enabled) if enabled == nil then enabled = true end return ImGui.BeginMenuEx(label, nil, enabled) end function ImGui.EndMenu() local g = GImGui local window = g.CurrentWindow IM_ASSERT_USER_ERROR_RET(bit32.band(window.Flags, bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.ChildMenu)) == bit32.bor(ImGuiWindowFlags.Popup, ImGuiWindowFlags.ChildMenu), "Calling EndMenu() in wrong window!") local parent_window = window.ParentWindow if window.BeginCount == window.BeginCountPreviousFrame then if g.NavMoveDir == ImGuiDir.Left and ImGui.NavMoveRequestButNoResultYet() then if g.NavWindow and g.NavWindow.RootWindowForNav == window and parent_window.DC.LayoutType == ImGuiLayoutType.Vertical then ImGui.ClosePopupToLevel(g.BeginPopupStack.Size - 1, true) ImGui.NavMoveRequestCancel() end end end ImGui.EndPopup() end --- @param label string --- @param icon? string --- @param shortcut? string --- @param selected? bool --- @param enabled? bool function ImGui.MenuItemEx(label, icon, shortcut, selected, enabled) if selected == nil then selected = false end if enabled == nil then enabled = true end local window = ImGui.GetCurrentWindow() if window.SkipItems then return false end local g = GImGui local style = g.Style local pos = ImVec2() ImVec2_Copy(pos, window.DC.CursorPos) local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) local menuset_is_open = IsRootOfOpenMenuSet() if menuset_is_open then g.NextItemData.ItemFlagsSet = bit32.bor(g.NextItemData.ItemFlagsSet, ImGuiItemFlags.NoWindowHoverableCheck) end ImGui.PushID(label) if not enabled then ImGui.BeginDisabled() end local pressed local backup_rounding = style.SelectableRounding style.SelectableRounding = style.MenuItemRounding local selectable_flags = bit32.bor(ImGuiSelectableFlags.SelectOnRelease, ImGuiSelectableFlags.SetNavIdOnHover) local offsets = window.DC.MenuColumns if window.DC.LayoutType == ImGuiLayoutType.Horizontal then window.DC.CursorPos.x = window.DC.CursorPos.x + IM_TRUNC(style.ItemSpacing.x * 0.5) local text_pos = ImVec2(window.DC.CursorPos.x + offsets.OffsetLabel, window.DC.CursorPos.y + window.DC.CurrLineTextBaseOffset) ImGui.PushStyleVarX(ImGuiStyleVar.ItemSpacing, style.ItemSpacing.x * 2.0) pressed = ImGui.Selectable("", selected, selectable_flags, ImVec2(label_size.x, 0.0)) ImGui.PopStyleVar() if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0 then ImGui.RenderText(text_pos, label, 1, label_end, false) end window.DC.CursorPos.x = window.DC.CursorPos.x + IM_TRUNC(style.ItemSpacing.x * (-1.0 + 0.5)) else local icon_w = 0.0 if icon and icon ~= "" then icon_w = ImGui.CalcTextSize(icon, nil).x end local shortcut_w = 0.0 if shortcut and shortcut ~= "" then shortcut_w = ImGui.CalcTextSize(shortcut, nil).x end local checkmark_w = IM_TRUNC(g.FontSize * 1.20) local min_w = offsets:DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w) local stretch_w = ImMax(0.0, ImGui.GetContentRegionAvail().x - min_w) local text_pos = ImVec2(pos.x, pos.y + window.DC.CurrLineTextBaseOffset) pressed = ImGui.Selectable("", false, bit32.bor(selectable_flags, ImGuiSelectableFlags.SpanAvailWidth), ImVec2(min_w, label_size.y)) if bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0 then ImGui.RenderText(text_pos + ImVec2(offsets.OffsetLabel, 0.0), label, 1, label_end, false) if icon_w > 0.0 then --- @cast icon string ImGui.RenderText(text_pos + ImVec2(offsets.OffsetIcon, 0.0), icon) end if shortcut_w > 0.0 then ImGui.PushStyleColor(ImGuiCol.Text, style.Colors[ImGuiCol.TextDisabled]) -- ImGui.LogSetNextTextDecoration("(", ")") --- @cast shortcut string ImGui.RenderText(text_pos + ImVec2(offsets.OffsetShortcut + stretch_w, 0.0), shortcut, nil, nil, false) ImGui.PopStyleColor() end if selected then ImGui.RenderCheckMark(window.DrawList, text_pos + ImVec2(offsets.OffsetMark + stretch_w + g.FontSize * 0.40, g.FontSize * 0.134 * 0.5), ImGui.GetColorU32(ImGuiCol.Text), g.FontSize * 0.866) end end end style.SelectableRounding = backup_rounding local id = g.LastItemData.ID if g.ActiveId == id and g.HoveredId ~= id and g.ActiveIdSource == ImGuiInputSource.Mouse and ImGui.IsMouseDragging(0) then ImGui.ClearActiveID() ImGui.SetKeyOwner(ImGuiKey.MouseLeft, ImGuiKeyOwner_NoOwner) end -- IMGUI_TEST_ENGINE_ITEM_INFO() if not enabled then ImGui.EndDisabled() end ImGui.PopID() return pressed end --- @param label string --- @param shortcut? string --- @param selected? bool --- @param enabled? bool function ImGui.MenuItem(label, shortcut, selected, enabled) if ImGui.MenuItemEx(label, nil, shortcut, selected, enabled) then if selected ~= nil then selected = not selected end return true, selected end return false, selected end do --[[ [SECTION] Widgets: BeginTabBar, EndTabBar, etc. (was imgui_tabs.lua) ]] --- Dear ImGui -- Tab bars & tab items: 1:1 port of imgui_widgets.cpp [SECTION] Widgets: BeginTabBar/BeginTabItem (docking branch) -- -- Port notes: -- - tab_bar.Tabs is an ImVector of ImGuiTabItem tables (references). C++ pointer arithmetic on the array is replaced by -- index lookups. tab_bar.LastTabItemIdx and tab orders are 0-based like upstream. -- - Tab names are stored on the tab itself (tab.Name) instead of tab_bar.TabsNames. -- - ImGui.BeginTabItem(label, p_open, flags) returns `visible, p_open`. local MT = ImGui.GetMetatables() local GImGui local function SyncContext() GImGui = ImGui.GetCurrentContext() end local function ImLinearSweep(current, target, speed) if current < target then return ImMin(current + speed, target) end if current > target then return ImMax(current - speed, target) end return current end local function TabItemGetSectionIdx(tab) if bit32.band(tab.Flags, ImGuiTabItemFlags.Leading) ~= 0 then return 0 end if bit32.band(tab.Flags, ImGuiTabItemFlags.Trailing) ~= 0 then return 2 end return 1 end -- Stable sorts (C++ ImQsort is not stable, but the comparers are total orders in practice) local function SortTabsBySection(tab_bar) table.sort(tab_bar.Tabs.Data, function(a, b) if a == nil or b == nil then return false end local sa, sb = TabItemGetSectionIdx(a), TabItemGetSectionIdx(b) if sa ~= sb then return sa < sb end return a.IndexDuringLayout < b.IndexDuringLayout end) end local function SortTabsByBeginOrder(tab_bar) local data = tab_bar.Tabs.Data if not data then return end local arr = {} for i = 1, tab_bar.Tabs.Size do arr[i] = data[i] end table.sort(arr, function(a, b) return a.BeginOrder < b.BeginOrder end) for i = 1, tab_bar.Tabs.Size do data[i] = arr[i] end end local function TabBarCalcScrollableWidth(tab_bar, sections) return tab_bar.BarRect:GetWidth() - sections[1].Width - sections[3].Width - sections[2].Spacing end local function ImGuiTabBarSection() return { TabCount = 0, Width = 0.0, WidthAfterShrinkMinWidth = 0.0, Spacing = 0.0 } end -- items: 1-based array of ImGuiShrinkWidthItem, `first` = 1-based index of first item, `count` items function ImGui.ShrinkWidths(items, first, count, width_excess, width_min) if count <= 0 then return end if count == 1 then local it = items[first] if it.Width >= 0.0 then it.Width = ImMax(it.Width - width_excess, width_min) end return end local slice = {} for n = 1, count do slice[n] = items[first + n - 1] end table.sort(slice, function(a, b) if a.Width ~= b.Width then return a.Width > b.Width end return a.Index < b.Index end) for n = 1, count do items[first + n - 1] = slice[n] end local it = slice local count_same_width = 1 while width_excess > 0.001 and count_same_width < count do while count_same_width < count and it[1].Width <= it[count_same_width + 1].Width do count_same_width = count_same_width + 1 end local max_width_to_remove_per_item = (count_same_width < count and it[count_same_width + 1].Width >= 0.0) and (it[1].Width - it[count_same_width + 1].Width) or (it[1].Width - 1.0) max_width_to_remove_per_item = ImMin(it[1].Width - width_min, max_width_to_remove_per_item) if max_width_to_remove_per_item <= 0.0 then break end local base_width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item) for item_n = 1, count_same_width do local w = ImMin(base_width_to_remove_per_item, it[item_n].Width - width_min) it[item_n].Width = it[item_n].Width - w width_excess = width_excess - w end end width_excess = 0.0 for n = 1, count do local width_rounded = ImTrunc(it[n].Width) width_excess = width_excess + it[n].Width - width_rounded it[n].Width = width_rounded end local guard = 0 while width_excess > 0.0 and guard < 10000 do guard = guard + 1 local progressed = false for n = 1, count do if width_excess <= 0.0 then break end local width_to_add = ImMin(it[n].InitialWidth - it[n].Width, 1.0) if width_to_add > 0 then progressed = true end it[n].Width = it[n].Width + width_to_add width_excess = width_excess - width_to_add end if not progressed then break end end end --------------------------------------------------------------------------------------- -- [SECTION] Widgets: BeginTabBar, EndTabBar, etc. --------------------------------------------------------------------------------------- function ImGui.TabBarFindByID(id) SyncContext() return GImGui.TabBars:GetByKey(id) end function ImGui.TabBarRemove(tab_bar) SyncContext() GImGui.TabBars:Remove(tab_bar.ID, tab_bar) end function ImGui.BeginTabBar(str_id, flags) if flags == nil then flags = 0 end SyncContext() local g = GImGui local window = g.CurrentWindow if window.SkipItems then return false end local id = window:GetID(str_id) local tab_bar = g.TabBars:GetOrAddByKey(id) local tab_bar_bb = ImRect(window.DC.CursorPos.x, window.DC.CursorPos.y, window.WorkRect.Max.x, window.DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2) tab_bar.ID = id tab_bar.SeparatorMinX = tab_bar_bb.Min.x - IM_TRUNC(window.WindowPadding.x * 0.5) tab_bar.SeparatorMaxX = tab_bar_bb.Max.x + IM_TRUNC(window.WindowPadding.x * 0.5) flags = bit32.bor(flags, ImGuiTabBarFlags.IsFocused) return ImGui.BeginTabBarEx(tab_bar, tab_bar_bb, flags) end function ImGui.BeginTabBarEx(tab_bar, tab_bar_bb, flags) SyncContext() local g = GImGui local window = g.CurrentWindow if window.SkipItems then return false end IM_ASSERT(tab_bar.ID ~= 0) if bit32.band(flags, ImGuiTabBarFlags.DockNode) == 0 then ImGui.PushOverrideID(tab_bar.ID) end g.CurrentTabBarStack:push_back(tab_bar) g.CurrentTabBar = tab_bar tab_bar.Window = window ImVec2_Copy(tab_bar.BackupCursorPos, window.DC.CursorPos) if tab_bar.CurrFrameVisible == g.FrameCount then ImVec2_CopyV(window.DC.CursorPos, tab_bar.BarRect.Min.x, tab_bar.BarRect.Max.y + tab_bar.ItemSpacingY) tab_bar.BeginCount = tab_bar.BeginCount + 1 return true end if bit32.band(flags, ImGuiTabBarFlags.Reorderable) ~= bit32.band(tab_bar.Flags, ImGuiTabBarFlags.Reorderable) or (tab_bar.TabsAddedNew and bit32.band(flags, ImGuiTabBarFlags.Reorderable) == 0) then if bit32.band(flags, ImGuiTabBarFlags.DockNode) == 0 then SortTabsByBeginOrder(tab_bar) end end tab_bar.TabsAddedNew = false if bit32.band(flags, ImGuiTabBarFlags.FittingPolicyMask_) == 0 then flags = bit32.bor(flags, ImGuiTabBarFlags.FittingPolicyDefault_) end tab_bar.Flags = flags tab_bar.BarRect = ImRect(tab_bar_bb.Min, tab_bar_bb.Max) tab_bar.WantLayout = true tab_bar.PrevFrameVisible = tab_bar.CurrFrameVisible tab_bar.CurrFrameVisible = g.FrameCount tab_bar.PrevTabsContentsHeight = tab_bar.CurrTabsContentsHeight tab_bar.CurrTabsContentsHeight = 0.0 tab_bar.ItemSpacingY = g.Style.ItemSpacing.y ImVec2_Copy(tab_bar.FramePadding, g.Style.FramePadding) tab_bar.TabsActiveCount = 0 tab_bar.LastTabItemIdx = -1 tab_bar.BeginCount = 1 ImVec2_CopyV(window.DC.CursorPos, tab_bar.BarRect.Min.x, tab_bar.BarRect.Max.y + tab_bar.ItemSpacingY) local col = ImGui.GetColorU32(bit32.band(flags, ImGuiTabBarFlags.IsFocused) ~= 0 and ImGuiCol.TabSelected or ImGuiCol.TabDimmedSelected) if g.Style.TabBarBorderSize > 0.0 then local y = tab_bar.BarRect.Max.y window.DrawList:AddRectFilled(ImVec2(tab_bar.SeparatorMinX, y - g.Style.TabBarBorderSize), ImVec2(tab_bar.SeparatorMaxX, y), col) end return true end function ImGui.EndTabBar() SyncContext() local g = GImGui local window = g.CurrentWindow if window.SkipItems then return end local tab_bar = g.CurrentTabBar IM_ASSERT(tab_bar ~= nil, "Mismatched BeginTabBar()/EndTabBar()!") if tab_bar.WantLayout then ImGui.TabBarLayout(tab_bar) end local tab_bar_appearing = (tab_bar.PrevFrameVisible + 1 < g.FrameCount) if tab_bar.VisibleTabWasSubmitted or tab_bar.VisibleTabId == 0 or tab_bar_appearing then tab_bar.CurrTabsContentsHeight = ImMax(window.DC.CursorPos.y - tab_bar.BarRect.Max.y, tab_bar.CurrTabsContentsHeight) window.DC.CursorPos.y = tab_bar.BarRect.Max.y + tab_bar.CurrTabsContentsHeight else window.DC.CursorPos.y = tab_bar.BarRect.Max.y + tab_bar.PrevTabsContentsHeight end if tab_bar.BeginCount > 1 then ImVec2_Copy(window.DC.CursorPos, tab_bar.BackupCursorPos) end tab_bar.LastTabItemIdx = -1 if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.DockNode) == 0 then ImGui.PopID() end g.CurrentTabBarStack:pop_back() if g.CurrentTabBarStack.Size == 0 then g.CurrentTabBar = nil else g.CurrentTabBar = g.CurrentTabBarStack.Data[g.CurrentTabBarStack.Size] end end function ImGui.TabBarLayout(tab_bar) SyncContext() local g = GImGui tab_bar.WantLayout = false local scroll_to_selected_tab = (tab_bar.BarRectPrevWidth > tab_bar.BarRect:GetWidth()) tab_bar.BarRectPrevWidth = tab_bar.BarRect:GetWidth() -- Garbage collect by compacting list local tabs = tab_bar.Tabs local tab_dst_n = 0 local need_sort_by_section = false local sections = { ImGuiTabBarSection(), ImGuiTabBarSection(), ImGuiTabBarSection() } -- 1-based: [1]=Leading,[2]=Central,[3]=Trailing for tab_src_n = 0, tabs.Size - 1 do local tab = tabs.Data[tab_src_n + 1] if tab.LastFrameVisible < tab_bar.PrevFrameVisible or tab.WantClose then if tab_bar.VisibleTabId == tab.ID then tab_bar.VisibleTabId = 0 end if tab_bar.SelectedTabId == tab.ID then tab_bar.SelectedTabId = 0 end if tab_bar.NextSelectedTabId == tab.ID then tab_bar.NextSelectedTabId = 0 end else if tab_dst_n ~= tab_src_n then tabs.Data[tab_dst_n + 1] = tab end tab.IndexDuringLayout = tab_dst_n local curr_tab_section_n = TabItemGetSectionIdx(tab) if tab_dst_n > 0 then local prev_tab = tabs.Data[tab_dst_n] local prev_tab_section_n = TabItemGetSectionIdx(prev_tab) if curr_tab_section_n == 0 and prev_tab_section_n ~= 0 then need_sort_by_section = true end if prev_tab_section_n == 2 and curr_tab_section_n ~= 2 then need_sort_by_section = true end end sections[curr_tab_section_n + 1].TabCount = sections[curr_tab_section_n + 1].TabCount + 1 tab_dst_n = tab_dst_n + 1 end end if tabs.Size ~= tab_dst_n then for i = tab_dst_n + 1, tabs.Size do tabs.Data[i] = nil end tabs.Size = tab_dst_n end if need_sort_by_section then SortTabsBySection(tab_bar) end local tab_spacing = g.Style.ItemInnerSpacing.x sections[1].Spacing = (sections[1].TabCount > 0 and (sections[2].TabCount + sections[3].TabCount) > 0) and tab_spacing or 0.0 sections[2].Spacing = (sections[2].TabCount > 0 and sections[3].TabCount > 0) and tab_spacing or 0.0 local scroll_to_tab_id = 0 if tab_bar.NextScrollToTabId ~= 0 then scroll_to_tab_id = tab_bar.NextScrollToTabId tab_bar.NextScrollToTabId = 0 end if tab_bar.NextSelectedTabId ~= 0 then tab_bar.SelectedTabId = tab_bar.NextSelectedTabId tab_bar.NextSelectedTabId = 0 scroll_to_tab_id = tab_bar.SelectedTabId end if tab_bar.ReorderRequestTabId ~= 0 then if ImGui.TabBarProcessReorder(tab_bar) then if tab_bar.ReorderRequestTabId == tab_bar.SelectedTabId then scroll_to_tab_id = tab_bar.ReorderRequestTabId end end tab_bar.ReorderRequestTabId = 0 end local tab_list_popup_button = bit32.band(tab_bar.Flags, ImGuiTabBarFlags.TabListPopupButton) ~= 0 if tab_list_popup_button then local tab_to_select = ImGui.TabBarTabListPopupButton(tab_bar) if tab_to_select then tab_bar.SelectedTabId = tab_to_select.ID scroll_to_tab_id = tab_to_select.ID end end -- shrink buffer layout: leading, trailing, central (0-based offsets) local shrink_buffer_indexes = { 0, sections[1].TabCount + sections[3].TabCount, sections[1].TabCount } local swb = g.ShrinkWidthBuffer swb:resize(tabs.Size) for i = 1, tabs.Size do if swb.Data[i] == nil then swb.Data[i] = ImGuiShrinkWidthItem() end end local shrink_min_width = (bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyMixed) ~= 0) and g.Style.TabMinWidthShrink or 1.0 local most_recently_selected_tab = nil local curr_section_n = -1 local found_selected_tab_id = false for tab_n = 0, tabs.Size - 1 do local tab = tabs.Data[tab_n + 1] IM_ASSERT(tab.LastFrameVisible >= tab_bar.PrevFrameVisible) if (most_recently_selected_tab == nil or most_recently_selected_tab.LastFrameSelected < tab.LastFrameSelected) and bit32.band(tab.Flags, ImGuiTabItemFlags.Button) == 0 then most_recently_selected_tab = tab end if tab.ID == tab_bar.SelectedTabId then found_selected_tab_id = true end if scroll_to_tab_id == 0 and g.NavJustMovedToId == tab.ID then scroll_to_tab_id = tab.ID end local tab_name = ImGui.TabBarGetTabName(tab_bar, tab) local has_close_button_or_unsaved_marker = bit32.band(tab.Flags, ImGuiTabItemFlags.NoCloseButton) == 0 or bit32.band(tab.Flags, ImGuiTabItemFlags.UnsavedDocument) ~= 0 tab.ContentWidth = (tab.RequestedWidth >= 0.0) and tab.RequestedWidth or ImGui.TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x if bit32.band(tab.Flags, ImGuiTabItemFlags.Button) == 0 then tab.ContentWidth = ImMax(tab.ContentWidth, g.Style.TabMinWidthBase) end local section_n = TabItemGetSectionIdx(tab) local section = sections[section_n + 1] section.Width = section.Width + tab.ContentWidth + ((section_n == curr_section_n) and tab_spacing or 0.0) section.WidthAfterShrinkMinWidth = section.WidthAfterShrinkMinWidth + ImMin(tab.ContentWidth, shrink_min_width) + ((section_n == curr_section_n) and tab_spacing or 0.0) curr_section_n = section_n local item = swb.Data[shrink_buffer_indexes[section_n + 1] + 1] shrink_buffer_indexes[section_n + 1] = shrink_buffer_indexes[section_n + 1] + 1 item.Index = tab_n item.Width = tab.ContentWidth item.InitialWidth = tab.ContentWidth tab.Width = ImMax(tab.ContentWidth, 1.0) end local width_all_tabs_after_min_width_shrink = 0.0 tab_bar.WidthAllTabsIdeal = 0.0 for section_n = 1, 3 do tab_bar.WidthAllTabsIdeal = tab_bar.WidthAllTabsIdeal + sections[section_n].Width + sections[section_n].Spacing width_all_tabs_after_min_width_shrink = width_all_tabs_after_min_width_shrink + sections[section_n].WidthAfterShrinkMinWidth + sections[section_n].Spacing end local can_scroll = bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyScroll) ~= 0 or bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyMixed) ~= 0 local width_all_tabs_to_use_for_scroll = (bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyScroll) ~= 0) and tab_bar.WidthAllTabs or width_all_tabs_after_min_width_shrink tab_bar.ScrollButtonEnabled = (width_all_tabs_to_use_for_scroll > tab_bar.BarRect:GetWidth() and tabs.Size > 1) and bit32.band(tab_bar.Flags, ImGuiTabBarFlags.NoTabListScrollingButtons) == 0 and can_scroll if tab_bar.ScrollButtonEnabled then local scroll_and_select_tab = ImGui.TabBarScrollingButtons(tab_bar) if scroll_and_select_tab then if bit32.band(scroll_and_select_tab.Flags, ImGuiTabItemFlags.Button) == 0 then tab_bar.SelectedTabId = scroll_and_select_tab.ID end scroll_to_tab_id = scroll_and_select_tab.ID end end if scroll_to_tab_id == 0 and scroll_to_selected_tab then scroll_to_tab_id = tab_bar.SelectedTabId end local section_0_w = sections[1].Width + sections[1].Spacing local section_1_w = sections[2].Width + sections[2].Spacing local section_2_w = sections[3].Width + sections[3].Spacing local central_section_is_visible = (section_0_w + section_2_w) < tab_bar.BarRect:GetWidth() local width_excess if central_section_is_visible then width_excess = ImMax(section_1_w - (tab_bar.BarRect:GetWidth() - section_0_w - section_2_w), 0.0) else width_excess = (section_0_w + section_2_w) - tab_bar.BarRect:GetWidth() end local can_shrink = bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyShrink) ~= 0 or bit32.band(tab_bar.Flags, ImGuiTabBarFlags.FittingPolicyMixed) ~= 0 if width_excess >= 1.0 and (can_shrink or not central_section_is_visible) then local shrink_data_count = central_section_is_visible and sections[2].TabCount or (sections[1].TabCount + sections[3].TabCount) local shrink_data_offset = central_section_is_visible and (sections[1].TabCount + sections[3].TabCount) or 0 ImGui.ShrinkWidths(swb.Data, shrink_data_offset + 1, shrink_data_count, width_excess, shrink_min_width) for tab_n = shrink_data_offset, shrink_data_offset + shrink_data_count - 1 do local item = swb.Data[tab_n + 1] local tab = tabs.Data[item.Index + 1] local shrinked_width = IM_TRUNC(item.Width) if shrinked_width >= 0.0 then shrinked_width = ImMax(1.0, shrinked_width) local section_n = TabItemGetSectionIdx(tab) sections[section_n + 1].Width = sections[section_n + 1].Width - (tab.Width - shrinked_width) tab.Width = shrinked_width end end end -- Layout all active tabs local section_tab_index = 0 local tab_offset = 0.0 tab_bar.WidthAllTabs = 0.0 for section_n = 0, 2 do local section = sections[section_n + 1] if section_n == 2 then tab_offset = ImMin(ImMax(0.0, tab_bar.BarRect:GetWidth() - section.Width), tab_offset) end for tab_n = 0, section.TabCount - 1 do local tab = tabs.Data[section_tab_index + tab_n + 1] tab.Offset = tab_offset tab.NameOffset = -1 tab_offset = tab_offset + tab.Width + ((tab_n < section.TabCount - 1) and g.Style.ItemInnerSpacing.x or 0.0) end tab_bar.WidthAllTabs = tab_bar.WidthAllTabs + ImMax(section.Width + section.Spacing, 0.0) tab_offset = tab_offset + section.Spacing section_tab_index = section_tab_index + section.TabCount end local tab_bar_appearing = (tab_bar.PrevFrameVisible + 1 < g.FrameCount) if found_selected_tab_id == false and not tab_bar_appearing then tab_bar.SelectedTabId = 0 end if tab_bar.SelectedTabId == 0 and tab_bar.NextSelectedTabId == 0 and most_recently_selected_tab ~= nil then tab_bar.SelectedTabId = most_recently_selected_tab.ID scroll_to_tab_id = tab_bar.SelectedTabId end tab_bar.VisibleTabId = tab_bar.SelectedTabId tab_bar.VisibleTabWasSubmitted = false -- CTRL+TAB can override visible tab temporarily if g.NavWindowingTarget ~= nil and g.NavWindowingTarget.DockNode and g.NavWindowingTarget.DockNode.TabBar == tab_bar then tab_bar.VisibleTabId = g.NavWindowingTarget.TabId scroll_to_tab_id = tab_bar.VisibleTabId end if scroll_to_tab_id ~= 0 then ImGui.TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections) elseif tab_bar.ScrollButtonEnabled and ImGui.IsMouseHoveringRect(tab_bar.BarRect.Min, tab_bar.BarRect.Max, true) and ImGui.IsWindowContentHoverable(g.CurrentWindow) then local wheel = g.IO.MouseWheelRequestAxisSwap and g.IO.MouseWheel or g.IO.MouseWheelH local wheel_key = g.IO.MouseWheelRequestAxisSwap and ImGuiKey.MouseWheelY or ImGuiKey.MouseWheelX if ImGui.TestKeyOwner(wheel_key, tab_bar.ID) and wheel ~= 0.0 then local scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0 tab_bar.ScrollingTargetDistToVisibility = 0.0 tab_bar.ScrollingTarget = ImGui.TabBarScrollClamp(tab_bar, tab_bar.ScrollingTarget - scroll_step) end ImGui.SetKeyOwner(wheel_key, tab_bar.ID) end tab_bar.ScrollingAnim = ImGui.TabBarScrollClamp(tab_bar, tab_bar.ScrollingAnim) tab_bar.ScrollingTarget = ImGui.TabBarScrollClamp(tab_bar, tab_bar.ScrollingTarget) if tab_bar.ScrollingAnim ~= tab_bar.ScrollingTarget then tab_bar.ScrollingSpeed = ImMax(tab_bar.ScrollingSpeed, 70.0 * g.FontSize) tab_bar.ScrollingSpeed = ImMax(tab_bar.ScrollingSpeed, math.abs(tab_bar.ScrollingTarget - tab_bar.ScrollingAnim) / 0.3) local teleport = (tab_bar.PrevFrameVisible + 1 < g.FrameCount) or (tab_bar.ScrollingTargetDistToVisibility > 10.0 * g.FontSize) tab_bar.ScrollingAnim = teleport and tab_bar.ScrollingTarget or ImLinearSweep(tab_bar.ScrollingAnim, tab_bar.ScrollingTarget, g.IO.DeltaTime * tab_bar.ScrollingSpeed) else tab_bar.ScrollingSpeed = 0.0 end tab_bar.ScrollingRectMinX = tab_bar.BarRect.Min.x + sections[1].Width + sections[1].Spacing tab_bar.ScrollingRectMaxX = tab_bar.BarRect.Max.x - sections[3].Width - sections[2].Spacing local window = g.CurrentWindow ImVec2_Copy(window.DC.CursorPos, tab_bar.BarRect.Min) ImGui.ItemSize(ImVec2(tab_bar.WidthAllTabs, tab_bar.BarRect:GetHeight()), tab_bar.FramePadding.y) window.DC.IdealMaxPos.x = ImMax(window.DC.IdealMaxPos.x, tab_bar.BarRect.Min.x + tab_bar.WidthAllTabsIdeal) end function ImGui.TabBarCalcTabID(tab_bar, label, docked_window) if docked_window ~= nil then IM_ASSERT(bit32.band(tab_bar.Flags, ImGuiTabBarFlags.DockNode) ~= 0) local id = docked_window.TabId ImGui.KeepAliveID(id) return id end return ImGui.GetCurrentContext().CurrentWindow:GetID(label) end function ImGui.TabBarCalcMaxTabWidth() return ImGui.GetCurrentContext().FontSize * 20.0 end function ImGui.TabBarFindTabByID(tab_bar, tab_id) if tab_id ~= 0 then for n = 1, tab_bar.Tabs.Size do local tab = tab_bar.Tabs.Data[n] if tab.ID == tab_id then return tab end end end return nil end --- @param order int # 0-based visible order function ImGui.TabBarFindTabByOrder(tab_bar, order) if order < 0 or order >= tab_bar.Tabs.Size then return nil end return tab_bar.Tabs.Data[order + 1] end --- @return int # 0-based order function ImGui.TabBarGetTabOrder(tab_bar, tab) local i = tab_bar.Tabs:find_index(tab) return i and (i - 1) or -1 end function ImGui.TabBarFindMostRecentlySelectedTabForActiveWindow(tab_bar) local most_recently_selected_tab = nil for n = 1, tab_bar.Tabs.Size do local tab = tab_bar.Tabs.Data[n] if most_recently_selected_tab == nil or most_recently_selected_tab.LastFrameSelected < tab.LastFrameSelected then if tab.Window and tab.Window.WasActive then most_recently_selected_tab = tab end end end return most_recently_selected_tab end function ImGui.TabBarGetCurrentTab(tab_bar) if tab_bar.LastTabItemIdx < 0 or tab_bar.LastTabItemIdx >= tab_bar.Tabs.Size then return nil end return tab_bar.Tabs.Data[tab_bar.LastTabItemIdx + 1] end function ImGui.TabBarGetTabName(tab_bar, tab) if tab.Window then return tab.Window.Name end if tab.Name == nil then return "N/A" end return tab.Name end function ImGui.TabBarGetTabPos(tab_bar, tab) if bit32.band(tab.Flags, ImGuiTabItemFlags.SectionMask_) == 0 then return tab_bar.BarRect.Min + ImVec2(IM_TRUNC(tab.Offset - tab_bar.ScrollingAnim), 0.0) end return tab_bar.BarRect.Min + ImVec2(tab.Offset, 0.0) end function ImGui.TabBarAddTab(tab_bar, tab_flags, window) local g = ImGui.GetCurrentContext() IM_ASSERT(ImGui.TabBarFindTabByID(tab_bar, window.TabId) == nil) IM_ASSERT(g.CurrentTabBar ~= tab_bar) if not window.HasCloseButton then tab_flags = bit32.bor(tab_flags, ImGuiTabItemFlags.NoCloseButton) end local new_tab = ImGuiTabItem() new_tab.ID = window.TabId new_tab.Flags = tab_flags new_tab.LastFrameVisible = tab_bar.CurrFrameVisible if new_tab.LastFrameVisible == -1 then new_tab.LastFrameVisible = g.FrameCount - 1 end new_tab.Window = window tab_bar.Tabs:push_back(new_tab) end function ImGui.TabBarRemoveTab(tab_bar, tab_id) local tab = ImGui.TabBarFindTabByID(tab_bar, tab_id) if tab then tab_bar.Tabs:erase(tab_bar.Tabs:find_index(tab)) end if tab_bar.VisibleTabId == tab_id then tab_bar.VisibleTabId = 0 end if tab_bar.SelectedTabId == tab_id then tab_bar.SelectedTabId = 0 end if tab_bar.NextSelectedTabId == tab_id then tab_bar.NextSelectedTabId = 0 end end function ImGui.TabBarCloseTab(tab_bar, tab) if bit32.band(tab.Flags, ImGuiTabItemFlags.Button) ~= 0 then return end if bit32.band(tab.Flags, bit32.bor(ImGuiTabItemFlags.UnsavedDocument, ImGuiTabItemFlags.NoAssumedClosure)) == 0 then tab.WantClose = true if tab_bar.VisibleTabId == tab.ID then tab.LastFrameVisible = -1 tab_bar.SelectedTabId = 0 tab_bar.NextSelectedTabId = 0 end else if tab_bar.VisibleTabId ~= tab.ID then ImGui.TabBarQueueFocus(tab_bar, tab) end end end function ImGui.TabBarScrollClamp(tab_bar, scrolling) scrolling = ImMin(scrolling, tab_bar.WidthAllTabs - tab_bar.BarRect:GetWidth()) return ImMax(scrolling, 0.0) end function ImGui.TabBarScrollToTab(tab_bar, tab_id, sections) local tab = ImGui.TabBarFindTabByID(tab_bar, tab_id) if tab == nil then return end if bit32.band(tab.Flags, ImGuiTabItemFlags.Leading) ~= 0 then tab = tab_bar.Tabs.Data[sections[1].TabCount + 1] elseif bit32.band(tab.Flags, ImGuiTabItemFlags.Trailing) ~= 0 then tab = tab_bar.Tabs.Data[sections[1].TabCount + sections[2].TabCount + 1] end if tab == nil or bit32.band(tab.Flags, ImGuiTabItemFlags.SectionMask_) ~= 0 then return end local g = ImGui.GetCurrentContext() local margin = ImClamp(tab_bar.ScrollingRectMaxX - tab_bar.ScrollingRectMinX - tab.Width, g.Style.ItemInnerSpacing.x, g.FontSize * 1.0) local order = ImGui.TabBarGetTabOrder(tab_bar, tab) local scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections) local tab_x1 = tab.Offset - sections[1].Width + ((order > sections[1].TabCount - 1) and -margin or 0.0) local tab_x2 = tab.Offset - sections[1].Width + tab.Width + ((order + 1 < tab_bar.Tabs.Size - sections[3].TabCount) and margin or 1.0) tab_bar.ScrollingTargetDistToVisibility = 0.0 if tab_bar.ScrollingTarget > tab_x1 or (tab_x2 - tab_x1 >= scrollable_width) then tab_bar.ScrollingTargetDistToVisibility = ImMax(tab_bar.ScrollingAnim - tab_x2, 0.0) tab_bar.ScrollingTarget = tab_x1 elseif tab_bar.ScrollingTarget < tab_x2 - scrollable_width then tab_bar.ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar.ScrollingAnim, 0.0) tab_bar.ScrollingTarget = tab_x2 - scrollable_width end end --- TabBarQueueFocus(tab_bar, tab) or TabBarQueueFocus(tab_bar, tab_name) function ImGui.TabBarQueueFocus(tab_bar, tab) if type(tab) == "string" then IM_ASSERT(bit32.band(tab_bar.Flags, ImGuiTabBarFlags.DockNode) == 0) tab_bar.NextSelectedTabId = ImGui.TabBarCalcTabID(tab_bar, tab, nil) return end tab_bar.NextSelectedTabId = tab.ID end function ImGui.TabBarQueueReorder(tab_bar, tab, offset) IM_ASSERT(offset ~= 0) IM_ASSERT(tab_bar.ReorderRequestTabId == 0) tab_bar.ReorderRequestTabId = tab.ID tab_bar.ReorderRequestOffset = offset end function ImGui.TabBarQueueReorderFromMousePos(tab_bar, src_tab, mouse_pos) local g = ImGui.GetCurrentContext() IM_ASSERT(tab_bar.ReorderRequestTabId == 0) if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.Reorderable) == 0 then return end local tab_spacing = g.Style.ItemInnerSpacing.x local is_central_section = bit32.band(src_tab.Flags, ImGuiTabItemFlags.SectionMask_) == 0 local bar_offset = tab_bar.BarRect.Min.x - (is_central_section and tab_bar.ScrollingTarget or 0) local dir = ((bar_offset + src_tab.Offset) > mouse_pos.x) and -1 or 1 local src_idx = ImGui.TabBarGetTabOrder(tab_bar, src_tab) local dst_idx = src_idx local i = src_idx while i >= 0 and i < tab_bar.Tabs.Size do local dst_tab = tab_bar.Tabs.Data[i + 1] if bit32.band(dst_tab.Flags, ImGuiTabItemFlags.NoReorder) ~= 0 then break end if bit32.band(dst_tab.Flags, ImGuiTabItemFlags.SectionMask_) ~= bit32.band(src_tab.Flags, ImGuiTabItemFlags.SectionMask_) then break end dst_idx = i local x1 = bar_offset + dst_tab.Offset - tab_spacing local x2 = bar_offset + dst_tab.Offset + dst_tab.Width + tab_spacing if (dir < 0 and mouse_pos.x > x1) or (dir > 0 and mouse_pos.x < x2) then break end i = i + dir end if dst_idx ~= src_idx then ImGui.TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx) end end function ImGui.TabBarProcessReorder(tab_bar) local tab1 = ImGui.TabBarFindTabByID(tab_bar, tab_bar.ReorderRequestTabId) if tab1 == nil or bit32.band(tab1.Flags, ImGuiTabItemFlags.NoReorder) ~= 0 then return false end local tab1_order = ImGui.TabBarGetTabOrder(tab_bar, tab1) local tab2_order = tab1_order + tab_bar.ReorderRequestOffset if tab2_order < 0 or tab2_order >= tab_bar.Tabs.Size then return false end local tab2 = tab_bar.Tabs.Data[tab2_order + 1] if bit32.band(tab2.Flags, ImGuiTabItemFlags.NoReorder) ~= 0 then return false end if bit32.band(tab1.Flags, ImGuiTabItemFlags.SectionMask_) ~= bit32.band(tab2.Flags, ImGuiTabItemFlags.SectionMask_) then return false end -- Move tab1 to tab2's position, shifting the tabs in between table.remove(tab_bar.Tabs.Data, tab1_order + 1) table.insert(tab_bar.Tabs.Data, tab2_order + 1, tab1) if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.SaveSettings) ~= 0 then ImGui.MarkIniSettingsDirty() end return true end function ImGui.TabBarScrollingButtons(tab_bar) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local arrow_button_size = ImVec2(g.FontSize - 2.0, g.FontSize + g.Style.FramePadding.y * 2.0) local scrolling_buttons_width = arrow_button_size.x * 2.0 local backup_cursor_pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y) local select_dir = 0 local tc = g.Style.Colors[ImGuiCol.Text] local arrow_col = ImVec4(tc.x, tc.y, tc.z, tc.w * 0.5) ImGui.PushStyleColor(ImGuiCol.Text, arrow_col) ImGui.PushStyleColor(ImGuiCol.Button, ImVec4(0, 0, 0, 0)) ImGui.PushItemFlag(bit32.bor(ImGuiItemFlags.ButtonRepeat, ImGuiItemFlags.NoNav), true) local backup_repeat_delay = g.IO.KeyRepeatDelay local backup_repeat_rate = g.IO.KeyRepeatRate g.IO.KeyRepeatDelay = 0.250 g.IO.KeyRepeatRate = 0.200 local x = ImMax(tab_bar.BarRect.Min.x, tab_bar.BarRect.Max.x - scrolling_buttons_width) ImVec2_CopyV(window.DC.CursorPos, x, tab_bar.BarRect.Min.y) if ImGui.ArrowButtonEx("##<", ImGuiDir.Left, arrow_button_size, ImGuiButtonFlags.PressedOnClick) then select_dir = -1 end ImVec2_CopyV(window.DC.CursorPos, x + arrow_button_size.x, tab_bar.BarRect.Min.y) if ImGui.ArrowButtonEx("##>", ImGuiDir.Right, arrow_button_size, ImGuiButtonFlags.PressedOnClick) then select_dir = 1 end ImGui.PopItemFlag() ImGui.PopStyleColor(2) g.IO.KeyRepeatRate = backup_repeat_rate g.IO.KeyRepeatDelay = backup_repeat_delay local tab_to_scroll_to = nil if select_dir ~= 0 then local tab_item = ImGui.TabBarFindTabByID(tab_bar, tab_bar.SelectedTabId) if tab_item then local selected_order = ImGui.TabBarGetTabOrder(tab_bar, tab_item) local target_order = selected_order + select_dir while tab_to_scroll_to == nil do local idx = (target_order >= 0 and target_order < tab_bar.Tabs.Size) and target_order or selected_order tab_to_scroll_to = tab_bar.Tabs.Data[idx + 1] if bit32.band(tab_to_scroll_to.Flags, ImGuiTabItemFlags.Button) ~= 0 then target_order = target_order + select_dir selected_order = selected_order + select_dir if not (target_order < 0 or target_order >= tab_bar.Tabs.Size) then tab_to_scroll_to = nil end end end end end ImVec2_Copy(window.DC.CursorPos, backup_cursor_pos) tab_bar.BarRect.Max.x = tab_bar.BarRect.Max.x - (scrolling_buttons_width + 1.0) return tab_to_scroll_to end function ImGui.TabBarTabListPopupButton(tab_bar) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow local tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y local backup_cursor_pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y) ImVec2_CopyV(window.DC.CursorPos, tab_bar.BarRect.Min.x - g.Style.FramePadding.y, tab_bar.BarRect.Min.y) tab_bar.BarRect.Min.x = tab_bar.BarRect.Min.x + tab_list_popup_button_width local tc = g.Style.Colors[ImGuiCol.Text] ImGui.PushStyleColor(ImGuiCol.Text, ImVec4(tc.x, tc.y, tc.z, tc.w * 0.5)) ImGui.PushStyleColor(ImGuiCol.Button, ImVec4(0, 0, 0, 0)) local open = ImGui.BeginCombo("##v", nil, bit32.bor(ImGuiComboFlags.NoPreview, ImGuiComboFlags.HeightLargest)) ImGui.PopStyleColor(2) local tab_to_select = nil if open then for n = 1, tab_bar.Tabs.Size do local tab = tab_bar.Tabs.Data[n] if bit32.band(tab.Flags, ImGuiTabItemFlags.Button) == 0 then local tab_name = ImGui.TabBarGetTabName(tab_bar, tab) if ImGui.Selectable(tab_name, tab_bar.SelectedTabId == tab.ID) then tab_to_select = tab end end end ImGui.EndCombo() end ImVec2_Copy(window.DC.CursorPos, backup_cursor_pos) return tab_to_select end --------------------------------------------------------------------------------------- -- [SECTION] Widgets: BeginTabItem, EndTabItem, etc. --------------------------------------------------------------------------------------- --- @return bool visible, bool? p_open function ImGui.BeginTabItem(label, p_open, flags) if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() local window = g.CurrentWindow if window.SkipItems then return false, p_open end local tab_bar = g.CurrentTabBar IM_ASSERT(tab_bar ~= nil, "Needs to be called between BeginTabBar() and EndTabBar()!") IM_ASSERT(bit32.band(flags, ImGuiTabItemFlags.Button) == 0) local ret ret, p_open = ImGui.TabItemEx(tab_bar, label, p_open, flags, nil) if ret and bit32.band(flags, ImGuiTabItemFlags.NoPushId) == 0 then local tab = tab_bar.Tabs.Data[tab_bar.LastTabItemIdx + 1] ImGui.PushOverrideID(tab.ID) end return ret, p_open end function ImGui.EndTabItem() local g = ImGui.GetCurrentContext() local window = g.CurrentWindow if window.SkipItems then return end local tab_bar = g.CurrentTabBar IM_ASSERT(tab_bar ~= nil, "Needs to be called between BeginTabBar() and EndTabBar()!") IM_ASSERT(tab_bar.LastTabItemIdx >= 0) local tab = tab_bar.Tabs.Data[tab_bar.LastTabItemIdx + 1] if bit32.band(tab.Flags, ImGuiTabItemFlags.NoPushId) == 0 then ImGui.PopID() end end function ImGui.TabItemButton(label, flags) if flags == nil then flags = 0 end local g = ImGui.GetCurrentContext() local window = g.CurrentWindow if window.SkipItems then return false end local tab_bar = g.CurrentTabBar IM_ASSERT(tab_bar ~= nil, "Needs to be called between BeginTabBar() and EndTabBar()!") return (ImGui.TabItemEx(tab_bar, label, nil, bit32.bor(flags, ImGuiTabItemFlags.Button, ImGuiTabItemFlags.NoReorder), nil)) end function ImGui.TabItemSpacing(str_id, flags, width) local g = ImGui.GetCurrentContext() local window = g.CurrentWindow if window.SkipItems then return end local tab_bar = g.CurrentTabBar IM_ASSERT(tab_bar ~= nil, "Needs to be called between BeginTabBar() and EndTabBar()!") ImGui.SetNextItemWidth(width) ImGui.TabItemEx(tab_bar, str_id, nil, bit32.bor(flags or 0, ImGuiTabItemFlags.Button, ImGuiTabItemFlags.NoReorder, ImGuiTabItemFlags.Invisible), nil) end --- @return bool ret, bool? p_open function ImGui.TabItemEx(tab_bar, label, p_open, flags, docked_window) local g = ImGui.GetCurrentContext() if tab_bar.WantLayout then local backup_next_item_data = {} for k, v in pairs(g.NextItemData) do backup_next_item_data[k] = v end ImGui.TabBarLayout(tab_bar) for k, v in pairs(backup_next_item_data) do g.NextItemData[k] = v end end local window = g.CurrentWindow if window.SkipItems then return false, p_open end local style = g.Style local id = ImGui.TabBarCalcTabID(tab_bar, label, docked_window) if p_open ~= nil and not p_open then ImGui.ItemAdd(ImRect(), id, nil, ImGuiItemFlags.NoNav) return false, p_open end IM_ASSERT(p_open == nil or bit32.band(flags, ImGuiTabItemFlags.Button) == 0) IM_ASSERT(bit32.band(flags, bit32.bor(ImGuiTabItemFlags.Leading, ImGuiTabItemFlags.Trailing)) ~= bit32.bor(ImGuiTabItemFlags.Leading, ImGuiTabItemFlags.Trailing)) local has_p_open = (p_open ~= nil) if bit32.band(flags, ImGuiTabItemFlags.NoCloseButton) ~= 0 then has_p_open = false elseif not has_p_open then flags = bit32.bor(flags, ImGuiTabItemFlags.NoCloseButton) end local tab = ImGui.TabBarFindTabByID(tab_bar, id) local tab_is_new = false if tab == nil then tab = ImGuiTabItem() tab_bar.Tabs:push_back(tab) tab.ID = id tab_bar.TabsAddedNew = true tab_is_new = true end tab_bar.LastTabItemIdx = ImGui.TabBarGetTabOrder(tab_bar, tab) local size = ImGui.TabItemCalcSize(label, has_p_open or bit32.band(flags, ImGuiTabItemFlags.UnsavedDocument) ~= 0) tab.RequestedWidth = -1.0 if bit32.band(g.NextItemData.HasFlags, ImGuiNextItemDataFlags.HasWidth) ~= 0 then size.x = g.NextItemData.Width tab.RequestedWidth = size.x end if tab_is_new then tab.Width = ImMax(1.0, size.x) end tab.ContentWidth = size.x tab.BeginOrder = tab_bar.TabsActiveCount tab_bar.TabsActiveCount = tab_bar.TabsActiveCount + 1 local tab_bar_appearing = (tab_bar.PrevFrameVisible + 1 < g.FrameCount) local tab_bar_focused = bit32.band(tab_bar.Flags, ImGuiTabBarFlags.IsFocused) ~= 0 local tab_appearing = (tab.LastFrameVisible + 1 < g.FrameCount) local tab_just_unsaved = bit32.band(flags, ImGuiTabItemFlags.UnsavedDocument) ~= 0 and bit32.band(tab.Flags, ImGuiTabItemFlags.UnsavedDocument) == 0 local is_tab_button = bit32.band(flags, ImGuiTabItemFlags.Button) ~= 0 tab.LastFrameVisible = g.FrameCount tab.Flags = flags tab.Window = docked_window if docked_window ~= nil then IM_ASSERT(bit32.band(tab_bar.Flags, ImGuiTabBarFlags.DockNode) ~= 0) tab.NameOffset = -1 tab.Name = nil else tab.NameOffset = 0 tab.Name = label end if not is_tab_button then if tab_appearing and bit32.band(tab_bar.Flags, ImGuiTabBarFlags.AutoSelectNewTabs) ~= 0 and tab_bar.NextSelectedTabId == 0 then if not tab_bar_appearing or tab_bar.SelectedTabId == 0 then ImGui.TabBarQueueFocus(tab_bar, tab) end end if bit32.band(flags, ImGuiTabItemFlags.SetSelected) ~= 0 and tab_bar.SelectedTabId ~= id then ImGui.TabBarQueueFocus(tab_bar, tab) end end local tab_contents_visible = (tab_bar.VisibleTabId == id) if tab_contents_visible then tab_bar.VisibleTabWasSubmitted = true end if not tab_contents_visible and tab_bar.SelectedTabId == 0 and tab_bar_appearing and docked_window == nil then if tab_bar.Tabs.Size == 1 and bit32.band(tab_bar.Flags, ImGuiTabBarFlags.AutoSelectNewTabs) == 0 then tab_contents_visible = true end end if tab_appearing and (not tab_bar_appearing or tab_is_new) then ImGui.ItemAdd(ImRect(), id, nil, ImGuiItemFlags.NoNav) if is_tab_button then return false, p_open end return tab_contents_visible, p_open end if tab_bar.SelectedTabId == id then tab.LastFrameSelected = g.FrameCount end local backup_main_cursor_pos = ImVec2(window.DC.CursorPos.x, window.DC.CursorPos.y) local is_central_section = bit32.band(tab.Flags, ImGuiTabItemFlags.SectionMask_) == 0 size.x = tab.Width local pos = ImGui.TabBarGetTabPos(tab_bar, tab) ImVec2_Copy(window.DC.CursorPos, pos) local bb = ImRect(pos, pos + size) local want_clip_rect = is_central_section and (bb.Min.x < tab_bar.ScrollingRectMinX or bb.Max.x > tab_bar.ScrollingRectMaxX) if want_clip_rect then ImGui.PushClipRect(ImVec2(ImClamp(bb.Min.x, tab_bar.ScrollingRectMinX, tab_bar.ScrollingRectMaxX), bb.Min.y - 1), ImVec2(tab_bar.ScrollingRectMaxX, bb.Max.y), true) end local backup_cursor_max_pos = ImVec2(window.DC.CursorMaxPos.x, window.DC.CursorMaxPos.y) ImGui.ItemSize(bb:GetSize(), style.FramePadding.y) ImVec2_Copy(window.DC.CursorMaxPos, backup_cursor_max_pos) if not ImGui.ItemAdd(bb, id) then if want_clip_rect then ImGui.PopClipRect() end ImVec2_Copy(window.DC.CursorPos, backup_main_cursor_pos) return tab_contents_visible, p_open end local button_flags = bit32.bor(is_tab_button and ImGuiButtonFlags.PressedOnClickRelease or ImGuiButtonFlags.PressedOnClick, ImGuiButtonFlags.AllowOverlap) if g.DragDropActive and not ImGuiPayload_IsDataType(g.DragDropPayload, IMGUI_PAYLOAD_TYPE_WINDOW) then button_flags = bit32.bor(button_flags, ImGuiButtonFlags.PressedOnDragDropHold) end local hovered, held, pressed if bit32.band(flags, ImGuiTabItemFlags.Invisible) ~= 0 then hovered, held, pressed = false, false, false else pressed, hovered, held = ImGui.ButtonBehavior(bb, id, button_flags) end if pressed and not is_tab_button then ImGui.TabBarQueueFocus(tab_bar, tab) end if held and docked_window and g.ActiveId == id and g.ActiveIdIsJustActivated then g.ActiveIdWindow = docked_window end local node = docked_window and docked_window.DockNode or nil local single_floating_window_node = node and node:IsFloatingNode() and (node.Windows.Size == 1) if held and single_floating_window_node and ImGui.IsMouseDragging(0, 0.0) then ImGui.StartMouseMovingWindow(docked_window) elseif held and not tab_appearing and ImGui.IsMouseDragging(0) then local drag_dir = 0 local drag_distance_from_edge_x = 0.0 if not g.DragDropActive and (bit32.band(tab_bar.Flags, ImGuiTabBarFlags.Reorderable) ~= 0 or docked_window ~= nil) then if g.IO.MouseDelta.x < 0.0 and g.IO.MousePos.x < bb.Min.x then drag_dir = -1 drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x ImGui.TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos) elseif g.IO.MouseDelta.x > 0.0 and g.IO.MousePos.x > bb.Max.x then drag_dir = 1 drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x ImGui.TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos) end end local can_undock = docked_window ~= nil and bit32.band(docked_window.Flags, ImGuiWindowFlags.NoMove) == 0 and bit32.band(node.MergedFlags, ImGuiDockNodeFlags.NoUndocking) == 0 if can_undock then local undocking_tab = (g.DragDropActive and g.DragDropPayload.SourceId == id) if not undocking_tab then local threshold_base = g.FontSize local threshold_x = threshold_base * 2.2 local threshold_y = (threshold_base * 1.5) + ImClamp((math.abs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0) * 0.20, 0.0, threshold_base * 4.0) local distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y) if distance_from_edge_y >= threshold_y then undocking_tab = true end if drag_distance_from_edge_x > threshold_x then if (drag_dir < 0 and ImGui.TabBarGetTabOrder(tab_bar, tab) == 0) or (drag_dir > 0 and ImGui.TabBarGetTabOrder(tab_bar, tab) == tab_bar.Tabs.Size - 1) then undocking_tab = true end end end if undocking_tab then ImGui.DockContextQueueUndockWindow(g, docked_window) g.MovingWindow = docked_window ImGui.SetActiveID(g.MovingWindow.MoveId, g.MovingWindow) ImVec2_Copy(g.ActiveIdClickOffset, g.ActiveIdClickOffset - (g.MovingWindow.Pos - bb.Min)) g.ActiveIdNoClearOnFocusLoss = true ImGui.SetActiveIdUsingAllKeyboardKeys() end end end local is_visible = bit32.band(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.Visible) ~= 0 and bit32.band(flags, ImGuiTabItemFlags.Invisible) == 0 if is_visible then local display_draw_list = window.DrawList local col_idx if held or hovered then col_idx = ImGuiCol.TabHovered elseif tab_contents_visible then col_idx = tab_bar_focused and ImGuiCol.TabSelected or ImGuiCol.TabDimmedSelected else col_idx = tab_bar_focused and ImGuiCol.Tab or ImGuiCol.TabDimmed end ImGui.TabItemBackground(display_draw_list, bb, flags, ImGui.GetColorU32(col_idx)) if tab_contents_visible and bit32.band(tab_bar.Flags, ImGuiTabBarFlags.DrawSelectedOverline) ~= 0 and style.TabBarOverlineSize > 0.0 then local tl = ImVec2(bb.Min.x, bb.Min.y + style.TabBarOverlineSize * 0.5) local tr = ImVec2(bb.Max.x, bb.Min.y + style.TabBarOverlineSize * 0.5) local overline_col = ImGui.GetColorU32(tab_bar_focused and ImGuiCol.TabSelectedOverline or ImGuiCol.TabDimmedSelectedOverline) if style.TabRounding > 0.0 then local rounding = style.TabRounding display_draw_list:PathArcToFast(tl + ImVec2(rounding, rounding), rounding, 7, 9) display_draw_list:PathArcToFast(tr + ImVec2(-rounding, rounding), rounding, 9, 11) display_draw_list:PathStroke(overline_col, style.TabBarOverlineSize) else display_draw_list:AddLine(tl, tr, overline_col, style.TabBarOverlineSize) end end ImGui.RenderNavCursor(bb, id) local hovered_unblocked = ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByPopup) if tab_bar.SelectedTabId ~= tab.ID and hovered_unblocked and (ImGui.IsMouseClicked(1) or ImGui.IsMouseReleased(1)) and not is_tab_button then ImGui.TabBarQueueFocus(tab_bar, tab) end if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.NoCloseWithMiddleMouseButton) ~= 0 then flags = bit32.bor(flags, ImGuiTabItemFlags.NoCloseWithMiddleMouseButton) end local close_button_id = has_p_open and ImGui.GetIDWithSeed("#CLOSE", nil, docked_window and docked_window.ID or id) or 0 local label_flags = tab_just_unsaved and bit32.band(flags, bit32.bnot(ImGuiTabItemFlags.UnsavedDocument)) or flags local just_closed, text_clipped = ImGui.TabItemLabelAndCloseButton(display_draw_list, bb, label_flags, tab_bar.FramePadding, label, id, close_button_id, tab_contents_visible) if just_closed and has_p_open then p_open = false ImGui.TabBarCloseTab(tab_bar, tab) end if docked_window and (hovered or g.HoveredId == close_button_id) then g.LastItemData.StatusFlags = bit32.bor(g.LastItemData.StatusFlags, ImGuiItemStatusFlags.HoveredWindow) end if text_clipped and g.HoveredId == id and not held then if bit32.band(tab_bar.Flags, ImGuiTabBarFlags.NoTooltip) == 0 and bit32.band(tab.Flags, ImGuiTabItemFlags.NoTooltip) == 0 then local label_end = ImGui.FindRenderedTextEnd(label) ImGui.SetItemTooltip("%s", string.sub(label, 1, label_end - 1)) end end end if want_clip_rect then ImGui.PopClipRect() end ImVec2_Copy(window.DC.CursorPos, backup_main_cursor_pos) if is_tab_button then return pressed, p_open end return tab_contents_visible, p_open end function ImGui.SetTabItemClosed(label) local g = ImGui.GetCurrentContext() local is_within_manual_tab_bar = g.CurrentTabBar and bit32.band(g.CurrentTabBar.Flags, ImGuiTabBarFlags.DockNode) == 0 if is_within_manual_tab_bar then local tab_bar = g.CurrentTabBar local tab_id = ImGui.TabBarCalcTabID(tab_bar, label, nil) local tab = ImGui.TabBarFindTabByID(tab_bar, tab_id) if tab then tab.WantClose = true end else local window = ImGui.FindWindowByName(label) if window and window.DockIsActive then local node = window.DockNode if node then local tab_id = ImGui.TabBarCalcTabID(node.TabBar, label, window) ImGui.TabBarRemoveTab(node.TabBar, tab_id) window.DockTabWantClose = true end end end end --- TabItemCalcSize(label, has_close_button_or_unsaved_marker) or TabItemCalcSize(window) function ImGui.TabItemCalcSize(label, has_close_button_or_unsaved_marker) if type(label) == "table" then local window = label return ImGui.TabItemCalcSize(window.Name, window.HasCloseButton or bit32.band(window.Flags, ImGuiWindowFlags.UnsavedDocument) ~= 0) end local g = ImGui.GetCurrentContext() local label_size = ImGui.CalcTextSize(label, nil, true) local size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0) if has_close_button_or_unsaved_marker then size.x = size.x + g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize) else size.x = size.x + g.Style.FramePadding.x + 1.0 end return ImVec2(ImMin(size.x, ImGui.TabBarCalcMaxTabWidth()), size.y) end function ImGui.TabItemBackground(draw_list, bb, flags, col) local g = ImGui.GetCurrentContext() local width = bb:GetWidth() IM_ASSERT(width > 0.0) local rounding = ImMax(0.0, ImMin(bit32.band(flags, ImGuiTabItemFlags.Button) ~= 0 and g.Style.FrameRounding or g.Style.TabRounding, width * 0.5 - 1.0)) local y1 = bb.Min.y + 1.0 local y2 = bb.Max.y - g.Style.TabBarBorderSize draw_list:AddRectFilled(ImVec2(bb.Min.x, y1), ImVec2(bb.Max.x, y2), col, rounding, ImDrawFlags.RoundCornersTop) if g.Style.TabBorderSize > 0.0 then draw_list:PathLineTo(ImVec2(bb.Min.x, y2)) draw_list:PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9) draw_list:PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12) draw_list:PathLineTo(ImVec2(bb.Max.x, y2)) draw_list:PathStroke(ImGui.GetColorU32(ImGuiCol.Border), g.Style.TabBorderSize) end end --- @return bool just_closed, bool text_clipped function ImGui.TabItemLabelAndCloseButton(draw_list, bb, flags, frame_padding, label, tab_id, close_button_id, is_contents_visible) local g = ImGui.GetCurrentContext() local label_end = ImGui.FindRenderedTextEnd(label) local label_size = ImGui.CalcTextSize(label, label_end, false) if bb:GetWidth() <= 1.0 then return false, false end local text_ellipsis_clip_bb = ImRect(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y) local text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_ellipsis_clip_bb.Max.x local button_sz = g.FontSize local button_pos = ImVec2(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y) local close_button_pressed = false local close_button_visible = false local is_hovered = g.HoveredId == tab_id or g.HoveredId == close_button_id or g.ActiveId == tab_id or g.ActiveId == close_button_id if close_button_id ~= 0 then if is_contents_visible then close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0) or (is_hovered and bb:GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected)) else close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0) or (is_hovered and bb:GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected)) end end local unsaved_marker_visible = bit32.band(flags, ImGuiTabItemFlags.UnsavedDocument) ~= 0 and (button_pos.x + button_sz <= bb.Max.x) and (not close_button_visible or not is_hovered) if unsaved_marker_visible then local bullet_pos = button_pos + ImVec2(button_sz, button_sz) * 0.5 ImGui.RenderBullet(draw_list, bullet_pos, ImGui.GetColorU32(ImGuiCol.UnsavedMarker)) elseif close_button_visible then local last_item_backup = ImGuiLastItemData() ImGuiLastItemData_Copy(last_item_backup, g.LastItemData) if ImGui.CloseButton(close_button_id, button_pos) then close_button_pressed = true end ImGuiLastItemData_Copy(g.LastItemData, last_item_backup) if is_hovered and bit32.band(flags, ImGuiTabItemFlags.NoCloseWithMiddleMouseButton) == 0 and ImGui.IsMouseClicked(2) then close_button_pressed = true end end local ellipsis_max_x = text_ellipsis_clip_bb.Max.x if close_button_visible or unsaved_marker_visible then local visible_without_hover = unsaved_marker_visible or ((is_contents_visible and g.Style.TabCloseButtonMinWidthSelected or g.Style.TabCloseButtonMinWidthUnselected) < 0.0) if visible_without_hover then text_ellipsis_clip_bb.Max.x = text_ellipsis_clip_bb.Max.x - button_sz * 0.90 ellipsis_max_x = ellipsis_max_x - button_sz * 0.90 else text_ellipsis_clip_bb.Max.x = text_ellipsis_clip_bb.Max.x - button_sz * 1.00 end end ImGui.LogSetNextTextDecoration("/", "\\") ImGui.RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, label_end, label_size) return close_button_pressed, text_clipped end end --[[ [SECTION] Widgets: BeginTabBar, EndTabBar, etc. (was imgui_tabs.lua) ]] return true -- [Roblox] ModuleScripts must return exactly one value end __FILES['imstb_rectpack.lua'] = function() --- Dear ImGui -- This is a Lua port of original `imstb_rectpack.h` -- ALL TABLES IN THIS FILE ARE 1-BASED! -- Avoids table creation when possible --- The `prev_link` can be stbrp_context or stbrp_node --- @diagnostic disable local bit32 = bit32 local STBRP_SORT = table.sort local STBRP_ASSERT = assert local STBRP__NOTUSED = function(_) end local STBRP__MAXVAL = 0x7fffffff --- @enum STBRP_HEURISTIC_Skyline local STBRP_HEURISTIC_Skyline = { default = 0, BL_sortHeight = 0, BF_sortHeight = 1 } local STBRP__INIT_skyline = 1 --- @enum STBRP__PREV_LINK_TYPE local STBRP__PREV_LINK_TYPE = { ACTIVE_HEAD = 0, NEXT = 1 } --- @alias stbrp_coord int --- @class stbrp_rect --- @field id int --- @field w stbrp_coord --- @field h stbrp_coord --- @field x stbrp_coord --- @field y stbrp_coord --- @field was_packed int --- @return stbrp_rect --- @nodiscard local function stbrp_rect() return { id = 0, w = 0, h = 0, x = 0, y = 0, was_packed = 0 } end --- @class stbrp_node --- @field x stbrp_coord --- @field y stbrp_coord --- @field next stbrp_node --- @return stbrp_node --- @nodiscard local function stbrp_node() return { x = 0, y = 0, next = nil } end --- @class stbrp_context --- @field width int --- @field height int --- @field align int --- @field init_mode int --- @field heuristic int --- @field num_nodes int --- @field active_head stbrp_node --- @field free_head stbrp_node --- @field extra stbrp_node[] --- @return stbrp_context --- @nodiscard local function stbrp_context() return { width = 0, height = 0, align = 0, init_mode = 0, heuristic = 0, num_nodes = 0, active_head = nil, free_head = nil, extra = {stbrp_node(), stbrp_node()} } end --- @class stbrp__findresult --- @field x int --- @field y int --- @field prev_link? table --- @field prev_link_type? int --- @return stbrp__findresult local function stbrp__findresult() return { x = 0, y = 0, prev_link = nil, prev_link_type = nil } end -------------------------- -------------------------- --- --- IMPLEMENTATION SECTION --- --- --- @param context stbrp_context --- @param heuristic int local function stbrp_setup_heuristic(context, heuristic) if context.init_mode == STBRP__INIT_skyline then STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline.BL_sortHeight or heuristic == STBRP_HEURISTIC_Skyline.BF_sortHeight) context.heuristic = heuristic else STBRP_ASSERT(false) end end --- @param context stbrp_context --- @param allow_out_of_mem boolean local function stbrp_setup_allow_out_of_mem(context, allow_out_of_mem) if allow_out_of_mem then context.align = 1 else context.align = (context.width + context.num_nodes - 1) / context.num_nodes end end --- @param context stbrp_context --- @param width int --- @param height int --- @param nodes stbrp_node[] --- @param num_nodes int function stbrp_init_target(context, width, height, nodes, num_nodes) for i = 1, num_nodes - 1 do nodes[i].next = nodes[i + 1] end nodes[num_nodes].next = nil context.init_mode = STBRP__INIT_skyline context.heuristic = STBRP_HEURISTIC_Skyline.default context.free_head = nodes[1] context.active_head = context.extra[1] context.width = width context.height = height context.num_nodes = num_nodes stbrp_setup_allow_out_of_mem(context, false) context.extra[1].x = 0 context.extra[1].y = 0 context.extra[1].next = context.extra[2] context.extra[2].x = width context.extra[2].y = bit32.lshift(1, 30) context.extra[2].next = nil end --- @param c stbrp_context --- @param first stbrp_node --- @param x0 int --- @param width int --- @return int, int local function stbrp__skyline_find_min_y(c, first, x0, width) local node = first local x1 = x0 + width STBRP__NOTUSED(c) STBRP_ASSERT(first.x <= x0) STBRP_ASSERT(node.next.x > x0) STBRP_ASSERT(node.x <= x0) local min_y = 0 local waste_area = 0 local visited_width = 0 while node.x < x1 do if node.y > min_y then waste_area = waste_area + visited_width * (node.y - min_y) min_y = node.y if node.x < x0 then visited_width = visited_width + node.next.x - x0 else visited_width = visited_width + node.next.x - node.x end else local under_width = node.next.x - node.x if under_width + visited_width > width then under_width = width - visited_width end waste_area = waste_area + under_width * (min_y - node.y) visited_width = visited_width + under_width end node = node.next end return min_y, waste_area end --- @param c stbrp_context --- @param width int --- @param height int --- @return stbrp__findresult local function stbrp__skyline_find_best_pos(c, width, height) local best_waste = bit32.lshift(1, 30) local best_x = 0 local best_y = bit32.lshift(1, 30) local fr = stbrp__findresult() local best_prev_link = nil local best_prev_link_type = nil width = width + c.align - 1 width = width - width % c.align STBRP_ASSERT(width % c.align == 0) if width > c.width or height > c.height then fr.prev_link = nil fr.prev_link_type = nil fr.x = 0 fr.y = 0 return fr end local prev_link = c local prev_link_type = STBRP__PREV_LINK_TYPE.ACTIVE_HEAD local node = c.active_head while (node.x + width <= c.width) do local y, waste = stbrp__skyline_find_min_y(c, node, node.x, width) if c.heuristic == STBRP_HEURISTIC_Skyline.BL_sortHeight then if y < best_y then best_y = y best_prev_link = prev_link best_prev_link_type = prev_link_type best_x = node.x end else if y + height <= c.height then if y < best_y or (y == best_y and waste < best_waste) then best_y = y best_waste = waste best_prev_link = prev_link best_prev_link_type = prev_link_type best_x = node.x end end end prev_link = node prev_link_type = STBRP__PREV_LINK_TYPE.NEXT node = node.next end if c.heuristic == STBRP_HEURISTIC_Skyline.BF_sortHeight then local tail = c.active_head local node_scan = c.active_head local prev_link_scan = c local prev_link_scan_type = STBRP__PREV_LINK_TYPE.ACTIVE_HEAD while tail and tail.x < width do tail = tail.next end while tail do local xpos = tail.x - width STBRP_ASSERT(xpos >= 0) while node_scan.next and node_scan.next.x <= xpos do prev_link_scan = node_scan prev_link_scan_type = STBRP__PREV_LINK_TYPE.NEXT node_scan = node_scan.next end if node_scan then STBRP_ASSERT(node_scan.next.x > xpos and node_scan.x <= xpos) local y, waste = stbrp__skyline_find_min_y(c, node_scan, xpos, width) if y + height <= c.height then if y <= best_y then if y < best_y or waste < best_waste or (waste == best_waste and xpos < best_x) then best_x = xpos best_y = y best_waste = waste best_prev_link = prev_link_scan best_prev_link_type = prev_link_scan_type end end end end tail = tail.next end end fr.prev_link = best_prev_link fr.prev_link_type = best_prev_link_type fr.x = best_x fr.y = best_y return fr end --- @param context stbrp_context --- @param width int --- @param height int --- @return stbrp__findresult local function stbrp__skyline_pack_rectangle(context, width, height) local res = stbrp__skyline_find_best_pos(context, width, height) if res.prev_link == nil or res.y + height > context.height or context.free_head == nil then res.prev_link = nil res.prev_link_type = nil return res end local node = context.free_head node.x = res.x node.y = res.y + height context.free_head = node.next local cur if res.prev_link_type == STBRP__PREV_LINK_TYPE.ACTIVE_HEAD then cur = res.prev_link.active_head else cur = res.prev_link.next end if cur.x < res.x then local next = cur.next cur.next = node cur = next else if res.prev_link_type == STBRP__PREV_LINK_TYPE.ACTIVE_HEAD then res.prev_link.active_head = node else res.prev_link.next = node end end while cur.next and cur.next.x <= res.x + width do local next = cur.next cur.next = context.free_head context.free_head = cur cur = next end node.next = cur if cur.x < res.x + width then cur.x = res.x + width end return res end --- @param a stbrp_rect --- @param b stbrp_rect --- @return bool --- @package local function rect_height_compare(a, b) if a.h > b.h then return true elseif a.h < b.h then return false else return a.w > b.w end end --- @param a stbrp_rect --- @param b stbrp_rect --- @return bool --- @package local function rect_original_order(a, b) return a.was_packed < b.was_packed end --- @param context stbrp_context --- @param rects stbrp_rect[] --- @param num_rects int --- @return int local function stbrp_pack_rects(context, rects, num_rects) local all_rects_packed = 1 for i = 1, num_rects do rects[i].was_packed = (i - 1) end STBRP_SORT(rects, rect_height_compare) for i = 1, num_rects do if rects[i].w == 0 or rects[i].h == 0 then rects[i].x = 0 rects[i].y = 0 else local fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h) if fr.prev_link then rects[i].x = fr.x rects[i].y = fr.y else rects[i].x = STBRP__MAXVAL rects[i].y = STBRP__MAXVAL end end end STBRP_SORT(rects, rect_original_order) for i = 1, num_rects do rects[i].was_packed = (rects[i].x == STBRP__MAXVAL and rects[i].y == STBRP__MAXVAL) and 0 or 1 if rects[i].was_packed == 0 then all_rects_packed = 0 end end return all_rects_packed end return { context = stbrp_context, rect = stbrp_rect, node = stbrp_node, pack_rects = stbrp_pack_rects, init_target = stbrp_init_target, setup_allow_out_of_mem = stbrp_setup_allow_out_of_mem, setup_heuristic = stbrp_setup_heuristic } end __FILES['imstb_textedit.lua'] = function() --- Dear ImGui -- This is a Lua port of original `imstb_textedit.h` -- ALL TABLES IN THIS FILE ARE 1-BASED! -- Character Indexing: -- idx=n, the n'th char (1-based) -- Cursor Indexing: -- idx=n, the position before the n'th char -- idx=n+1, the position after the n'th char -- Symbols that must be defined before using this: local STB_TEXTEDIT_STRINGLEN = ImStb.TEXTEDIT_STRINGLEN local STB_TEXTEDIT_GETCHAR = ImStb.TEXTEDIT_GETCHAR local STB_TEXTEDIT_GETWIDTH = ImStb.TEXTEDIT_GETWIDTH local STB_TEXTEDIT_LAYOUTROW = ImStb.TEXTEDIT_LAYOUTROW local IMSTB_TEXTEDIT_GETNEXTCHARINDEX = ImStb.TEXTEDIT_GETNEXTCHARINDEX local IMSTB_TEXTEDIT_GETPREVCHARINDEX = ImStb.TEXTEDIT_GETPREVCHARINDEX local STB_TEXTEDIT_MOVEWORDLEFT = ImStb.TEXTEDIT_MOVEWORDLEFT local STB_TEXTEDIT_MOVEWORDRIGHT = ImStb.TEXTEDIT_MOVEWORDRIGHT local STB_TEXTEDIT_MOVELINESTART = ImStb.TEXTEDIT_MOVELINESTART local STB_TEXTEDIT_MOVELINEEND = ImStb.TEXTEDIT_MOVELINEEND local STB_TEXTEDIT_DELETECHARS = ImStb.TEXTEDIT_DELETECHARS local STB_TEXTEDIT_INSERTCHARS = ImStb.TEXTEDIT_INSERTCHARS STB_TEXTEDIT_NEWLINE = 10 STB_TEXTEDIT_K_LEFT = 0x200000 -- keyboard input to move cursor left STB_TEXTEDIT_K_RIGHT = 0x200001 -- keyboard input to move cursor right STB_TEXTEDIT_K_UP = 0x200002 -- keyboard input to move cursor up STB_TEXTEDIT_K_DOWN = 0x200003 -- keyboard input to move cursor down STB_TEXTEDIT_K_LINESTART = 0x200004 -- keyboard input to move cursor to start of line STB_TEXTEDIT_K_LINEEND = 0x200005 -- keyboard input to move cursor to end of line STB_TEXTEDIT_K_TEXTSTART = 0x200006 -- keyboard input to move cursor to start of text STB_TEXTEDIT_K_TEXTEND = 0x200007 -- keyboard input to move cursor to end of text STB_TEXTEDIT_K_DELETE = 0x200008 -- keyboard input to delete selection or character under cursor STB_TEXTEDIT_K_BACKSPACE = 0x200009 -- keyboard input to delete selection or character left of cursor STB_TEXTEDIT_K_UNDO = 0x20000A -- keyboard input to perform undo STB_TEXTEDIT_K_REDO = 0x20000B -- keyboard input to perform redo STB_TEXTEDIT_K_WORDLEFT = 0x20000C -- keyboard input to move cursor left one word STB_TEXTEDIT_K_WORDRIGHT = 0x20000D -- keyboard input to move cursor right one word STB_TEXTEDIT_K_PGUP = 0x20000E -- keyboard input to move cursor up a page STB_TEXTEDIT_K_PGDOWN = 0x20000F -- keyboard input to move cursor down a page STB_TEXTEDIT_K_SHIFT = 0x400000 IMSTB_TEXTEDIT_UNDOSTATECOUNT = 99 local IMSTB_TEXTEDIT_UNDOCHARCOUNT = 999 local IMSTB_TEXTEDIT_memmove = ImStb.TEXTEDIT_memmove local stb_text_undo local stb_text_redo ---------------------------------------------------------------- ---------------------------------------------------------------- --- --- STB_TexteditState --- --- Definition of STB_TexteditState which you should store --- per-textfield; it includes cursor position, selection state, --- and undo state. --- --- @alias IMSTB_TEXTEDIT_POSITIONTYPE int --- @alias IMSTB_TEXTEDIT_CHARTYPE char --- @alias STB_TEXTEDIT_KEYTYPE int --- @class StbUndoRecord --- @field where IMSTB_TEXTEDIT_POSITIONTYPE --- @field insert_length IMSTB_TEXTEDIT_POSITIONTYPE --- @field delete_length IMSTB_TEXTEDIT_POSITIONTYPE --- @field char_storage int --- @return StbUndoRecord --- @nodiscard local function StbUndoRecord() return { where = 1, insert_length = 0, delete_length = 0, char_storage = 1 } end --- @class StbUndoState --- @field undo_rec StbUndoRecord[] # size = IMSTB_TEXTEDIT_UNDOSTATECOUNT --- @field undo_char IMSTB_TEXTEDIT_CHARTYPE[] # size = IMSTB_TEXTEDIT_UNDOCHARCOUNT --- @field undo_point short # next available slot --- @field redo_point short # next available slot --- @field undo_char_point int # next available slot --- @field redo_char_point int # next available slot --- @return StbUndoState --- @nodiscard local function StbUndoState() local undo_rec = {} for i = 1, IMSTB_TEXTEDIT_UNDOSTATECOUNT do undo_rec[i] = StbUndoRecord() end local undo_char = {} for i = 1, IMSTB_TEXTEDIT_UNDOCHARCOUNT do undo_char[i] = 0 end return { undo_rec = undo_rec, undo_char = undo_char, undo_point = 1, redo_point = 1, undo_char_point = 1, redo_char_point = 1 } end --- @class STB_TexteditState --- @field cursor int # position of the text cursor within the string --- @field select_start int # selection start point --- @field select_end int --- @field insert_mode bool --- @field row_count_per_page int --- @field cursor_at_end_of_line bool # not implemented yet --- @field initialized bool --- @field has_preferred_x bool --- @field single_line bool --- @field padding1 unsigned_char --- @field padding2 unsigned_char --- @field padding3 unsigned_char --- @field preferred_x float --- @field undostate StbUndoState --- @return STB_TexteditState --- @nodiscard function STB_TexteditState() return { cursor = 0, select_start = 0, select_end = 0, insert_mode = false, row_count_per_page = 0, cursor_at_end_of_line = false, initialized = false, has_preferred_x = false, single_line = false, padding1 = 0, padding2 = 0, padding3 = 0, preferred_x = 0.0, undostate = StbUndoState() } end --- @param s STB_TexteditState local function STB_TEXT_HAS_SELECTION(s) return s.select_start ~= s.select_end end --- @class StbTexteditRow --- @field x0 float # starting x location --- @field x1 float # end x location --- @field baseline_y_delta float # position of baseline relative to previous row's baseline --- @field ymin float # height of row above baseline --- @field ymax float # height of row below baseline --- @field num_chars int --- @return StbTexteditRow --- @nodiscard local function StbTexteditRow() return { x0 = 0.0, x1 = 0.0, baseline_y_delta = 0.0, ymin = 0.0, ymax = 0.0, num_chars = 0 } end --- @param r StbTexteditRow local function StbTexteditRow_Reset(r) r.x0 = 0.0 r.x1 = 0.0 r.baseline_y_delta = 0.0 r.ymin = 0.0 r.ymax = 0.0 r.num_chars = 0 end ---------------------------------------- ---------------------------------------- --- --- Implementation --- --- local stb_text_locate_coord do -- only create once, reuse later local r = StbTexteditRow() --- traverse the layout to locate the nearest character to a display position --- @param str IMSTB_TEXTEDIT_STRING --- @param x float --- @param y float --- @return int idx --- @return bool side_on_line function stb_text_locate_coord(str, x, y) local n = STB_TEXTEDIT_STRINGLEN(str) local base_y = 0 local prev_x StbTexteditRow_Reset(r) local out_side_on_line = false -- search rows to find one that straddles 'y' local i = 1 while i <= n do STB_TEXTEDIT_LAYOUTROW(r, str, i) if r.num_chars <= 0 then return n + 1, out_side_on_line end if i == 1 and y < base_y + r.ymin then return 1, out_side_on_line end if y < base_y + r.ymax then break end i = i + r.num_chars base_y = base_y + r.baseline_y_delta end -- below all text, return 'after' last character if i > n then out_side_on_line = true return n + 1, out_side_on_line end -- check if it's before the beginning of the line if x < r.x0 then return i, out_side_on_line end -- check if it's before the end of the line if x < r.x1 then -- search characters in row for one that straddles 'x' prev_x = r.x0 local k = 1 while k <= r.num_chars do local w = STB_TEXTEDIT_GETWIDTH(str, i, k) if x < prev_x + w then out_side_on_line = (k == 1) and false or true if x < prev_x + w / 2 then return k + i - 1, out_side_on_line else return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k - 1), out_side_on_line end end prev_x = prev_x + w k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k - 1) - i + 1 end -- shouldn't happen, but if it does, fall through to end-of-line case end -- if the last character is a newline, return that. otherwise return 'after' the last character out_side_on_line = true if STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) == STB_TEXTEDIT_NEWLINE then return i + r.num_chars - 1, out_side_on_line else return i + r.num_chars, out_side_on_line end end end local stb_textedit_click do local r = StbTexteditRow() -- API click: on mouse down, move the cursor to the clicked location, and reset the selection --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param x float --- @param y float function stb_textedit_click(str, state, x, y) -- In single-line mode, just always make y = 0. This lets the drag keep working if the mouse -- goes off the top or bottom of the text local side_on_line if state.single_line then StbTexteditRow_Reset(r) STB_TEXTEDIT_LAYOUTROW(r, str, 1) y = r.ymin end state.cursor, side_on_line = stb_text_locate_coord(str, x, y) state.select_start = state.cursor state.select_end = state.cursor state.has_preferred_x = false str.LastMoveDirectionLR = side_on_line and ImGuiDir.Right or ImGuiDir.Left end end local stb_textedit_drag do local r = StbTexteditRow() -- API drag: on mouse drag, move the cursor and selection endpoint to the clicked location --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param x float --- @param y float function stb_textedit_drag(str, state, x, y) local p = 1 local side_on_line -- In single-line mode, just always make y = 0. This lets the drag keep working if the mouse -- goes off the top or bottom of the text if state.single_line then StbTexteditRow_Reset(r) STB_TEXTEDIT_LAYOUTROW(r, str, 1) y = r.ymin end if state.select_start == state.select_end then state.select_start = state.cursor end p, side_on_line = stb_text_locate_coord(str, x, y) state.cursor = p state.select_end = p str.LastMoveDirectionLR = (side_on_line ~= false) and ImGuiDir.Right or ImGuiDir.Left end end --------------------------- --------------------------- --- --- Keyboard input handling --- --- local stb_text_makeundo_insert local stb_text_makeundo_delete local stb_text_makeundo_replace --- @class StbFindState --- @field x float # position of n'th character --- @field y float --- @field height float # height of line --- @field first_char int # first char of row, and length --- @field length int --- @field prev_first int # first char of previous row --- @return StbFindState local function StbFindState() return { x = 0.0, y = 0.0, height = 0.0, first_char = 0, length = 0, prev_first = 0 } end --- @param f StbFindState local function StbFindState_Reset(f) f.x = 0.0 f.y = 0.0 f.height = 0.0 f.first_char = 0 f.length = 0 f.prev_first = 0 end local stb_textedit_find_charpos do local r = StbTexteditRow() -- find the x/y location of a character, and remember info about the previous row in -- case we get a move-up event (for page up, we'll have to rescan) --- @param find StbFindState --- @param str IMSTB_TEXTEDIT_STRING --- @param n int --- @param single_line bool function stb_textedit_find_charpos(find, str, n, single_line) StbTexteditRow_Reset(r) local prev_start = 1 local z = STB_TEXTEDIT_STRINGLEN(str) local first -- special case if it's at the end (may not be needed?) if n == z + 1 and single_line then STB_TEXTEDIT_LAYOUTROW(r, str, 1) find.y = 0 find.first_char = 1 find.length = z find.height = r.ymax - r.ymin find.x = r.x1 return end -- search rows to find the one that straddles character n find.y = 0 local i = 1 while true do STB_TEXTEDIT_LAYOUTROW(r, str, i) if n < i + r.num_chars - 1 then break end if str.LastMoveDirectionLR == ImGuiDir.Right and str.Stb.cursor > 1 and str.Stb.cursor == i + r.num_chars and STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) ~= STB_TEXTEDIT_NEWLINE then -- [IMGUI] Wrapping point handling break end if (i - 1) + r.num_chars == z and z > 0 and STB_TEXTEDIT_GETCHAR(str, z) ~= STB_TEXTEDIT_NEWLINE then -- [IMGUI] special handling for last line break end prev_start = i i = i + r.num_chars find.y = find.y + r.baseline_y_delta if i == z + 1 then -- [IMGUI] r.num_chars = 0 break end end find.first_char = i first = i find.length = r.num_chars find.height = r.ymax - r.ymin find.prev_first = prev_start -- now scan to find xpos find.x = r.x0 i = 1 while first + i <= n + 1 do find.x = find.x + STB_TEXTEDIT_GETWIDTH(str, first, i) i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i - 1) - first + 1 end end end -- make the selection/cursor state valid if client altered the string --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState local function stb_textedit_clamp(str, state) local n = STB_TEXTEDIT_STRINGLEN(str) if STB_TEXT_HAS_SELECTION(state) then if state.select_start > n + 1 then state.select_start = n + 1 end if state.select_end > n + 1 then state.select_end = n + 1 end -- if clamping forced them to be equal, move the cursor to match if state.select_start == state.select_end then state.cursor = state.select_start end end if state.cursor > n + 1 then state.cursor = n + 1 end end -- delete characters while updating undo --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param where int --- @param len int local function stb_textedit_delete(str, state, where, len) stb_text_makeundo_delete(str, state, where, len) STB_TEXTEDIT_DELETECHARS(str, where, len) state.has_preferred_x = false end -- delete the selection --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState local function stb_textedit_delete_selection(str, state) stb_textedit_clamp(str, state) if STB_TEXT_HAS_SELECTION(state) then if state.select_start < state.select_end then stb_textedit_delete(str, state, state.select_start, state.select_end - state.select_start) state.cursor = state.select_start state.select_end = state.cursor else stb_textedit_delete(str, state, state.select_end, state.select_start - state.select_end) state.cursor = state.select_end state.select_start = state.cursor end state.has_preferred_x = false end end -- canonicalize the selection so start <= end --- @param state STB_TexteditState local function stb_textedit_sortselection(state) if state.select_end < state.select_start then local temp = state.select_end state.select_end = state.select_start state.select_start = temp end end -- move cursor to first character of selection --- @param state STB_TexteditState local function stb_textedit_move_to_first(state) if STB_TEXT_HAS_SELECTION(state) then stb_textedit_sortselection(state) state.cursor = state.select_start state.select_end = state.select_start state.has_preferred_x = false end end -- move cursor to last character of selection --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState local function stb_textedit_move_to_last(str, state) if STB_TEXT_HAS_SELECTION(state) then stb_textedit_sortselection(state) stb_textedit_clamp(str, state) state.cursor = state.select_end state.select_start = state.select_end state.has_preferred_x = false end end -- update selection and cursor to match each other --- @param state STB_TexteditState local function stb_textedit_prep_selection_at_cursor(state) if not STB_TEXT_HAS_SELECTION(state) then state.select_start = state.cursor state.select_end = state.cursor else state.cursor = state.select_end end end -- API cut: delete selection --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @return bool local function stb_textedit_cut(str, state) if STB_TEXT_HAS_SELECTION(state) then stb_textedit_delete_selection(str, state) -- implicitly clamps state.has_preferred_x = false return true end return false end -- API paste: replace existing selection with passed-in text --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param text IMSTB_TEXTEDIT_CHARTYPE[] --- @param len int --- @return bool local function stb_textedit_paste_internal(str, state, text, len) -- if there's a selection, the paste should delete it stb_textedit_clamp(str, state) stb_textedit_delete_selection(str, state) -- try to insert the characters len = STB_TEXTEDIT_INSERTCHARS(str, state.cursor, text, 1, len) if len then stb_text_makeundo_insert(state, state.cursor, len) state.cursor = state.cursor + len state.has_preferred_x = false return true end -- note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) return false end -- API key: process text input -- [IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility. --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param text IMSTB_TEXTEDIT_CHARTYPE[] --- @param text_len int local function stb_textedit_text(str, state, text, text_len) -- can't add newline in single-line mode if text[1] == STB_TEXTEDIT_NEWLINE and state.single_line then return end if state.insert_mode and not STB_TEXT_HAS_SELECTION(state) and state.cursor < STB_TEXTEDIT_STRINGLEN(str) then stb_text_makeundo_replace(str, state, state.cursor, 1, 1) STB_TEXTEDIT_DELETECHARS(str, state.cursor, 1) text_len = STB_TEXTEDIT_INSERTCHARS(str, state.cursor, text, 1, text_len) if text_len then state.cursor = state.cursor + text_len state.has_preferred_x = false end else stb_textedit_delete_selection(str, state) -- implicitly clamps text_len = STB_TEXTEDIT_INSERTCHARS(str, state.cursor, text, 1, text_len) if text_len then stb_text_makeundo_insert(state, state.cursor, text_len) state.cursor = state.cursor + text_len state.has_preferred_x = false end end end local stb_textedit_key do local find = StbFindState() local row = StbTexteditRow() -- API key: process a keyboard input --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param key STB_TEXTEDIT_KEYTYPE function stb_textedit_key(str, state, key) if key == STB_TEXTEDIT_K_UNDO then stb_text_undo(str, state) state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_REDO then stb_text_redo(str, state) state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_LEFT then -- if currently there's a selection, move cursor to start of selection if STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_first(state) else if state.cursor > 1 then state.cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state.cursor) end end state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_RIGHT then -- if currently there's a selection, move cursor to end of selection if STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_last(str, state) else state.cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state.cursor) end stb_textedit_clamp(str, state) state.has_preferred_x = false elseif key == bit32.bor(STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_SHIFT) then stb_textedit_clamp(str, state) stb_textedit_prep_selection_at_cursor(state) -- move selection left if state.select_end > 1 then state.select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state.select_end) end state.cursor = state.select_end state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_WORDLEFT then -- if currently there's a selection, move cursor to start of selection if STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_first(state) else state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor) stb_textedit_clamp(str, state) end elseif key == bit32.bor(STB_TEXTEDIT_K_WORDLEFT, STB_TEXTEDIT_K_SHIFT) then if not STB_TEXT_HAS_SELECTION(state) then stb_textedit_prep_selection_at_cursor(state) end state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor) state.select_end = state.cursor stb_textedit_clamp(str, state) elseif key == STB_TEXTEDIT_K_WORDRIGHT then -- if currently there's a selection, move cursor to end of selection if STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_last(str, state) else state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor) stb_textedit_clamp(str, state) end elseif key == bit32.bor(STB_TEXTEDIT_K_WORDRIGHT, STB_TEXTEDIT_K_SHIFT) then if not STB_TEXT_HAS_SELECTION(state) then stb_textedit_prep_selection_at_cursor(state) end state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor) state.select_end = state.cursor stb_textedit_clamp(str, state) elseif key == bit32.bor(STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT) then stb_textedit_prep_selection_at_cursor(state) -- move selection right state.select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state.select_end) stb_textedit_clamp(str, state) state.cursor = state.select_end state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_DOWN or key == bit32.bor(STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_SHIFT) or key == STB_TEXTEDIT_K_PGDOWN or key == bit32.bor(STB_TEXTEDIT_K_PGDOWN, STB_TEXTEDIT_K_SHIFT) then StbFindState_Reset(find) StbTexteditRow_Reset(row) local sel = (bit32.band(key, STB_TEXTEDIT_K_SHIFT) ~= 0) local is_page = (bit32.band(key, bit32.bnot(STB_TEXTEDIT_K_SHIFT)) == STB_TEXTEDIT_K_PGDOWN) local row_count = is_page and state.row_count_per_page or 1 if not is_page and state.single_line then -- on windows, up&down in single-line behave like left&right key = bit32.bor(STB_TEXTEDIT_K_RIGHT, bit32.band(key, STB_TEXTEDIT_K_SHIFT)) return stb_textedit_key(str, state, key) -- was `goto retry` end if sel then stb_textedit_prep_selection_at_cursor(state) elseif STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_last(str, state) end -- compute current position of cursor point stb_textedit_clamp(str, state) stb_textedit_find_charpos(find, str, state.cursor, state.single_line) for j = 1, row_count do local goal_x = state.has_preferred_x and state.preferred_x or find.x local x local start = find.first_char + find.length if find.length == 0 then break end -- [IMGUI] -- going down while being on the last line shouldn't bring us to that line end --if STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) ~= STB_TEXTEDIT_NEWLINE then -- break --end -- now find character position down a row state.cursor = start STB_TEXTEDIT_LAYOUTROW(row, str, state.cursor) x = row.x0 local i = 1 while i <= row.num_chars do local dx = STB_TEXTEDIT_GETWIDTH(str, start, i) local next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state.cursor) x = x + dx if x > goal_x then break end i = i + (next - state.cursor) state.cursor = next end stb_textedit_clamp(str, state) if state.cursor == find.first_char + find.length then str.LastMoveDirectionLR = ImGuiDir.Left end state.has_preferred_x = true state.preferred_x = goal_x if sel then state.select_end = state.cursor end -- go to next line find.first_char = find.first_char + find.length find.length = row.num_chars end elseif key == STB_TEXTEDIT_K_UP or key == bit32.bor(STB_TEXTEDIT_K_UP, STB_TEXTEDIT_K_SHIFT) or key == STB_TEXTEDIT_K_PGUP or key == bit32.bor(STB_TEXTEDIT_K_PGUP, STB_TEXTEDIT_K_SHIFT) then StbFindState_Reset(find) StbTexteditRow_Reset(row) local sel = (bit32.band(key, STB_TEXTEDIT_K_SHIFT) ~= 0) local is_page = (bit32.band(key, bit32.bnot(STB_TEXTEDIT_K_SHIFT)) == STB_TEXTEDIT_K_PGUP) local row_count = is_page and state.row_count_per_page or 1 if not is_page and state.single_line then -- on windows, up&down become left&right key = bit32.bor(STB_TEXTEDIT_K_LEFT, bit32.band(key, STB_TEXTEDIT_K_SHIFT)) return stb_textedit_key(str, state, key) -- was `goto retry` end if sel then stb_textedit_prep_selection_at_cursor(state) elseif STB_TEXT_HAS_SELECTION(state) then stb_textedit_move_to_first(state) end -- compute current position of cursor point stb_textedit_clamp(str, state) stb_textedit_find_charpos(find, str, state.cursor, state.single_line) for j = 1, row_count do local goal_x if state.has_preferred_x then goal_x = state.preferred_x else goal_x = find.x end local x -- can only go up if there's a previous row if find.prev_first == find.first_char then break end -- now find character position up a row state.cursor = find.prev_first STB_TEXTEDIT_LAYOUTROW(row, str, state.cursor) x = row.x0 local i = 1 while i <= row.num_chars do local dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i) local next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state.cursor) x = x + dx if x > goal_x then break end i = i + (next - state.cursor) state.cursor = next end stb_textedit_clamp(str, state) if state.cursor == find.first_char then str.LastMoveDirectionLR = ImGuiDir.Right elseif state.cursor == find.prev_first then str.LastMoveDirectionLR = ImGuiDir.Left end state.has_preferred_x = true state.preferred_x = goal_x if sel then state.select_end = state.cursor end -- go to previous line -- (we need to scan previous line the hard way. maybe we could expose this as a new API function?) local prev_scan = find.prev_first > 1 and find.prev_first - 1 or 1 while prev_scan > 1 do local prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan) if STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE then break end prev_scan = prev end find.first_char = find.prev_first find.prev_first = STB_TEXTEDIT_MOVELINESTART(str, state, prev_scan) end elseif key == STB_TEXTEDIT_K_DELETE or key == bit32.bor(STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_SHIFT) then if STB_TEXT_HAS_SELECTION(state) then stb_textedit_delete_selection(str, state) else local n = STB_TEXTEDIT_STRINGLEN(str) if state.cursor <= n then stb_textedit_delete(str, state, state.cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state.cursor) - state.cursor) end end state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_BACKSPACE or key == bit32.bor(STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_SHIFT) then if STB_TEXT_HAS_SELECTION(state) then stb_textedit_delete_selection(str, state) else stb_textedit_clamp(str, state) if state.cursor > 1 then local prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state.cursor) stb_textedit_delete(str, state, prev, state.cursor - prev) state.cursor = prev end end state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_TEXTSTART then state.cursor = 1 state.select_start = 1 state.select_end = 1 state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_TEXTEND then state.cursor = STB_TEXTEDIT_STRINGLEN(str) + 1 state.select_start = 1 state.select_end = 1 state.has_preferred_x = false elseif key == bit32.bor(STB_TEXTEDIT_K_TEXTSTART, STB_TEXTEDIT_K_SHIFT) then stb_textedit_prep_selection_at_cursor(state) state.cursor = 1 state.select_end = 1 state.has_preferred_x = false elseif key == bit32.bor(STB_TEXTEDIT_K_TEXTEND, STB_TEXTEDIT_K_SHIFT) then stb_textedit_prep_selection_at_cursor(state) state.cursor = STB_TEXTEDIT_STRINGLEN(str) + 1 state.select_end = state.cursor state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_LINESTART then stb_textedit_clamp(str, state) stb_textedit_move_to_first(state) state.cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state.cursor) state.has_preferred_x = false elseif key == STB_TEXTEDIT_K_LINEEND then stb_textedit_clamp(str, state) stb_textedit_move_to_last(str, state) state.cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state.cursor) state.has_preferred_x = false elseif key == bit32.bor(STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_SHIFT) then stb_textedit_clamp(str, state) stb_textedit_prep_selection_at_cursor(state) state.cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state.cursor) state.select_end = state.cursor state.has_preferred_x = false elseif key == bit32.bor(STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_SHIFT) then stb_textedit_clamp(str, state) stb_textedit_prep_selection_at_cursor(state) state.cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state.cursor) state.select_end = state.cursor state.has_preferred_x = false end end end ----------------------------------------------------- ----------------------------------------------------- --- --- Undo processing --- OPTIMIZE: the undo/redo buffer should be circular --- --- @param state StbUndoState local function stb_textedit_flush_redo(state) state.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT + 1 state.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT + 1 end -- discard the oldest entry in the undo list --- @param state StbUndoState local function stb_textedit_discard_undo(state) if state.undo_point > 0 then -- if the 1th undo state has characters, clean those up if state.undo_rec[1].char_storage >= 0 then local n = state.undo_rec[1].insert_length -- delete n characters from all other records state.undo_char_point = state.undo_char_point - n IMSTB_TEXTEDIT_memmove(state.undo_char, 1, state.undo_char, n + 1, state.undo_char_point - 1) for i = 1, state.undo_point do if state.undo_rec[i].char_storage >= 0 then state.undo_rec[i].char_storage = state.undo_rec[i].char_storage - n -- OPTIMIZE: get rid of char_storage and infer it end end end state.undo_point = state.undo_point - 1 IMSTB_TEXTEDIT_memmove(state.undo_rec, 1, state.undo_rec, 2, state.undo_point - 1) end end -- discard the oldest entry in the redo list--it's bad if this -- ever happens, but because undo & redo have to store the actual -- characters in different cases, the redo character buffer can -- fill up even though the undo buffer didn't --- @param state StbUndoState local function stb_textedit_discard_redo(state) local k = IMSTB_TEXTEDIT_UNDOSTATECOUNT if state.redo_point <= k then -- if the k'th undo state has characters, clean those up if state.undo_rec[k].char_storage >= 1 then local n = state.undo_rec[k].insert_length -- move the remaining redo character data to the end of the buffer state.redo_char_point = state.redo_char_point + n IMSTB_TEXTEDIT_memmove(state.undo_char, state.redo_char_point, state.undo_char, state.redo_char_point - n, IMSTB_TEXTEDIT_UNDOCHARCOUNT - state.redo_char_point + 1) -- adjust the position of all the other records to account for above memmove for i = state.redo_point, k - 1 do if state.undo_rec[i].char_storage >= 1 then state.undo_rec[i].char_storage = state.undo_rec[i].char_storage + n end end end -- now move all the redo records towards the end of the buffer; the first one is at 'redo_point' -- [IMGUI] local move_size = IMSTB_TEXTEDIT_UNDOSTATECOUNT - state.redo_point - 1 IMSTB_TEXTEDIT_memmove(state.undo_rec, state.redo_point + 1, state.undo_rec, state.redo_point, move_size) -- now move redo_point to point to the new one state.redo_point = state.redo_point + 1 end end --- @param state StbUndoState --- @param numchars int local function stb_text_create_undo_record(state, numchars) -- any time we create a new undo record, we discard redo stb_textedit_flush_redo(state) -- if we have no free records, we have to make room, by sliding the -- existing records down if state.undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT then stb_textedit_discard_undo(state) end -- if the characters to store won't possibly fit in the buffer, we can't undo if numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT then state.undo_point = 1 state.undo_char_point = 1 return nil end -- if we don't have enough free characters in the buffer, we have to make room while state.undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT do stb_textedit_discard_undo(state) end local ret = state.undo_rec[state.undo_point] state.undo_point = state.undo_point + 1 return ret end --- @param state StbUndoState --- @param pos int --- @param insert_len int --- @param delete_len int --- @return int? # index into undostate.undo_char[] local function stb_text_createundo(state, pos, insert_len, delete_len) local r = stb_text_create_undo_record(state, insert_len) if r == nil then return nil end r.where = pos r.insert_length = insert_len r.delete_length = delete_len if insert_len == 0 then r.char_storage = -1 return nil else r.char_storage = state.undo_char_point state.undo_char_point = state.undo_char_point + insert_len return r.char_storage end end --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState function stb_text_undo(str, state) local s = state.undostate if s.undo_point == 1 then return end -- we need to do two things: apply the undo record, and create a redo record local u = s.undo_rec[s.undo_point - 1] local r = s.undo_rec[s.redo_point - 1] r.char_storage = -1 r.insert_length = u.delete_length r.delete_length = u.insert_length r.where = u.where if u.delete_length > 0 then -- if the undo record says to delete characters, then the redo record will -- need to re-insert the characters that get deleted, so we need to store -- them. -- there are three cases: -- there's enough room to store the characters -- characters stored for *redoing* don't leave room for redo -- characters stored for *undoing* don't leave room for redo -- if the last is true, we have to bail if s.undo_char_point + u.delete_length > IMSTB_TEXTEDIT_UNDOCHARCOUNT then -- the undo records take up too much character space; there's no space to store the redo characters r.insert_length = 0 else -- there's definitely room to store the characters eventually while s.undo_char_point + u.delete_length > s.redo_char_point do -- should never happen: if s.redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT + 1 then return end -- there's currently not enough room, so discard a redo record stb_textedit_discard_redo(s) end r = s.undo_rec[s.redo_point - 1] r.char_storage = s.redo_char_point - u.delete_length s.redo_char_point = s.redo_char_point - u.delete_length -- now save the characters for i = 0, u.delete_length - 1 do s.undo_char[r.char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i) end end -- now we can carry out the deletion STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length) end -- check type of recorded action: if u.insert_length > 0 then -- easy case: was a deletion, so we need to insert n characters u.insert_length = STB_TEXTEDIT_INSERTCHARS(str, u.where, s.undo_char, u.char_storage, u.insert_length) s.undo_char_point = s.undo_char_point - u.insert_length end state.cursor = u.where + u.insert_length s.undo_point = s.undo_point - 1 s.redo_point = s.redo_point - 1 end --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState function stb_text_redo(str, state) local s = state.undostate if s.undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT + 1 then return end -- we need to do two things: apply the redo record, and create an undo record local u = s.undo_rec[s.undo_point] local r = s.undo_rec[s.redo_point] u.delete_length = r.insert_length u.insert_length = r.delete_length u.where = r.where u.char_storage = -1 if r.delete_length > 0 then -- the redo record requires us to delete characters, so the undo record -- needs to store the characters if s.undo_char_point + u.insert_length > s.redo_char_point then u.insert_length = 0 u.delete_length = 0 else u.char_storage = s.undo_char_point s.undo_char_point = s.undo_char_point + u.insert_length for i = 0, u.insert_length - 1 do s.undo_char[u.char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i) end end STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length) end if r.insert_length ~= 0 then r.insert_length = STB_TEXTEDIT_INSERTCHARS(str, r.where, s.undo_char, r.char_storage, r.insert_length) s.redo_char_point = s.redo_char_point + r.insert_length end state.cursor = r.where + r.insert_length s.undo_point = s.undo_point + 1 s.redo_point = s.redo_point + 1 end --- @param state STB_TexteditState --- @param where int --- @param length int function stb_text_makeundo_insert(state, where, length) stb_text_createundo(state.undostate, where, 0, length) end --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param where int --- @param length int function stb_text_makeundo_delete(str, state, where, length) local s = state.undostate local p = stb_text_createundo(s, where, length, 0) if p then for i = 0, length - 1 do s.undo_char[p + i] = STB_TEXTEDIT_GETCHAR(str, where + i) end end end --- @param str IMSTB_TEXTEDIT_STRING --- @param state STB_TexteditState --- @param where int --- @param old_length int --- @param new_length int function stb_text_makeundo_replace(str, state, where, old_length, new_length) local s = state.undostate local p = stb_text_createundo(s, where, old_length, new_length) if p then for i = 0, old_length - 1 do s.undo_char[p + i] = STB_TEXTEDIT_GETCHAR(str, where + i) end end end --- @param state STB_TexteditState --- @param is_single_line bool local function stb_textedit_clear_state(state, is_single_line) state.undostate.undo_point = 1 state.undostate.undo_char_point = 1 state.undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT + 1 state.undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT + 1 state.select_end = 1 state.select_start = 1 state.cursor = 1 state.has_preferred_x = false state.preferred_x = 0 state.cursor_at_end_of_line = false state.initialized = true state.single_line = is_single_line state.insert_mode = false state.row_count_per_page = 0 end return { click = stb_textedit_click, drag = stb_textedit_drag, createundo = stb_text_createundo, initialize_state = stb_textedit_clear_state, text = stb_textedit_text, key = stb_textedit_key, makeundo_replace = stb_text_makeundo_replace, clamp = stb_textedit_clamp, prep_selection_at_cursor = stb_textedit_prep_selection_at_cursor, cut = stb_textedit_cut, paste = stb_textedit_paste_internal, HAS_SELECTION = STB_TEXT_HAS_SELECTION } end __FILES['imstb_truetype.lua'] = function() --- Dear ImGui -- This is a Lua port of original `imstb_truetype.h` --- STBTT_RASTERIZER_VERSION == 2 local stbtt_fontinfo local stbtt_InitFont local stbtt_MakeGlyphBitmapSubpixelPrefilter local stbtt_GetFontVMetrics local stbtt__GetGlyphInfoT2 local stbtt__GetGlyphShapeT2 local stbtt_GetGlyphShape local stbtt_GetGlyphBitmapBox local stbtt_GetGlyphBitmapBoxSubpixel local stbtt_GetGlyphHMetrics local stbtt_GetFontOffsetForIndex local stbtt_ScaleForPixelHeight local stbtt_FindGlyphIndex local STBTT_MAX_OVERSAMPLE = 8 --- @enum STBTT_PLATFORM_ID local STBTT_PLATFORM_ID = { UNICODE = 0, MAC = 1, ISO = 2, MICROSOFT = 3, } --- @enum STBTT_MS_EID local STBTT_MS_EID = { SYMBOL = 0, UNICODE_BMP = 1, SHIFTJIS = 2, UNICODE_FULL = 10 } -- original enum doesn't have a name, so we name it --- @enum STBTT_VTX local STBTT_VTX = { MOVE = 1, LINE = 2, CURVE = 3, CUBIC = 4 } local bit32 = bit32 local math = math local STBTT_assert = assert local STBTT_sort = table.sort local STBTT_sqrt = math.sqrt local STBTT_fabs = math.abs local STBTT_ifloor = math.floor local STBTT_iceil = math.ceil local trunc = function(x) if x >= 0 then return math.floor(x) else return math.ceil(x) end end local function STBTT__NOTUSED(_) return end --- @alias stbtt_int32 int local stbtt_int32 = ImS32 local stbtt_uint32 = ImU32 local stbtt_int16 = ImS16 local stbtt_uint16 = ImU16 local stbtt_int8 = ImS8 local stbtt_uint8 = ImU8 local unsigned_char = stbtt_uint8 --- @class stbtt__buf --- @field data? table # 1-based byte table --- @field offset int # Every access to `data` will be offset by this --- @field cursor int # >= 0 --- @field size int --- @param initial_offset? int --- @return stbtt__buf --- @nodiscard local function stbtt__buf(initial_offset) return { data = nil, offset = initial_offset or 0, cursor = 0, size = nil } end --- @class stbtt_fontinfo --- @field userdata any --- @field data table # pointer to .ttf file --- @field fontstart int # offset of start of font --- @field numGlyphs int # number of glyphs, needed for range checking --- @field loca int # table location as offset from start of .ttf --- @field head int # table location as offset from start of .ttf --- @field glyf int # table location as offset from start of .ttf --- @field hhea int # table location as offset from start of .ttf --- @field hmtx int # table location as offset from start of .ttf --- @field kern int # table location as offset from start of .ttf --- @field gpos int # table location as offset from start of .ttf --- @field svg int # table location as offset from start of .ttf --- @field index_map int # a cmap mapping for our chosen character encoding --- @field indexToLocFormat int # format needed to map from glyph index to glyph --- @field cff stbtt__buf # cff font data --- @field charstrings stbtt__buf # the charstring index --- @field gsubrs stbtt__buf # global charstring subroutines index --- @field subrs stbtt__buf # private charstring subroutines index --- @field fontdicts stbtt__buf # array of font dicts --- @field fdselect stbtt__buf # map from glyph to fontdict --- @return stbtt_fontinfo function stbtt_fontinfo() return { data = nil, fontstart = nil, numGlyphs = nil, loca = nil, head = nil, glyf = nil, hhea = nil, hmtx = nil, kern = nil, gpos = nil, svg = nil, index_map = nil, indexToLocFormat = nil, cff = nil, charstrings = nil, gsubrs = nil, subrs = nil, fontdicts = nil, fdselect = nil } end --- @class stbtt_vertex --- @field x int --- @field y int --- @field cx int --- @field cy int --- @field cx1 int --- @field cy1 int --- @field type int --- @field padding int --- @return stbtt_vertex --- @nodiscard local function stbtt_vertex() return { x = nil, y = nil, cx = nil, cy = nil, cx1 = nil, cy1 = nil, type = nil, padding = nil } end --- @class stbtt__csctx --- @field bounds bool --- @field started bool --- @field first_x float --- @field first_y float --- @field x float --- @field y float --- @field min_x int --- @field max_x int --- @field min_y int --- @field max_y int --- @field pvertices stbtt_vertex[] --- @field num_vertices int --- @return stbtt__csctx --- @nodiscard local function stbtt__csctx() return { bounds = false, started = false, first_x = nil, first_y = nil, x = nil, y = nil, min_x = nil, max_x = nil, min_y = nil, max_y = nil, pvertices = nil, num_vertices = nil } end --- @param bounds bool --- @return stbtt__csctx --- @nodiscard local function STBTT__CSCTX_INIT(bounds) local this = stbtt__csctx() this.bounds = bounds this.started = false this.first_x = 0 this.first_y = 0 this.x = 0 this.y = 0 this.min_x = 0 this.max_x = 0 this.min_y = 0 this.max_y = 0 this.pvertices = nil this.num_vertices = 0 return this end --- stbtt_kerningentry --- stbtt_pack_range --- stbtt_packedchar --- @class stbtt__edge --- @field x0 float --- @field y0 float --- @field x1 float --- @field y1 float --- @field invert bool --- @return stbtt__edge --- @nodiscard local function stbtt__edge() return { x0 = nil, y0 = nil, x1 = nil, y1 = nil, invert = false } end --- @class stbtt__active_edge --- @return stbtt__active_edge --- @nodiscard local function stbtt__active_edge() return { next = nil, fx = nil, fdx = nil, fdy = nil, direction = nil, sy = nil, ey = nil } end --- @return stbtt__active_edge --- @nodiscard local function stbtt__new_active(e, off_x, start_point) local z = stbtt__active_edge() local dxdy = (e.x1 - e.x0) / (e.y1 - e.y0) z.fdx = dxdy z.fdy = (dxdy ~= 0.0) and (1.0 / dxdy) or 0.0 z.fx = e.x0 + dxdy * (start_point - e.y0) z.fx = z.fx - off_x z.direction = (e.invert) and 1.0 or -1.0 z.sy = e.y0 z.ey = e.y1 z.next = nil return z end --- @class stbtt__bitmap --- @field w int --- @field h int --- @field stride int --- @field pixels unsigned_char[] --- @return stbtt__bitmap --- @nodiscard local function stbtt__bitmap() return { w = nil, h = nil, stride = nil, pixels = nil } end --- @class stbtt__point --- @field x number --- @field y number --- @return stbtt__point --- @nodiscard local function stbtt__point() return { x = nil, y = nil } end ---------------------------------------------- ---------------------------------------------- --- --- stbtt__buf helpers to parse data from file --- --- --- @param b stbtt__buf local function stbtt__buf_get8(b) if b.cursor >= b.size then return 0 end local result = b.data[b.offset + b.cursor + 1] b.cursor = b.cursor + 1 return result end --- @param b stbtt__buf local function stbtt__buf_peek8(b) if b.cursor >= b.size then return 0 end return b.data[b.offset + b.cursor + 1] end --- @param b stbtt__buf --- @param o int local function stbtt__buf_seek(b, o) STBTT_assert(not (o > b.size or o < 0)) if o > b.size or o < 0 then b.cursor = b.size else b.cursor = o end end --- @param b stbtt__buf --- @param o int local function stbtt__buf_skip(b, o) stbtt__buf_seek(b, b.cursor + o) end local function stbtt__buf_get(b, n) local v = 0 STBTT_assert(n >= 1 and n <= 4) for _ = 1, n do v = bit32.bor(bit32.lshift(v, 8), stbtt__buf_get8(b)) end return v end --- @param p? table --- @param size int --- @param offset? int --- @return stbtt__buf --- @nodiscard local function stbtt__new_buf(p, size, offset) local r = stbtt__buf(offset) STBTT_assert(size < 0x40000000) r.data = p r.size = trunc(size) r.cursor = 0 return r end --- @param b stbtt__buf local function stbtt__buf_get16(b) return stbtt__buf_get(b, 2) end --- @param b stbtt__buf local function stbtt__buf_get32(b) return stbtt__buf_get(b, 4) end --- @param b stbtt__buf --- @param o int --- @param s int --- @return stbtt__buf --- @nodiscard local function stbtt__buf_range(b, o, s) local r = stbtt__new_buf(nil, 0) if (o < 0 or s < 0 or o > b.size or s > (b.size - o)) then return r end r.data = b.data r.offset = b.offset + o r.size = s return r end --- @param b stbtt__buf local function stbtt__cff_get_index(b) local count, start, offsize start = b.cursor count = stbtt__buf_get16(b) if count > 0 then offsize = stbtt__buf_get8(b) STBTT_assert(offsize >= 1 and offsize <= 4) stbtt__buf_skip(b, count * offsize) stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1) end return stbtt__buf_range(b, start, b.cursor - start) end --- @param b stbtt__buf local function stbtt__cff_int(b) local b0 = stbtt__buf_get8(b) if b0 >= 32 and b0 <= 246 then return b0 - 139 elseif b0 >= 247 and b0 <= 250 then return (b0 - 247) * 256 + stbtt__buf_get8(b) + 108 elseif b0 >= 251 and b0 <= 254 then return -(b0 - 251) * 256 - stbtt__buf_get8(b) - 108 elseif b0 == 28 then return stbtt__buf_get16(b) elseif b0 == 29 then return stbtt__buf_get32(b) end STBTT_assert(false) return 0 end --- @param b stbtt__buf local function stbtt__cff_skip_operand(b) local v local b0 = stbtt__buf_peek8(b) STBTT_assert(b0 >= 28) if b0 == 30 then stbtt__buf_skip(b, 1) while b.cursor < b.size do v = stbtt__buf_get8(b) if (bit32.band(v, 0xF) == 0xF or bit32.rshift(v, 4) == 0xF) then break end end else stbtt__cff_int(b) end end --- @param b stbtt__buf --- @param key int --- @return stbtt__buf --- @nodiscard local function stbtt__dict_get(b, key) stbtt__buf_seek(b, 0) while b.cursor < b.size do local start = b.cursor local _end, op while stbtt__buf_peek8(b) >= 28 do stbtt__cff_skip_operand(b) end _end = b.cursor op = stbtt__buf_get8(b) if op == 12 then op = bit32.bor(stbtt__buf_get8(b), 0x100) end if op == key then return stbtt__buf_range(b, start, _end - start) end end return stbtt__buf_range(b, 0, 0) end --- @param b stbtt__buf --- @param key int --- @param outcount int --- @return int[] --- @nodiscard local function stbtt__dict_get_ints(b, key, outcount) local operands = stbtt__dict_get(b, key) local out = {} for i = 1, outcount do if operands.cursor >= operands.size then break end out[i] = stbtt__cff_int(operands) end return out end --- @param b stbtt__buf local function stbtt__cff_index_count(b) stbtt__buf_seek(b, 0) return stbtt__buf_get16(b) end --- @param b stbtt__buf --- @param i int --- @return stbtt__buf --- @nodiscard local function stbtt__cff_index_get(b, i) local count, offsize, start, _end stbtt__buf_seek(b, 0) count = stbtt__buf_get16(b) offsize = stbtt__buf_get8(b) STBTT_assert(i >= 0 and i < count) STBTT_assert(offsize >= 1 and offsize <= 4) stbtt__buf_skip(b, i * offsize) start = stbtt__buf_get(b, offsize) _end = stbtt__buf_get(b, offsize) return stbtt__buf_range(b, 2 + (count + 1) * offsize + start, _end - start) end ------------------------------------- ------------------------------------- --- --- Accessors to parse data from file --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt_IsGlyphEmpty --- stbtt_GetKerningTableLength --- stbtt_GetKerningTable --- stbtt__GetGlyphKernInfoAdvance --- stbtt__GetCoverageIndex --- stbtt__GetGlyphClass --- stbtt__GetGlyphGPOSInfoAdvance --- stbtt_GetGlyphKernAdvance --- stbtt_FindSVGDoc --- stbtt_GetGlyphSVG --- stbtt_GetCodepointSVG --- stbtt_GetCodepointKernAdvance --- stbtt_GetFontVMetricsOS2 --- stbtt_GetCodepointHMetrics --- stbtt_ScaleForMappingEmToPixels --- stbtt_GetFontBoundingBox --- stbtt_GetCodepointBitmapBox --- stbtt_GetCodepointBitmapBoxSubpixel --- stbtt_GetCodepointBox --- stbtt_GetNumberOfFonts_internal --- stbtt__get_svg local function ttUSHORT(p, offset) return stbtt_uint16(p[offset + 1] * 256 + p[offset + 2]) end local function ttSHORT(p, offset) return stbtt_int16(p[offset + 1] * 256 + p[offset + 2]) end local function ttULONG(p, offset) return stbtt_uint32(bit32.lshift(p[offset + 1], 24) + bit32.lshift(p[offset + 2], 16) + bit32.lshift(p[offset + 3], 8) + p[offset + 4]) end local function ttLONG(p, offset) return stbtt_int32(bit32.lshift(p[offset + 1], 24) + bit32.lshift(p[offset + 2], 16) + bit32.lshift(p[offset + 3], 8) + p[offset + 4]) end local function ttBYTE(p, offset) return stbtt_uint8(p[offset + 1]) end local function ttCHAR(p, offset) return stbtt_int8(p[offset + 1]) end local function stbtt_tag4(p, c0, c1, c2, c3, offset) offset = offset or 0; return p[offset + 1] == c0 and p[offset + 2] == c1 and p[offset + 3] == c2 and p[offset + 4] == c3 end local function stbtt_tag(p, str, offset) local c0, c1, c2, c3 = string.byte(str, 1, 4); return stbtt_tag4(p, c0, c1, c2, c3, offset) end local function stbtt__isfont(font) if stbtt_tag4(font, 49, 0, 0, 0) then return true end if stbtt_tag(font, "typ1") then return true end if stbtt_tag(font, "OTTO") then return true end if stbtt_tag4(font, 0, 1, 0, 0) then return true end if stbtt_tag(font, "true") then return true end return false end local function stbtt__find_table(data, font_start, tag) local num_tables = ttUSHORT(data, font_start + 4) local tabledir = font_start + 12 for i = 0, num_tables - 1 do local loc = tabledir + i * 16 if stbtt_tag(data, tag, loc + 0) then return ttULONG(data, loc + 8) end end return 0 end local function stbtt_GetFontOffsetForIndex_internal(font_collection, index) if stbtt__isfont(font_collection) then if index == 0 then return 0 else return -1 end end if stbtt_tag(font_collection, "ttcf") then if ttULONG(font_collection, 4) == 0x00010000 or ttULONG(font_collection, 4) == 0x00020000 then local n = ttLONG(font_collection, 8) if index >= n then return -1 end return ttULONG(font_collection, 12 + index * 4) end end return -1 end --- @param cff stbtt__buf --- @param fontdict stbtt__buf local function stbtt__get_subrs(cff, fontdict) local private_loc = stbtt__dict_get_ints(fontdict, 18, 2) if (private_loc[2] == 0 or private_loc[1] == 0) then return stbtt__new_buf(nil, 0) end local pdict = stbtt__buf_range(cff, private_loc[2], private_loc[1]) local subrsoff = stbtt__dict_get_ints(pdict, 19, 1) if subrsoff[1] == 0 then return stbtt__new_buf(nil, 0) end stbtt__buf_seek(cff, private_loc[2] + subrsoff[1]) return stbtt__cff_get_index(cff) end --- @return bool local function stbtt_InitFont_internal(info, data, fontstart) local cmap local numTables info.data = data info.fontstart = fontstart info.cff = stbtt__new_buf(nil, 0) cmap = stbtt__find_table(data, fontstart, "cmap") info.loca = stbtt__find_table(data, fontstart, "loca") info.head = stbtt__find_table(data, fontstart, "head") info.glyf = stbtt__find_table(data, fontstart, "glyf") info.hhea = stbtt__find_table(data, fontstart, "hhea") info.hmtx = stbtt__find_table(data, fontstart, "hmtx") info.kern = stbtt__find_table(data, fontstart, "kern") info.gpos = stbtt__find_table(data, fontstart, "GPOS") if (cmap == 0 or info.head == 0 or info.hhea == 0 or info.hmtx == 0) then return false end if info.glyf ~= 0 then if info.loca == 0 then return false end else local cff = stbtt__find_table(data, fontstart, "CFF ") if cff == 0 then return false end info.fontdicts = stbtt__new_buf(nil, 0) info.fdselect = stbtt__new_buf(nil, 0) info.cff = stbtt__new_buf(data, 64 * 1024 * 1024, cff) -- TODO: this should use size from table local b = info.cff -- read the header stbtt__buf_skip(b, 2) stbtt__buf_seek(b, stbtt__buf_get8(b)) -- TODO: the name INDEX could list multiple fonts, but we just use the first one. stbtt__cff_get_index(b) -- name INDEX local topdictidx = stbtt__cff_get_index(b) local topdict = stbtt__cff_index_get(topdictidx, 0) stbtt__cff_get_index(b) -- string INDEX info.gsubrs = stbtt__cff_get_index(b) local charstrings = stbtt__dict_get_ints(topdict, 17, 1) local cstype = stbtt__dict_get_ints(topdict, bit32.bor(0x100, 6), 1) local fdarrayoff = stbtt__dict_get_ints(topdict, bit32.bor(0x100, 36), 1) local fdselectoff = stbtt__dict_get_ints(topdict, bit32.bor(0x100, 37), 1) info.subrs = stbtt__get_subrs(b, topdict) if cstype[1] ~= 2 then return false end if charstrings[1] == 0 then return false end if fdarrayoff[1] ~= 0 then if fdselectoff[1] == 0 then return false end stbtt__buf_seek(b, fdarrayoff[1]) info.fontdicts = stbtt__cff_get_index(b) info.fdselect = stbtt__buf_range(b, fdselectoff[1], b.size - fdselectoff[1]) end stbtt__buf_seek(b, charstrings[1]) info.charstrings = stbtt__cff_get_index(b) end local t = stbtt__find_table(data, fontstart, "maxp") if t ~= 0 then info.numGlyphs = ttUSHORT(data, t + 4) else info.numGlyphs = 0xffff end info.svg = -1 numTables = ttUSHORT(data, cmap + 2) info.index_map = 0 for i = 0, numTables - 1 do local encoding_record = cmap + 4 + 8 * i local platform_id = ttUSHORT(data, encoding_record) if platform_id == STBTT_PLATFORM_ID.MICROSOFT then local ms_eid = ttUSHORT(data, encoding_record + 2) if ms_eid == STBTT_MS_EID.UNICODE_BMP or ms_eid == STBTT_MS_EID.UNICODE_FULL then info.index_map = cmap + ttULONG(data, encoding_record + 4) end elseif platform_id == STBTT_PLATFORM_ID.UNICODE then info.index_map = cmap + ttULONG(data, encoding_record + 4) end end if info.index_map == 0 then return false end info.indexToLocFormat = ttUSHORT(data, info.head + 50) return true end --- @param info stbtt_fontinfo --- @param unicode_codepoint int function stbtt_FindGlyphIndex(info, unicode_codepoint) local data = info.data local index_map = info.index_map local format = ttUSHORT(data, index_map + 0) if format == 0 then local bytes = ttUSHORT(data, index_map + 2) if unicode_codepoint < bytes - 6 then return ttBYTE(data, index_map + 6 + unicode_codepoint) end return 0 elseif format == 6 then local first = ttUSHORT(data, index_map + 6) local count = ttUSHORT(data, index_map + 8) if unicode_codepoint >= first and unicode_codepoint < first + count then return ttUSHORT(data, index_map + 10 + (unicode_codepoint - first) * 2) end return 0 elseif format == 2 then STBTT_assert(false) -- TODO: high-byte mapping for japanese/chinese/korean return 0 elseif format == 4 then local segcount = bit32.rshift(ttUSHORT(data, index_map + 6), 1) local searchRange = bit32.rshift(ttUSHORT(data, index_map + 8), 1) local entrySelector = ttUSHORT(data, index_map + 10) local rangeShift = bit32.rshift(ttUSHORT(data, index_map + 12), 1) local endCount = index_map + 14 local search = endCount if unicode_codepoint > 0xffff then return 0 end if unicode_codepoint >= ttUSHORT(data, search + rangeShift * 2) then search = search + rangeShift * 2 end search = search - 2 while entrySelector ~= 0 do searchRange = bit32.rshift(searchRange, 1) local _end = ttUSHORT(data, search + searchRange * 2) if unicode_codepoint > _end then search = search + searchRange * 2 end entrySelector = entrySelector - 1 end search = search + 2 do local item = stbtt_uint16(bit32.rshift(search - endCount, 1)) local start = ttUSHORT(data, index_map + 14 + segcount * 2 + 2 + 2 * item) local last = ttUSHORT(data, endCount + 2 * item) if unicode_codepoint < start or unicode_codepoint > last then return 0 end local offset = ttUSHORT(data, index_map + 14 + segcount * 6 + 2 + 2 * item) if offset == 0 then return stbtt_uint16(unicode_codepoint + ttSHORT(data, index_map + 14 + segcount * 4 + 2 + 2 * item)) end return ttUSHORT(data, offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + 2 * item) end elseif format == 12 or format == 13 then local ngroups = ttULONG(data, index_map + 12) local low = 0 local high = ngroups while low < high do local mid = low + bit32.rshift(high - low, 1) local start_char = ttULONG(data, index_map + 16 + mid * 12) local end_char = ttULONG(data, index_map + 16 + mid * 12 + 4) if unicode_codepoint < start_char then high = mid elseif unicode_codepoint > end_char then low = mid + 1 else local start_glyph = ttULONG(data, index_map + 16 + mid * 12 + 8) if format == 12 then return start_glyph + unicode_codepoint - start_char else -- format == 13 return start_glyph end end end return 0 end -- TODO: STBTT_assert(false) return 0 end --- @param v stbtt_vertex --- @param vtx_type STBTT_VTX --- @param x stbtt_int32 --- @param y stbtt_int32 --- @param cx stbtt_int32 --- @param cy stbtt_int32 local function stbtt_setvertex(v, vtx_type, x, y, cx, cy) v.type = vtx_type v.x = (stbtt_int16)(x) v.y = (stbtt_int16)(y) v.cx = (stbtt_int16)(cx) v.cy = (stbtt_int16)(cy) end local function stbtt__GetGlyfOffset(info, glyph_index) STBTT_assert(info.cff.size == 0) if glyph_index >= info.numGlyphs then return -1 end if info.indexToLocFormat >= 2 then return -1 end local g1, g2 if info.indexToLocFormat == 0 then g1 = info.glyf + ttUSHORT(info.data, info.loca + glyph_index * 2) * 2 g2 = info.glyf + ttUSHORT(info.data, info.loca + glyph_index * 2 + 2) * 2 else g1 = info.glyf + ttULONG(info.data, info.loca + glyph_index * 4) g2 = info.glyf + ttULONG(info.data, info.loca + glyph_index * 4 + 4) end if g1 == g2 then return -1 else return g1 end end --- @return integer, integer?, integer?, integer?, integer? local function stbtt_GetGlyphBox(info, glyph_index) local n, x0, y0, x1, y1 if info.cff.size ~= 0 then n, x0, y0, x1, y1 = stbtt__GetGlyphInfoT2(info, glyph_index) else local g = stbtt__GetGlyfOffset(info, glyph_index) if g < 0 then return 0 end x0 = ttSHORT(info.data, g + 2) y0 = ttSHORT(info.data, g + 4) x1 = ttSHORT(info.data, g + 6) y1 = ttSHORT(info.data, g + 8) end return 1, x0, y0, x1, y1 end --- @param vertices stbtt_vertex[] --- @param num_vertices int --- @param was_off bool --- @param start_off bool --- @param sx stbtt_int32 --- @param sy stbtt_int32 --- @param scx stbtt_int32 --- @param scy stbtt_int32 --- @param cx stbtt_int32 --- @param cy stbtt_int32 local function stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy) if start_off then if was_off then stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.CURVE, bit32.rshift(cx + scx, 1), bit32.rshift(cy + scy, 1), cx, cy) num_vertices = num_vertices + 1 end stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.CURVE, sx, sy, scx, scy) num_vertices = num_vertices + 1 else if was_off then stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.CURVE, sx, sy, cx, cy) num_vertices = num_vertices + 1 else stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.LINE, sx, sy, 0, 0) num_vertices = num_vertices + 1 end end return num_vertices end --- @param info stbtt_fontinfo --- @param glyph_index int --- @return int num_vertices --- @return stbtt_vertex[]? vertices local function stbtt__GetGlyphShapeTT(info, glyph_index) local data = info.data local num_vertices local vertices = nil local g = stbtt__GetGlyfOffset(info, glyph_index) if g < 0 then return 0 end local numberOfContours = ttSHORT(data, g) if numberOfContours > 0 then local endPtsOfContours = g + 10 local ins = ttUSHORT(data, endPtsOfContours + numberOfContours * 2) local points = (endPtsOfContours + numberOfContours * 2 + 2 + ins) + 1 -- 1-based idx local n = 1 + ttUSHORT(data, endPtsOfContours + numberOfContours * 2 - 2) local m = n + 2 * numberOfContours vertices = {} for i = 1, m do vertices[i] = stbtt_vertex() end local j = 0 local was_off = false local start_off = false local next_move = 0 local flagcount = 0 local off = m - n -- first load flags local flags = 0 for i = 1, n do if flagcount == 0 then flags = data[points] points = points + 1 if bit32.band(flags, 8) ~= 0 then flagcount = data[points] points = points + 1 end else flagcount = flagcount - 1 end vertices[off + i].type = flags end -- now load x coordinates local x = 0 for i = 1, n do flags = vertices[off + i].type if bit32.band(flags, 2) ~= 0 then local dx = data[points] points = points + 1 if bit32.band(flags, 16) ~= 0 then x = x + dx else x = x - dx end else if bit32.band(flags, 16) == 0 then x = x + stbtt_int16(data[points] * 256 + data[points + 1]) points = points + 2 end end vertices[off + i].x = stbtt_int16(x) end -- now load y coordinates local y = 0 for i = 1, n do flags = vertices[off + i].type if bit32.band(flags, 4) ~= 0 then local dy = data[points] points = points + 1 if bit32.band(flags, 32) ~= 0 then y = y + dy else y = y - dy end else if bit32.band(flags, 32) == 0 then y = y + stbtt_int16(data[points] * 256 + data[points + 1]) points = points + 2 end end vertices[off + i].y = stbtt_int16(y) end -- now convert them to our format num_vertices = 0 local sx, sy, cx, cy, scx, scy = 0, 0, 0, 0, 0, 0 for i = 1, n do flags = vertices[off + i].type x = stbtt_int16(vertices[off + i].x) y = stbtt_int16(vertices[off + i].y) if next_move == i - 1 then if i ~= 1 then num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy) end -- now start the new one start_off = (bit32.band(flags, 1) == 0) if start_off then scx = x scy = y if bit32.band(vertices[off + i + 1].type, 1) == 0 then sx = bit32.rshift(x + stbtt_int32(vertices[off + i + 1].x), 1) sy = bit32.rshift(y + stbtt_int32(vertices[off + i + 1].y), 1) else sx = stbtt_int32(vertices[off + i + 1].x) sy = stbtt_int32(vertices[off + i + 1].y) i = i + 1 end else sx = x sy = y end stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.MOVE, sx, sy, 0, 0) num_vertices = num_vertices + 1 was_off = false next_move = 1 + ttUSHORT(data, endPtsOfContours + j * 2) j = j + 1 else if bit32.band(flags, 1) == 0 then if was_off then stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.CURVE, bit32.rshift(cx + x, 1), bit32.rshift(cy + y, 1), cx, cy) num_vertices = num_vertices + 1 end cx = x cy = y was_off = true else if was_off then stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.CURVE, x, y, cx, cy) num_vertices = num_vertices + 1 else stbtt_setvertex(vertices[num_vertices + 1], STBTT_VTX.LINE, x, y, 0, 0) num_vertices = num_vertices + 1 end was_off = false end end end num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy) elseif numberOfContours < 0 then local more = 1 local comp = g + 10 num_vertices = 0 while more ~= 0 do local flags, gidx local comp_num_vertices = 0 local comp_verts local mtx = {1, 0, 0, 1, 0, 0} local m, n flags = ttSHORT(data, comp) comp = comp + 2 gidx = ttSHORT(data, comp) comp = comp + 2 if bit32.band(flags, 2) ~= 0 then if bit32.band(flags, 1) ~= 0 then mtx[5] = ttSHORT(data, comp) comp = comp + 2 mtx[6] = ttSHORT(data, comp) comp = comp + 2 else mtx[5] = ttCHAR(data, comp) comp = comp + 1 mtx[6] = ttCHAR(data, comp) comp = comp + 1 end else -- TODO: handle matching point STBTT_assert(false) end if bit32.band(flags, bit32.lshift(1, 3)) ~= 0 then -- WE_HAVE_A_SCALE mtx[4] = ttSHORT(data, comp) / 16384.0 mtx[1] = mtx[4] comp = comp + 2 mtx[3] = 0 mtx[2] = mtx[3] elseif bit32.band(flags, bit32.lshift(1, 6)) ~= 0 then -- WE_HAVE_AN_X_AND_YSCALE mtx[1] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 mtx[3] = 0 mtx[2] = mtx[3] mtx[4] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 elseif bit32.band(flags, bit32.lshift(1, 7)) ~= 0 then -- WE_HAVE_A_TWO_BY_TWO mtx[1] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 mtx[2] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 mtx[3] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 mtx[4] = ttSHORT(data, comp) / 16384.0 comp = comp + 2 end m = STBTT_sqrt(mtx[1] * mtx[1] + mtx[2] * mtx[2]) n = STBTT_sqrt(mtx[3] * mtx[3] + mtx[4] * mtx[4]) comp_num_vertices, comp_verts = stbtt_GetGlyphShape(info, gidx) if comp_num_vertices > 0 then for i = 1, comp_num_vertices do local v = comp_verts[i] local x = v.x local y = v.y v.x = stbtt_int16(m * (mtx[1] * x + mtx[3] * y + mtx[5])) v.y = stbtt_int16(n * (mtx[2] * x + mtx[4] * y + mtx[6])) x = v.cx y = v.cy v.cx = stbtt_int16(m * (mtx[1] * x + mtx[3] * y + mtx[5])) v.cy = stbtt_int16(n * (mtx[2] * x + mtx[4] * y + mtx[6])) end if num_vertices == 0 then -- LUA: No malloc vertices = comp_verts else for i = 1, comp_num_vertices do vertices[num_vertices + i] = comp_verts[i] end end num_vertices = num_vertices + comp_num_vertices end more = bit32.band(flags, bit32.lshift(1, 5)) end end return num_vertices, vertices end --- @param c stbtt__csctx --- @param x stbtt_int32 --- @param y stbtt_int32 local function stbtt__track_vertex(c, x, y) if x > c.max_x or not c.started then c.max_x = x end if y > c.max_y or not c.started then c.max_y = y end if x < c.min_x or not c.started then c.min_x = x end if y < c.min_y or not c.started then c.min_y = y end c.started = true end --- @param c stbtt__csctx --- @param vtx_type STBTT_VTX --- @param x stbtt_int32 --- @param y stbtt_int32 --- @param cx stbtt_int32 --- @param cy stbtt_int32 --- @param cx1 stbtt_int32 --- @param cy1 stbtt_int32 local function stbtt__csctx_v(c, vtx_type, x, y, cx, cy, cx1, cy1) if c.bounds then stbtt__track_vertex(c, x, y) if vtx_type == STBTT_VTX.CUBIC then stbtt__track_vertex(c, cx, cy) stbtt__track_vertex(c, cx1, cy1) end else stbtt_setvertex(c.pvertices[c.num_vertices + 1], vtx_type, x, y, cx, cy) c.pvertices[c.num_vertices + 1].cx1 = stbtt_int16(cx1) c.pvertices[c.num_vertices + 1].cy1 = stbtt_int16(cy1) end end --- @param ctx stbtt__csctx local function stbtt__csctx_close_shape(ctx) if ctx.first_x ~= ctx.x or ctx.first_y ~= ctx.y then stbtt__csctx_v(ctx, STBTT_VTX.LINE, trunc(ctx.first_x), trunc(ctx.first_y), 0, 0, 0, 0) end end --- @param ctx stbtt__csctx --- @param dx float --- @param dy float local function stbtt__csctx_rmove_to(ctx, dx, dy) stbtt__csctx_close_shape(ctx) ctx.x = ctx.x + dx ctx.first_x = ctx.x ctx.y = ctx.y + dy ctx.first_y = ctx.y stbtt__csctx_v(ctx, STBTT_VTX.MOVE, trunc(ctx.x), trunc(ctx.y), 0, 0, 0, 0) end --- @param ctx stbtt__csctx --- @param dx float --- @param dy float local function stbtt__csctx_rline_to(ctx, dx, dy) ctx.x = ctx.x + dx ctx.y = ctx.y + dy stbtt__csctx_v(ctx, STBTT_VTX.LINE, trunc(ctx.x), trunc(ctx.y), 0, 0, 0, 0) end --- @param ctx stbtt__csctx --- @param dx1 float --- @param dy1 float --- @param dx2 float --- @param dy2 float --- @param dx3 float --- @param dy3 float local function stbtt__csctx_rccurve_to(ctx, dx1, dy1, dx2, dy2, dx3, dy3) local cx1 = ctx.x + dx1 local cy1 = ctx.y + dy1 local cx2 = cx1 + dx2 local cy2 = cy1 + dy2 ctx.x = cx2 + dx3 ctx.y = cy2 + dy3 stbtt__csctx_v(ctx, STBTT_VTX.CUBIC, trunc(ctx.x), trunc(ctx.y), trunc(cx1), trunc(cy1), trunc(cx2), trunc(cy2)) end local function stbtt__get_subr(idx, n) local count = stbtt__cff_index_count(idx) local bias = 107 if count >= 33900 then bias = 32768 elseif count >= 1240 then bias = 1131 end n = n + bias if n < 0 or n >= count then return stbtt__new_buf(nil, 0) end return stbtt__cff_index_get(idx, n) end local function stbtt__cid_get_glyph_subrs(info, glyph_index) local fdselect = info.fdselect local fdselector = -1 stbtt__buf_seek(fdselect, 0) local fmt = stbtt__buf_get8(fdselect) if fmt == 0 then -- untested stbtt__buf_skip(fdselect, glyph_index) fdselector = stbtt__buf_get8(fdselect) elseif fmt == 3 then local nranges = stbtt__buf_get16(fdselect) local start = stbtt__buf_get16(fdselect) for i = 0, nranges - 1 do local v = stbtt__buf_get8(fdselect) local _end = stbtt__buf_get16(fdselect) if glyph_index >= start and glyph_index < _end then fdselector = v break end start = _end end end if fdselector == -1 then return stbtt__new_buf(nil, 0) end -- [DEAR IMGUI] fixed, see #6007 and nothings/stb#1422 return stbtt__get_subrs(info.cff, stbtt__cff_index_get(info.fontdicts, fdselector)) end --- @param info stbtt_fontinfo --- @param glyph_index int --- @param c stbtt__csctx local function stbtt__run_charstring(info, glyph_index, c) local in_header = true local maskbits = 0 local subr_stack_height = 0 local sp = 0 local has_subrs = 0 local clear_stack local s = {} -- size = 48, 0-based local subr_stack = {} for i = 1, 10 do subr_stack[i] = stbtt__buf() end local subrs = info.subrs local b, f local function STBTT__CSERR(_s) return 0 end -- this currently ignores the initial width value, which isn't needed if we have hmtx b = stbtt__cff_index_get(info.charstrings, glyph_index) local i, v, b0 while b.cursor < b.size do i = 0 clear_stack = 1 b0 = stbtt__buf_get8(b) -- TODO: implement hinting if b0 == 0x13 or b0 == 0x14 then -- hintmask or cntrmask if in_header then maskbits = maskbits + trunc(sp / 2) -- implicit "vstem" end in_header = false stbtt__buf_skip(b, trunc((maskbits + 7) / 8)) elseif b0 == 0x01 or b0 == 0x03 or b0 == 0x12 or b0 == 0x17 then -- hstem, vstem, hstemhm, vstemhm maskbits = maskbits + trunc(sp / 2) elseif b0 == 0x15 then -- rmoveto in_header = false if sp < 2 then return STBTT__CSERR("rmoveto stack") end stbtt__csctx_rmove_to(c, s[sp - 2], s[sp - 1]) elseif b0 == 0x04 then -- vmoveto in_header = false if sp < 1 then return STBTT__CSERR("vmoveto stack") end stbtt__csctx_rmove_to(c, 0, s[sp - 1]) elseif b0 == 0x16 then -- hmoveto in_header = false if sp < 1 then return STBTT__CSERR("hmoveto stack") end stbtt__csctx_rmove_to(c, s[sp - 1], 0) elseif b0 == 0x05 then -- rlineto if sp < 2 then return STBTT__CSERR("rlineto stack") end while i + 1 < sp do stbtt__csctx_rline_to(c, s[i], s[i + 1]) i = i + 2 end -- hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical -- starting from a different place. elseif b0 == 0x07 then -- vlineto if sp < 1 then return STBTT__CSERR("vlineto stack") end while true do if i >= sp then break end stbtt__csctx_rline_to(c, 0, s[i]) i = i + 1 if i >= sp then break end stbtt__csctx_rline_to(c, s[i], 0) i = i + 1 end elseif b0 == 0x06 then -- hlineto if sp < 1 then return STBTT__CSERR("hlineto stack") end while true do if i >= sp then break end stbtt__csctx_rline_to(c, s[i], 0) i = i + 1 -- vlineto if i >= sp then break end stbtt__csctx_rline_to(c, 0, s[i]) i = i + 1 end elseif b0 == 0x1F then -- hvcurveto if sp < 4 then return STBTT__CSERR("hvcurveto stack") end while true do if i + 3 >= sp then break end stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], ((sp - i) == 5) and s[i + 4] or 0.0, s[i + 3]) i = i + 4 if i + 3 >= sp then break end stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i + 3], ((sp - i) == 5) and s[i + 4] or 0.0) i = i + 4 end elseif b0 == 0x1E then -- vhcurveto if sp < 4 then return STBTT__CSERR("vhcurveto stack") end while true do if i + 3 >= sp then break end stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i + 3], ((sp - i) == 5) and s[i + 4] or 0.0) i = i + 4 -- hvcurveto if i + 3 >= sp then break end stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], ((sp - i) == 5) and s[i + 4] or 0.0, s[i + 3]) i = i + 4 end elseif b0 == 0x08 then -- rrcurveto if sp < 6 then return STBTT__CSERR("rcurveline stack") end while i + 5 < sp do stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]) i = i + 6 end elseif b0 == 0x18 then -- rcurveline if sp < 8 then return STBTT__CSERR("rcurveline stack") end while i + 5 < sp - 2 do stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]) i = i + 6 end if i + 1 >= sp then return STBTT__CSERR("rcurveline stack") end stbtt__csctx_rline_to(c, s[i], s[i + 1]) elseif b0 == 0x19 then -- rlinecurve if sp < 8 then return STBTT__CSERR("rlinecurve stack") end while i + 1 < sp - 6 do stbtt__csctx_rline_to(c, s[i], s[i + 1]) i = i + 2 end if i + 5 >= sp then return STBTT__CSERR("rlinecurve stack") end stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]) elseif b0 == 0x1A or b0 == 0x1B then -- vvcurveto or hhcurveto if sp < 4 then return STBTT__CSERR("(vv|hh)curveto stack") end f = 0.0 if bit32.band(sp, 1) ~= 0 then f = s[i] i = i + 1 end while i + 3 < sp do if b0 == 0x1B then stbtt__csctx_rccurve_to(c, s[i], f, s[i + 1], s[i + 2], s[i + 3], 0.0) else stbtt__csctx_rccurve_to(c, f, s[i], s[i + 1], s[i + 2], 0.0, s[i + 3]) end f = 0.0 i = i + 4 end elseif b0 == 0x0A -- callsubr or b0 == 0x1D then if b0 == 0x0A and has_subrs == 0 then if info.fdselect.size ~= 0 then subrs = stbtt__cid_get_glyph_subrs(info, glyph_index) end has_subrs = 1 end -- callgsubr if sp < 1 then return STBTT__CSERR("call(g|)subr stack") end sp = sp - 1 v = trunc(s[sp]) if subr_stack_height >= 10 then return STBTT__CSERR("recursion limit") end subr_stack[subr_stack_height + 1] = b subr_stack_height = subr_stack_height + 1 b = stbtt__get_subr((b0 == 0x0A) and subrs or info.gsubrs, v) if b.size == 0 then return STBTT__CSERR("subr not found") end b.cursor = 0 clear_stack = 0 elseif b0 == 0x0B then -- return if subr_stack_height <= 0 then return STBTT__CSERR("return outside subr") end subr_stack_height = subr_stack_height - 1 b = subr_stack[subr_stack_height + 1] clear_stack = 0 elseif b0 == 0x0E then -- endchar stbtt__csctx_close_shape(c) return 1 elseif b0 == 0x0C then -- two-byte escape local b1 = stbtt__buf_get8(b) if b1 == 0x22 then -- hflex if sp < 7 then return STBTT__CSERR("hflex stack") end local dx1 = s[0] local dx2 = s[1] local dy2 = s[2] local dx3 = s[3] local dx4 = s[4] local dx5 = s[5] local dx6 = s[6] stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0) stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0) elseif b1 == 0x23 then -- flex if sp < 13 then return STBTT__CSERR("flex stack") end local dx1 = s[0] local dy1 = s[1] local dx2 = s[2] local dy2 = s[3] local dx3 = s[4] local dy3 = s[5] local dx4 = s[6] local dy4 = s[7] local dx5 = s[8] local dy5 = s[9] local dx6 = s[10] local dy6 = s[11] -- fd is s[12] stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3) stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6) elseif b1 == 0x24 then -- hflex1 if sp < 9 then return STBTT__CSERR("hflex1 stack") end local dx1 = s[0] local dy1 = s[1] local dx2 = s[2] local dy2 = s[3] local dx3 = s[4] local dx4 = s[5] local dx5 = s[6] local dy5 = s[7] local dx6 = s[8] stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0) stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1 + dy2 + dy5)) elseif b1 == 0x25 then -- flex1 if sp < 11 then return STBTT__CSERR("flex1 stack") end local dx1 = s[0] local dy1 = s[1] local dx2 = s[2] local dy2 = s[3] local dx3 = s[4] local dy3 = s[5] local dx4 = s[6] local dy4 = s[7] local dx5 = s[8] local dy5 = s[9] local dx6 = s[10] local dy6 = s[10] local dx = dx1 + dx2 + dx3 + dx4 + dx5 local dy = dy1 + dy2 + dy3 + dy4 + dy5 if STBTT_fabs(dx) > STBTT_fabs(dy) then dy6 = -dy else dx6 = -dx end stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3) stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6) else return STBTT__CSERR("unimplemented") end else if b0 ~= 255 and b0 ~= 28 and b0 < 32 then return STBTT__CSERR("reserved operator") end -- push immediate if b0 == 255 then f = stbtt__buf_get32(b) / 0x10000 else stbtt__buf_skip(b, -1) f = stbtt_int16(stbtt__cff_int(b)) end if sp >= 48 then return STBTT__CSERR("push stack overflow") end s[sp] = f sp = sp + 1 clear_stack = 0 end if clear_stack ~= 0 then sp = 0 end end return STBTT__CSERR("no endchar") end --- @param info stbtt_fontinfo --- @param glyph_index int --- @return int num_vertices --- @return stbtt_vertex[]? vertices function stbtt__GetGlyphShapeT2(info, glyph_index) -- runs the charstring twice, once to count and once to output (to avoid realloc) local vertices = nil local count_ctx = STBTT__CSCTX_INIT(true) local output_ctx = STBTT__CSCTX_INIT(false) if stbtt__run_charstring(info, glyph_index, count_ctx) ~= 0 then vertices = {} for i = 1, count_ctx.num_vertices do vertices[i] = stbtt_vertex() end output_ctx.pvertices = vertices if stbtt__run_charstring(info, glyph_index, output_ctx) ~= 0 then STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices) return output_ctx.num_vertices, vertices end end return 0, vertices end --- @param info stbtt_fontinfo --- @param glyph_index int --- @return int --- @return int x0 --- @return int y0 --- @return int x1 --- @return int y1 function stbtt__GetGlyphInfoT2(info, glyph_index) local c = STBTT__CSCTX_INIT(true) local r = stbtt__run_charstring(info, glyph_index, c) local x0 = (r ~= 0) and c.min_x or 0 local y0 = (r ~= 0) and c.min_y or 0 local x1 = (r ~= 0) and c.max_x or 0 local y1 = (r ~= 0) and c.max_y or 0 return ((r ~= 0) and c.num_vertices or 0), x0, y0, x1, y1 end --- @param info stbtt_fontinfo --- @param glyph_index int function stbtt_GetGlyphShape(info, glyph_index) if info.cff.size == 0 then return stbtt__GetGlyphShapeTT(info, glyph_index) else return stbtt__GetGlyphShapeT2(info, glyph_index) end end --- @param info stbtt_fontinfo --- @param glyph_index int function stbtt_GetGlyphHMetrics(info, glyph_index) local numOfLongHorMetrics = ttUSHORT(info.data, info.hhea + 34) local advanceWidth, leftSideBearing if glyph_index < numOfLongHorMetrics then advanceWidth = ttSHORT(info.data, info.hmtx + 4 * glyph_index) leftSideBearing = ttSHORT(info.data, info.hmtx + 4 * glyph_index + 2) else advanceWidth = ttSHORT(info.data, info.hmtx + 4 * (numOfLongHorMetrics - 1)) leftSideBearing = ttSHORT(info.data, info.hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics)) end return advanceWidth, leftSideBearing end --- @param info stbtt_fontinfo function stbtt_GetFontVMetrics(info) local ascent = ttSHORT(info.data, info.hhea + 4) local descent = ttSHORT(info.data, info.hhea + 6) local lineGap = ttSHORT(info.data, info.hhea + 8) return ascent, descent, lineGap end --- @param info stbtt_fontinfo --- @param height float function stbtt_ScaleForPixelHeight(info, height) local fheight = ttSHORT(info.data, info.hhea + 4) - ttSHORT(info.data, info.hhea + 6) return height / fheight end ------------------------------------ ------------------------------------ --- --- Antialiasing software rasterizer --- --- --- @param font stbtt_fontinfo --- @param glyph int --- @param scale_x float --- @param scale_y float --- @param shift_x float --- @param shift_y float function stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, shift_x, shift_y) local n, x0, y0, x1, y1 = stbtt_GetGlyphBox(font, glyph) local ix0, iy0, ix1, iy1 if n == 0 then -- e.g. space character ix0 = 0 iy0 = 0 ix1 = 0 iy1 = 0 else -- move to integral bboxes (treating pixels as little squares, what pixels get touched)? ix0 = STBTT_ifloor( x0 * scale_x + shift_x) iy0 = STBTT_ifloor(-y1 * scale_y + shift_y) ix1 = STBTT_iceil( x1 * scale_x + shift_x) iy1 = STBTT_iceil(-y0 * scale_y + shift_y) end return ix0, iy0, ix1, iy1 end --- @param font stbtt_fontinfo --- @param glyph int --- @param scale_x float --- @param scale_y float function stbtt_GetGlyphBitmapBox(font, glyph, scale_x, scale_y) return stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0, 0.0) end -------------- -------------- --- --- Rasterizer --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt_MakeCodepointBitmap --- stbtt_MakeCodepointBitmapSubpixelPrefilter --- stbtt_GetGlyphBitmap --- stbtt_MakeGlyphBitmap --- stbtt_GetGlyphBitmapSubpixel --- @param scanline float[] --- @param x int --- @param e stbtt__active_edge --- @param x0 float --- @param y0 float --- @param x1 float --- @param y1 float local function stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1) if y0 == y1 then return end STBTT_assert(y0 < y1) STBTT_assert(e.sy <= e.ey) if y0 > e.ey then return end if y1 < e.sy then return end if y0 < e.sy then x0 = x0 + (x1 - x0) * (e.sy - y0) / (y1 - y0) y0 = e.sy end if y1 > e.ey then x1 = x1 + (x1 - x0) * (e.ey - y1) / (y1 - y0) y1 = e.ey end if x0 == x then STBTT_assert(x1 <= x + 1) elseif x0 == x + 1 then STBTT_assert(x1 >= x) elseif x0 <= x then STBTT_assert(x1 <= x) elseif x0 >= x + 1 then STBTT_assert(x1 >= x + 1) else STBTT_assert(x1 >= x and x1 <= x + 1) end if x0 <= x and x1 <= x then scanline[x] = scanline[x] + e.direction * (y1 - y0) elseif x0 >= x + 1 and x1 >= x + 1 then -- do nothing else STBTT_assert(x0 >= x and x0 <= x + 1 and x1 >= x and x1 <= x + 1) scanline[x] = scanline[x] + e.direction * (y1 - y0) * (1 - ((x0 - x) + (x1 - x)) / 2) end end --- @param height float --- @param top_width float --- @param bottom_width float local function stbtt__sized_trapezoid_area(height, top_width, bottom_width) STBTT_assert(top_width >= 0) STBTT_assert(bottom_width >= 0) return (top_width + bottom_width) / 2.0 * height end --- @param height float --- @param tx0 float --- @param tx1 float --- @param bx0 float --- @param bx1 float local function stbtt__position_trapezoid_area(height, tx0, tx1, bx0, bx1) return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0) end --- @param height float --- @param width float local function stbtt__sized_triangle_area(height, width) return height * width / 2 end --- @param scanline float[] --- @param scanline_fill float[] --- @param len int --- @param e stbtt__active_edge --- @param y_top float local function stbtt__fill_active_edges_new(scanline, scanline_fill, len, e, y_top) local y_bottom = y_top + 1 while e do -- brute force every pixel -- compute intersection points with top & bottom STBTT_assert(e.ey >= y_top) if e.fdx == 0 then local x0 = e.fx if x0 < len then if x0 >= 0 then stbtt__handle_clipped_edge(scanline, trunc(x0), e, x0, y_top, x0, y_bottom) stbtt__handle_clipped_edge(scanline_fill, trunc(x0) + 1, e, x0, y_top, x0, y_bottom) else stbtt__handle_clipped_edge(scanline_fill, 0, e, x0, y_top, x0, y_bottom) end end else local x0 = e.fx local dx = e.fdx local xb = x0 + dx local x_top, x_bottom local sy0, sy1 local dy = e.fdy STBTT_assert(e.sy <= y_bottom and e.ey >= y_top) -- compute endpoints of line segment clipped to this scanline (if the -- line segment starts on this scanline. x0 is the intersection of the -- line with y_top, but that may be off the line segment. if e.sy > y_top then x_top = x0 + dx * (e.sy - y_top) sy0 = e.sy else x_top = x0 sy0 = y_top end if e.ey < y_bottom then x_bottom = x0 + dx * (e.ey - y_top) sy1 = e.ey else x_bottom = xb sy1 = y_bottom end if x_top >= 0 and x_bottom >= 0 and x_top < len and x_bottom < len then -- from here on, we don't have to range check x values if trunc(x_top) == trunc(x_bottom) then -- simple case, only spans one pixel local height local x = trunc(x_top) height = (sy1 - sy0) * e.direction STBTT_assert(x >= 0 and x < len) scanline[x] = scanline[x] + stbtt__position_trapezoid_area(height, x_top, x + 1.0, x_bottom, x + 1.0) scanline_fill[x + 1] = scanline_fill[x + 1] + height -- everything right of this pixel is filled else local x1, x2 local y_crossing, y_final, step, sign, area -- covers 2+ pixels if x_top > x_bottom then -- flip scanline vertically; signed area is the same sy0 = y_bottom - (sy0 - y_top) sy1 = y_bottom - (sy1 - y_top) local t t = sy0; sy0 = sy1; sy1 = t t = x_bottom; x_bottom = x_top; x_top = t dx = -dx dy = -dy t = x0; x0 = xb; xb = t end STBTT_assert(dy >= 0) STBTT_assert(dx >= 0) x1 = trunc(x_top) x2 = trunc(x_bottom) -- compute intersection with y axis at x1+1 y_crossing = y_top + dy * (x1 + 1 - x0) -- compute intersection with y axis at x2 y_final = y_top + dy * (x2 - x0) -- if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 -- TODO: maybe test against sy1 rather than y_bottom? if y_crossing > y_bottom then y_crossing = y_bottom end sign = e.direction -- area of the rectangle covered from sy0..y_crossing area = sign * (y_crossing - sy0) -- area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) scanline[x1] = scanline[x1] + stbtt__sized_triangle_area(area, x1 + 1 - x_top) -- check if final y_crossing is blown up; no test case for this if y_final > y_bottom then local denom = (x2 - (x1 + 1)) y_final = y_bottom if denom ~= 0 then -- [DEAR IMGUI] Avoid div by zero (https://github.com/nothings/stb/issues/1316) dy = (y_final - y_crossing) / denom -- if denom=0, y_final = y_crossing, so y_final <= y_bottom end end step = sign * dy * 1 -- dy is dy/dx, change in y for every 1 change in x, -- which multiplied by 1-pixel-width is how much pixel area changes for each step in x -- so the area advances by 'step' every time for x = x1 + 1, x2 - 1 do scanline[x] = scanline[x] + area + step / 2 -- area of trapezoid is 1*step/2 area = area + step end STBTT_assert(STBTT_fabs(area) <= 1.01) -- accumulated error from area += step unless we round step down STBTT_assert(sy1 > y_final - 0.01) -- area covered in the last pixel is the rectangle from all the pixels to the left, -- plus the trapezoid filled by the line segment in this pixel all the way to the right edge scanline[x2] = scanline[x2] + area + sign * stbtt__position_trapezoid_area(sy1 - y_final, x2, x2 + 1.0, x_bottom, x2 + 1.0) -- the rest of the line is filled based on the total height of the line segment in this pixel scanline_fill[x2 + 1] = scanline_fill[x2 + 1] + sign * (sy1 - sy0) end else for x = 0, len - 1 do -- rename variables to clearly-defined pairs local y0 = y_top local x1 = x local x2 = x + 1 local x3 = xb local y3 = y_bottom -- x = e->x + e->dx * (y-y_top) -- (y-y_top) = (x - e->x) / e->dx -- y = (x - e->x) / e->dx + y_top local y1 = (x - x0) / dx + y_top local y2 = (x + 1 - x0) / dx + y_top if x0 < x1 and x3 > x2 then -- three segments descending down-right stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1) stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2) stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3) elseif x3 < x1 and x0 > x2 then -- three segments descending down-left stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2) stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1) stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3) elseif x0 < x1 and x3 > x1 then -- two segments across x, down-right stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1) stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3) elseif x3 < x1 and x0 > x1 then -- two segments across x, down-left stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1) stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3) elseif x0 < x2 and x3 > x2 then -- two segments across x+1, down-right stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2) stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3) elseif x3 < x2 and x0 > x2 then -- two segments across x+1, down-left stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2) stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3) else -- one segment stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3) end end end end e = e.next end end --- @param result stbtt__bitmap --- @param e stbtt__edge --- @param n int --- @param vsubsample int --- @param off_x int --- @param off_y int local function stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y) local active = nil local scanline = {} -- size = result.w, 0-based local scanline2 = {} -- size = result.w + 1, 0-based STBTT__NOTUSED(vsubsample) local y = off_y e[n + 1].y0 = off_y + result.h + 1 local j = 0 local p = 1 while j < result.h do -- find center of pixel for this scanline local scan_y_top = y + 0.0 local scan_y_bottom = y + 1.0 for i = 0, result.w - 1 do scanline[i] = 0 end for i = 0, result.w do scanline2[i] = 0 end local prev = nil local curr = active while curr do local next = curr.next if curr.ey <= scan_y_top then if prev then prev.next = next else active = next end curr.direction = 0 else prev = curr end curr = next end local edge = e[p] while edge.y0 <= scan_y_bottom do if edge.y0 ~= edge.y1 then local z = stbtt__new_active(edge, off_x, scan_y_top) if j == 0 and off_y ~= 0 and z.ey < scan_y_top then z.ey = scan_y_top end STBTT_assert(z.ey >= scan_y_top) z.next = active active = z end p = p + 1 edge = e[p] end if active then stbtt__fill_active_edges_new(scanline, scanline2, result.w, active, scan_y_top) end do local sum = 0 for i = 0, result.w - 1 do local k local m sum = sum + scanline2[i] k = scanline[i] + sum k = STBTT_fabs(k) * 255 + 0.5 m = trunc(k) if m > 255 then m = 255 end result.pixels[j * result.stride + i + 1] = unsigned_char(m) end end step = active while step do step.fx = step.fx + step.fdx step = step.next end y = y + 1 j = j + 1 end end --- @param a stbtt__edge --- @param b stbtt__edge local STBTT__COMPARE = function(a, b) if a.y0 == nil then return false end -- sentinels on the back if b.y0 == nil then return true end return a.y0 < b.y0 end --- @param p stbtt__edge[] local function stbtt__sort_edges(p) STBTT_sort(p, STBTT__COMPARE) end --- @param result stbtt__bitmap --- @param pts stbtt__point[] --- @param wcount int[] --- @param windings int --- @param scale_x float --- @param scale_y float --- @param shift_x float --- @param shift_y float --- @param off_x int --- @param off_y int --- @param invert bool local function stbtt__rasterize(result, pts, wcount, windings, scale_x, scale_y, shift_x, shift_y, off_x, off_y, invert) local y_scale_inv = (invert) and -scale_y or scale_y local vsubsample = 1 -- STBTT_RASTERIZER_VERSION == 2 -- now we have to blow out the windings into explicit edge lists local n = 0 for i = 1, windings do n = n + wcount[i] end local e = {} for i = 1, n + 1 do e[i] = stbtt__edge() end -- add an extra one as a sentinel n = 0 local m = 0 local j for i = 1, windings do local p = m m = m + wcount[i] j = wcount[i] for k = 1, wcount[i] do repeat local a = k local b = j -- skip the edge if horizontal if pts[p + j].y == pts[p + k].y then break end -- add edge from j to k to the list n = n + 1 e[n].invert = false if invert then if pts[p + j].y > pts[p + k].y then e[n].invert = true a = j b = k end else if pts[p + j].y < pts[p + k].y then e[n].invert = true a = j b = k end end e[n].x0 = pts[p + a].x * scale_x + shift_x e[n].y0 = (pts[p + a].y * y_scale_inv + shift_y) * vsubsample e[n].x1 = pts[p + b].x * scale_x + shift_x e[n].y1 = (pts[p + b].y * y_scale_inv + shift_y) * vsubsample until true j = k end end -- now sort the edges by their highest point (should snap to integer, and then by x) stbtt__sort_edges(e) -- now, traverse the scanlines and find the intersections on each scanline, use xor winding rule stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y) end --- @param points? stbtt__point[] --- @param n int --- @param x float --- @param y float local function stbtt__add_point(points, n, x, y) if points == nil then return end -- during first pass, it's unallocated points[n + 1].x = x points[n + 1].y = y end -- tessellate until threshold p is happy... -- TODO: warped to compensate for non-linear stretching --- @param points? stbtt__point[] --- @param num_points int --- @param x0 float --- @param y0 float --- @param x1 float --- @param y1 float --- @param x2 float --- @param y2 float --- @param objspace_flatness_squared float --- @param n int --- @return int num_points # updated num_points passed in local function stbtt__tesselate_curve(points, num_points, x0, y0, x1, y1, x2, y2, objspace_flatness_squared, n) -- midpoint local mx = (x0 + 2 * x1 + x2) / 4 local my = (y0 + 2 * y1 + y2) / 4 -- versus directly drawn line local dx = (x0 + x2) / 2 - mx local dy = (y0 + y2) / 2 - my if n > 16 then -- 65536 segments on one curve better be enough! return num_points end if dx * dx + dy * dy > objspace_flatness_squared then -- half-pixel error allowed... need to be smaller if AA num_points = stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0, (y0 + y1) / 2.0, mx, my, objspace_flatness_squared, n + 1) num_points = stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0, (y1 + y2) / 2.0, x2, y2, objspace_flatness_squared, n + 1) else stbtt__add_point(points, num_points, x2, y2) num_points = num_points + 1 end return num_points end --- @param points? stbtt__point[] --- @param num_points int --- @param x0 float --- @param y0 float --- @param x1 float --- @param y1 float --- @param x2 float --- @param y2 float --- @param x3 float --- @param y3 float --- @param objspace_flatness_squared float --- @param n int --- @return int num_points # updated num_points passed in local function stbtt__tesselate_cubic(points, num_points, x0, y0, x1, y1, x2, y2, x3, y3, objspace_flatness_squared, n) -- TODO: this "flatness" calculation is just made-up nonsense that seems to work well enough local dx0 = x1 - x0 local dy0 = y1 - y0 local dx1 = x2 - x1 local dy1 = y2 - y1 local dx2 = x3 - x2 local dy2 = y3 - y2 local dx = x3 - x0 local dy = y3 - y0 local longlen = STBTT_sqrt(dx0 * dx0 + dy0 * dy0) + STBTT_sqrt(dx1 * dx1 + dy1 * dy1) + STBTT_sqrt(dx2 * dx2 + dy2 * dy2) local shortlen = STBTT_sqrt(dx * dx + dy * dy) local flatness_squared = longlen * longlen - shortlen * shortlen if n > 16 then -- 65536 segments on one curve better be enough! return num_points end if flatness_squared > objspace_flatness_squared then local x01 = (x0 + x1) / 2 local y01 = (y0 + y1) / 2 local x12 = (x1 + x2) / 2 local y12 = (y1 + y2) / 2 local x23 = (x2 + x3) / 2 local y23 = (y2 + y3) / 2 local xa = (x01 + x12) / 2 local ya = (y01 + y12) / 2 local xb = (x12 + x23) / 2 local yb = (y12 + y23) / 2 local mx = (xa + xb) / 2 local my = (ya + yb) / 2 num_points = stbtt__tesselate_cubic(points, num_points, x0, y0, x01, y01, xa, ya, mx, my, objspace_flatness_squared, n + 1) num_points = stbtt__tesselate_cubic(points, num_points, mx, my, xb, yb, x23, y23, x3, y3, objspace_flatness_squared, n + 1) else stbtt__add_point(points, num_points, x3, y3) num_points = num_points + 1 end return num_points end --- @param vertices stbtt_vertex[] --- @param num_verts int --- @param objspace_flatness float --- @return stbtt__point[]? points --- @return int? num_contours --- @return int[]? contour_lengths local function stbtt_FlattenCurves(vertices, num_verts, objspace_flatness) local points = nil local num_points = 0 local objspace_flatness_squared = objspace_flatness * objspace_flatness local n = 0 local start = 0 -- count how many "moves" there are to get the contour count for i = 1, num_verts do if vertices[i].type == STBTT_VTX.MOVE then n = n + 1 end end local num_contours = n if n == 0 then return nil end local contour_lengths = {} -- size = n -- make two passes through the points so we don't need to realloc for pass = 0, 1 do local x, y = 0, 0 if pass == 1 then points = {} for i = 1, num_points do points[i] = stbtt__point() end end num_points = 0 n = -1 for i = 1, num_verts do if vertices[i].type == STBTT_VTX.MOVE then -- start the next contour if n >= 0 then contour_lengths[n + 1] = num_points - start end n = n + 1 start = num_points x = vertices[i].x y = vertices[i].y stbtt__add_point(points, num_points, x, y) num_points = num_points + 1 elseif vertices[i].type == STBTT_VTX.LINE then x = vertices[i].x y = vertices[i].y stbtt__add_point(points, num_points, x, y) num_points = num_points + 1 elseif vertices[i].type == STBTT_VTX.CURVE then num_points = stbtt__tesselate_curve(points, num_points, x, y, vertices[i].cx, vertices[i].cy, vertices[i].x, vertices[i].y, objspace_flatness_squared, 0) x = vertices[i].x y = vertices[i].y elseif vertices[i].type == STBTT_VTX.CUBIC then num_points = stbtt__tesselate_cubic(points, num_points, x, y, vertices[i].cx, vertices[i].cy, vertices[i].cx1, vertices[i].cy1, vertices[i].x, vertices[i].y, objspace_flatness_squared, 0) x = vertices[i].x y = vertices[i].y end end contour_lengths[n + 1] = num_points - start end return points, num_contours, contour_lengths end --- @param result stbtt__bitmap --- @param flatness_in_pixels float --- @param vertices stbtt_vertex[] --- @param num_verts int --- @param scale_x float --- @param scale_y float --- @param shift_x float --- @param shift_y float --- @param x_off int --- @param y_off int --- @param invert bool local function stbtt_Rasterize(result, flatness_in_pixels, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert) local scale = (scale_x > scale_y) and scale_y or scale_x local windings, winding_count, winding_lengths = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale) if windings then --- @cast winding_lengths int[] --- @cast winding_count int stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert) end end --- @param info stbtt_fontinfo --- @param output unsigned_char[] --- @param out_w int --- @param out_h int --- @param out_stride int --- @param scale_x float --- @param scale_y float --- @param shift_x float --- @param shift_y float --- @param glyph int local function stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, glyph) local num_verts, vertices = stbtt_GetGlyphShape(info, glyph) local gbm = stbtt__bitmap() local ix0, iy0 = stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y) gbm.pixels = output gbm.w = out_w gbm.h = out_h gbm.stride = out_stride if gbm.w ~= 0 and gbm.h ~= 0 then stbtt_Rasterize(gbm, 0.35, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, true) end end ----------------- ----------------- --- --- Bitmap baking --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt_BakeFontBitmap_internal --- stbtt_BakeFontBitmap --- stbtt_GetBakedQuad --------------------------- --------------------------- --- --- Bitmap baking / packing --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt_PackBegin --- stbtt_PackSetOversampling --- stbtt_PackSetSkipMissingCodepoints --- stbtt_PackFontRangesGatherRects --- stbtt_PackFontRangesRenderIntoRects --- stbtt_PackFontRangesPackRects --- stbtt_PackFontRanges --- stbtt_PackFontRange --- stbtt_GetPackedQuad --- stbtt_GetScaledFontVMetrics local STBTT__OVER_MASK = STBTT_MAX_OVERSAMPLE - 1 --- @param pixels table --- @param w int --- @param h int --- @param stride_in_bytes int --- @param kernel_width unsigned_int local function stbtt__h_prefilter(pixels, w, h, stride_in_bytes, kernel_width) local buffer = {} local safe_w = w - kernel_width for j = 0, h - 1 do local total = 0 local row_offset = j * stride_in_bytes for i = 1, kernel_width do buffer[i] = 0 end for i = 0, safe_w do total = total + pixels[row_offset + i + 1] - buffer[bit32.band(i, STBTT__OVER_MASK) + 1] buffer[bit32.band(i + kernel_width, STBTT__OVER_MASK) + 1] = pixels[row_offset + i + 1] pixels[row_offset + i + 1] = unsigned_char(total / kernel_width) end for i = safe_w + 1, w - 1 do STBTT_assert(pixels[row_offset + i + 1] == 0) total = total - buffer[bit32.band(i, STBTT__OVER_MASK) + 1] pixels[row_offset + i + 1] = unsigned_char(total / kernel_width) end end end --- @param pixels table --- @param w int --- @param h int --- @param stride_in_bytes int --- @param kernel_width unsigned_int local function stbtt__v_prefilter(pixels, w, h, stride_in_bytes, kernel_width) local buffer = {} local safe_h = h - kernel_width for j = 0, w - 1 do local total = 0 local col_offset = j for i = 1, kernel_width do buffer[i] = 0 end for i = 0, safe_h do total = total + pixels[col_offset + i * stride_in_bytes + 1] - buffer[bit32.band(i, STBTT__OVER_MASK) + 1] buffer[bit32.band(i + kernel_width, STBTT__OVER_MASK) + 1] = pixels[col_offset + i * stride_in_bytes + 1] pixels[col_offset + i * stride_in_bytes + 1] = unsigned_char(total / kernel_width) end for i = safe_h + 1, h - 1 do STBTT_assert(pixels[col_offset + i * stride_in_bytes + 1] == 0) total = total - buffer[bit32.band(i, STBTT__OVER_MASK) + 1] pixels[col_offset + i * stride_in_bytes + 1] = unsigned_char(total / kernel_width) end end end --- @param oversample int --- @return float local function stbtt__oversample_shift(oversample) if oversample == 0 then return 0.0 end return -(oversample - 1) / (2.0 * oversample) end --- @param info stbtt_fontinfo --- @param output unsigned_char[] --- @param out_w int --- @param out_h int --- @param out_stride int --- @param scale_x float --- @param scale_y float --- @param shift_x float --- @param shift_y float --- @param prefilter_x int --- @param prefilter_y int --- @param glyph int function stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, prefilter_x, prefilter_y, glyph) stbtt_MakeGlyphBitmapSubpixel(info, output, out_w - (prefilter_x - 1), out_h - (prefilter_y - 1), out_stride, scale_x, scale_y, shift_x, shift_y, glyph) if prefilter_x > 1 then stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x) end if prefilter_y > 1 then stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y) end local sub_x, sub_y sub_x = stbtt__oversample_shift(prefilter_x) sub_y = stbtt__oversample_shift(prefilter_y) return sub_x, sub_y end ------------------- ------------------- --- --- SDF computation --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt__ray_intersect_bezier --- stbtt__compute_crossings_x --- stbtt__cuberoot --- stbtt__solve_cubic --- stbtt_GetGlyphSDF --- stbtt_GetCodepointSDF ----------------------------------------------------- ----------------------------------------------------- --- --- Font name matching -- recommended not to use this --- --- --- UNIMPLEMENTED / UNUSED: --- stbtt__CompareUTF8toUTF16_bigendian_prefix --- stbtt_CompareUTF8toUTF16_bigendian_internal --- stbtt_GetFontNameString --- stbtt__matchpair --- stbtt__matches --- @param data table --- @param index int function stbtt_GetFontOffsetForIndex(data, index) return stbtt_GetFontOffsetForIndex_internal(data, index) end --- @param info stbtt_fontinfo --- @param data table --- @param offset int function stbtt_InitFont(info, data, offset) return stbtt_InitFont_internal(info, data, offset) end return { fontinfo = stbtt_fontinfo, InitFont = stbtt_InitFont, FindGlyphIndex = stbtt_FindGlyphIndex, MakeGlyphBitmapSubpixelPrefilter = stbtt_MakeGlyphBitmapSubpixelPrefilter, GetFontVMetrics = stbtt_GetFontVMetrics, GetGlyphBitmapBox = stbtt_GetGlyphBitmapBox, GetGlyphBitmapBoxSubpixel = stbtt_GetGlyphBitmapBoxSubpixel, GetGlyphHMetrics = stbtt_GetGlyphHMetrics, GetFontOffsetForIndex = stbtt_GetFontOffsetForIndex, ScaleForPixelHeight = stbtt_ScaleForPixelHeight } end __FILES['imstd_minstdio.lua'] = function() --- Dear ImGui -- This is a minimal Lua impl of C-like sscanf, sprintf sub-set -- Supports: -- - %x, %X, %nx, %nX (where n is a number) -- - %d, %nd (where n is a number) -- - %f, %lf (very limited) -- -- Returns items_matched instead of EOF on error local _byte = string.byte local CHAR_PERCENT = _byte'%' local CHAR_DOT = _byte'.' local CHAR_PLUS, CHAR_MINUS = _byte'+', _byte'-' local CHAR_0, CHAR_9 = _byte'0', _byte'9' local CHAR_a, CHAR_A = _byte'a', _byte'A' local CHAR_d = _byte'd' local CHAR_l = _byte'l' local CHAR_f, CHAR_F = _byte'f', _byte'F' local CHAR_x, CHAR_X = _byte'x', _byte'X' local function isspace(c) return c == 32 or c == 9 end local function isdigit(c) return c >= CHAR_0 and c <= CHAR_9 end local function isxdigit(c) return isdigit(c) or (c >= CHAR_a and c <= CHAR_f) or (c >= CHAR_A and c <= CHAR_F) end local function isdigit_under_base(c, base) if base == 10 then return isdigit(c) elseif base == 16 then return isxdigit(c) end end local function hex_digit_to_int(c) if c >= CHAR_0 and c <= CHAR_9 then return c - CHAR_0 end if c >= CHAR_a and c <= CHAR_f then return c - CHAR_a + 10 end if c >= CHAR_A and c <= CHAR_F then return c - CHAR_A + 10 end end -- we force this behavior by default local function clamp_if_overflow(spec, val) if spec == CHAR_d or spec == CHAR_x or spec == CHAR_X then if val > INT_MAX then return INT_MAX end if val < INT_MIN then return INT_MIN end end return val end --- @param buffer char[] --- @param buffer_begin int --- @param format string --- @param result table # table to store parsed values local function sscanf(buffer, buffer_begin, format, result) local p = buffer_begin local f = 1 -- format_begin local format_len = #format local assigned = 0 local items_matched = 0 while f <= format_len do repeat if isspace(_byte(format, f, f)) then while isspace(buffer[p]) do p = p + 1 end f = f + 1 break end if _byte(format, f, f) ~= CHAR_PERCENT then if buffer[p] == _byte(format, f, f) then p = p + 1 f = f + 1 else return items_matched end break end -- encountered % in fmt f = f + 1 -- %% if _byte(format, f, f) == CHAR_PERCENT then if buffer[p] == CHAR_PERCENT then p = p + 1 f = f + 1 else return items_matched end break end -- handle optional width local width = 0 while isdigit(_byte(format, f, f)) do width = width * 10 + _byte(format, f, f) - CHAR_0 f = f + 1 end if width == 0 then width = math.huge end local spec = _byte(format, f, f) local base local is_float = false if spec == CHAR_x or spec == CHAR_X then base = 16 elseif spec == CHAR_d then base = 10 elseif spec == CHAR_f or spec == CHAR_F then is_float = true elseif spec == CHAR_l then f = f + 1 if _byte(format, f, f) == CHAR_f then is_float = true -- TODO: distinguish from float? else return items_matched end else return items_matched end f = f + 1 while isspace(buffer[p]) do p = p + 1 end local val if is_float then local sign = 1 if buffer[p] == CHAR_PLUS then p = p + 1 elseif buffer[p] == CHAR_MINUS then sign = -1 p = p + 1 end -- inf, nan are not handled local p_start = p local int_part = 0 while isdigit(buffer[p]) do int_part = int_part * 10 + (buffer[p] - CHAR_0) p = p + 1 end local frac_part = 0 local frac_div = 1 if buffer[p] == CHAR_DOT then p = p + 1 while isdigit(buffer[p]) do frac_part = frac_part * 10 + (buffer[p] - CHAR_0) frac_div = frac_div * 10 p = p + 1 end end if p == p_start then return items_matched end val = sign * (int_part + frac_part / frac_div) else local sign = 1 -- optional sign if base == 10 then if buffer[p] == CHAR_PLUS then p = p + 1 width = width - 1 elseif buffer[p] == CHAR_MINUS then sign = -1 p = p + 1 width = width - 1 end end local p_start = p while width > 0 and buffer[p] and isdigit_under_base(buffer[p], base) do p = p + 1 width = width - 1 end if p == p_start then -- failed to match return items_matched end val = 0 while p_start < p do local c = buffer[p_start] p_start = p_start + 1 val = val * base + sign * hex_digit_to_int(c) local old_val = val val = clamp_if_overflow(spec, val) if old_val ~= val then break end end end result[assigned + 1] = val assigned = assigned + 1 items_matched = items_matched + 1 until true end return items_matched end local function sprintf() end return sscanf end IM_INCLUDE('imgui.lua') IM_INCLUDE('imgui_impl_roblox.lua') IM_INCLUDE('imgui_demo.lua') return { BuildLoadGlyphGetAdvanceOrFallback = BuildLoadGlyphGetAdvanceOrFallback, CalcNextScrollFromScrollTargetAndClamp = CalcNextScrollFromScrollTargetAndClamp, 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, DemoWindowLayout = DemoWindowLayout, DemoWindowPopups = DemoWindowPopups, DemoWindowTables = DemoWindowTables, DemoWindowWidgets = DemoWindowWidgets, DemoWindowWidgetsBasic = DemoWindowWidgetsBasic, DemoWindowWidgetsBullets = DemoWindowWidgetsBullets, DemoWindowWidgetsCollapsingHeaders = DemoWindowWidgetsCollapsingHeaders, DemoWindowWidgetsColorAndPickers = DemoWindowWidgetsColorAndPickers, DemoWindowWidgetsComboBoxes = DemoWindowWidgetsComboBoxes, DemoWindowWidgetsDataTypes = DemoWindowWidgetsDataTypes, DemoWindowWidgetsDisableBlocks = DemoWindowWidgetsDisableBlocks, DemoWindowWidgetsDragAndDrop = DemoWindowWidgetsDragAndDrop, DemoWindowWidgetsDragsAndSliders = DemoWindowWidgetsDragsAndSliders, DemoWindowWidgetsFonts = DemoWindowWidgetsFonts, DemoWindowWidgetsImages = DemoWindowWidgetsImages, DemoWindowWidgetsListBoxes = DemoWindowWidgetsListBoxes, DemoWindowWidgetsLiveEdit = DemoWindowWidgetsLiveEdit, DemoWindowWidgetsMixedValues = DemoWindowWidgetsMixedValues, DemoWindowWidgetsMultiComponents = DemoWindowWidgetsMultiComponents, DemoWindowWidgetsPlotting = DemoWindowWidgetsPlotting, DemoWindowWidgetsProgressBars = DemoWindowWidgetsProgressBars, DemoWindowWidgetsQueryingStatuses = DemoWindowWidgetsQueryingStatuses, DemoWindowWidgetsSelectables = DemoWindowWidgetsSelectables, DemoWindowWidgetsTabs = DemoWindowWidgetsTabs, DemoWindowWidgetsText = DemoWindowWidgetsText, DemoWindowWidgetsTextFilter = DemoWindowWidgetsTextFilter, DemoWindowWidgetsTextInput = DemoWindowWidgetsTextInput, DemoWindowWidgetsTooltips = DemoWindowWidgetsTooltips, DemoWindowWidgetsTreeNodes = DemoWindowWidgetsTreeNodes, DemoWindowWidgetsVerticalSliders = DemoWindowWidgetsVerticalSliders, DockSettingsFindNodeSettings = DockSettingsFindNodeSettings, DockSettingsHandler_ApplyAll = DockSettingsHandler_ApplyAll, DockSettingsHandler_ClearAll = DockSettingsHandler_ClearAll, DockSettingsHandler_ReadLine = DockSettingsHandler_ReadLine, DockSettingsHandler_ReadOpen = DockSettingsHandler_ReadOpen, DockSettingsHandler_WriteAll = DockSettingsHandler_WriteAll, DockSettingsRemoveNodeReferences = DockSettingsRemoveNodeReferences, DockSettingsRenameNodeReferences = DockSettingsRenameNodeReferences, ExampleImageViewerData = ExampleImageViewerData, ExampleImageViewer_DrawCanvas = ExampleImageViewer_DrawCanvas, ExampleImageViewer_DrawOptions = ExampleImageViewer_DrawOptions, ExampleTreeNode = ExampleTreeNode, ExampleTree_CreateDemoTree = ExampleTree_CreateDemoTree, ExampleTree_CreateNode = ExampleTree_CreateNode, ExampleTree_DestroyNode = ExampleTree_DestroyNode, FLT_MAX = FLT_MAX, FLT_MIN = FLT_MIN, FONT_ATLAS_DEFAULT_TEX_DATA_H = FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_W = FONT_ATLAS_DEFAULT_TEX_DATA_W, FormatCached = FormatCached, GetDefaultFontDataProggyClean = GetDefaultFontDataProggyClean, GetDefaultFontDataProggyForever = GetDefaultFontDataProggyForever, GetMinimumStepAtDecimalPrecision = GetMinimumStepAtDecimalPrecision, HelpMarker = HelpMarker, IMGUI_DEBUG_LOG_ACTIVEID = IMGUI_DEBUG_LOG_ACTIVEID, IMGUI_DEBUG_LOG_CLIPPER = IMGUI_DEBUG_LOG_CLIPPER, IMGUI_DEBUG_LOG_DOCKING = IMGUI_DEBUG_LOG_DOCKING, IMGUI_DEBUG_LOG_ERROR = IMGUI_DEBUG_LOG_ERROR, IMGUI_DEBUG_LOG_FOCUS = IMGUI_DEBUG_LOG_FOCUS, IMGUI_DEBUG_LOG_FONT = IMGUI_DEBUG_LOG_FONT, IMGUI_DEBUG_LOG_INPUTROUTING = IMGUI_DEBUG_LOG_INPUTROUTING, IMGUI_DEBUG_LOG_IO = IMGUI_DEBUG_LOG_IO, IMGUI_DEBUG_LOG_NAV = IMGUI_DEBUG_LOG_NAV, IMGUI_DEBUG_LOG_POPUP = IMGUI_DEBUG_LOG_POPUP, IMGUI_DEBUG_LOG_SELECTION = IMGUI_DEBUG_LOG_SELECTION, IMGUI_DEBUG_LOG_TABLE = IMGUI_DEBUG_LOG_TABLE, IMGUI_DEBUG_LOG_VIEWPORT = IMGUI_DEBUG_LOG_VIEWPORT, IMGUI_DEMO_MARKER = IMGUI_DEMO_MARKER, IMGUI_DISABLE_DEBUG_TOOLS = IMGUI_DISABLE_DEBUG_TOOLS, IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS = IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS, IMGUI_FONT_SIZE_MAX = IMGUI_FONT_SIZE_MAX, IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE = IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE, IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F, IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F, IMGUI_PAYLOAD_TYPE_WINDOW = IMGUI_PAYLOAD_TYPE_WINDOW, IMGUI_TABLE_MAX_COLUMNS = IMGUI_TABLE_MAX_COLUMNS, IMGUI_VERSION = IMGUI_VERSION, IMGUI_VERSION_NUM = IMGUI_VERSION_NUM, IMGUI_WINDOW_HARD_MIN_SIZE = IMGUI_WINDOW_HARD_MIN_SIZE, IMSTB_TEXTEDIT_UNDOSTATECOUNT = IMSTB_TEXTEDIT_UNDOSTATECOUNT, IM_ALLOC = IM_ALLOC, IM_ASSERT = IM_ASSERT, IM_ASSERT_PARANOID = IM_ASSERT_PARANOID, IM_ASSERT_USER_ERROR = IM_ASSERT_USER_ERROR, IM_ASSERT_USER_ERROR_RET = IM_ASSERT_USER_ERROR_RET, IM_BITARRAY_CLEARBIT = IM_BITARRAY_CLEARBIT, IM_BITARRAY_TESTBIT = IM_BITARRAY_TESTBIT, IM_COL32 = IM_COL32, IM_COL32_A_MASK = IM_COL32_A_MASK, IM_COL32_A_SHIFT = IM_COL32_A_SHIFT, IM_COL32_BLACK = IM_COL32_BLACK, IM_COL32_BLACK_TRANS = IM_COL32_BLACK_TRANS, IM_COL32_B_SHIFT = IM_COL32_B_SHIFT, IM_COL32_DISABLE = IM_COL32_DISABLE, IM_COL32_G_SHIFT = IM_COL32_G_SHIFT, IM_COL32_R_SHIFT = IM_COL32_R_SHIFT, IM_COL32_WHITE = IM_COL32_WHITE, IM_DELETE = IM_DELETE, IM_DRAWLIST_ARCFAST_SAMPLE_MAX = IM_DRAWLIST_ARCFAST_SAMPLE_MAX, IM_DRAWLIST_ARCFAST_TABLE_SIZE = IM_DRAWLIST_ARCFAST_TABLE_SIZE, IM_F32_TO_INT8_SAT = IM_F32_TO_INT8_SAT, IM_F32_TO_INT8_UNBOUND = IM_F32_TO_INT8_UNBOUND, IM_FILE_CLOSE = IM_FILE_CLOSE, IM_FILE_READ = IM_FILE_READ, IM_FILE_SIZE = IM_FILE_SIZE, IM_FILE_WRITE = IM_FILE_WRITE, IM_FREE = IM_FREE, IM_PI = IM_PI, IM_ROUND = IM_ROUND, IM_ROUNDUP_TO_EVEN = IM_ROUNDUP_TO_EVEN, IM_TABSIZE = IM_TABSIZE, IM_TRUNC = IM_TRUNC, IM_UNICODE_CODEPOINT_INVALID = IM_UNICODE_CODEPOINT_INVALID, IM_UNICODE_CODEPOINT_MAX = IM_UNICODE_CODEPOINT_MAX, INT_MAX = INT_MAX, INT_MIN = INT_MIN, ImAbs = ImAbs, ImAcos = ImAcos, ImAddClampOverflow = ImAddClampOverflow, ImAtan2 = ImAtan2, ImAtof = ImAtof, ImBezierCubicCalc = ImBezierCubicCalc, ImBezierQuadraticCalc = ImBezierQuadraticCalc, ImBitArray = ImBitArray, ImBitArraySetBit = ImBitArraySetBit, ImCeil = ImCeil, ImCeilFast = ImCeilFast, ImCharIsBlankA = ImCharIsBlankA, ImCharIsBlankW = ImCharIsBlankW, ImCharIsSeparatorW = ImCharIsSeparatorW, ImClamp = ImClamp, ImCos = ImCos, ImCountSetBits = ImCountSetBits, ImDot = ImDot, ImDrawChannel = ImDrawChannel, ImDrawCmd = ImDrawCmd, ImDrawCmdHeader = ImDrawCmdHeader, ImDrawData = ImDrawData, ImDrawFlags = ImDrawFlags, ImDrawList = ImDrawList, ImDrawListFlags = ImDrawListFlags, ImDrawListSharedData = ImDrawListSharedData, ImDrawListSplitter = ImDrawListSplitter, ImDrawTextFlags = ImDrawTextFlags, ImDrawVert = ImDrawVert, ImDrawVtxBuffer = ImDrawVtxBuffer, ImDrawVtx_Col = ImDrawVtx_Col, ImDrawVtx_Pos = ImDrawVtx_Pos, ImFabs = ImFabs, ImFloor = ImFloor, ImFmod = ImFmod, ImFont = ImFont, ImFontAtlas = ImFontAtlas, ImFontAtlasAddDrawListSharedData = ImFontAtlasAddDrawListSharedData, ImFontAtlasBakedAdd = ImFontAtlasBakedAdd, ImFontAtlasBakedAddFontGlyph = ImFontAtlasBakedAddFontGlyph, ImFontAtlasBakedAddFontGlyphAdvancedX = ImFontAtlasBakedAddFontGlyphAdvancedX, ImFontAtlasBakedDiscard = ImFontAtlasBakedDiscard, ImFontAtlasBakedGetClosestMatch = ImFontAtlasBakedGetClosestMatch, ImFontAtlasBakedGetId = ImFontAtlasBakedGetId, ImFontAtlasBakedGetOrAdd = ImFontAtlasBakedGetOrAdd, ImFontAtlasBuildAcceptCodepointForSource = ImFontAtlasBuildAcceptCodepointForSource, ImFontAtlasBuildClear = ImFontAtlasBuildClear, ImFontAtlasBuildDestroy = ImFontAtlasBuildDestroy, ImFontAtlasBuildInit = ImFontAtlasBuildInit, ImFontAtlasBuildMain = ImFontAtlasBuildMain, ImFontAtlasBuildNotifySetFont = ImFontAtlasBuildNotifySetFont, ImFontAtlasBuildRenderBitmapFromString = ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasBuildSetTexture = ImFontAtlasBuildSetTexture, ImFontAtlasBuildSetupFontBakedBlanks = ImFontAtlasBuildSetupFontBakedBlanks, ImFontAtlasBuildSetupFontBakedEllipsis = ImFontAtlasBuildSetupFontBakedEllipsis, ImFontAtlasBuildSetupFontBakedFallback = ImFontAtlasBuildSetupFontBakedFallback, ImFontAtlasBuildSetupFontLoader = ImFontAtlasBuildSetupFontLoader, ImFontAtlasBuildSetupFontSpecialGlyphs = ImFontAtlasBuildSetupFontSpecialGlyphs, ImFontAtlasBuildUpdateTexData = ImFontAtlasBuildUpdateTexData, ImFontAtlasBuildUpdateTexDataBasic = ImFontAtlasBuildUpdateTexDataBasic, ImFontAtlasBuildUpdateTexDataLines = ImFontAtlasBuildUpdateTexDataLines, ImFontAtlasBuilder = ImFontAtlasBuilder, ImFontAtlasFlags = ImFontAtlasFlags, ImFontAtlasFontDestroyOutput = ImFontAtlasFontDestroyOutput, ImFontAtlasFontDestroySourceData = ImFontAtlasFontDestroySourceData, ImFontAtlasFontDiscardBakes = ImFontAtlasFontDiscardBakes, ImFontAtlasFontInitOutput = ImFontAtlasFontInitOutput, ImFontAtlasFontSourceAddToFont = ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit = ImFontAtlasFontSourceInit, ImFontAtlasGetMouseCursorTexData = ImFontAtlasGetMouseCursorTexData, ImFontAtlasPackAddRect = ImFontAtlasPackAddRect, ImFontAtlasPackDiscardRect = ImFontAtlasPackDiscardRect, ImFontAtlasPackGetRect = ImFontAtlasPackGetRect, ImFontAtlasPackGetRectSafe = ImFontAtlasPackGetRectSafe, ImFontAtlasPackInit = ImFontAtlasPackInit, ImFontAtlasPostProcessData = ImFontAtlasPostProcessData, ImFontAtlasRect = ImFontAtlasRect, ImFontAtlasRectEntry = ImFontAtlasRectEntry, ImFontAtlasRectId_GetGeneration = ImFontAtlasRectId_GetGeneration, ImFontAtlasRectId_GetIndex = ImFontAtlasRectId_GetIndex, ImFontAtlasRectId_Invalid = ImFontAtlasRectId_Invalid, ImFontAtlasRectId_Make = ImFontAtlasRectId_Make, ImFontAtlasRemoveDrawListSharedData = ImFontAtlasRemoveDrawListSharedData, ImFontAtlasTextureAdd = ImFontAtlasTextureAdd, ImFontAtlasTextureBlockConvert = ImFontAtlasTextureBlockConvert, ImFontAtlasTextureBlockCopy = ImFontAtlasTextureBlockCopy, ImFontAtlasTextureBlockPostProcess = ImFontAtlasTextureBlockPostProcess, ImFontAtlasTextureBlockPostProcessMultiply = ImFontAtlasTextureBlockPostProcessMultiply, ImFontAtlasTextureBlockQueueUpload = ImFontAtlasTextureBlockQueueUpload, ImFontAtlasTextureCompact = ImFontAtlasTextureCompact, ImFontAtlasTextureGetSizeEstimate = ImFontAtlasTextureGetSizeEstimate, ImFontAtlasTextureGrow = ImFontAtlasTextureGrow, ImFontAtlasUpdateDrawListsSharedData = ImFontAtlasUpdateDrawListsSharedData, ImFontAtlasUpdateNewFrame = ImFontAtlasUpdateNewFrame, ImFontBaked = ImFontBaked, ImFontBaked_BuildGrowIndex = ImFontBaked_BuildGrowIndex, ImFontBaked_BuildLoadGlyph = ImFontBaked_BuildLoadGlyph, ImFontBaked_BuildLoadGlyphAdvanceX = ImFontBaked_BuildLoadGlyphAdvanceX, ImFontCalcTextSizeEx = ImFontCalcTextSizeEx, ImFontCalcWordWrapPositionEx = ImFontCalcWordWrapPositionEx, ImFontConfig = ImFontConfig, ImFontFlags = ImFontFlags, ImFontGlyph = ImFontGlyph, ImFontLoader = ImFontLoader, ImFontStackData = ImFontStackData, ImFormatString = ImFormatString, ImGui = ImGui, ImGuiActivateFlags = ImGuiActivateFlags, ImGuiAxis = ImGuiAxis, ImGuiBackendFlags = ImGuiBackendFlags, ImGuiButtonFlags = ImGuiButtonFlags, ImGuiChildFlags = ImGuiChildFlags, ImGuiCol = ImGuiCol, ImGuiColorEditFlags = ImGuiColorEditFlags, ImGuiColorMod = ImGuiColorMod, ImGuiComboFlags = ImGuiComboFlags, ImGuiCond = ImGuiCond, ImGuiConfigFlags = ImGuiConfigFlags, ImGuiContext = ImGuiContext, ImGuiDataAuthority = ImGuiDataAuthority, ImGuiDataType = ImGuiDataType, ImGuiDebugLogFlags = ImGuiDebugLogFlags, ImGuiDemoWindowData = ImGuiDemoWindowData, ImGuiDir = ImGuiDir, ImGuiDockContext = ImGuiDockContext, ImGuiDockNode = ImGuiDockNode, ImGuiDockNodeFlags = ImGuiDockNodeFlags, ImGuiDockNodeState = ImGuiDockNodeState, ImGuiDragDropFlags = ImGuiDragDropFlags, ImGuiErrorRecoveryState = ImGuiErrorRecoveryState, ImGuiFocusRequestFlags = ImGuiFocusRequestFlags, ImGuiFocusScopeData = ImGuiFocusScopeData, ImGuiFocusedFlags = ImGuiFocusedFlags, ImGuiGroupData = ImGuiGroupData, ImGuiHoveredFlags = ImGuiHoveredFlags, ImGuiIO = ImGuiIO, ImGuiInputEvent = ImGuiInputEvent, ImGuiInputEventAppFocused = ImGuiInputEventAppFocused, ImGuiInputEventKey = ImGuiInputEventKey, ImGuiInputEventMouseButton = ImGuiInputEventMouseButton, ImGuiInputEventMousePos = ImGuiInputEventMousePos, ImGuiInputEventMouseViewport = ImGuiInputEventMouseViewport, ImGuiInputEventMouseWheel = ImGuiInputEventMouseWheel, ImGuiInputEventText = ImGuiInputEventText, ImGuiInputEventType = ImGuiInputEventType, ImGuiInputFlags = ImGuiInputFlags, ImGuiInputSource = ImGuiInputSource, ImGuiInputTextCallbackData = ImGuiInputTextCallbackData, ImGuiInputTextFlags = ImGuiInputTextFlags, ImGuiItemFlags = ImGuiItemFlags, ImGuiItemStatusFlags = ImGuiItemStatusFlags, ImGuiKey = ImGuiKey, ImGuiKeyData = ImGuiKeyData, ImGuiKeyOwnerData = ImGuiKeyOwnerData, ImGuiKeyOwner_Any = ImGuiKeyOwner_Any, ImGuiKeyOwner_NoOwner = ImGuiKeyOwner_NoOwner, ImGuiKeyRoutingData = ImGuiKeyRoutingData, ImGuiKey_Aliases_BEGIN = ImGuiKey_Aliases_BEGIN, ImGuiKey_Aliases_END = ImGuiKey_Aliases_END, ImGuiKey_Gamepad_BEGIN = ImGuiKey_Gamepad_BEGIN, ImGuiKey_Gamepad_END = ImGuiKey_Gamepad_END, ImGuiKey_Keyboard_BEGIN = ImGuiKey_Keyboard_BEGIN, ImGuiKey_Keyboard_END = ImGuiKey_Keyboard_END, ImGuiKey_Mouse_BEGIN = ImGuiKey_Mouse_BEGIN, ImGuiKey_Mouse_END = ImGuiKey_Mouse_END, ImGuiLastItemData = ImGuiLastItemData, ImGuiLastItemData_Copy = ImGuiLastItemData_Copy, ImGuiLayoutType = ImGuiLayoutType, ImGuiListClipper = ImGuiListClipper, ImGuiListClipperFlags = ImGuiListClipperFlags, ImGuiLocKey = ImGuiLocKey, ImGuiLogFlags = ImGuiLogFlags, ImGuiMod_Alt = ImGuiMod_Alt, ImGuiMod_Ctrl = ImGuiMod_Ctrl, ImGuiMod_Mask_ = ImGuiMod_Mask_, ImGuiMod_None = ImGuiMod_None, ImGuiMod_Shift = ImGuiMod_Shift, ImGuiMod_Super = ImGuiMod_Super, ImGuiMouseButton = ImGuiMouseButton, ImGuiMouseCursor = ImGuiMouseCursor, ImGuiMouseSource = ImGuiMouseSource, ImGuiNavLayer = ImGuiNavLayer, ImGuiNavMoveFlags = ImGuiNavMoveFlags, ImGuiNavRenderCursorFlags = ImGuiNavRenderCursorFlags, ImGuiNextItemData = ImGuiNextItemData, ImGuiNextItemDataFlags = ImGuiNextItemDataFlags, ImGuiNextWindowData = ImGuiNextWindowData, ImGuiNextWindowDataFlags = ImGuiNextWindowDataFlags, ImGuiOldColumnData = ImGuiOldColumnData, ImGuiOldColumnFlags = ImGuiOldColumnFlags, ImGuiOldColumns = ImGuiOldColumns, ImGuiPayload = ImGuiPayload, ImGuiPayload_Clear = ImGuiPayload_Clear, ImGuiPayload_IsDataType = ImGuiPayload_IsDataType, ImGuiPayload_IsDelivery = ImGuiPayload_IsDelivery, ImGuiPayload_IsPreview = ImGuiPayload_IsPreview, ImGuiPlatformIO = ImGuiPlatformIO, ImGuiPlatformImeData = ImGuiPlatformImeData, ImGuiPlatformImeData_Compare = ImGuiPlatformImeData_Compare, ImGuiPlatformImeData_Copy = ImGuiPlatformImeData_Copy, ImGuiPlatformMonitor = ImGuiPlatformMonitor, ImGuiPlotArrayGetterData = ImGuiPlotArrayGetterData, ImGuiPlotType = ImGuiPlotType, ImGuiPopupData = ImGuiPopupData, ImGuiPopupFlags = ImGuiPopupFlags, ImGuiPopupPositionPolicy = ImGuiPopupPositionPolicy, ImGuiScrollFlags = ImGuiScrollFlags, ImGuiSelectableFlags = ImGuiSelectableFlags, ImGuiSelectionUserData_Invalid = ImGuiSelectionUserData_Invalid, ImGuiSeparatorFlags = ImGuiSeparatorFlags, ImGuiSettingsHandler = ImGuiSettingsHandler, ImGuiShrinkWidthItem = ImGuiShrinkWidthItem, ImGuiSliderFlags = ImGuiSliderFlags, ImGuiSortDirection = ImGuiSortDirection, ImGuiStyle = ImGuiStyle, ImGuiStyleMod = ImGuiStyleMod, ImGuiStyleVar = ImGuiStyleVar, ImGuiStyleVarInfo = ImGuiStyleVarInfo, ImGuiTabBar = ImGuiTabBar, ImGuiTabBarFlags = ImGuiTabBarFlags, ImGuiTabItem = ImGuiTabItem, ImGuiTabItemFlags = ImGuiTabItemFlags, ImGuiTable = ImGuiTable, ImGuiTableBgTarget = ImGuiTableBgTarget, ImGuiTableColumn = ImGuiTableColumn, ImGuiTableColumnFlags = ImGuiTableColumnFlags, ImGuiTableColumnSettings = ImGuiTableColumnSettings, ImGuiTableColumnSortSpecs = ImGuiTableColumnSortSpecs, ImGuiTableFlags = ImGuiTableFlags, ImGuiTableInstanceData = ImGuiTableInstanceData, ImGuiTableRowFlags = ImGuiTableRowFlags, ImGuiTableSettings = ImGuiTableSettings, ImGuiTableSortSpecs = ImGuiTableSortSpecs, ImGuiTableTempData = ImGuiTableTempData, ImGuiTextBuffer = ImGuiTextBuffer, ImGuiTextFilter = ImGuiTextFilter, ImGuiTextFlags = ImGuiTextFlags, ImGuiTooltipFlags = ImGuiTooltipFlags, ImGuiTreeNodeFlags = ImGuiTreeNodeFlags, ImGuiViewport = ImGuiViewport, ImGuiViewportFlags = ImGuiViewportFlags, ImGuiViewportP = ImGuiViewportP, ImGuiWindow = ImGuiWindow, ImGuiWindowBgClickFlags = ImGuiWindowBgClickFlags, ImGuiWindowClass = ImGuiWindowClass, ImGuiWindowDockStyleCol = ImGuiWindowDockStyleCol, ImGuiWindowFlags = ImGuiWindowFlags, ImGuiWindowRefreshFlags = ImGuiWindowRefreshFlags, ImGuiWindowSettings = ImGuiWindowSettings, ImGuiWindowStackData = ImGuiWindowStackData, ImGui_ImplRoblox = ImGui_ImplRoblox, ImGui_ImplRoblox_GetBackendData = ImGui_ImplRoblox_GetBackendData, ImGui_ImplRoblox_Init = ImGui_ImplRoblox_Init, ImGui_ImplRoblox_NewFrame = ImGui_ImplRoblox_NewFrame, ImGui_ImplRoblox_RenderDrawData = ImGui_ImplRoblox_RenderDrawData, ImGui_ImplRoblox_SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate, ImGui_ImplRoblox_SetProfiling = ImGui_ImplRoblox_SetProfiling, ImGui_ImplRoblox_SetRenderRate = ImGui_ImplRoblox_SetRenderRate, ImGui_ImplRoblox_SetRenderScale = ImGui_ImplRoblox_SetRenderScale, ImGui_ImplRoblox_Shutdown = ImGui_ImplRoblox_Shutdown, ImGui_ImplRoblox_UpdateTexture = ImGui_ImplRoblox_UpdateTexture, ImHashData = ImHashData, ImHashStr = ImHashStr, ImHashStrRaw = ImHashStrRaw, ImIsPowerOfTwo = ImIsPowerOfTwo, ImLengthSqr = ImLengthSqr, ImLerp = ImLerp, ImLog = ImLog, ImMax = ImMax, ImMemchr = ImMemchr, ImMin = ImMin, ImMul = ImMul, ImParseFormatFindStart = ImParseFormatFindStart, ImParseFormatSanitizeForScanning = ImParseFormatSanitizeForScanning, ImPool = ImPool, ImPow = ImPow, ImRect = ImRect, ImRect_Copy = ImRect_Copy, ImRect_CopyFromV4 = ImRect_CopyFromV4, ImRotate = ImRotate, ImRound64 = ImRound64, ImRsqrt = ImRsqrt, ImS16 = ImS16, ImS32 = ImS32, ImS8 = ImS8, ImSaturate = ImSaturate, ImSin = ImSin, ImSqrt = ImSqrt, ImStb = ImStb, ImStd = ImStd, ImStrByte = ImStrByte, ImSubClampOverflow = ImSubClampOverflow, ImTextClassifierClear = ImTextClassifierClear, ImTextClassifierGet = ImTextClassifierGet, ImTextClassifierSetCharClass = ImTextClassifierSetCharClass, ImTextClassifierSetCharClassFromStr = ImTextClassifierSetCharClassFromStr, ImTextInitClassifiers = ImTextInitClassifiers, ImTextureData = ImTextureData, ImTextureDataGetFormatBytesPerPixel = ImTextureDataGetFormatBytesPerPixel, ImTextureDataUpdateNewFrame = ImTextureDataUpdateNewFrame, ImTextureFormat = ImTextureFormat, ImTextureID_Invalid = ImTextureID_Invalid, ImTextureRect = ImTextureRect, ImTextureRef = ImTextureRef, ImTextureStatus = ImTextureStatus, ImTrunc = ImTrunc, ImTrunc64 = ImTrunc64, ImU16 = ImU16, ImU32 = ImU32, ImU8 = ImU8, ImUpperPowerOfTwo = ImUpperPowerOfTwo, ImVec1_Copy = ImVec1_Copy, ImVec2 = ImVec2, ImVec2_AddVA = ImVec2_AddVA, ImVec2_Copy = ImVec2_Copy, ImVec2_CopyV = ImVec2_CopyV, ImVec2_MulVX = ImVec2_MulVX, ImVec2_SubVA = ImVec2_SubVA, ImVec4 = ImVec4, ImVec4_Copy = ImVec4_Copy, ImVector = ImVector, ImWcharClass = ImWcharClass, 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, STB_TEXTEDIT_K_BACKSPACE = STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE = STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN = STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_LEFT = STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_LINEEND = STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_LINESTART = STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_PGDOWN = STB_TEXTEDIT_K_PGDOWN, STB_TEXTEDIT_K_PGUP = STB_TEXTEDIT_K_PGUP, STB_TEXTEDIT_K_REDO = STB_TEXTEDIT_K_REDO, STB_TEXTEDIT_K_RIGHT = STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT = STB_TEXTEDIT_K_SHIFT, STB_TEXTEDIT_K_TEXTEND = STB_TEXTEDIT_K_TEXTEND, STB_TEXTEDIT_K_TEXTSTART = STB_TEXTEDIT_K_TEXTSTART, STB_TEXTEDIT_K_UNDO = STB_TEXTEDIT_K_UNDO, STB_TEXTEDIT_K_UP = STB_TEXTEDIT_K_UP, STB_TEXTEDIT_K_WORDLEFT = STB_TEXTEDIT_K_WORDLEFT, STB_TEXTEDIT_K_WORDRIGHT = STB_TEXTEDIT_K_WORDRIGHT, STB_TEXTEDIT_NEWLINE = STB_TEXTEDIT_NEWLINE, STB_TexteditState = STB_TexteditState, ShowDockingDisabledMessage = ShowDockingDisabledMessage, ShowExampleAppAutoResize = ShowExampleAppAutoResize, ShowExampleAppConsole = ShowExampleAppConsole, ShowExampleAppConstrainedResize = ShowExampleAppConstrainedResize, ShowExampleAppCustomRendering = ShowExampleAppCustomRendering, ShowExampleAppDockSpace = ShowExampleAppDockSpace, ShowExampleAppDocuments = ShowExampleAppDocuments, ShowExampleAppFullscreen = ShowExampleAppFullscreen, ShowExampleAppLayout = ShowExampleAppLayout, ShowExampleAppLog = ShowExampleAppLog, ShowExampleAppLongText = ShowExampleAppLongText, ShowExampleAppMainMenuBar = ShowExampleAppMainMenuBar, ShowExampleAppPropertyEditor = ShowExampleAppPropertyEditor, ShowExampleAppSimpleOverlay = ShowExampleAppSimpleOverlay, ShowExampleAppWindowTitles = ShowExampleAppWindowTitles, ShowExampleMenuFile = ShowExampleMenuFile, TILE_SIZE = TILE_SIZE, UINT_MAX = UINT_MAX, VTX_STRIDE = VTX_STRIDE, stb_text_locate_coord = stb_text_locate_coord, stb_text_makeundo_delete = stb_text_makeundo_delete, stb_text_makeundo_insert = stb_text_makeundo_insert, stb_text_makeundo_replace = stb_text_makeundo_replace, stb_text_redo = stb_text_redo, stb_text_undo = stb_text_undo, stb_textedit_click = stb_textedit_click, stb_textedit_drag = stb_textedit_drag, stb_textedit_find_charpos = stb_textedit_find_charpos, stb_textedit_key = stb_textedit_key, stbrp_init_target = stbrp_init_target, stbte = stbte, stbtt_FindGlyphIndex = stbtt_FindGlyphIndex, stbtt_GetFontOffsetForIndex = stbtt_GetFontOffsetForIndex, stbtt_GetFontVMetrics = stbtt_GetFontVMetrics, stbtt_GetGlyphBitmapBox = stbtt_GetGlyphBitmapBox, stbtt_GetGlyphBitmapBoxSubpixel = stbtt_GetGlyphBitmapBoxSubpixel, stbtt_GetGlyphHMetrics = stbtt_GetGlyphHMetrics, stbtt_GetGlyphShape = stbtt_GetGlyphShape, stbtt_InitFont = stbtt_InitFont, stbtt_MakeGlyphBitmapSubpixelPrefilter = stbtt_MakeGlyphBitmapSubpixelPrefilter, stbtt_ScaleForPixelHeight = stbtt_ScaleForPixelHeight, stbtt__GetGlyphInfoT2 = stbtt__GetGlyphInfoT2, stbtt__GetGlyphShapeT2 = stbtt__GetGlyphShapeT2, stbtt_fontinfo = stbtt_fontinfo, }