diff --git a/level_editor/editor.lua b/level_editor/editor.lua index 174a9ea..72f2c52 100644 --- a/level_editor/editor.lua +++ b/level_editor/editor.lua @@ -40,6 +40,52 @@ local worldRoomButtons = {} local worldControls = {} local worldPage = 1 local worldPageSize = 5 +local assetSearchText = "" +local assetSearchButtons = {} +local worldSearchText = "" +local worldSearchBox = { x = 10, y = 34, w = 0, h = 28 } + +local function fuzzyMatches(value, query) + query = (query or ""):lower():gsub("%s+", "") + if query == "" then return true end + local index = 1 + for character in value:lower():gmatch(".") do + if character == query:sub(index, index) then + index = index + 1 + if index > #query then return true end + end + end + return false +end + +local function beginSearch(field) + activeField = field + inputText = field == "assetSearch" and assetSearchText or worldSearchText + response = inputText +end + +local function rebuildAssetSearchButtons() + assetSearchButtons = {} + if assetSearchText == "" then return end + local names = {} + for asset in pairs(gameAssets) do + if fuzzyMatches(asset, assetSearchText) then table.insert(names, asset) end + end + table.sort(names) + for index, asset in ipairs(names) do + if index > 8 then break end + local sprites = {} + for color, location in pairs(gameAssets[asset].sprites) do sprites[color] = love.graphics.newImage(location) end + table.insert(assetSearchButtons, createUIElement{ + sprites = sprites, + name = "asset", + text = asset, + x = 30, + y = 45 + (index - 1) * 62, + onClic = { left = function() selectAsset(asset) end } + }) + end +end local function buttonContains(button, x, y) return x > button.x and x < button.x + button.w and y > button.y and y < button.y + button.h @@ -47,14 +93,17 @@ end local function rebuildWorldRoomButtons() worldRoomButtons = {} - local names = gameWorld:listRoomNames() + local names = {} + for _, name in ipairs(gameWorld:listRoomNames()) do + if fuzzyMatches(name, worldSearchText) then table.insert(names, name) end + end local pages = math.max(1, math.ceil(#names / worldPageSize)) worldPage = constrain(worldPage, 1, pages) local first = (worldPage - 1) * worldPageSize + 1 for index = first, math.min(first + worldPageSize - 1, #names) do local roomName = names[index] local row = index - first - table.insert(worldRoomButtons, { name = roomName, x = 10, y = 36 + row * 68, w = sideBarBox.w - 20, h = 60 }) + table.insert(worldRoomButtons, { name = roomName, x = 10, y = 70 + row * 68, w = sideBarBox.w - 20, h = 60 }) end worldControls = { { text = worldMode == "place" and "MODE: PLACE ROOMS" or "MODE: OPEN LEVELS", x = 10, y = sideBarBox.h - 194, w = sideBarBox.w - 20, h = 34, @@ -82,7 +131,10 @@ end local function drawWorldSidebar() love.graphics.setColor(gColor.white:set()) - love.graphics.printf("ROOMS — " .. (worldMode == "place" and "select to place; re-click to clear" or "click a map room to open"), 8, 10, sideBarBox.w - 16, "center") + love.graphics.printf("ROOMS — " .. (worldMode == "place" and "select to place; re-click to clear" or "click a map room to open"), 8, 6, sideBarBox.w - 16, "center") + worldSearchBox.w = sideBarBox.w - 20 + love.graphics.rectangle("line", worldSearchBox.x, worldSearchBox.y, worldSearchBox.w, worldSearchBox.h) + love.graphics.printf("SEARCH: " .. worldSearchText, worldSearchBox.x + 6, worldSearchBox.y + 7, worldSearchBox.w - 12, "left") for _, button in ipairs(worldRoomButtons) do love.graphics.setColor(button.name == selectedRoom and 255 or 100, button.name == selectedRoom and 255 or 100, button.name == selectedRoom and 255 or 100, 255) love.graphics.rectangle("line", button.x, button.y, button.w, button.h) @@ -194,7 +246,10 @@ function _initLevelEditor() table.insert(hierarchy[gameAssets[asset].directory], asset) end - for folder, object in pairs(hierarchy) do + local folders = {} + for folder in pairs(hierarchy) do table.insert(folders, folder) end + table.sort(folders) + for _, folder in ipairs(folders) do local button = createUIElement{ name = "folder", text = folder, @@ -320,7 +375,8 @@ function selectFolder(folder) local counter = 1 local limit = 10 - for _, asset in pairs(hierarchy[selectedFolder]) do + table.sort(hierarchy[selectedFolder]) + for _, asset in ipairs(hierarchy[selectedFolder]) do if counter % limit == 0 then counter = 1 @@ -338,7 +394,7 @@ function selectFolder(folder) end } } - table.insert(assetButtons[row], forwardbutton) + table.insert(assetButtons[row], forwardButton) row = row + 1 table.insert(assetButtons, {}) @@ -542,7 +598,17 @@ function editorMouseHandler(x, y, button) x = x - width if editorView == "room" then - if not selectedFolder then + if buttonContains({ x = 10, y = 5, w = sideBarBox.w - 20, h = 28 }, x, y) then + beginSearch("assetSearch") + return + elseif assetSearchText ~= "" then + for _, uiElement in ipairs(assetSearchButtons) do + if uiElement:clicIsInBox(x, y) then + uiElement:onClic(button) + return + end + end + elseif not selectedFolder then for _, uiElement in pairs(folderButtons) do if uiElement:clicIsInBox(x, y) then uiElement:onClic(button) @@ -570,6 +636,10 @@ function editorMouseHandler(x, y, button) end end elseif editorView == "world" then + if buttonContains(worldSearchBox, x, y) then + beginSearch("worldSearch") + return + end for _, roomButton in ipairs(worldRoomButtons) do if buttonContains(roomButton, x, y) then if selectedRoom == roomButton.name then @@ -584,7 +654,7 @@ function editorMouseHandler(x, y, button) end for _, control in ipairs(worldControls) do if buttonContains(control, x, y) then - control:onClic(x) + control.onClic(x) return end end @@ -617,6 +687,15 @@ function editorTextHandler(text) elseif editorView == "room" and activeField == "roomName" then inputText = text roomNameField:editText(text) + elseif editorView == "room" and activeField == "assetSearch" then + inputText = text + assetSearchText = text + rebuildAssetSearchButtons() + elseif editorView == "world" and activeField == "worldSearch" then + inputText = text + worldSearchText = text + worldPage = 1 + rebuildWorldRoomButtons() end end @@ -625,6 +704,10 @@ function editorCompleteResponse() assetProperties[activeField] = inputText elseif editorView == "room" and activeField == "roomName" then editorRoomName = inputText + elseif editorView == "room" and activeField == "assetSearch" then + assetSearchText = inputText + elseif editorView == "world" and activeField == "worldSearch" then + worldSearchText = inputText end activeField = nil end @@ -639,12 +722,17 @@ end function editorDraw() if editorView == "room" then + love.graphics.setColor(gColor.white:set()) + love.graphics.rectangle("line", 10, 5, sideBarBox.w - 20, 28) + love.graphics.printf("ASSET SEARCH: " .. assetSearchText, 16, 12, sideBarBox.w - 32, "left") love.graphics.setColor(gColor.white:set()) love.graphics.printf("LEVEL NAME", 0, sideBarBox.h * (7 / 10) - 24, sideBarBox.w, "center") for _, button in pairs(uiButtons) do button:draw() end - if not selectedFolder then + if assetSearchText ~= "" then + for _, asset in ipairs(assetSearchButtons) do asset:draw() end + elseif not selectedFolder then for _, folder in pairs(folderButtons) do folder:draw() end