Files
gtav-src/script/dev_ng/shared/include/public/UIUtil.sch
T
2025-09-29 00:52:08 +02:00

406 lines
14 KiB
Scheme
Executable File

//////////////////////////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : UIUtil //
// AUTHOR : Taylor Wright //
// DESCRIPTION : Util to help manage Script UI //
// //
//////////////////////////////////////////////////////////////////////////////////////////
USING "commands_graphics.sch"
USING "commands_pad.sch"
USING "hud_drawing.sch"
// Used for screen position, size and scaling methods
CONST_INT DEFAULT_SCREEN_WIDTH 1280
CONST_INT DEFAULT_SCREEN_HEIGHT 720
// Used for gamepad input methods
CONST_INT STICK_DEAD_ZONE 28
CONST_INT DELAY_BEFORE_REACTIVATED 250
////////////////////////////////////
// PIXEL & FLOAT CONVERSION TOOLS //
////////////////////////////////////
/// PURPOSE:
/// Convert an x pixel position to a screen float position
/// PARAMS:
/// x - X position
/// iScreenWidth - Screen width, when passed in prevents a call to GET_SCREEN_RESOLUTION
/// RETURNS:
/// x position as a screen float
FUNC FLOAT PIXEL_X_TO_FLOAT(FLOAT x, INT iScreenWidth = 0)
IF iScreenWidth = 0
INT iScreenHeight
GET_SCREEN_RESOLUTION(iScreenWidth, iScreenHeight)
ENDIF
RETURN x / iScreenWidth
ENDFUNC
/// PURPOSE:
/// Convert an y pixel position to a screen float position
/// PARAMS:
/// y - Y position
/// iScreenHeight - Screen height, when passed in prevents a call to GET_SCREEN_RESOLUTION
/// RETURNS:
/// y position as a screen float
FUNC FLOAT PIXEL_Y_TO_FLOAT(FLOAT y, INT iScreenHeight = 0)
IF iScreenHeight = 0
INT iScreenWidth
GET_SCREEN_RESOLUTION(iScreenWidth, iScreenHeight)
ENDIF
RETURN y / iScreenHeight
ENDFUNC
/// PURPOSE:
/// Convert a x screen float position to a x pixel position
/// PARAMS:
/// x - X position
/// iScreenWidth - Screen width, when passed in prevents a call to GET_SCREEN_RESOLUTION
/// rounded - Rounds float value to nearest pixel (default = true)
/// RETURNS:
/// x positon as a pixel
FUNC FLOAT FLOAT_X_TO_PIXEL(FLOAT x, INT iScreenWidth = 0, BOOL rounded = TRUE)
IF iScreenWidth = 0
INT iScreenHeight
GET_SCREEN_RESOLUTION(iScreenWidth, iScreenHeight)
ENDIF
FLOAT pixel = x * iScreenWidth
IF rounded
RETURN TO_FLOAT(ROUND(pixel))
ENDIF
RETURN pixel
ENDFUNC
/// PURPOSE:
/// Convert a y screen float position to a y pixel position
/// PARAMS:
/// y - Y position
/// iScreenHeight - Screen height, when passed in prevents a call to GET_SCREEN_RESOLUTION
/// rounded - Rounds float value to nearest pixel (default = true)
/// RETURNS:
/// y positon as a pixel
FUNC FLOAT FLOAT_Y_TO_PIXEL(FLOAT y, INT iScreenHeight = 0, BOOL rounded = TRUE)
IF iScreenHeight = 0
INT iScreenWidth
GET_SCREEN_RESOLUTION(iScreenWidth, iScreenHeight)
ENDIF
FLOAT pixel = y * iScreenHeight
IF rounded
RETURN TO_FLOAT(ROUND(pixel))
ENDIF
RETURN pixel
ENDFUNC
/////////////////////////////////
// RECT: POSITION, SIZE & COLOR//
/////////////////////////////////
/// PURPOSE:
/// Position Rect with pixel values (based on 720p source)
/// PARAMS:
/// target - Rect to manipulate
/// x - X positon as pixel of 1280
/// y - Y positon as pixel of 720
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_RECT(RECT &target, FLOAT x, FLOAT y, BOOL fromTopLeft = FALSE)
target.x = PIXEL_X_TO_FLOAT(x, DEFAULT_SCREEN_WIDTH)
target.y = PIXEL_Y_TO_FLOAT(y, DEFAULT_SCREEN_HEIGHT)
IF fromTopLeft
target.x += target.w/2
target.y += target.h/2
ENDIF
ENDPROC
/// PURPOSE:
/// Size Rect with pixel values (based on 720p source)
/// PARAMS:
/// target - Rect to manipulate
/// w - Width as pixel of 1280
/// h - Height as pixel of 720
PROC PIXEL_SIZE_RECT(RECT &target, FLOAT w, FLOAT h)
target.w = PIXEL_X_TO_FLOAT(w, DEFAULT_SCREEN_WIDTH)
target.h = PIXEL_Y_TO_FLOAT(h, DEFAULT_SCREEN_HEIGHT)
ENDPROC
/// PURPOSE:
/// Position and size a Rect with pixel values (based on 720p source)
/// PARAMS:
/// target - Rect to manipulate
/// x - X positon as pixel of 1280
/// y - Y positon as pixel of 720
/// w - Width as pixel of 1280
/// h - Height as pixel of 720
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_AND_SIZE_RECT(RECT &target, FLOAT x, FLOAT y, FLOAT w, FLOAT h, BOOL fromTopLeft = FALSE)
PIXEL_SIZE_RECT(target, w, h)
PIXEL_POSITION_RECT(target, x, y, fromTopLeft)
ENDPROC
/// PURPOSE:
/// Set Color of RECT
/// PARAMS:
/// target - Rect to manipulate
/// r - red
/// g - green
/// b - blue
/// a - alpha
PROC RECT_COLOR(RECT &target, INT r = 255, INT g = 255, INT b = 255, INT a = 255)
target.r = r
target.g = g
target.b = b
target.a = a
ENDPROC
///////////////////////////////////////////
// SPRITE: POSITION, SIZE, SCALE & COLOR //
///////////////////////////////////////////
/// PURPOSE:
/// Position sprite with pixel values (based on 720p source)
/// PARAMS:
/// target - Sprite to manipulate
/// x - X positon as pixel of 1280
/// y - Y positon as pixel of 720
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_SPRITE(SPRITE_PLACEMENT &target, FLOAT x, FLOAT y, BOOL fromTopLeft = FALSE)
target.x = PIXEL_X_TO_FLOAT(x, DEFAULT_SCREEN_WIDTH)
target.y = PIXEL_Y_TO_FLOAT(y, DEFAULT_SCREEN_HEIGHT)
IF fromTopLeft
target.x += target.w/2
target.y += target.h/2
ENDIF
ENDPROC
/// PURPOSE:
/// Size sprite with pixel values (based on 72p source)
/// PARAMS:
/// target - Sprite to manipulate
/// w - Width as pixel of 1280
/// h - Height as pixel of 720
PROC PIXEL_SIZE_SPRITE(SPRITE_PLACEMENT &target, FLOAT w, FLOAT h)
target.w = PIXEL_X_TO_FLOAT(w, DEFAULT_SCREEN_WIDTH)
target.h = PIXEL_Y_TO_FLOAT(h, DEFAULT_SCREEN_HEIGHT)
ENDPROC
/// PURPOSE:
/// Position and size a sprite with pixel values (based on 720p source)
/// PARAMS:
/// target - Sprite to manipulate
/// x - X positon as pixel of 1280
/// y - Y positon as pixel of 720
/// w - Width as pixel of 1280
/// h - Height as pixel of 720
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_AND_SIZE_SPRITE(SPRITE_PLACEMENT &target, FLOAT x, FLOAT y, FLOAT w, FLOAT h, BOOL fromTopLeft = FALSE)
PIXEL_SIZE_SPRITE(target, w, h)
PIXEL_POSITION_SPRITE(target, x, y, fromTopLeft)
ENDPROC
/// PURPOSE:
/// Size sprite with pixel values (based on 72p source)
/// PARAMS:
/// target - Sprite to manipulate
/// w - Width as pixel of 1280
/// h - Height as pixel of 720
PROC PIXEL_SCALE_SPRITE(STRING pTextureDictionaryName, STRING pSpriteName, SPRITE_PLACEMENT &target, FLOAT w = 1.0, FLOAT h = 1.0)
VECTOR vTexture = GET_TEXTURE_RESOLUTION(pTextureDictionaryName, pSpriteName)
target.w = PIXEL_X_TO_FLOAT(vTexture.x, DEFAULT_SCREEN_WIDTH) * w
target.h = PIXEL_Y_TO_FLOAT(vTexture.y, DEFAULT_SCREEN_HEIGHT) * h
ENDPROC
/// PURPOSE:
/// Position a sprite with pixel values and size with float scale values
/// PARAMS:
/// pTextureDictionaryName - Texture Dictionary Name
/// pSpriteName - Sprite Name
/// target - Sprite to manipulate
/// x - X positon as pixel
/// y - Y positon as pixel
/// w - Width as scale of texture (Default 1.0 = 100%)
/// h - Height as scale of texture (Default 1.0 = 100%)
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_AND_SCALE_SPRITE(STRING pTextureDictionaryName, STRING pSpriteName, SPRITE_PLACEMENT &target, FLOAT x, FLOAT y, FLOAT w = 1.0, FLOAT h = 1.0, BOOL fromTopLeft = FALSE)
PIXEL_SCALE_SPRITE(pTextureDictionaryName, pSpriteName, target, w, h)
PIXEL_POSITION_SPRITE(target, x, y, fromTopLeft)
ENDPROC
/// PURPOSE:
/// Simple expansion of DRAW_2D_SPRITE to draw texture to scale (initial scale is determiend in relation to 1280x720 but will scale propperly to other resolutions)
/// PARAMS:
/// pTextureDictionaryName - Texture Dictionary Name
/// pSpriteName - Sprite Name
/// target - Sprite to manipulate
/// DoScreenScaling - ???
/// option - Choice between the following options:
/// HIGHLIGHT_OPTION_NORMAL
/// HIGHLIGHT_OPTION_NOTSELECTED_ACTIVE
/// HIGHLIGHT_OPTION_EMPTY_SELECTED
/// HIGHLIGHT_OPTION_EMPTY_NOTSELECTED
/// HIGHLIGHT_OPTION_NUMBER_SELECTED
/// HIGHLIGHT_OPTION_NUMBER_NOTSELECTED
/// HIGHLIGHT_OPTION_SELECTED_GREY
/// bDrawBeforeFade - ???
PROC DRAW_2D_SPRITE_UNSCALED(STRING pTextureDictionaryName, STRING pSpriteName, SPRITE_PLACEMENT &target, BOOL DoScreenScaling = TRUE, HIGHLIGHT_OPTION option = HIGHLIGHT_OPTION_NORMAL, BOOL bDrawBeforeFade = FALSE)
PIXEL_SCALE_SPRITE(pTextureDictionaryName, pSpriteName, target)
DRAW_2D_SPRITE(pTextureDictionaryName, pSpriteName, target, DoScreenScaling, option, bDrawBeforeFade)
ENDPROC
/// PURPOSE:
/// Set Color of SPRITE
/// PARAMS:
/// target - Rect to manipulate
/// r - red
/// g - green
/// b - blue
/// a - alpha
PROC SPRITE_COLOR(SPRITE_PLACEMENT &target, INT r = 255, INT g = 255, INT b = 255, INT a = 255)
target.r = r
target.g = g
target.b = b
target.a = a
ENDPROC
/// PURPOSE:
/// Set the rotation of a SPRITE_PLACEMENT
/// PARAMS:
/// target - the SPRITE_PLACEMENT to manipulate.
/// fRotation - the new rotation to give the sprite.
PROC SPRITE_ROTATION(SPRITE_PLACEMENT &target, FLOAT fRotation = 0.0)
target.fRotation = fRotation
ENDPROC
////////////////////
// TEXT: POSITION //
////////////////////
/// PURPOSE:
/// Position Text with pixel values (based on 720p source)
/// PARAMS:
/// target - Text to manipulate
/// x - X positon as pixel of 1280
/// y - Y positon as pixel of 720
/// fromTopLeft - Register positon from Top Left or Center
PROC PIXEL_POSITION_TEXT(TEXT_PLACEMENT &target, FLOAT x, FLOAT y, BOOL fromTopLeft = TRUE)
target.x = PIXEL_X_TO_FLOAT(x, DEFAULT_SCREEN_WIDTH)
target.y = PIXEL_Y_TO_FLOAT(y, DEFAULT_SCREEN_HEIGHT)
IF NOT fromTopLeft
// TODO: enable fromTopLeft false -TAYLOR
PRINTLN("Unable to position from middle center")
// target.x -= target.w/2
// target.y -= target.h/2
ENDIF
ENDPROC
//////////////////////
// CONTROLLER INPUT //
//////////////////////
/// PURPOSE: Stores data used for Analog as DPad support
STRUCT UI_INPUT_DATA
BOOL bAcceptLeftStickInput = TRUE
INT iLastUpdateLeftStick = 0
ENDSTRUCT
ENUM eLeftAnalogAsDpad
LEFT_ANALOG_AS_DPAD_UP,
LEFT_ANALOG_AS_DPAD_DOWN,
LEFT_ANALOG_AS_DPAD_LEFT,
LEFT_ANALOG_AS_DPAD_RIGHT
ENDENUM
/// PURPOSE:
/// Allows you to evaluate the left analog stick like it's a DPAD
/// PARAMS:
/// PadNumber - Game Pad number
/// ButtonNumber - Pad Button number (only tests for: LEFT_ANALOG_AS_DPAD_UP, LEFT_ANALOG_AS_DPAD_DOWN, LEFT_ANALOG_AS_DPAD_LEFT, LEFT_ANALOG_AS_DPAD_RIGHT)
/// RETURNS:
/// True = Current analog equivelent active, False = Current analog equivelent not active
FUNC BOOL IS_LEFT_ANALOG_AS_DPAD(eLeftAnalogAsDpad ButtonNumber, UI_INPUT_DATA &inputData)
BOOL returnValue = FALSE
INT iLSX, iLSY
iLSX = GET_CONTROL_VALUE(FRONTEND_CONTROL, INPUT_FRONTEND_AXIS_X)
iLSY = GET_CONTROL_VALUE(FRONTEND_CONTROL, INPUT_FRONTEND_AXIS_Y)
// If stick goes to deadzone method fails but enables stick for next time called
IF ABSI(iLSX) < STICK_DEAD_ZONE AND ABSI(iLSY) < STICK_DEAD_ZONE
inputData.bAcceptLeftStickInput = TRUE
inputData.iLastUpdateLeftStick = 0
RETURN FALSE
ENDIF
// If delay time hasn't elapsed method fails
IF GET_GAME_TIMER() < inputData.iLastUpdateLeftStick + DELAY_BEFORE_REACTIVATED
inputData.bAcceptLeftStickInput = FALSE
RETURN FALSE
ELSE
inputData.bAcceptLeftStickInput = TRUE
ENDIF
// Failsafe, This should never fire given above conditions
IF NOT inputData.bAcceptLeftStickInput
RETURN FALSE
ENDIF
SWITCH ButtonNumber
CASE LEFT_ANALOG_AS_DPAD_UP
returnValue = iLSY < (128 - STICK_DEAD_ZONE)
BREAK
CASE LEFT_ANALOG_AS_DPAD_DOWN
returnValue = iLSY > (128 + STICK_DEAD_ZONE)
BREAK
CASE LEFT_ANALOG_AS_DPAD_LEFT
returnValue = iLSX < (128 - STICK_DEAD_ZONE)
BREAK
CASE LEFT_ANALOG_AS_DPAD_RIGHT
returnValue = iLSX > (128 + STICK_DEAD_ZONE)
BREAK
ENDSWITCH
IF returnValue
inputData.iLastUpdateLeftStick = GET_GAME_TIMER()
inputData.bAcceptLeftStickInput = FALSE
ENDIF
RETURN returnValue
ENDFUNC
FUNC FLOAT SET_RECT_DYNAMIC_TO_STRING(RECT& rectToSet, STRING sText, TEXT_PLACEMENT& textPlacement, TEXT_STYLE & tStyle, FLOAT fLineHeight, FLOAT fLineSpace, INT iLinesDown, FLOAT fStartingPixelTL)
// Have to set the style first!
SET_TEXT_STYLE(tStyle)
// Figure out how any rows the text is going to take, given that it's wrapped to this rect, and using the given font.
BEGIN_TEXT_COMMAND_GET_NUMBER_OF_LINES_FOR_STRING(sText)
INT iLines = END_TEXT_COMMAND_GET_NUMBER_OF_LINES_FOR_STRING(textPlacement.x, textPlacement.y)
PRINTLN("Num lines: ", iLines)
// Set the height.
INT iScreenHeight = 720
IF NOT GET_IS_WIDESCREEN()
iScreenHeight = 480
ENDIF
rectToSet.h = PIXEL_Y_TO_FLOAT((TO_FLOAT(iLines) * fLineHeight) - fLineSpace, iScreenHeight)
// Need to place the rect at the top of the text.
rectToSet.y = PIXEL_Y_TO_FLOAT(fStartingPixelTL + ((TO_FLOAT(iLinesDown) + TO_FLOAT(iLines) * 0.5) * fLineHeight) - fLineSpace * 0.5, iScreenHeight)
RETURN 0.0
ENDFUNC
PROC FIXUP_SPRITE_FOR_NON_WIDESCREEN(SPRITE_PLACEMENT & sprPlacement, BOOL bWidthOnly = FALSE)
IF NOT bWidthOnly
sprPlacement.x = ((sprPlacement.x - 0.5) * 1.33) + 0.5
ENDIF
sprPlacement.w = (sprPlacement.w * 1.33)
ENDPROC
PROC FIXUP_TEXT_FOR_NON_WIDESCREEN(TEXT_PLACEMENT & txtPlacement, TEXT_STYLE & txtStyle)
txtPlacement.x = ((txtPlacement.x - 0.5) * 1.33) + 0.5
txtStyle.WrapStartX = ((txtStyle.WrapStartX - 0.5) * 1.33) + 0.5
txtStyle.WrapEndX = ((txtStyle.WrapEndX - 0.5) * 1.33) + 0.5
ENDPROC
PROC FIXUP_RECT_FOR_NON_WIDESCREEN(RECT & rectPlacement)
rectPlacement.x = ((rectPlacement.x - 0.5) * 1.33) + 0.5
rectPlacement.w = (rectPlacement.w * 1.33)
ENDPROC