1-- Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details 2-- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt 3 4-- Convenience wrappers for the C++ UI functions and general functions 5local Engine = require 'Engine' 6local Game = require 'Game' 7local utils = require 'utils' 8local pigui = Engine.pigui 9local ui = require 'pigui.libs.forwarded' 10 11-- 12-- Function: ui.rescaleUI 13-- 14-- ui.rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) 15-- 16-- Scales a set of values (normally a size or a position) based on a base 17-- resolution and the current or target resultion. 18-- 19-- 20-- Example: 21-- 22-- > size = ui.rescaleUI(Vector2(96, 96), Vector2(1600, 900)) 23-- 24-- Parameters: 25-- 26-- val - number|Vector2|Table, the values to scale 27-- baseResolution - Vector2, the resolution at which val is valid 28-- rescaleToScreenAspect - (Optional) number, when scaling a Vector2, scale x and y 29-- appropriately to match the given aspect ratio 30-- targetResolution - (Optional) Vector2, the target resolution to scale 31-- the value to. Default: current screen resolution. 32-- 33-- Returns: 34-- 35-- number|Vector2|Table - the scaled value 36-- 37function ui.rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) 38 if not targetResolution then 39 targetResolution = Vector2(pigui.screen_width, pigui.screen_height) 40 end 41 42 local rescaleVector = Vector2(targetResolution.x / baseResolution.x, targetResolution.y / baseResolution.y) 43 local rescaleFactor = math.min(rescaleVector.x, rescaleVector.y) 44 local type = type(val) 45 46 if type == 'table' then 47 local result = {} 48 for k, v in pairs(val) do 49 result[k] = ui.rescaleUI(v, baseResolution, rescaleToScreenAspect, targetResolution) 50 end 51 52 return result 53 elseif type == 'userdata' and val.x and val.y then 54 return Vector2(val.x * ((rescaleToScreenAspect and rescaleVector.x) or rescaleFactor), val.y * ((rescaleToScreenAspect and rescaleVector.y) or rescaleFactor)) 55 elseif type == 'number' then 56 return val * rescaleFactor 57 end 58end 59 60-- 61-- Function: ui.pcall 62-- 63-- ui.pcall(fun, ...) 64-- 65-- Clean up the ImGui stack in case of an error 66-- 67-- 68-- Example: 69-- 70-- > 71-- 72-- Parameters: 73-- 74-- fun - 75-- ... - 76-- 77-- Returns: 78-- 79-- nil 80-- 81function ui.pcall(fun, ...) 82 local stack = pigui.GetImguiStack() 83 return xpcall(fun, function(msg) 84 return debug.traceback(msg, 2) .. "\n" .. pigui.CleanupImguiStack(stack) 85 end, ...) 86end 87 88-- 89-- Function: ui.window 90-- 91-- ui.window(name, params, fun) 92-- 93-- Display a window 94-- 95-- 96-- Example: 97-- 98-- > 99-- 100-- Parameters: 101-- 102-- name - String, a unique name for the window, 103-- used to group its children 104-- params - Table, window options: 105-- - NoTitleBar : Disable title-bar 106-- - NoResize : Disable user resizing with the lower-right grip 107-- - NoMove : Disable user moving the window 108-- - NoScrollbar : Disable scrollbars (window can still scroll with 109-- mouse or programmatically) 110-- - NoScrollWithMouse : Disable user vertically scrolling with mouse wheel. 111-- On child window, mouse wheel will be forwarded to 112-- the parent unless NoScrollbar is also set. 113-- - NoCollapse : Disable user collapsing window by double-clicking 114-- on it 115-- - AlwaysAutoResize : Resize every window to its content every frame 116-- - NoSavedSettings : Never load/save settings in .ini file 117-- - NoInputs : 118-- - MenuBar : Has a menu-bar 119-- - HorizontalScrollbar : Allow horizontal scrollbar to appear (off by default). 120-- - NoFocusOnAppearing : Disable taking focus when transitioning from hidden to 121-- visible state 122-- - NoBringToFrontOnFocus : Disable bringing window to front when taking focus 123-- (e.g. clicking on it or programmatically giving it 124-- focus) 125-- - AlwaysVerticalScrollbar : Always show vertical scrollbar 126-- - AlwaysHorizontalScrollbar : Always show horizontal scrollbar 127-- - AlwaysUseWindowPadding : Ensure child windows without border uses 128-- style.WindowPadding (ignored by default for 129-- non-bordered child windows, because more convenient) 130-- fun - Function, a function that is called to define the window contents 131-- 132-- Returns: 133-- 134-- nil 135-- 136function ui.window(name, params, fun) 137 local ok = pigui.Begin(name, params) 138 if ok then fun() end 139 pigui.End() 140end 141 142-- 143-- Function: ui.group 144-- 145-- ui.group(fun) 146-- 147-- Display items in a group 148-- 149-- 150-- Example: 151-- 152-- > 153-- 154-- Parameters: 155-- 156-- fun - Function, a function that is called to define the group contents 157-- 158-- Returns: 159-- 160-- nil 161-- 162function ui.group(fun) 163 pigui.BeginGroup() 164 fun() 165 pigui.EndGroup() 166end 167 168-- 169-- Function: ui.popup 170-- 171-- ui.popup(name, params, fun) 172-- 173-- Display a popup window 174-- 175-- 176-- Example: 177-- 178-- > 179-- 180-- Parameters: 181-- 182-- name - String, a unique name for the window, 183-- used to group its children 184-- fun - Function, a function that is called to define the popup contents 185-- 186-- Returns: 187-- 188-- nil 189-- 190function ui.popup(name, fun) 191 if pigui.BeginPopup(name) then 192 fun() 193 pigui.EndPopup() 194 end 195end 196 197-- 198-- Function: ui.customTooltip 199-- 200-- ui.customTooltip(fun) 201-- 202-- Display a tooltip window 203-- 204-- 205-- Example: 206-- 207-- > 208-- 209-- Parameters: 210-- 211-- fun - Function, a function that is called to define the tooltip contents 212-- 213-- Returns: 214-- 215-- nil 216-- 217function ui.customTooltip(fun) 218 pigui.BeginTooltip() 219 fun() 220 pigui.EndTooltip() 221end 222 223-- 224-- Function: ui.child 225-- 226-- ui.child(id, size, flags, fun) 227-- 228-- Define a child window 229-- 230-- 231-- Example: 232-- 233-- > 234-- 235-- Parameters: 236-- 237-- id - String, a unique name for the window, 238-- used to group its children 239-- size - (Optional)Vector2 240-- flags - (Optional)Table, options: 241-- - NoTitleBar : Disable title-bar 242-- - NoResize : Disable user resizing with the lower-right grip 243-- - NoMove : Disable user moving the window 244-- - NoScrollbar : Disable scrollbars (window can still scroll with 245-- mouse or programmatically) 246-- - NoScrollWithMouse : Disable user vertically scrolling with mouse wheel. 247-- On child window, mouse wheel will be forwarded to 248-- the parent unless NoScrollbar is also set. 249-- - NoCollapse : Disable user collapsing window by double-clicking 250-- on it 251-- - AlwaysAutoResize : Resize every window to its content every frame 252-- - NoSavedSettings : Never load/save settings in .ini file 253-- - NoInputs : 254-- - MenuBar : Has a menu-bar 255-- - HorizontalScrollbar : Allow horizontal scrollbar to appear (off by default). 256-- - NoFocusOnAppearing : Disable taking focus when transitioning from hidden to 257-- visible state 258-- - NoBringToFrontOnFocus : Disable bringing window to front when taking focus 259-- (e.g. clicking on it or programmatically giving it 260-- focus) 261-- - AlwaysVerticalScrollbar : Always show vertical scrollbar 262-- - AlwaysHorizontalScrollbar : Always show horizontal scrollbar 263-- - AlwaysUseWindowPadding : Ensure child windows without border uses 264-- style.WindowPadding (ignored by default for 265-- non-bordered child windows, because more convenient) 266-- fun - Function, a function that is called to define the popup contents 267-- 268-- Returns: 269-- 270-- nil 271-- 272function ui.child(id, size, flags, fun) 273 if flags == nil and fun == nil then -- size is optional 274 fun = size 275 size = Vector2(-1,-1) 276 flags = {} 277 elseif fun == nil then 278 fun = flags 279 flags = {} 280 end 281 282 pigui.BeginChild(id, size, flags) 283 fun() 284 pigui.EndChild() 285end 286 287-- 288-- Function: ui.withTooltip 289-- 290-- ui.withTooltip(tooltip, fun) 291-- 292-- Display something, but with a tooltip shown on mouseover 293-- 294-- 295-- Example: 296-- 297-- > 298-- 299-- Parameters: 300-- 301-- tooltip - String, the tooltip to display 302-- fun - Function, a function that is called to display the contents 303-- that will have the tooltip 304-- 305-- Returns: 306-- 307-- nil 308-- 309function ui.withTooltip(tooltip, fun) 310 local startPos = pigui.GetCursorPos() 311 pigui.BeginGroup() 312 fun() 313 pigui.EndGroup() 314 if string.len(tooltip) > 0 and pigui.IsItemHovered() then 315 pigui.SetTooltip(tooltip) 316 end 317end 318 319-- 320-- Function: ui.playBoinkNoise 321-- 322-- ui.playBoinkNoise() 323-- 324-- Boink! 325-- 326-- Example: 327-- 328-- > ui.playBoinkNoise() 329-- 330-- Parameters: 331-- 332-- Returns: 333-- 334-- nil 335-- 336function ui.playBoinkNoise() 337 ui.playSfx("Click", 0.3) 338end 339 340-- 341-- Function: ui.isMouseHoveringWindow 342-- 343-- ui.isMouseHoveringWindow() 344-- 345-- 346-- Example: 347-- 348-- > 349-- 350-- Parameters: 351-- 352-- Returns: 353-- 354-- boolean - true if the mouse is currently within the current 355-- window, false otherwise 356-- 357function ui.isMouseHoveringWindow() 358 return ui.isWindowHovered({"AllowWhenBlockedByPopup", "AllowWhenBlockedByActiveItem"}) 359end 360 361-- 362-- Function: ui.isAnyWindowHovered 363-- 364-- ui.isAnyWindowHovered() 365-- 366-- 367-- Example: 368-- 369-- > 370-- 371-- Parameters: 372-- 373-- Returns: 374-- 375-- boolean - true if the mouse is currently within any window, 376-- false otherwise 377-- 378function ui.isAnyWindowHovered() 379 return ui.isWindowHovered({"AnyWindow"}) 380end 381 382-- 383-- Function: ui.ctrlHeld 384-- 385-- ui.ctrlHeld() 386-- 387-- 388-- Example: 389-- 390-- > 391-- 392-- Parameters: 393-- 394-- Returns: 395-- 396-- boolean - true if a ctrl key is being held 397-- 398function ui.ctrlHeld() return pigui.key_ctrl end 399 400-- 401-- Function: ui.altHeld 402-- 403-- ui.altHeld() 404-- 405-- 406-- Example: 407-- 408-- > 409-- 410-- Parameters: 411-- 412-- Returns: 413-- 414-- boolean - true if an alt key is being held 415-- 416function ui.altHeld() return pigui.key_alt end 417 418-- 419-- Function: ui.shiftHeld 420-- 421-- ui.shiftHeld() 422-- 423-- 424-- Example: 425-- 426-- > 427-- 428-- Parameters: 429-- 430-- Returns: 431-- 432-- boolean - true if a shift key is being held 433-- 434function ui.shiftHeld() return pigui.key_shift end 435 436-- 437-- Function: ui.noModifierHeld 438-- 439-- ui.noModifierHeld() 440-- 441-- 442-- Example: 443-- 444-- > 445-- 446-- Parameters: 447-- 448-- Returns: 449-- 450-- boolean - true if no modifier (alt, shift, ctrl) keys are being held 451-- 452function ui.noModifierHeld() return pigui.key_none end 453 454-- 455-- Function: ui.escapeKeyReleased 456-- 457-- Performs some sanity checks and returns true if the user has pressed escape 458-- and the escape key is not currently being consumed. 459-- 460-- 461-- Parameters: 462-- 463-- ignorePopup - if true, skip checking for open popups. 464-- 465-- Returns: 466-- 467-- boolean - true if the escape key is pressed and not being consumed 468-- 469function ui.escapeKeyReleased(ignorePopup) 470 return (ignorePopup or not ui.isAnyPopupOpen()) and ui.noModifierHeld() and ui.isKeyReleased(ui.keys.escape) 471end 472 473-- 474-- Function: ui.tabBar 475-- 476-- ui.tabBar(id, items) 477-- 478-- 479-- Example: 480-- 481-- > 482-- 483-- Parameters: 484-- id - String, unique id to identify the group of tabs by 485-- items - Table, a list of contents. Each item should be a 486-- table containing a table of tab options and a function 487-- to call that displays the tabs contents 488-- 489-- Returns: 490-- 491-- boolean - true if the tab bar is open, false otherwise 492-- 493function ui.tabBar(id, items) 494 local open = pigui.BeginTabBar(id) 495 if not open then return false end 496 497 for i, v in ipairs(items) do 498 if type(v) == "table" and v[1] and type(v[2]) == "function" then 499 if pigui.BeginTabItem(tostring(v[1]) .. "##" .. tostring(i)) then 500 v[2](v) 501 end 502 end 503 end 504 505 pigui.EndTabBar() 506 return true 507end 508 509-- 510-- Function: ui.withFont 511-- 512-- ui.withFont(name, size, fun) 513-- 514-- 515-- Example: 516-- 517-- > 518-- 519-- Parameters: 520-- name - Table|String, a table defining the font name and size or 521-- a string containing the name of the font 522-- size - (Optional) number, font size. Optional if name is a table and defines size 523-- fun - function, a function to call that shows the contents with the defined font 524-- 525-- Returns: 526-- 527-- any - the value returned from fun 528-- 529function ui.withFont(name, size, fun) 530 -- allow `withFont(fontObj, fun)` 531 if type(name) == "table" and type(size) == "function" then 532 name, size, fun = table.unpack{name.name, name.size, size} 533 end 534 535 local font = pigui:PushFont(name, size) 536 local res = fun() 537 if font then 538 pigui.PopFont() 539 end 540 return res 541end 542 543-- 544-- Function: ui.withStyleColors 545-- 546-- ui.withStyleColors(styles, fun) 547-- 548-- Display UI content with defined colors 549-- 550-- Example: 551-- 552-- > 553-- 554-- Parameters: 555-- styles - table, table of style elements with the desired colors: 556-- Text, TextDisabled, WindowBg, ChildWindowBg, PopupBg, Border, 557-- BorderShadow, FrameBg, FrameBgHovered, FrameBgActive,TitleBg, 558-- TitleBgCollapsed, TitleBgActive, MenuBarBg, ScrollbarBg, 559-- ScrollbarGrab, ScrollbarGrabHovered, ScrollbarGrabActive, 560-- CheckMark, SliderGrab, SliderGrabActive, Button, 561-- ButtonHovered, ButtonActive, Header, HeaderHovered, 562-- HeaderActive, Separator, SeparatorHovered, SeparatorActive, 563-- ResizeGrip, ResizeGripHovered, ResizeGripActive, PlotLines, 564-- PlotLinesHovered, PlotHistogram, PlotHistogramHovered, 565-- TextSelectedBg, ModalWindowDarkening 566-- fun - function, a function to call that shows the contents with the defined font 567-- 568-- Returns: 569-- 570-- any - the value returned from fun 571-- 572function ui.withStyleColors(styles, fun) 573 for k,v in pairs(styles) do 574 pigui.PushStyleColor(k, v) 575 end 576 local res = fun() 577 pigui.PopStyleColor(utils.count(styles)) 578 return res 579end 580 581-- 582-- Function: ui.withStyleVars 583-- 584-- ui.withStyleVars(styles, fun) 585-- 586-- Display UI content with defined styles 587-- 588-- Example: 589-- 590-- > 591-- 592-- Parameters: 593-- vars - table, table of style elements with the desired values: 594-- Alpha, WindowPadding, WindowRounding, WindowBorderSize, 595-- WindowMinSize, ChildRounding, ChildBorderSize, FramePadding, 596-- FrameRounding, FrameBorderSize, ItemSpacing, 597-- ItemInnerSpacing, IndentSpacing, GrabMinSize, 598-- ButtonTextAlign 599-- fun - function, a function to call that shows the contents with the defined font 600-- 601-- Returns: 602-- 603-- any - the value returned from fun 604-- 605function ui.withStyleVars(vars, fun) 606 for k,v in pairs(vars) do 607 pigui.PushStyleVar(k, v) 608 end 609 local res = fun() 610 pigui.PopStyleVar(utils.count(vars)) 611 return res 612end 613 614-- 615-- Function: ui.withStyleColorsAndVars 616-- 617-- ui.withStyleColorsAndVars(styles, vars, fun) 618-- 619-- Display UI content with defined styles and colors 620-- 621-- Example: 622-- 623-- > 624-- 625-- Parameters: 626-- styles - table, table of style elements with the desired colors (see ui.withStyleColors) 627-- vars - table, table of style elements with the desired values (see ui.withStyleVars) 628-- fun - function, a function to call that shows the contents with the defined font 629-- 630-- Returns: 631-- 632-- any - the value returned from fun 633-- 634function ui.withStyleColorsAndVars(styles, vars, fun) 635 for k,v in pairs(styles) do 636 pigui.PushStyleColor(k, v) 637 end 638 for k,v in pairs(vars) do 639 pigui.PushStyleVar(k, v) 640 end 641 local res = fun() 642 pigui.PopStyleVar(utils.count(vars)) 643 pigui.PopStyleColor(utils.count(styles)) 644 return res 645end 646 647-- 648-- Function: ui.screenSize 649-- 650-- ui.screenSize() 651-- 652-- Return the current screen resolution as a Vector2 653-- 654-- Example: 655-- 656-- > 657-- 658-- Parameters: 659-- 660-- Returns: 661-- 662-- Vector2 - screen width and height 663-- 664function ui.screenSize() 665 return Vector2(ui.screenWidth, ui.screenHeight) 666end 667 668-- 669-- Function: ui.setNextWindowPosCenter 670-- 671-- ui.setNextWindowPosCenter(cond) 672-- 673-- Set the next window position to be centered on screen 674-- 675-- Example: 676-- 677-- > 678-- 679-- Parameters: 680-- cond - table, condition flags: Always, Once, FirstUseEver, Appearing 681-- 682-- Returns: 683-- 684-- nil 685-- 686function ui.setNextWindowPosCenter(cond) 687 ui.setNextWindowPos(ui.screenSize() / 2, cond, Vector2(0.5, 0.5)) 688end 689 690-- 691-- Function: ui.sameLine 692-- 693-- ui.sameLine(pos_x, spacing_w) 694-- 695-- Draw the next command on the same line as the previous 696-- 697-- Example: 698-- 699-- > 700-- 701-- Parameters: 702-- pos_x - (Optional) number, X position for next draw command, default 0 703-- spacing_w - (Optional) number, draw with spacing relative to previous, default -1 704-- 705-- Returns: 706-- 707-- nil 708-- 709function ui.sameLine(pos_x, spacing_w) 710 local px = pos_x or 0.0 711 local sw = spacing_w or -1.0 712 pigui.SameLine(px, sw) 713end 714 715-- 716-- Function: ui.withID 717-- 718-- ui.withID(id, fun) 719-- 720-- Display content with a specified ID 721-- 722-- Example: 723-- 724-- > 725-- 726-- Parameters: 727-- id - string, the desired ID 728-- fun - function, function called to display content 729-- 730-- Returns: 731-- 732-- nil 733-- 734function ui.withID(id, fun) 735 pigui.PushID(id) 736 fun() 737 pigui.PopID() 738end 739 740-- 741-- Function: ui.loadTextureFromSVG 742-- 743-- ui.loadTextureFromSVG(filename, width, height) 744-- 745-- Create a texture from an SVG 746-- 747-- Example: 748-- 749-- > 750-- 751-- Parameters: 752-- filename - string, svg path 753-- width - number, width of texture to create 754-- height - number, height of texture to create 755-- 756-- Returns: 757-- 758-- userdata - the texture 759-- 760function ui.loadTextureFromSVG(filename, width, height) 761 return pigui:LoadTextureFromSVG(filename, width, height) 762end 763 764-- 765-- Function: ui.loadTexture 766-- 767-- ui.loadTexture(filename) 768-- 769-- Load a texture from file 770-- 771-- Example: 772-- 773-- > 774-- 775-- Parameters: 776-- filename - string, texture file path 777-- 778-- Returns: 779-- 780-- userdata - the texture 781-- 782function ui.loadTexture(filename) 783 return pigui:LoadTexture(filename) 784end 785 786function ui.maybeSetTooltip(tooltip) 787 if not Game.player:IsMouseActive() then 788 pigui.SetTooltip(tooltip) 789 end 790end 791 792ui.setTooltip = ui.maybeSetTooltip 793