Files
Endfield-Data/LuaScripts/Common/Utils/UIUtils.lua
2026-01-31 21:42:01 +07:00

2351 lines
79 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local UIUtils = {}
function UIUtils.initLuaCustomConfig(self)
self.luaCustomConfig = self.luaCustomConfig or self.transform:GetComponent("LuaCustomConfig")
if not self.luaCustomConfig then
return
end
self.config = {}
self.config.HasValue = function(_, key)
local flag = self.luaCustomConfig.itemDict:TryGetValue(key)
if not flag then
return false
end
return true
end
if UNITY_EDITOR and CS.Beyond.DebugDefines.realTimeLuaCustomConfig then
setmetatable(self.config, {
__index = function(_, key)
local flag, item = self.luaCustomConfig.itemDict:TryGetValue(key)
if flag then
local valueType = CS.Beyond.Lua.LuaCustomConfig.ValueType
if item.valueType == valueType.Bool then
return item.boolValue
elseif item.valueType == valueType.Int then
return item.intValue
elseif item.valueType == valueType.Float then
return item.floatValue
elseif item.valueType == valueType.String then
return item.stringValue
elseif item.valueType == valueType.Vector2 then
return item.vector2Value
elseif item.valueType == valueType.Vector3 then
return item.vector3Value
elseif item.valueType == valueType.Vector4 then
return item.vector4Value
elseif item.valueType == valueType.Color then
return item.colorValue
elseif item.valueType == valueType.Lua then
return lume.dostring("return " .. item.luaValue)
elseif item.valueType == valueType.FMODEvent then
return item.fmodEventValue
elseif item.valueType == valueType.GameObject then
return item.gameObjectValue
elseif item.valueType == valueType.RectTransform then
return item.rectTransformValue
elseif item.valueType == valueType.AnimationCurve then
return item.curveValue
elseif item.valueType == valueType.LayerMask then
return item.layerMaskValue
elseif item.valueType == valueType.Material then
return item.material
elseif item.valueType == valueType.Enum then
local exception = string.format(
"return CS.%s.__CastFrom(%d)",
item.enumTypeFullName,
item.enumValue
)
local enumValue = lume.dostring(exception)
return enumValue
end
end
logger.error("无法获取 LuaCustomConfig 配置项", key)
end
})
else
local componentConfig = {}
self.luaCustomConfig:InitConfigTable(componentConfig)
setmetatable(self.config, {
__index = function(_, key)
local componentValue = componentConfig[key]
if componentValue ~= nil then
return componentValue
end
logger.error("无法获取 LuaCustomConfig 配置项", key)
end
})
end
getmetatable(self.config).__newindex = function()
logger.error("请在面板上配置 LuaCustomConfig勿在代码中修改 view.config 中的值!")
end
end
function UIUtils.genCachedCellFunction(list, onMiss)
onMiss = onMiss or function(obj)
return Utils.wrapLuaNode(obj)
end
local cache = {}
local getCell = function(object)
local cell = cache[object]
if not cell then
cell = onMiss(object)
cache[object] = cell
end
return cell
end
return function(object)
if not object then
return
end
if type(object) == "number" then
if not list then
logger.error("genCachedCellFunction fail", list)
return
end
local luaIndex = object
object = list:Get(CSIndex(luaIndex))
end
if object then
return getCell(object)
end
end
end
function UIUtils.addChild(parent, prefab, keepScale)
if not prefab or IsNull(prefab.gameObject) then
logger.error("Invalid prefab", parent.transform:PathFromRoot())
end
local item = {}
item.gameObject = CSUtils.CreateObject(prefab.gameObject, parent.gameObject)
item.transform = item.gameObject.transform:GetComponent("RectTransform")
if not keepScale then
item.transform.localScale = Vector3.one
end
return item
end
local UIListCacheClass = require_ex("Common/Utils/UI/UIListCache").UIListCache
function UIUtils.genCellCache(itemTemplate, wrapFunction, parent)
return UIListCacheClass(itemTemplate, wrapFunction, parent)
end
local UIGoCacheClass = require_ex("Common/Utils/UI/UIGoCache").UIGoCache
function UIUtils.genGoCache(goTemplate, wrapFunction, parent)
return UIGoCacheClass(goTemplate, wrapFunction, parent)
end
function UIUtils.getStandardScreenX(x)
return x / Screen.width * UIConst.CANVAS_DEFAULT_WIDTH
end
function UIUtils.getStandardScreenY(y)
return y / Screen.height * UIConst.CANVAS_DEFAULT_HEIGHT
end
function UIUtils.getNormalizedScreenX(x)
return x / Screen.width
end
function UIUtils.getNormalizedScreenY(y)
return y / Screen.height
end
function UIUtils.isInputEventScopeValid(scope)
scope = scope or Types.EInputBindingScope.IncludeStandalone
local isValid
if scope == Types.EInputBindingScope.EditorOnly then
isValid = UNITY_EDITOR
elseif scope == Types.EInputBindingScope.IncludeDev then
isValid = UNITY_EDITOR or DEVELOPMENT_BUILD
elseif scope == Types.EInputBindingScope.IncludeStandalone then
isValid = UNITY_EDITOR or DEVELOPMENT_BUILD or UNITY_STANDALONE
end
return isValid
end
function UIUtils.bindInputPlayerAction(actionId, callback, groupId)
return InputManagerInst:CreateBinding(actionId, callback, groupId)
end
function UIUtils.bindInputEvent(key, action, modifyKeys, timing, groupId)
return InputManagerInst:CreateBinding(key, modifyKeys or "", timing or InputTimingType.OnClick, action, groupId or UIManager.persistentInputBindingKey)
end
function UIUtils.setAsNaviTarget(targetSelectable)
InputManagerInst.controllerNaviManager:SetTarget(targetSelectable)
end
function UIUtils.setAsNaviTargetInSilentModeIfNecessary(targetNaviGroup, targetSelectable)
InputManagerInst.controllerNaviManager:SetTargetInSilentModeIfNecessary(targetNaviGroup, targetSelectable)
end
function UIUtils.changeAndTrySetNaviBindingType(naviGroup, naviBindingType)
InputManagerInst.controllerNaviManager:ChangeAndTrySetNaviBindingType(naviGroup, naviBindingType)
end
function UIUtils.initUIDragHelper(uiDragItem, info)
if uiDragItem.luaTable then
local dragHelper = uiDragItem.luaTable[1]
dragHelper:RefreshInfo(info)
return dragHelper
else
local DragHelperClass = require_ex("Common/Utils/UI/UIDragHelper")
return DragHelperClass(uiDragItem, info)
end
end
function UIUtils.initUIDropHelper(uiDropItem, info)
if uiDropItem.luaTable then
local dropHelper = uiDropItem.luaTable[1]
if BEYOND_DEBUG_COMMAND then
if not dropHelper or type(dropHelper) ~= "userdata" then
logger.error("InValid dropHelper", uiDropItem.luaTable, uiDropItem.transform:PathFromRoot())
end
end
dropHelper:RefreshInfo(info)
return dropHelper
else
local DropHelperClass = require_ex("Common/Utils/UI/UIDropHelper")
return DropHelperClass(uiDropItem, info)
end
end
function UIUtils.isTypeDropValid(dragHelper, acceptTypes)
local isSourceValid = not acceptTypes.sources or lume.find(acceptTypes.sources, dragHelper.source)
if not isSourceValid then
return false
end
local isTypeValid = not acceptTypes.types or lume.find(acceptTypes.types, dragHelper.type)
if not isTypeValid then
return false
end
return true
end
function UIUtils.playItemDragAudio(itemId)
local res, audioData = Tables.audioItemDragAndDrop:TryGetValue(itemId)
if res and not string.isEmpty(audioData.audioDrag) then
AudioAdapter.PostEvent(audioData.audioDrag)
return
end
local _, itemData = Tables.itemTable:TryGetValue(itemId)
if itemData then
local audioTypeData = Tables.audioItemTypeDragAndDrop[itemData.showingType]
if audioTypeData ~= nil and not string.isEmpty(audioTypeData.audioDrag) then
AudioAdapter.PostEvent(audioTypeData.audioDrag)
end
end
end
function UIUtils.playItemDropAudio(itemId)
if string.isEmpty(itemId) then
return
end
local res, audioData = Tables.audioItemDragAndDrop:TryGetValue(itemId)
if res and not string.isEmpty(audioData.audioDrop) then
AudioAdapter.PostEvent(audioData.audioDrop)
return
end
local _, itemData = Tables.itemTable:TryGetValue(itemId)
if itemData then
local audioTypeData = Tables.audioItemTypeDragAndDrop[itemData.showingType]
if audioTypeData ~= nil and not string.isEmpty(audioTypeData.audioDrop) then
AudioAdapter.PostEvent(audioTypeData.audioDrop)
end
end
end
function UIUtils.screenPointToUI(screenPos, uiCamera, canvasRect)
canvasRect = canvasRect or UIManager.uiCanvasRect
local isInside, uiPos = Unity.RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPos, uiCamera)
return uiPos, isInside
end
function UIUtils.objectPosToUI(pos, uiCamera, canvasRect)
local screenPos = CameraManager.mainCamera:WorldToScreenPoint(pos)
if screenPos.z < 0 then
screenPos.x = -screenPos.x
screenPos.y = -screenPos.y
end
return UIUtils.screenPointToUI(Vector2(screenPos.x, screenPos.y), uiCamera, canvasRect)
end
function UIUtils.getUIRectOfRectTransform(rectTransform, uiCamera)
local rect = CSUtils.RectTransformToScreenRect(rectTransform, uiCamera)
rect.y = Screen.height - rect.yMax
local canvasRect = UIManager.uiCanvasRect.rect
local scaleX = canvasRect.width / Screen.width
local scaleY = canvasRect.height / Screen.height
return Unity.Rect(rect.x * scaleX, rect.y * scaleY, rect.size.x * scaleX, rect.size.y * scaleY)
end
function UIUtils.addRectSizeKeepCenter(rect, addWidth, addHeight)
local center = rect.center
rect.size = rect.size + Vector2(addWidth or 0, addHeight or 0)
rect.center = center
return rect
end
function UIUtils.getSpritePath(path, name)
if name then
path = path .. "/" .. name
end
return UIConst.UI_SPRITE_PATH:format(path)
end
function UIUtils.getSpriteDevPath(path, name)
if name then
path = path .. "/" .. name
end
return UIConst.UI_SPRITE_DEV_PATH:format(path)
end
function UIUtils.isScreenPosInRectTransform(pos, rectTransform, uiCamera)
return CS.Beyond.UI.UIUtils.IsScreenPosInRectTransform(pos, rectTransform, uiCamera)
end
function UIUtils.getTransformScreenRect(transform, uiCamera)
local bounds = CSUtils.GetRectTransformBounds(transform)
local min = bounds.min
local size = bounds.size
if uiCamera then
min = uiCamera:WorldToScreenPoint(min)
local max = uiCamera:WorldToScreenPoint(bounds.max)
size = max - min
end
return Unity.Rect(min.x, Screen.height - (min.y + size.y), size.x, size.y)
end
function UIUtils.getRectTransformCenterPosition(rectTransform)
return CSUtils.GetRectTransformCenterPosition(rectTransform)
end
function UIUtils.updateTipsPosition(contentRectTrans, targetTransform, canvasRectTrans, uiCamera, posType, padding, xOffset)
if IsNull(targetTransform) then
contentRectTrans.anchoredPosition = Vector2.zero
return
end
local targetScreenRect = UIUtils.getTransformScreenRect(targetTransform, uiCamera)
UIUtils.updateTipsPositionWithScreenRect(contentRectTrans, targetScreenRect, canvasRectTrans, uiCamera, posType, padding, xOffset)
end
function UIUtils.updateTipsPositionWithScreenRect(contentRectTrans, targetScreenRect, canvasRectTrans, uiCamera, posType, padding, xOffset)
posType = posType or UIConst.UI_TIPS_POS_TYPE.RightDown
LayoutRebuilder.ForceRebuildLayoutImmediate(contentRectTrans)
if BEYOND_DEBUG then
if contentRectTrans.pivot ~= Vector2(0.5, 0.5) then
logger.error(string.format("Tips位置计算错误: [%s] 的锚点不在中心", contentRectTrans:PathFromRoot()))
end
end
local width = contentRectTrans.rect.width
local height = contentRectTrans.rect.height
local canvasSize = canvasRectTrans.rect.size
local oriScreenSize = Vector2(Screen.width, Screen.height)
local xRation = oriScreenSize.x / canvasSize.x
local yRation = oriScreenSize.y / canvasSize.y
local widthInScreen = width * xRation
local heightInScreen = height * yRation
local halfHeightInScreen = heightInScreen / 2
local halfWidthInScreen = widthInScreen / 2
padding = padding or {}
local paddingTop = (padding.top or 0) * yRation
local paddingLeft = (padding.left or 0) * xRation
local paddingRight = (padding.right or 0) * xRation
local paddingBottom = (padding.bottom or 0) * yRation
local screenSize = Vector2(oriScreenSize.x - (paddingLeft + paddingRight), oriScreenSize.y - (paddingTop + paddingBottom))
targetScreenRect.x = targetScreenRect.x - paddingLeft
targetScreenRect.y = targetScreenRect.y - paddingTop
local screenPos = Vector2(0, 0)
local finalXPos, finalYPos
if posType == UIConst.UI_TIPS_POS_TYPE.MidBottom then
local verticalSpaceEnough = true
local downHeight = screenSize.y - targetScreenRect.yMax
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
local upHeightEnough = targetScreenRect.yMin >= heightInScreen
if upHeightEnough then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = targetScreenRect.center.y
verticalSpaceEnough = false
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Mid
end
end
local rightWidth = screenSize.x - targetScreenRect.xMax
local leftWidth = targetScreenRect.xMin
if verticalSpaceEnough then
if rightWidth >= halfWidthInScreen and leftWidth >= halfWidthInScreen then
screenPos.x = targetScreenRect.center.x
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
else
if leftWidth < halfWidthInScreen then
screenPos.x = targetScreenRect.center.x + halfWidthInScreen - leftWidth
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = targetScreenRect.center.x - (halfWidthInScreen - rightWidth)
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
end
else
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
end
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.LeftTop then
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = 0
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.LeftTopOrRightTop then
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.RightTopOrLeftTop then
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.RightTop then
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = screenSize.x - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.RightDown then
local downHeight = screenSize.y - targetScreenRect.yMax
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
local upHeight = targetScreenRect.yMin
if upHeight >= downHeight then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = screenSize.x - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
end
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.LeftDown then
local downHeight = screenSize.y - targetScreenRect.yMax
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
local upHeight = targetScreenRect.yMin
if upHeight >= downHeight then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
end
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = 0
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.MidTop then
if targetScreenRect.yMin >= heightInScreen then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
local downHeight = screenSize.y - targetScreenRect.yMax
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
end
screenPos.x = targetScreenRect.center.x
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
elseif posType == UIConst.UI_TIPS_POS_TYPE.LeftMid then
local downHeight = screenSize.y - targetScreenRect.center.y
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.center.y
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Mid
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
screenPos.x = 0
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.RightMid then
local downHeight = screenSize.y - targetScreenRect.center.y
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.center.y
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Mid
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = screenSize.x - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.GuideTips then
local outDistance = UIConst.UI_GUIDE_OUT_OF_SCREEN_DISTANCE
if targetScreenRect.xMin < -outDistance or targetScreenRect.xMax - screenSize.x > outDistance or
targetScreenRect.yMin < -outDistance or targetScreenRect.yMax - screenSize.y > outDistance then
screenPos.x = targetScreenRect.x
screenPos.y = targetScreenRect.y
screenPos = screenPos - oriScreenSize / 2
screenPos.y = -screenPos.y
local canvasPos = Vector2(screenPos.x / xRation, screenPos.y / yRation)
contentRectTrans.anchoredPosition = canvasPos
return targetScreenRect.xMin < 0 and UIConst.UI_TIPS_X_POS_TYPE.Left or UIConst.UI_TIPS_X_POS_TYPE.Right,
targetScreenRect.yMin < 0 and UIConst.UI_TIPS_Y_POS_TYPE.Top or UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local leftWidth = targetScreenRect.xMin
if leftWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMin - halfWidthInScreen - xOffset
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
else
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen + xOffset
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = targetScreenRect.center.x
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
if targetScreenRect.yMin >= (screenSize.y - targetScreenRect.yMax) then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
end
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.FacTopViewOption then
if targetScreenRect.center.y >= screenSize.y then
screenPos.x = targetScreenRect.center.x
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
elseif targetScreenRect.center.y <= 0 then
screenPos.x = targetScreenRect.center.x
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
local downHeight = screenSize.y - targetScreenRect.center.y
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.center.y
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Mid
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = screenSize.x - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
end
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.FacTopViewBuildActionIcons then
if targetScreenRect.yMin >= heightInScreen then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = targetScreenRect.yMax + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
screenPos.x = targetScreenRect.center.x
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Mid
elseif posType == UIConst.UI_TIPS_POS_TYPE.FacSmartAlertTop then
screenPos.y = targetScreenRect.yMin - halfHeightInScreen
screenPos.x = targetScreenRect.center.x
elseif posType == UIConst.UI_TIPS_POS_TYPE.AdaptiveRightTop then
local downHeight = screenSize.y - targetScreenRect.yMin
if downHeight >= heightInScreen then
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
else
screenPos.y = screenSize.y - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
elseif posType == UIConst.UI_TIPS_POS_TYPE.DailyAbsentRightTop then
if targetScreenRect.yMin >= heightInScreen then
screenPos.y = targetScreenRect.yMax - halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Top
else
screenPos.y = targetScreenRect.yMin + halfHeightInScreen
finalYPos = UIConst.UI_TIPS_Y_POS_TYPE.Bottom
end
local rightWidth = screenSize.x - targetScreenRect.xMax
if rightWidth >= widthInScreen then
screenPos.x = targetScreenRect.xMax + halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Right
else
screenPos.x = targetScreenRect.xMin - halfWidthInScreen
finalXPos = UIConst.UI_TIPS_X_POS_TYPE.Left
end
end
screenPos.x = lume.clamp(screenPos.x, halfWidthInScreen, screenSize.x - halfWidthInScreen) + paddingLeft
screenPos.y = lume.clamp(screenPos.y, halfHeightInScreen, screenSize.y - halfHeightInScreen) + paddingTop
screenPos = screenPos - oriScreenSize / 2
screenPos.y = -screenPos.y
local canvasPos = Vector2(screenPos.x / xRation, screenPos.y / yRation)
contentRectTrans.anchoredPosition = canvasPos
return finalXPos, finalYPos
end
function UIUtils.rectTransToPadding(rectTransform)
local anchoredPos = rectTransform.anchoredPosition
local size = rectTransform.rect.size
local parentSize = rectTransform.parent.rect.size
local left = (parentSize.x - size.x) / 2 + anchoredPos.x
local right = (parentSize.x - size.x) / 2 - anchoredPos.x
local top = (parentSize.y - size.y) / 2 - anchoredPos.y
local bottom = (parentSize.y - size.y) / 2 + anchoredPos.y
return {
top = top,
left = left,
right = right,
bottom = bottom,
}
end
function UIUtils.screenPosToWorldPos(x, y, yPlane)
local ray = CameraManager.mainCamera:ScreenPointToRay(Vector3(x, y, 0))
local length = (yPlane - ray.origin.y) / ray.direction.y
local worldPos = ray.origin + ray.direction * length
return worldPos
end
function UIUtils.changeAlpha(target, a)
local color = target.color
color.a = a
target.color = color
end
function UIUtils.changeColorExceptAlpha(target, color)
local a = target.color.a
color.a = a
target.color = color
end
function UIUtils.isPosInScreen(worldPos, camera, xFrame, yFrame)
xFrame = xFrame or 0
yFrame = yFrame or 0
local xMin = xFrame
local xMax = Screen.width - xFrame
local yMin = yFrame
local yMax = Screen.height - yFrame
camera = camera or CameraManager.mainCamera
local pos = camera:WorldToScreenPoint(worldPos)
return pos.x >= xMin and pos.y >= yMin and pos.z >= 0 and pos.x <= xMax and pos.y <= yMax, pos
end
function UIUtils.getRemainingText(t)
local hour = math.floor(t / 3600)
t = t % 3600
local min = math.floor(t / 60)
t = math.floor(t % 60)
return string.format("%02d:%02d:%02d", hour, min, t)
end
function UIUtils.getRemainingTextToMinute(t)
local min = math.floor(t / 60)
t = math.floor(t % 60)
return string.format("%02d:%02d", min, t)
end
function UIUtils.getItemRarity(itemId)
local data = Tables.itemTable:GetValue(itemId)
return data.rarity
end
function UIUtils.getItemUseDesc(itemId)
return CS.Beyond.Gameplay.TacticalItemUtil.GetUseItemDesc(itemId)
end
function UIUtils.getItemEquippedDesc(itemId)
return CS.Beyond.Gameplay.TacticalItemUtil.GetEquipItemDesc(itemId)
end
function UIUtils.getItemEquippedExtraDesc(itemId)
return CS.Beyond.Gameplay.TacticalItemUtil.GetEquipItemExtraDesc(itemId)
end
function UIUtils.getItemRarityColor(rarity)
local rarityColorStr = Tables.rarityColorTable[rarity]
return UIUtils.getColorByString(rarityColorStr.color)
end
function UIUtils.getCharRarityColor(rarity)
return UIUtils.getItemRarityColor(rarity)
end
function UIUtils.getColorByString(strColor, a)
local r = 0
local g = 0
local b = 0
a = a or 255
if string.len(strColor) == 6 then
local strR = string.sub(strColor, 1, 2)
local strG = string.sub(strColor, 3, 4)
local strB = string.sub(strColor, 5, 6)
r = tonumber(strR, 16)
g = tonumber(strG, 16)
b = tonumber(strB, 16)
end
if string.len(strColor) == 8 then
local strR = string.sub(strColor, 1, 2)
local strG = string.sub(strColor, 3, 4)
local strB = string.sub(strColor, 5, 6)
local strA = string.sub(strColor, 7, 8)
r = tonumber(strR, 16)
g = tonumber(strG, 16)
b = tonumber(strB, 16)
a = tonumber(strA, 16)
end
local color = CS.UnityEngine.Color(r / 255, g / 255, b / 255, a / 255)
return color
end
function UIUtils.setSpecialFillAmount(img, percent, minMaxVector2)
img.fillAmount = percent * (minMaxVector2.y - minMaxVector2.x) + minMaxVector2.x
end
function UIUtils.checkInputValid(value)
return true
end
function UIUtils.getStringLength(str)
return CS.Beyond.I18n.I18nUtils.GetStringLength(str)
end
function UIUtils.getNumString(num, isPrice)
if isPrice and num < 100000 then
return string.format("%d", num)
end
local curLang = CS.Beyond.I18n.I18nUtils.curEnvLang
local isChineseStyleLang = curLang == GEnums.EnvLang.CN
if isChineseStyleLang then
local wan = num / 10000
if wan < 1 then
return string.format("%d", num)
end
if wan < 10000 then
return UIUtils._getNumAbbrStr(wan, Language.LUA_NUM_UNIT_WAN, isPrice)
end
local yi = wan / 10000
return UIUtils._getNumAbbrStr(yi, Language.LUA_NUM_UNIT_YI, isPrice)
else
local m = num / 1000 / 1000
local k = num / 1000
if m >= 1 then
return UIUtils._getNumAbbrStr(m, Language.LUA_NUM_UNIT_MILLION, isPrice)
elseif k >= 1 then
return UIUtils._getNumAbbrStr(k, Language.LUA_NUM_UNIT_THOUSAND, isPrice)
else
return string.format("%d", num)
end
end
end
function UIUtils._getNumAbbrStr(num, text, isCeiling)
local carryFunc = function(x)
return isCeiling and math.ceil(x - 1e-10) or math.floor(x + 1e-10)
end
if num < 100 then
if num < 10 then
if carryFunc(num * 100) % 10 > 0 then
return string.format("%.2f%s", carryFunc(num * 100) / 100, text)
elseif math.floor(num * 10) % 10 > 0 then
return string.format("%.1f%s", carryFunc(num * 10) / 10, text)
end
else
if carryFunc(num * 10) % 10 > 0 then
return string.format("%.1f%s", carryFunc(num * 10) / 10, text)
end
end
end
return string.format("%d%s", carryFunc(num), text)
end
function UIUtils.ceilToTenthStr(num)
return string.format("%.1f", math.ceil(num * 10 - 1e-6) * 0.1)
end
function UIUtils.floorToTenthStr(num)
return string.format("%.1f", math.floor(num * 10 + 1e-6) * 0.1)
end
local ROMAN_VAL = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
local ROMAN_SYM = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
function UIUtils.intToRoman(num)
local roman = ""
for i = 1, #ROMAN_VAL do
while num >= ROMAN_VAL[i] do
num = num - ROMAN_VAL[i]
roman = roman .. ROMAN_SYM[i]
end
end
return roman
end
function UIUtils.setSizeDeltaX(rect, value)
local size = rect.sizeDelta
size.x = value
rect.sizeDelta = size
end
function UIUtils.setSizeDeltaY(rect, value)
local size = rect.sizeDelta
size.y = value
rect.sizeDelta = size
end
function UIUtils.mapScreenPosToEllipseEdge (screenPos, ellipseXRadius, ellipseYRadius)
local x = screenPos.x
local y = screenPos.y
local angle = math.atan(y, x)
local k = y / x
local uiPos = Vector2.zero
local a = ellipseXRadius
local b = ellipseYRadius
uiPos.x = a * b / math.sqrt(b * b + a * a * k * k)
if x < 0 then
uiPos.x = -uiPos.x
end
uiPos.y = uiPos.x * k
if uiPos.magnitude < screenPos.magnitude then
return uiPos, math.deg(angle), true
end
return screenPos, math.deg(angle), false
end
function UIUtils.resolveOriginalText(text)
return CS.Beyond.Gameplay.GameplayUIUtils.ResolveOriginalText(text)
end
function UIUtils.resolveTextCinematic(text)
local cfg = {
playerName = true,
gender = true,
}
return UIUtils.resolveText(text, cfg)
end
function UIUtils.resolveText(text, cfg)
return CS.Beyond.Gameplay.GameplayUIUtils.ResolveText(text, cfg.playerName, cfg.gender)
end
function UIUtils.resolveTextPlayerName(text)
return CS.Beyond.Gameplay.GameplayUIUtils.ResolveTextPlayerName(text)
end
function UIUtils.resolveTextGender(text)
return CS.Beyond.Gameplay.GameplayUIUtils.ResolveTextGender(text)
end
function UIUtils.genDynamicBlackScreenMaskData(systemName, fadeInTime, fadeOutTime, fadeInCallback)
local maskData = CS.Beyond.Gameplay.UICommonMaskData()
maskData.fadeInTime = fadeInTime
maskData.fadeBeforeTime = 0
maskData.fadeOutTime = fadeOutTime
if fadeInCallback ~= nil then
maskData.fadeInCallback = function()
fadeInCallback()
end
end
if BEYOND_DEBUG or BEYOND_DEBUG_COMMAND then
maskData.extraData = CS.Beyond.Gameplay.CommonMaskExtraData()
maskData.extraData.desc = systemName
end
return maskData
end
function UIUtils.genDynamicBlackScreenMaskDataWithWaitTime(systemName, fadeInTime, fadeOutTime, fadeWaitTime, fadeInCallback)
local maskData = CS.Beyond.Gameplay.UICommonMaskData()
maskData.fadeInTime = fadeInTime
maskData.fadeBeforeTime = 0
maskData.fadeWaitTime = fadeWaitTime
maskData.fadeOutTime = fadeOutTime
if fadeInCallback ~= nil then
maskData.fadeInCallback = function()
fadeInCallback()
end
end
if BEYOND_DEBUG or BEYOND_DEBUG_COMMAND then
maskData.extraData = CS.Beyond.Gameplay.CommonMaskExtraData()
maskData.extraData.desc = systemName
end
return maskData
end
local rewardItemRarityEffectNames = {
[1] = "normaGlow",
[2] = "greenGlow",
[3] = "blueGlow",
[4] = "purpleGlow",
[5] = "goldGlow",
}
function UIUtils.setRewardItemRarityGlow(cell, rarity)
local count = #rewardItemRarityEffectNames
rarity = math.min(count, rarity)
for k = 1, count do
local name = rewardItemRarityEffectNames[k]
cell.view[name].gameObject:SetActiveIfNecessary(k == rarity)
end
end
function UIUtils.getItemTypeName(itemId)
local itemCfg = Tables.itemTable:GetValue(itemId)
local itemTypeCfg = Tables.itemTypeTable:GetValue(itemCfg.type:GetHashCode())
local defaultTypeName = itemTypeCfg.name
if itemCfg.type == GEnums.ItemType.Weapon then
local weaponCfg = Tables.weaponBasicTable:GetValue(itemId)
if not weaponCfg then
return defaultTypeName
end
local weaponTypeInt = weaponCfg.weaponType:ToInt()
local weaponTypeName = Language[string.format("LUA_WEAPON_TYPE_%d", weaponTypeInt)]
return weaponTypeName
end
if itemCfg.type == GEnums.ItemType.Equip then
local _, equipBasicCfg = Tables.equipTable:TryGetValue(itemId)
if not equipBasicCfg then
return defaultTypeName
end
local equipTemplateId = itemId
local _, equipTemplate = Tables.equipTable:TryGetValue(equipTemplateId)
if not equipTemplate then
return defaultTypeName
end
local equipType = equipTemplate.partType
local equipTypeName = Language[UIConst.CHAR_INFO_EQUIP_TYPE_TILE_PREFIX .. LuaIndex(equipType:ToInt())]
return equipTypeName
end
return defaultTypeName
end
function UIUtils.displayItemBasicInfos(view, loader, itemId, instId)
local data = Tables.itemTable:GetValue(itemId)
local itemType = data.type
if view.itemNameTxt then
view.itemNameTxt.text = UIUtils.getItemName(itemId, instId)
end
if view.itemIcon then
view.itemIcon:InitItemIcon(itemId, true, instId)
end
if view.itemTypeTxt then
local itemTypeName = UIUtils.getItemTypeName(itemId)
view.itemTypeTxt.text = itemTypeName
end
if view.rarityLine then
UIUtils.setItemRarityImage(view.rarityLine, data.rarity)
end
end
function UIUtils.getItemName(itemId, instId)
local data = Tables.itemTable:GetValue(itemId)
if not instId then
return data.name
end
if data.type == GEnums.ItemType.WeaponGem then
local leadTermId = CharInfoUtils.getGemLeadSkillTermId(instId)
if not leadTermId then
return data.name
end
local leadTermCfg = Tables.gemTable:GetValue(leadTermId)
return string.format(Language.LUA_ITEM_COMPOSITE_NAME, data.name, leadTermCfg.tagName)
end
return data.name
end
function UIUtils.checkIfReachAdventureLv(needLv)
local adventureLevelData = GameInstance.player.adventure.adventureLevelData
return adventureLevelData.lv >= needLv
end
function UIUtils.displayCommercialItemInfo(view, loader, itemId, instId)
local itemData = Tables.itemTable[itemId]
if itemData.type == GEnums.ItemType.GemLockedTermBox then
view.stateCtrl:SetState("GemLockedTermBox")
local tipsGemWidget = view.tipsGemAttributeNode
tipsGemWidget:InitTipsGemAttributeNode()
tipsGemWidget:RefreshView(itemId)
end
end
function UIUtils.displayWeaponInfo(view, loader, itemId, instId)
local itemData = Tables.itemTable[itemId]
local weaponInstData = instId and CharInfoUtils.getWeaponByInstId(instId)
view.starGroup:InitStarGroup(itemData.rarity)
view.potentialStar:InitWeaponPotentialStar(weaponInstData and weaponInstData.refineLv or 0)
view.weaponGemSlimNode:InitWeaponGemSlimNode(weaponInstData and weaponInstData.attachedGemInstId or 0)
if weaponInstData then
view.tipWeaponLevelNode:InitTipWeaponLevelNode(itemId, instId)
view.weaponAttributeNode:InitWeaponAttributeNode(instId, weaponInstData.attachedGemInstId)
view.weaponSkillNode:InitWeaponSkillNode(instId)
else
local hasValue
local weaponBasicData
local weaponBreakThroughDetailList
local initMaxLevel, breakThroughCount, maxBreakthroughLevel = 0, 0, 0
hasValue, weaponBasicData = Tables.weaponBasicTable:TryGetValue(itemId)
if hasValue then
hasValue, weaponBreakThroughDetailList = Tables.weaponBreakThroughTemplateTable:TryGetValue(weaponBasicData.breakthroughTemplateId)
if hasValue then
breakThroughCount = #weaponBreakThroughDetailList.list
if breakThroughCount > 1 then
initMaxLevel = weaponBreakThroughDetailList.list[1].breakthroughLv
maxBreakthroughLevel = breakThroughCount - 1
end
end
end
view.tipWeaponLevelNode:InitTipWeaponLevelNodeNoInst(1, initMaxLevel, 0, maxBreakthroughLevel)
view.weaponAttributeNode:InitWeaponAttributeNodeByTemplateId(itemId)
view.weaponSkillNode:InitWeaponSkillNodeByTemplateId(itemId, 0, 0, false)
end
if view.equippedNode then
if instId and instId > 0 then
view.equippedNode:InitEquipNodeByWeaponInstId(instId)
else
view.equippedNode.gameObject:SetActive(false)
end
if view.equippedSpace then
view.equippedSpace.gameObject:SetActive(view.equippedNode.gameObject.activeSelf)
end
end
end
function UIUtils.displayEquipInfo(view, loader, itemId, instId)
local equipCfg = Tables.equipTable[itemId]
view.equipLvTxt.text = equipCfg.minWearLv
view.equipSuitNode:InitEquipSuitNode(itemId)
local hasInst = CharInfoUtils.getEquipByInstId(instId) ~= nil
if hasInst then
view.weaponAttributeNode:InitEquipAttributeNode(instId)
else
view.weaponAttributeNode:InitEquipAttributeNodeByTemplateId(itemId)
end
if view.equippedNode then
if hasInst then
view.equippedNode:InitEquippedNodeByEquipInstId(instId)
else
view.equippedNode.gameObject:SetActive(false)
end
if view.equippedSpace then
view.equippedSpace.gameObject:SetActive(view.equippedNode.gameObject.activeSelf)
end
end
end
function UIUtils.displayWeaponGemInfo(view, loader, itemId, instId)
view.gemSkillNode:InitGemSkillNode(instId)
if view.equippedNode then
if instId and instId > 0 then
view.equippedNode:InitEquippedNodeByGemInstId(instId)
else
view.equippedNode.gameObject:SetActive(false)
end
end
if view.domainTagNode then
local domainId
local isInst = instId and instId > 0
if isInst then
local gemInst = CharInfoUtils.getGemByInstId(instId)
if gemInst then
domainId = gemInst.domainId
end
end
view.domainTagNode:InitDomainTagNode(domainId)
end
end
function UIUtils.displayGiftItemTags(view, itemId)
local _, giftData = Tables.giftItemTable:TryGetValue(itemId)
if not giftData or #giftData.tagList == 0 then
view.gameObject:SetActive(false)
return
end
view.gameObject:SetActive(true)
view.tagCellCache = view.tagCellCache or UIUtils.genCellCache(view.tagCell)
view.tagCellCache:Refresh(#giftData.tagList, function(cell, index)
local tagId = giftData.tagList[CSIndex(index)]
local _, tagData = Tables.tagDataTable:TryGetValue(tagId)
if tagData then
cell.nameTxt.text = tagData.tagName
end
end)
end
function UIUtils.checkText(text, errHint)
if string.isEmpty(text) then
return errHint
end
return text
end
function UIUtils.getShortLeftTime(leftSec)
if leftSec < Const.SEC_PER_MIN then
return string.format(Language.TIME_FORMAT_MIN, 0)
elseif leftSec < Const.SEC_PER_HOUR then
return string.format(Language.TIME_FORMAT_MIN, math.floor(leftSec / Const.SEC_PER_MIN))
elseif leftSec < Const.SEC_PER_DAY then
return string.format(Language.TIME_FORMAT_HOUR, math.floor(leftSec / Const.SEC_PER_HOUR))
else
return string.format(Language.TIME_FORMAT_DAY, math.floor(leftSec / Const.SEC_PER_DAY))
end
end
function UIUtils.getSecondsLeftTime(leftSec)
if leftSec < 0 then
leftSec = 0
end
leftSec = math.floor(leftSec)
return string.format(Language.TIME_FORMAT_SEC, leftSec)
end
function UIUtils.getFullLeftTime(leftSec)
if leftSec < 0 then
leftSec = 0
end
local days = math.floor(leftSec / Const.SEC_PER_DAY)
local hours = math.floor((leftSec % Const.SEC_PER_DAY) / Const.SEC_PER_HOUR)
local minutes = math.floor((leftSec % Const.SEC_PER_HOUR) / Const.SEC_PER_MIN)
if days >= 1 then
return string.format(Language.TIME_FORMAT_DAY_HOUR_MIN, days, hours, minutes)
end
return UIUtils.getLeftTime(leftSec)
end
function UIUtils.getLeftTime(leftSec)
if leftSec < Const.SEC_PER_MIN then
return string.format(Language.TIME_FORMAT_MIN, 0)
elseif leftSec < Const.SEC_PER_HOUR then
return string.format(Language.TIME_FORMAT_MIN, math.floor(leftSec / Const.SEC_PER_MIN))
elseif leftSec < Const.SEC_PER_DAY then
local hourTime = math.floor(leftSec / Const.SEC_PER_HOUR)
local minTime = math.floor((leftSec % Const.SEC_PER_HOUR) / Const.SEC_PER_MIN)
return string.format(Language.TIME_FORMAT_HOUR_MIN, hourTime, minTime)
else
local dayTime = math.floor(leftSec / Const.SEC_PER_DAY)
local hourTime = math.floor((leftSec % Const.SEC_PER_DAY) / Const.SEC_PER_HOUR)
return string.format(Language.TIME_FORMAT_DAY_HOUR, dayTime, hourTime)
end
end
function UIUtils.getLeftTimeToSecond(leftSec)
leftSec = lume.round(leftSec)
if leftSec <= Const.SEC_PER_HOUR then
local format = Language.TIME_FORMAT_ONE_COLON
return string.format(format, math.floor(leftSec / Const.SEC_PER_MIN), math.fmod(leftSec, Const.SEC_PER_MIN))
else
local hourTime = math.floor(leftSec / Const.SEC_PER_HOUR)
local minTime = math.floor((leftSec % Const.SEC_PER_HOUR) / Const.SEC_PER_MIN)
local secTime = math.fmod((leftSec % Const.SEC_PER_HOUR), Const.SEC_PER_MIN)
local format = Language.TIME_FORMAT_TWO_COLON
return string.format(format, hourTime, minTime, secTime)
end
end
function UIUtils.setItemSprite(img, id, self, isBig)
local data = Tables.itemTable:GetValue(id)
local sprite
if isBig then
img:LoadSprite(UIConst.UI_SPRITE_ITEM_BIG, data.iconId)
end
if not sprite then
img:LoadSprite(UIConst.UI_SPRITE_ITEM, data.iconId)
end
end
function UIUtils.tryGetTagList(itemId, itemType)
if not itemType then
local itemData = Tables.itemTable[itemId]
itemType = itemData.type
end
if itemType == GEnums.ItemType.NormalBuilding or itemType == GEnums.ItemType.FuncBuilding then
local machineId = FactoryUtils.getItemBuildingId(itemId)
local succ, machineId2TagIdData = Tables.factoryMachineId2tagIdsTable:TryGetValue(machineId)
if not succ then
return false
end
return true, machineId2TagIdData.tagIds
end
local succ, ingredientId2TagIdData = Tables.factoryResourceItemId2TagIdTable:TryGetValue(itemId)
if not succ then
return false
end
local tagIds = {}
local count = 0
local facCore = GameInstance.player.remoteFactory.core
for craftId, tagId in pairs(ingredientId2TagIdData.craftId2TagId) do
if facCore:IsFormulaVisible(craftId) then
if not lume.find(tagIds, tagId) then
tagIds[count] = tagId
count = count + 1
end
end
end
if count == 0 then
return false
end
tagIds.Count = count
return true, tagIds
end
function UIUtils.getTrackerColorByMissionImportance(t)
return DataManager.worldSetting.missionIconColor[t]
end
function UIUtils.getNumTextByLanguage(num)
return Language[string.format("LUA_NUM_%d", num)]
end
function UIUtils.setFacBuffColorText(uiText, text, isBuff)
local colorStr = UIConst.FAC_BUILDING_DEBUFF_COLOR_STR
if isBuff then
colorStr = UIConst.FAC_BUILDING_BUFF_COLOR_STR
end
uiText.text = string.format(UIConst.COLOR_STRING_FORMAT,
colorStr, text)
end
function UIUtils.childrenArrayActive(root, activeCount)
local childrenCount = root.transform.childCount
for i = 0, childrenCount - 1 do
local child = root.transform:GetChild(i)
child.gameObject:SetActive(i < activeCount)
end
end
function UIUtils.useItemOnTip(itemId)
if GameInstance.playerController.mainCharacter == nil or
GameInstance.playerController.mainCharacter:HasTag(CS.Beyond.Gameplay.PredefinedTag.ForbiddenUsingItem) then
Notify(MessageConst.SHOW_TOAST, Language.LUA_ITEM_BAR_TAG_FORBIDDEN)
return false
end
if GameInstance.mode:IsItemForbidden(itemId) then
Notify(MessageConst.SHOW_TOAST, Language.LUA_ITEM_BAR_TOAST_GAME_MODE_FORBID)
return false
end
local useItemData = Tables.useItemTable:GetValue(itemId)
if useItemData.uiType == GEnums.ItemUseUiType.SingleHeal or
useItemData.uiType == GEnums.ItemUseUiType.AllHeal or
useItemData.uiType == GEnums.ItemUseUiType.Revive or
useItemData.uiType == GEnums.ItemUseUiType.Alive or
useItemData.uiType == GEnums.ItemUseUiType.SingleUsp or
useItemData.uiType == GEnums.ItemUseUiType.AllUsp then
UIManager:Open(PanelId.TacticalItem, { itemId = itemId })
return true
elseif useItemData.uiType == GEnums.ItemUseUiType.Throw then
if GameInstance.player.inventory:UseItem(Utils.getCurrentScope(), itemId) then
return true
end
end
return false
end
function UIUtils.lineLog(title, sep)
local lines = {
string.format("====== %s ======", title)
}
sep = sep or " :: "
return function(...)
local t = {...}
local st = {}
for _, v in ipairs(t) do
st[#st + 1] = tostring(v)
end
local line = table.concat(st, sep)
if not line:isEmpty() then
table.insert(lines, line)
else
logger.error(table.concat(lines, "\n"))
end
end
end
function UIUtils.parseAllRecipedAsInput(itemId)
end
function UIUtils.getCellNums(width, space, cellWidthList)
local nums = {}
local count = #cellWidthList
local curWidth = 0
local curCellNum = 0
for i = 1, count do
local cellWidth = cellWidthList[i]
if curWidth == 0 then
curWidth = cellWidth
else
curWidth = curWidth + cellWidth + space
end
if curWidth > width then
local num = i - curCellNum - 1
table.insert(nums, num)
curCellNum = i - 1
curWidth = cellWidth
end
end
if count > curCellNum then
table.insert(nums, count - curCellNum)
end
return nums
end
function UIUtils.setItemStorageCountText(storageCountNode, itemId, needCount, ignoreInSafeZone)
local inventory = GameInstance.player.inventory
local itemData = Tables.itemTable[itemId]
local isMoneyType = inventory:IsMoneyType(itemData.type)
local valuableDepotType = itemData.valuableTabType
local isValuableItem = valuableDepotType ~= GEnums.ItemValuableDepotType.Factory
local count, bagCount, _ = Utils.getItemCount(itemId, ignoreInSafeZone, true)
if ignoreInSafeZone or Utils.isInSafeZone() or isMoneyType or isValuableItem then
storageCountNode:InitStorageNode(count, needCount, true)
else
storageCountNode:InitStorageNode(bagCount, needCount, false)
end
end
function UIUtils.setNoEnoughCountColor(countStr)
UIUtils.setCountColor(countStr, true)
end
function UIUtils.setCountColor(countStr, isLack)
if isLack then
return string.format(UIConst.COLOR_STRING_FORMAT, UIConst.COUNT_NOT_ENOUGH_COLOR_STR, countStr)
else
return countStr
end
end
function UIUtils.setCountColorByCustomColor(countStr, isLack, customLackColorStr)
if isLack then
local color = string.isEmpty(customLackColorStr) and UIConst.COUNT_NOT_ENOUGH_COLOR_STR or customLackColorStr
return string.format(UIConst.COLOR_STRING_FORMAT, color, countStr)
else
return countStr
end
end
function UIUtils.PlayAnimationAndToggleActive(animationWrapper, isOn, callback)
animationWrapper:ClearTween(false)
if animationWrapper.gameObject.activeSelf == isOn then
if isOn then
animationWrapper:SampleToInAnimationEnd()
end
if callback then
callback()
end
return
end
if isOn then
animationWrapper.gameObject:SetActive(true)
animationWrapper:PlayInAnimation(callback)
else
animationWrapper:PlayOutAnimation(function()
if animationWrapper and animationWrapper.gameObject then
animationWrapper.gameObject:SetActiveIfNecessary(false)
end
if callback then
callback()
end
end)
end
end
function UIUtils.inTimeline()
local inTimeline = GameWorld.cutsceneManager.isMainTimelinePlaying
return inTimeline
end
function UIUtils.inCG()
local inCG = VideoManager.isPlayingFMV
return inCG
end
function UIUtils.inDialog()
local inDialog = GameWorld.dialogManager.isPlaying
return inDialog
end
function UIUtils.inCinematic()
return UIUtils.inCG() or UIUtils.inTimeline() or UIUtils.inDialog()
end
function UIUtils.inDungeon()
return GameInstance.dungeonManager.inDungeon
end
function UIUtils.IsPhaseLevelOnTop()
return PhaseManager:GetTopPhaseId() == PhaseId.Level
end
function UIUtils.usingBlockTransition()
local BlockGlitchTransition = require_ex("UI/Panels/BlockGlitchTransition/BlockGlitchTransitionCtrl")
return BlockGlitchTransition.BlockGlitchTransitionCtrl.s_renderTexture ~= nil
end
function UIUtils.getTextShowDuration(text, tSpeed)
local speed = tSpeed or 1
local duration = I18nUtils.GetTextShowDuration(text)
return duration / speed
end
function UIUtils.removePattern(str, pattern)
local result = ""
for match in string.gmatch(str, pattern) do
local cleaned = string.gsub(match, "{.*}", "")
result = result .. cleaned
end
if string.isEmpty(result) then
result = str
end
return result
end
function UIUtils.loadSprite(loader, path, name)
local fullPath = UIUtils.getSpritePath(path, name)
if BEYOND_DEBUG then
local fullDevPath = UIUtils.getSpriteDevPath(path, name)
if ResourceManager.CheckExists(fullDevPath) then
fullPath = fullDevPath
end
end
local pathHash = __beyond_calculate_ab_path_hash(fullPath)
if not ResourceManager.CheckExistsWithStringPathHash(pathHash) then
logger.error("资源不存在", fullPath, pathHash)
return nil
end
local sprite = loader:LoadSprite(fullPath)
return sprite
end
function UIUtils.getPuzzleColorByColorType(colorType)
local colorStr = UIConst.MINI_PUZZLE_GAME_ECOLOR_STR[colorType]
colorStr = string.isEmpty(colorStr) and "FF00FF" or colorStr
return UIUtils.getColorByString(colorStr)
end
function UIUtils.calcPivotVecByData(data, puzzleCellSize, puzzleCellPadding)
local centerCell = data.originBlocks[0]
local xMax = centerCell.x
local xMin = centerCell.x
local yMax = centerCell.y
local yMin = centerCell.y
for _, originBlock in pairs(data.originBlocks) do
xMax = math.max(xMax, originBlock.x)
xMin = math.min(xMin, originBlock.x)
yMax = math.max(yMax, originBlock.y)
yMin = math.min(yMin, originBlock.y)
end
local width = (xMax - xMin + 1) * (puzzleCellSize + 2 * puzzleCellPadding)
local height = (yMax - yMin + 1) * (puzzleCellSize + 2 * puzzleCellPadding)
local centerX = ((centerCell.x - xMin) * 2 + 1) * (puzzleCellSize / 2 + puzzleCellPadding)
local centerY = ((centerCell.y - yMin) * 2 + 1) * (puzzleCellSize / 2 + puzzleCellPadding)
return Vector2(centerX / width, centerY / height)
end
function UIUtils.splitItem(slotIndex)
local toSlot = GameInstance.player.inventory.itemBag:GetOrFallback(Utils.getCurrentScope()):GetFirstEmptySlotIndex()
if toSlot < 0 then
Notify(MessageConst.SHOW_TOAST, Language.LUA_ITEM_TIPS_TOAST_1)
return
end
UIManager:Open(PanelId.ItemSplit, {
slotIndex = slotIndex,
})
end
function UIUtils.getRewardFirstItem(rewardId)
local rewardTableData = Tables.rewardTable[rewardId]
return rewardTableData.itemBundles[0]
end
function UIUtils.getSoilRewardFirstItem(rewardId)
local rewardTableData = Tables.rewardSoilTable[rewardId]
return rewardTableData.itemBundles[0]
end
function UIUtils.getRewardItems(rewardId, items)
local _, rewardTableData = Tables.rewardTable:TryGetValue(rewardId)
items = items or {}
if rewardTableData then
for _, v in pairs(rewardTableData.itemBundles) do
table.insert(items, v)
end
else
logger.error("RewardTable表数据缺失reward id" .. rewardId)
end
return items
end
function UIUtils.getRewardItemsMergeSameId(rewardId, items)
local _, rewardTableData = Tables.rewardTable:TryGetValue(rewardId)
items = items or {}
if rewardTableData then
for _, v in pairs(rewardTableData.itemBundles) do
local found = false
for i, existingItem in ipairs(items) do
if existingItem.id == v.id then
local mergedItem = {
id = v.id,
count = existingItem.count + v.count
}
items[i] = mergedItem
found = true
break
end
end
if not found then
table.insert(items, {
id = v.id,
count = v.count,
})
end
end
else
logger.error("RewardTable表数据缺失reward id" .. rewardId)
end
return items
end
function UIUtils.getMonsterIconByMonsterId(monsterId)
return string.format("Assets/Beyond/DynamicAssets/Gameplay/UI/Sprites/Wiki/MonsterImage/%s.png", monsterId)
end
function UIUtils.getParentCenterAnchoredPosition(rectTransform)
local position = Vector2.zero
if rectTransform == nil then
return position
end
if rectTransform.parent == nil then
return position
end
local parentRectTransform = rectTransform.parent:GetComponent("RectTransform")
if parentRectTransform == nil then
return position
end
local anChorOffset = Vector2(
parentRectTransform.rect.width * (0.5 - rectTransform.anchorMin.x),
parentRectTransform.rect.height * (0.5 - rectTransform.anchorMin.y)
)
local pivotOffset = Vector2(
rectTransform.rect.width * (rectTransform.pivot.x - 0.5),
rectTransform.rect.height * (rectTransform.pivot.y - 0.5)
);
return anChorOffset + pivotOffset;
end
function UIUtils.getRomanNumberText(number)
if number < 1 or number > 10 then
return ""
end
return Language[string.format("ui_common_roman_num_%d", number)]
end
function UIUtils.setItemRarityImage(img, rarity)
local rarityColor = UIUtils.getItemRarityColor(rarity)
img.color = rarityColor
end
function UIUtils.getEnemyInfoByIdAndLevel(enemyId, enemyLevel)
local hasEnemyCfg, enemyCfg = Tables.enemyTable:TryGetValue(enemyId)
local hasEnemyDisplayInfoCfg, enemyDisplayInfoCfg = Tables.enemyDisplayInfoTable:TryGetValue(enemyId)
if not hasEnemyCfg and not hasEnemyDisplayInfoCfg then
logger.error(string.format("敌人表和敌人展示信息表中都找不到enemyId:%s。", enemyId))
return
end
local enemyTemplateId = hasEnemyCfg and enemyCfg.templateId or (hasEnemyDisplayInfoCfg and enemyDisplayInfoCfg.templateId)
local hasEnemyTemplateDisplayCfg, enemyTemplateDisplayCfg = Tables.enemyTemplateDisplayInfoTable:TryGetValue(enemyTemplateId)
if not hasEnemyTemplateDisplayCfg then
logger.error(string.format("敌人模板展示信息表中都找不到enemyTemplateId:%senemyId:%s。", enemyTemplateId, enemyId))
return
end
local enemyInfo = {}
enemyInfo.name = (hasEnemyDisplayInfoCfg and not string.isEmpty(enemyDisplayInfoCfg.name)) and
enemyDisplayInfoCfg.name or enemyTemplateDisplayCfg.name
enemyInfo.desc = (hasEnemyDisplayInfoCfg and not string.isEmpty(enemyDisplayInfoCfg.description)) and
enemyDisplayInfoCfg.description or enemyTemplateDisplayCfg.description
enemyInfo.level = enemyLevel
enemyInfo.templateId = enemyTemplateId
enemyInfo.ability = {}
local abilityIds = (hasEnemyDisplayInfoCfg and enemyDisplayInfoCfg.abilityDescIds.Count > 0) and
enemyDisplayInfoCfg.abilityDescIds or enemyTemplateDisplayCfg.abilityDescIds
for _, abilityId in pairs(abilityIds) do
local abilityDescCfg = Tables.enemyAbilityDescTable[abilityId]
table.insert(enemyInfo.ability, {
abilityId = abilityDescCfg.abilityId,
name = abilityDescCfg.name,
description = abilityDescCfg.description,
})
end
return enemyInfo
end
function UIUtils.isItemTypeForbidden(dungeonId, itemType)
local _, subGameInstData = DataManager.subGameInstDataTable:TryGetValue(dungeonId)
if not subGameInstData then
return false
end
local _, gameModeData = DataManager.gameModeTable:TryGetData(subGameInstData.modeId)
if not gameModeData then
return false
end
if not gameModeData.functionSettings then
return false
end
for index, functionSetting in cs_pairs(gameModeData.functionSettings) do
if functionSetting.modeFuncType == GEnums.GameModeFuncType.ForbidUseItemType then
local funcParams = functionSetting.funcParams
if funcParams and funcParams.itemTypes and
funcParams.itemTypes:Contains(itemType) then
return true
end
end
end
return false
end
function UIUtils.convertRewardItemBundlesToDataList(itemBundles, isIncremental)
local rewardItemDataList = {}
if itemBundles == nil or itemBundles.Count == 0 then
return rewardItemDataList
end
for index = 0, itemBundles.Count - 1 do
local rewardItem = itemBundles[index]
local itemId = rewardItem.id
local success, itemData = Tables.itemTable:TryGetValue(itemId)
if success then
table.insert(rewardItemDataList, {
id = itemId,
count = rewardItem.count,
rarity = itemData.rarity,
sortId1 = itemData.sortId1,
sortId2 = itemData.sortId2,
})
end
end
table.sort(rewardItemDataList, Utils.genSortFunction({ "rarity", "sortId1", "sortId2", "id" }, isIncremental))
return rewardItemDataList
end
function UIUtils.getMobileHudPanelMaxHeight(panelHeight, minHudHeight, maxHudHeight)
local minSupHeight = CS.Beyond.UI.UIConst.STANDARD_VERTICAL_RESOLUTION
local maxSupHeight = CS.Beyond.UI.UIConst.STANDARD_HORIZONTAL_RESOLUTION
local realHeight = lume.clamp(panelHeight, minSupHeight, maxSupHeight)
local realMaxHeight = (realHeight - minSupHeight) / (maxSupHeight - minSupHeight) *
(maxHudHeight - minHudHeight) + minHudHeight
return realMaxHeight
end
function UIUtils.commonAdaptHudTrack(view, config)
local layoutGroup = view.verticalLayoutGroup
local padding = layoutGroup.padding.vertical
local spacing = layoutGroup.spacing
local diffY = config.DIFF_HEIGHT or 0
LayoutRebuilder.ForceRebuildLayoutImmediate(view.rectTransform)
LayoutRebuilder.ForceRebuildLayoutImmediate(view.objectiveContent)
local hasVaryingNode = view.varyingNode.gameObject.activeInHierarchy
local varyingHeight = hasVaryingNode and view.varyingNode.rect.height + spacing or 0
local contentHeight = view.objectiveContent.rect.height + spacing + (hasVaryingNode and 0 or diffY)
local realMainHeight = padding + view.headNode.rect.height + contentHeight + varyingHeight
local width = view.rectTransform.rect.width
local rectHeight = realMainHeight
local canScrollContent = false
if DeviceInfo.usingTouch then
local minSupHeight = CS.Beyond.UI.UIConst.STANDARD_VERTICAL_RESOLUTION
local maxSupHeight = CS.Beyond.UI.UIConst.STANDARD_HORIZONTAL_RESOLUTION
local realHeight = lume.clamp(view.rectTransform.rect.height, minSupHeight, maxSupHeight)
local realMaxHeight = (realHeight - minSupHeight) / (maxSupHeight - minSupHeight) *
(config.MAX_MAIN_RECT_HEIGHT_FOR_MOBILE - config.MIN_MAIN_RECT_HEIGHT_FOR_MOBILE) +
config.MIN_MAIN_RECT_HEIGHT_FOR_MOBILE
rectHeight = math.min(realMainHeight, realMaxHeight)
canScrollContent = realMainHeight > realMaxHeight
end
view.rectTransform.sizeDelta = Vector2(width, rectHeight)
view.contentScrollView.enabled = canScrollContent
view.arrowBottomNode.gameObject:SetActiveIfNecessary(canScrollContent)
if canScrollContent then
view.contentScrollView:ScrollTo(Vector2(0, -1), true)
end
return canScrollContent
end
function UIUtils.commonAdaptHudTrackV2(view, config, canFoldThresholdOffsetY)
local layoutGroup = view.verticalLayoutGroup
local padding = layoutGroup.padding.vertical
local spacing = layoutGroup.spacing
local canFoldThresholdOffsetY = canFoldThresholdOffsetY or 0
LayoutRebuilder.ForceRebuildLayoutImmediate(view.rectTransform)
LayoutRebuilder.ForceRebuildLayoutImmediate(view.objectiveContent)
local contentHeight = view.objectiveContent.rect.height + spacing
local realMainHeight = padding + view.headNode.rect.height + contentHeight
local rectFoldHeight = realMainHeight
local rectUnfoldHeight = realMainHeight
local scrollState = UIConst.TRACK_HUD_SCROLL_STATE.AlwaysCantScroll
local ignoreScrollMask = false
if DeviceInfo.usingTouch then
local canFoldThresholdForMobile = config.CAN_FOLD_THRESHOLD_FOR_MOBILE + canFoldThresholdOffsetY
local minSupHeight = CS.Beyond.UI.UIConst.STANDARD_VERTICAL_RESOLUTION
local maxSupHeight = CS.Beyond.UI.UIConst.STANDARD_HORIZONTAL_RESOLUTION
local realCanvasHeight = lume.clamp(view.rectTransform.rect.height, minSupHeight, maxSupHeight)
local maxTrackHudHeight = realCanvasHeight - UIConst.ON_TRACK_HUD_CONST_HEIGHT -
realCanvasHeight * UIConst.JOYSTICK_IN_SCREEN_HEIGHT_PROPORTION * (1 - UIConst.TRACK_HUD_UNFOLD_OCCLUSION_JOYSTICK_PROPORTION)
+ canFoldThresholdOffsetY
if realMainHeight <= canFoldThresholdForMobile then
scrollState = UIConst.TRACK_HUD_SCROLL_STATE.AlwaysCantScroll
rectFoldHeight = realMainHeight
rectUnfoldHeight = realMainHeight
ignoreScrollMask = false
elseif realMainHeight <= canFoldThresholdForMobile + config.CAN_FOLD_THRESHOLD_FOR_MOBILE_OFFSET then
scrollState = UIConst.TRACK_HUD_SCROLL_STATE.AlwaysCantScroll
rectFoldHeight = canFoldThresholdForMobile
rectUnfoldHeight = realMainHeight
ignoreScrollMask = true
elseif realMainHeight <= maxTrackHudHeight then
scrollState = UIConst.TRACK_HUD_SCROLL_STATE.CanScrollWhenFold
rectFoldHeight = canFoldThresholdForMobile
rectUnfoldHeight = realMainHeight
ignoreScrollMask = false
else
scrollState = UIConst.TRACK_HUD_SCROLL_STATE.AlwaysCanScroll
rectFoldHeight = canFoldThresholdForMobile
rectUnfoldHeight = maxTrackHudHeight
ignoreScrollMask = false
end
end
return ignoreScrollMask, scrollState, rectFoldHeight, rectUnfoldHeight
end
function UIUtils.getMovingItemMode()
local mode
if UIUtils.isBatchMovingItem() then
mode = CS.Proto.ITEM_MOVE_MODE.BatchItemId
elseif UIUtils.isQuickMovingItem() then
mode = CS.Proto.ITEM_MOVE_MODE.Grid
elseif UIUtils.isQuickMovingHalfItem() then
mode = CS.Proto.ITEM_MOVE_MODE.HalfGrid
end
return mode
end
function UIUtils.isBatchMovingItem()
return Input.GetKey(Unity.KeyCode.LeftControl) or Input.GetKey(Unity.KeyCode.RightControl)
end
function UIUtils.isQuickMovingItem()
return Input.GetKey(Unity.KeyCode.LeftShift) or Input.GetKey(Unity.KeyCode.RightShift)
end
function UIUtils.isQuickMovingHalfItem()
return Input.GetKey(Unity.KeyCode.LeftAlt) or Input.GetKey(Unity.KeyCode.RightAlt)
end
function UIUtils.getSettlementEnhanceEffectDesc(enhanceMoneyProduceSpeedRate, enhanceMoneyProfitRate, enhanceExpProfitRate)
local effectStr = ""
if enhanceMoneyProduceSpeedRate ~= 0 then
effectStr = string.format(Language.LUA_SETTLEMENT_ENHANCE_MONEY_PRODUCE_SPEED, enhanceMoneyProduceSpeedRate) .. "\n"
end
if enhanceMoneyProfitRate ~= 0 then
effectStr = effectStr .. string.format(Language.LUA_SETTLEMENT_ENHANCE_MONEY_PROFIT, enhanceMoneyProfitRate) .. "\n"
end
if enhanceExpProfitRate ~= 0 then
effectStr = effectStr .. string.format(Language.LUA_SETTLEMENT_ENHANCE_EXP_PROFIT, enhanceExpProfitRate)
end
return effectStr
end
function UIUtils.showItemSideTips(itemCell, tipsPosType, tipsPosTransform)
local posInfo
if DeviceInfo.usingController then
posInfo = {
tipsPosType = tipsPosType or UIConst.UI_TIPS_POS_TYPE.RightDown,
tipsPosTransform = tipsPosTransform or itemCell.transform,
isSideTips = true,
}
end
itemCell:ShowTips(posInfo)
end
function UIUtils.bindHyperlinkPopup(bindTarget, hyperlinkUITextGroupId, inputGroupId, actionId)
if string.isEmpty(actionId) then
actionId = "hyperlink_show_popup"
end
local bindId = UIUtils.bindInputPlayerAction(actionId, function()
Notify(MessageConst.SHOW_HYPERLINK_POPUP_BY_GROUP_ID, hyperlinkUITextGroupId)
end, inputGroupId)
local curValid = CS.Beyond.UI.UIText.IsHyperlinkUITextGroupDisplayable(hyperlinkUITextGroupId)
InputManagerInst:ToggleBinding(bindId, curValid)
MessageManager:Register(MessageConst.HYPERLINK_UITEXT_GROUP_DISPLAYABLE_CHANGE, function(args)
local groupId, isValid = unpack(args)
if groupId == hyperlinkUITextGroupId then
InputManagerInst:ToggleBinding(bindId, isValid)
logger.info("[Hyperlink] bind displayable change :", isValid)
end
end, bindTarget)
end
function UIUtils.bindControllerCamZoom(groupId)
local inId = UIUtils.bindInputPlayerAction("cam_zoom_in_ct", function()
Utils.zoomCamera(4)
end, groupId)
local outId = UIUtils.bindInputPlayerAction("cam_zoom_out_ct", function()
Utils.zoomCamera(-4)
end, groupId)
return inId, outId
end
function UIUtils.setTabIcons(cell, iconPath, iconName)
cell.selectedIcon:LoadSprite(iconPath, iconName)
cell.defaultIcon:LoadSprite(iconPath, iconName .. "_shadow")
end
function UIUtils.setTabIconsWithFullPath(cell, iconPath)
cell.selectedIcon:LoadSprite(iconPath)
cell.defaultIcon:LoadSprite(iconPath .. "_shadow")
end
function UIUtils.hideItemTipsOnLoseFocus(isFocused)
if not isFocused then
Notify(MessageConst.HIDE_ITEM_TIPS)
end
end
function UIUtils.waitMsgExecute(msg, msgGroupKey, callback)
local registerKey
registerKey = MessageManager:Register(msg, function(msgArg)
if not callback(msgArg) then
MessageManager:Unregister(registerKey)
Notify(MessageConst.ON_WAIT_MSG_EXECUTE_COMPLETE, registerKey)
end
end, msgGroupKey)
return registerKey
end
function UIUtils.isBattleControllerModifyKeyChanged()
return CS.Beyond.GameSetting.gamepadCacheSkillCombo
end
function UIUtils.updateStaminaNode(node, staminaInfo)
node.descStaminaTxt.text = string.isEmpty(staminaInfo.descStamina) and Language["ui_dungeon_details_ap_refresh"] or
staminaInfo.descStamina
local costStamina = staminaInfo.costStamina
local isLack = GameInstance.player.inventory.curStamina < costStamina
node.costStaminaTxt.text = UIUtils.setCountColor(costStamina, isLack)
local delStamina = staminaInfo.delStamina
local hasDelStamina = delStamina ~= nil and type(delStamina) == "number"
node.delStaminaTxt.text = hasDelStamina and delStamina or 0
node.delStaminaTxt.gameObject:SetActive(hasDelStamina)
end
function UIUtils.initSearchInput(inputField, initInfo)
if inputField == nil or initInfo == nil then
return
end
if initInfo.characterLimit ~= nil then
inputField.characterLimit = initInfo.characterLimit
else
inputField.characterLimit = UIConst.INPUT_FIELD_NAME_CHARACTER_LIMIT
end
if initInfo.clearBtn ~= nil then
initInfo.clearBtn.gameObject:SetActive(not string.isEmpty(inputField.text))
end
inputField.onValueChanged:RemoveAllListeners()
inputField.onValueChanged:AddListener(function(str)
if initInfo.clearBtn ~= nil then
local isPsController = Utils.checkIsPSDevice()
if isPsController then
initInfo.clearBtn.gameObject:SetActive(false)
else
initInfo.clearBtn.gameObject:SetActive(not string.isEmpty(str))
end
end
if initInfo.onInputValueChanged ~= nil then
initInfo.onInputValueChanged(str)
end
end)
if initInfo.onInputSubmit ~= nil then
inputField.onSubmit:RemoveAllListeners()
inputField.onSubmit:AddListener(function(newText)
if Utils.checkIsPSDevice() then
return
end
initInfo.onInputSubmit(newText)
end)
end
inputField.onFocused:RemoveAllListeners()
inputField.onFocused:AddListener(function()
local isPsController = Utils.checkIsPSDevice()
if initInfo.clearBtn ~= nil and isPsController then
initInfo.clearBtn.gameObject:SetActive(false)
end
if initInfo.onInputFocused ~= nil then
initInfo.onInputFocused()
end
end)
inputField.onEndEdit:RemoveAllListeners()
inputField.onEndEdit:AddListener(function(newText)
local isPsController = Utils.checkIsPSDevice()
if initInfo.clearBtn ~= nil and isPsController then
initInfo.clearBtn.gameObject:SetActive(not string.isEmpty(inputField.text))
end
if initInfo.onInputEndEdit ~= nil then
initInfo.onInputEndEdit(newText)
end
end)
if initInfo.clearBtn ~= nil and initInfo.onClearClick ~= nil then
initInfo.clearBtn.onClick:RemoveAllListeners()
initInfo.clearBtn.onClick:AddListener(function()
initInfo.onClearClick()
CS.UnityEngine.EventSystems.EventSystem.current:SetSelectedGameObject(inputField.gameObject);
end)
end
if initInfo.searchBtn ~= nil and initInfo.onSearchClick ~= nil then
initInfo.searchBtn.onClick:RemoveAllListeners()
initInfo.searchBtn.onClick:AddListener(function()
initInfo.onSearchClick()
end)
end
end
function UIUtils.getUIVideoFullPath(path)
if string.isEmpty(path) then
return false
end
return CS.Beyond.Gameplay.View.VideoManager.TryGetVideoPlayFullPath('UI/' .. path)
end
function UIUtils.inDungeonOrFocusMode()
return GameInstance.dungeonManager.inDungeon or FocusModeUtils.isInFocusMode
end
function UIUtils.isUIGOActive(go)
return go.activeInHierarchy and go.layer ~= UIConst.HIDE_LAYER
end
_G.UIUtils = UIUtils
return UIUtils