1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  4. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  5. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  6. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  7. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  8. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

UI: Frames and Tooltips

Discussion in 'JASS/AI Scripts Tutorials' started by Tasyen, Jun 27, 2019.

Tags:
  1. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,263
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16

    Introduction


    In the UI-frame natives, tooltips are frames that are on default hidden. When one hovers the frame the tooltip is assigned to, the tooltip becomes visible. Tooltips itself are also frames that can have childs and be customized.

    That is the native one uses to make a tooltip-Frame become some frames tooltip.
    BlzFrameSetTooltip takes framehandle frame, framehandle tooltip returns nothing


    SimpleFrames and Tooltips


    SimpleFrames can normally not have tooltips and they can also not be a tooltip.

    One can give a SimpleFrame a tooltip by creating a substitute FRAME which copies all points of the simpleframe. That substitute only handles the tooltip and is empty. When one hovers the SimpleFrame the substitute FRAME kicks in and shows its tooltip giving the feeling that it is the SimpleFrames tooltip. That way also SimpleFrames or BACKDROPs can have tooltips.

    Example 1


    In example 1, we create 3 Frames: a BACKDROP, a TEXT and a FRAME. The BACKDROP shows a Paladin icon. The FRAME copies the points of the BACKDROP and handles the Tooltip showing. As last the TEXT-Frame is the tooltip itself which is shown when one hovers the Paladin icon with the mouse.
    The FRAME is needed in this example because BACKDROPs can not have events nor tooltips.

    In this example all frames are created with BlzCreateFrameByType, that is done so one does not have to bother fdf for this example.
    BlzCreateFrameByType takes string typeName, string name, framehandle owner, string inherits, integer createContext

    Code (Lua):

    function Face()
      local face = BlzCreateFrameByType("BACKDROP", "Face", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)--Create a new frame of Type BACKDROP
       local faceHover = BlzCreateFrameByType("FRAME", "FaceFrame", face,"", 0) --face is a BACKDROP it can not have events nor a tooltip, thats why one creates an empty frame managing that.
       local tooltip = BlzCreateFrameByType("TEXT", "FaceFrameTooltip", face,"", 0)--Create a new frame of Type TEXT
       --faceHover would be unneeded if face would support events/tooltip

       BlzFrameSetAllPoints(faceHover, face) --faceHover copies the size and position of face.
       BlzFrameSetTooltip(faceHover, tooltip) --when faceHover is hovered with the mouse frame tooltip becomes visible.

       BlzFrameSetSize(face, 0.04, 0.04)
       BlzFrameSetAbsPoint(face, FRAMEPOINT_CENTER, 0.4, 0.3)
       BlzFrameSetAbsPoint(tooltip, FRAMEPOINT_CENTER, 0.2, 0.3)
       BlzFrameSetText(tooltip, "Human Paladin Face")

       BlzFrameSetTexture(face, "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin",0, true)--face uses paladin blp as texture.
    end
     
    That code has to be executed. It does not run by itself.
    • Start
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Custom script: Face()

    Backdrop + Tooltip Text Not hovered.jpg Backdrop + Tooltip Text.jpg

    Example 2


    The tooltip in the previous example is not really good looking, it's just some Text on the screen. I want it to be in a box and look similar to the default tooltip. Well because such a frame does not exist in the default fdf and one can not manipulate the shown text of the default tooltip frame (as far as I know), one has to create it.

    That will be our Boxed Text fdf. "BoxedText" is the frame we create. What can that "BoxedText" do? It mimics the default Tooltip-Box and has 2 children: "BoxedTextTitle" and "BoxedTextValue". The title is shown in the first line and below that title BoxedTextValue will be placed. BoxedTextValue has a smaller Text size than BoxedTextTitle.
    Code (Text):

    // -- LOCAL TEMPLATES -------------------------------------------------------
    Frame "BACKDROP" "BoxedTextBackgroundTemplate" {
            DecorateFileNames, //Look-Up Names in some String table (for example gameinterface)
            BackdropTileBackground, //Tile mode enabled
            BackdropBackground  "ToolTipBackground", //BackgroundFile
            BackdropCornerFlags "UL|UR|BL|BR|T|L|B|R",
            BackdropCornerSize  0.008, //higher numbers make the corners bigger.
            BackdropBackgroundInsets 0.0022 0.0022 0.0022 0.0022, //makes the background smaller, from the outside.
            BackdropEdgeFile  "ToolTipBorder", //the border File
            BackdropBlendAll,
    }
    // -- Frames -------------------------------------------------------
    Frame "BACKDROP" "BoxedText" INHERITS "BoxedTextBackgroundTemplate" {
       UseActiveContext,
     
       Frame "TEXT" "BoxedTextTitle" {
           UseActiveContext,
           DecorateFileNames,
           SetPoint TOPLEFT, "BoxedText", TOPLEFT, 0.005, -0.005, //Positionate "BoxedTextSimpleTitle"'s TOPLEFT to "BoxedText"'s TOPLEFT with an offset
           SetPoint TOPRIGHT, "BoxedText", TOPRIGHT, -0.005, -0.005,
           FontFlags "FIXEDSIZE",
           FrameFont "MasterFont", 0.014, "",
           FontColor 1.0 1.0 1.0 1.0, //Red Green Blue Alpha 0.0 to 1.0
           FontShadowColor 0.0 0.0 0.0 0.9,
           FontShadowOffset 0.001 -0.001,
       }
     
       Frame "TEXT" "BoxedTextValue" {
           UseActiveContext,
           DecorateFileNames,
           SetPoint TOPLEFT, "BoxedText", TOPLEFT, 0.005, -0.02,
           SetPoint BOTTOMRIGHT,  "BoxedText", BOTTOMRIGHT, -0.005, 0.005,
           FontFlags "FIXEDSIZE",
           FrameFont "MasterFont", 0.012, "",
           FontColor 1.0 1.0 1.0 1.0,
           FontShadowColor 0.0 0.0 0.0 0.9,
           FontShadowOffset 0.001 -0.001,
       }
    }
     
    Now we need to change the code a bit. Instead of TEXT, we now create a Frame of name "BoxedText". Also the tooltip is not a TEXT anymore, it's now a box, means we have to access the children of the box showing the text. They are BoxedTextValue and BoxedTextTitle.
    Code (Lua):

    function Face2()
       BlzLoadTOCFile("war3mapimported\\BoxedText.toc")
      local face = BlzCreateFrameByType("BACKDROP", "Face", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)--Create a new frame of Type BACKDROP
       local faceHover = BlzCreateFrameByType("FRAME", "FaceFrame", face,"", 0) --face is a BACKDROP it can not have events nor a tooltip, thats why one creates an empty frame managing that.
       local tooltip = BlzCreateFrame("BoxedText", face, 0, 0)--Create the BoxedText Frame
       --faceHover would be unneeded if face would support events/tooltip

       BlzFrameSetAllPoints(faceHover, face) --faceHover copies the size and position of face.
       BlzFrameSetTooltip(faceHover, tooltip) --when faceHover is hovered with the mouse frame tooltip becomes visible.

       BlzFrameSetSize(face, 0.04, 0.04)
       BlzFrameSetAbsPoint(face, FRAMEPOINT_CENTER, 0.4, 0.3)
       BlzFrameSetAbsPoint(tooltip, FRAMEPOINT_CENTER, 0.2, 0.3)
       BlzFrameSetSize(tooltip, 0.15, 0.08)

      BlzFrameSetText(BlzGetFrameByName("BoxedTextValue",0), "Human Paladin Face, but it is not uther.")--BoxedText has a child showing the text, set that childs Text.
        BlzFrameSetText(BlzGetFrameByName("BoxedTextTitle",0), "Paladin")--BoxedText has a child showing the Title-text, set that childs Text.

       BlzFrameSetTexture(face, "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin",0, true)--face uses paladin blp as texture.
    end
     
    That code does not execute itself, one has to execute it.
    • Start
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Custom script: Face2()


    Face + BoxedText.jpg
    That is nice, Text in a box, also similar to the default one.

    Instead of creating such a BoxedText one could use a TEXTAREA. TEXTAREA does most of BoxedText, but it has a scrollbar blocking a part of the right side and it requires the box to have a min size (else it crashes the game / the thread). Also it becomes a bit tricky with the title.

    ChangeLog: Added <UseActiveContext,> to the children in fdf. Without it, the tooltip text inside the box would work wrong for createcontext not be 0.
     

    Attached Files:

    Last edited by a moderator: Jul 4, 2019
  2. Coldgamer

    Coldgamer

    Joined:
    Jun 4, 2019
    Messages:
    8
    Resources:
    0
    Resources:
    0
    Thanks for your tutorial, could you mabye make a JASS example? Can't convert my map to lua :ugly:
     
  3. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,659
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    The code is almost identical to JASS. Just add a couple keywords and you're good to go.
     
  4. Coldgamer

    Coldgamer

    Joined:
    Jun 4, 2019
    Messages:
    8
    Resources:
    0
    Resources:
    0
    I've already tried it:

    Code (Text):
    function face2 takes nothing returns nothing
        call LoadToc("war3mapimported\\BoxedText.toc")
        local framehandle face = BlzCreateFrameByType("BACKDROP", "Face", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
        local framehandle faceHover = BlzCreateFrameByType("FRAME", "FaceFrame", face,"", 0)
        local framehandle tooltip = BlzCreateFrame("BoxedText", face, 0, 0)
     
        call BlzFrameSetAllPoints(faceHover, face)
        call BlzFrameSetTooltip(faceHover, tooltip)
     
        call BlzFrameSetSize(face, 0.04, 0.04)
        call BlzFrameSetAbsPoint(face, FRAMEPOINT_CENTER, 0.4, 0.3)
        call BlzFrameSetAbsPoint(tooltip, FRAMEPOINT_CENTER, 0.2, 0.3)
        call BlzFrameSetPoint(tooltip, FRAMEPOINT_BOTTOM, face, FRAMEPOINT_TOP, 0.0, 0.0)
        call BlzFrameSetSize(tooltip, 0.15, 0.08)
     
        call BlzFrameSetText(BlzGetFrameByName("BoxedTextValue", 0), "Human Paladin Face, but it is not uther.")
        call BlzFrameSetText(BlzGetFrameByName("BoxedTextTitle", 0), "Paladin")
     
        call BlzFrameSetTexture(face, "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin",0, true)
    endfunction
    But the JASS-Compiler throws an error relatively early:

    upload_2019-7-4_10-46-19.png
     
    Last edited: Jul 4, 2019
  5. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,263
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    in jass local variables have to be created as 1.actions of a function. LoadToc is no local and is done before locals are created, making the locals the 2.Actions which is not allowed.
    Do the toc loading in an seperate funtion which executes before that one runs. Or use the vanila one BlzLoadTOCFile and save that in a local boolean.
     
  6. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,427
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Very useful tutorial! Thanks for writing this up. Approved!
     
  7. xorkatoss

    xorkatoss

    Joined:
    Jul 12, 2010
    Messages:
    1,514
    Resources:
    7
    Models:
    5
    Maps:
    1
    Spells:
    1
    Resources:
    7
    @Coldgamer no fear xorkatoss is near!

    Code (vJASS):
    function CreateUther takes nothing returns nothing
        local framehandle face = BlzCreateFrameByType("BACKDROP", "Face", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
        local framehandle faceHover = BlzCreateFrameByType("FRAME", "FaceFrame", face,"", 0)
        local framehandle tooltip = BlzCreateFrame("BoxedText", face, 0, 0)
        call BlzFrameSetAllPoints(faceHover, face)
        call BlzFrameSetTooltip(faceHover, tooltip)
     
        call BlzFrameSetSize(face, 0.04, 0.04)
        call BlzFrameSetAbsPoint(face, FRAMEPOINT_CENTER, 0.4, 0.3)
    //  call BlzFrameSetAbsPoint(tooltip, FRAMEPOINT_CENTER, 0.2, 0.3)
        call BlzFrameSetPoint(tooltip, FRAMEPOINT_BOTTOM, face, FRAMEPOINT_TOP, 0.0, 0.0)
        call BlzFrameSetSize(tooltip, 0.15, 0.08)
        call BlzFrameSetText(BlzGetFrameByName("BoxedTextValue", 0), "Human Paladin Face, but it is not uther.")
        call BlzFrameSetText(BlzGetFrameByName("BoxedTextTitle", 0), "Paladin")
     
        call BlzFrameSetTexture(face, "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin",0, true)
    endfunction
    //===========================================================================
    function InitTrig_Uther takes nothing returns nothing
       set gg_trg_Uther = CreateTrigger(  )
       call TriggerRegisterTimerEventSingle( gg_trg_Uther, 1.00 )
       call TriggerAddAction( gg_trg_Uther, function CreateUther)
       call BlzLoadTOCFile("war3mapimported\\BoxedText.toc")
    endfunction
    Who would have though jass was so easy?

    I had to convert this for me because lua is so inconvenient, having all your code in the map header is a HUGE mess, I mean who even though creating lua was gonna be useful? am I right? lol

    anyway so I thought why not share it here to help some people, enjoy.
     

    Attached Files:

  8. Uncle

    Uncle

    Joined:
    Aug 10, 2018
    Messages:
    383
    Resources:
    0
    Resources:
    0
    Still a bit confused on how to make use of this one.

    I want 20 different frames of "BoxedText" for my Inventory System but how would I go about doing so? If I use BlzFrameSetText(BlzGetFrameByName("BoxedTextValue",0) how do I reference a specific frame?

    Sorry if this is unclear or a stupid question. Anyway, here's an idea of what I'm trying to make work, I cropped out the Button creation and other stuff so hopefully it will still make sense:
    Code (Lua):

    function CreateTooltip(player)
        --[tooltipframe] is a unique Integer that I change each time I run CreateTooltip(). So each frame will have it's own unique index.
        InventorySlots[player][tooltipframe] = BlzCreateFrame("BoxedText", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 1, 0)
        BlzFrameSetAbsPoint(InventorySlots[player][tooltipframe], FRAMEPOINT_CENTER, 0.4, 0.3)
        BlzFrameSetSize(InventorySlots[player][tooltipframe], 0.15, 0.12)
        BlzFrameSetVisible(InventorySlots[player][tooltipframe], false)
        MouseEnter(player)
    end
     
    Code (Lua):

    function MouseEnter(player)
        local trigger = CreateTrigger()
        BlzTriggerRegisterFrameEvent(trigger, InventorySlots[player][buttonframe], FRAMEEVENT_MOUSE_ENTER)
        TriggerAddAction(trigger, function()
            BlzFrameSetVisible(InventorySlots[player][tooltipframe], true)
            BlzFrameSetText(BlzGetFrameByName("BoxedTextValue",0), InventorySlots[player][itemdescription])
            --InventorySlots[player][itemdescription] will be a unique String associated with this specific Inventory Slot
        end)
    end
     
    With this setup, only the last created Tooltipframe will display any text. So how do I reference specific Frames using: BlzFrameSetText(BlzGetFrameByName("BoxedTextValue",0), "some string"

    I had this working before using:
    Code (Lua):

    --Instead of "BoxedText" Frame I used:
    InventorySlots[player][tooltipframe] = BlzCreateFrame("EscMenuTextAreaTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 1, 0)

    --Instead of GetFrameByName I used:
    BlzFrameSetText(InventorySlots[player][tooltipframe], InventorySlots[player][itemdescription])
     
     
    Last edited: Aug 23, 2019
  9. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,263
    Resources:
    16
    Tools:
    2
    Maps:
    2
    Spells:
    7
    Tutorials:
    4
    JASS:
    1
    Resources:
    16
    This BoxedText Frame has 2 TEXT child-Frames: "BoxedTextTitle" and "BoxedTextValue". When creating "BoxedText" the child Frames are also created and get the same createcontext number, that is the last argument in the create function. Each of the now created Frames takes a Slot in an inner storage. When using BlzGetFrameByName one reads that inner storage and gets the Frame saved with that Name at that index/createcontext. In case one wants to Access Frames with BlzGetFrameByName one has to avoid losing Frames hence unique names/createcontexts.
    But that is not nessacary when saving all later edited Frames in variables. After creating the mainframe "BoxedText", you use BlzGetFrameByName and also save the child Frames in variables then you can access them later using the variables, without having to care about createcontext or framenames.

    Code (Lua):

    --Create the mainframe "BoxedText"
    local tooltip = BlzCreateFrame("BoxedText", parent, 0, 0)
    --Get the childFrames and save them in variables
    local tooltipValue = BlzGetFrameByName("BoxedTextValue",0)
    local tooltipTitle = BlzGetFrameByName("BoxedTextTitle",0)
    --Set the text of the childFrames
    BlzFrameSetText(tooltipValue, "Super Long Text")
    BlzFrameSetText(tooltipTitle, "Title")
     
    That is cause a TEXTAREA is all in one BACKDROP, SCROLLBAR and TEXT.
    One can also set the text of a child Frame if the child is setuped as for example as ButtonText in the fdf as seen in "ScriptDialogButton".
     
    Last edited: Aug 23, 2019
  10. Uncle

    Uncle

    Joined:
    Aug 10, 2018
    Messages:
    383
    Resources:
    0
    Resources:
    0
    Excellent, I got it working. Much appreciated!