Thread: Making hover buttons (standard 317/Jagex way)

Results 1 to 7 of 7
  1. #1 Making hover buttons (standard 317/Jagex way) 


    Omar's Avatar
    Join Date
    Dec 2007
    Posts
    279
    Thanks given
    640
    Thanks received
    783
    Rep Power
    5000
    This tutorial is part of a series on 317 interfaces. For some of the other entries, see the list below:



    In this guide, we’ll cover the creation of standard, 317-compatible hover buttons.

    Essentially, the way this works is by creating three separate interfaces ("components"):

    • The unhovered interface (typically a sprite that acts a button, for example)
    • An invisible container interface that is only to be shown when moused over
      • A child interface of the aforementioned container which will be used as the hovered state of the first interface


    This does have some limitations, however; with the way the 317 client renders interfaces, nested containers do not have their children clipped to the boundaries of the parent container.

    What I mean by that is, for example, let’s imagine we create an interface with a scrolling container. Inside of which, we place hover buttons. You can see a real-world demo of this with a replica of Roat Pkz’ task interface that @mikan and I had done for a customer.

    Attached image

    In this interface, we have the main scrolling container and inside of it we have child containers used for the claim buttons. With standard hover buttons, scrolling the container downwards to a position where one of the buttons is partially hidden, and then hovering, we would see the hovered state of that button appear fully and completely rather than have some of it clipped by the scroll boundaries. This is an unfortunate limitation of the engine.

    As an example of what I mean, here is a demonstration of Jagex-style hover buttons being used inside of a scroll container:

    Attached image

    Having said that, for interfaces where you do not need hovers inside of scrolling containers, this method is ideal as it can be cache-packed straight to the standard if1 format found in the client without any modifications to the engine or interface decoders. This also means that, should you use an interface editor like Displee’s tool, you’ll be able to view the interface properly.

    The reason why this is not possible with custom hover buttons is because the essential field we need to make all of this work, the "hidden" property, is only ever decoded if the interface type is a container (type 0). For reference, here is the relevant line in my refactored interface class (special thanks to @Dane for his work on the RS2 beta client): Interface.java

    In the coming days, I'll make a separate tutorial showing you how to modify the engine to support hovers without the use of a container, which will alleviate the issues mentioned above (do note that you will need to modify your decoders if you intend on cache packing those!!).

    Anyway, preface and explanations aside, let’s get into the actual creation of these buttons. In your interface class, which may be labelled as Interface, RSInterface, Widget or perhaps even Class9, you’ll need to add a set of functions like so (NOTE: As Jagex uses XZY coordinates for 3D space, this code had been refactored similarly for consistency rather than accuracy - "Z" in these examples will typically be, and should be, "Y" in your client):


    Code:
        private static int getFreeIndex() {
            for (int i = 0; i < instances.length; i++) {
                if (instances[i] == null) {
                    return i;
                }
            }
            return -1;
        }
    
        public static Interface createSprite(final int parentIndex, final int index, final String disabled, final String enabled) {
            final Sprite spriteDisabled = Sprite.fetchSprite(disabled);
            final Sprite spriteEnabled = Sprite.fetchSprite(enabled);
            final Interface sprite = instances[index] = new Interface();
            sprite.index = index;
            sprite.parent = parentIndex;
            sprite.type = 5;
            sprite.width = spriteDisabled.myWidth;
            sprite.height = spriteDisabled.myHeight;
            sprite.spriteDisabled = spriteDisabled;
            sprite.spriteEnabled = spriteEnabled;
            return sprite;
        }
    
        public static Interface createSprite(final int parentIndex, final String disabled, final String enabled) {
            final int index = getFreeIndex();
            if (index < 0) {
                throw new IllegalStateException("Interface cache full; expand the size of the array before attempting to create a component!");
            }
            return createSprite(parentIndex, index, disabled, enabled);
        }
    
        public static void createHoverButton(final int x, final int z, final Interface parent, final Interface unhovered, final Interface hovered) {
            final int index = getFreeIndex();
            if (index < 0) {
                throw new IllegalStateException("Interface cache full; expand the size of the array before attempting to create a component!");
            }
            final Interface container = instances[index] = new Interface();
            container.id = index;
            container.parent = index;
            container.hoverParentIndex = -1;
            container.width = hovered.width;
            container.height = hovered.height;
            container.hidden = true;
            container.childX = new int[1];
            container.childZ = new int[1];
            container.children = new int[]{hovered.id};
            unhovered.hoverParentIndex = index;
    
            final int[] childX = new int[parent.childX.length + 2];
            final int[] childZ = new int[parent.childZ.length + 2];
            final int[] children = new int[parent.children.length + 2];
            System.arraycopy(parent.childX, 0, childX, 0, parent.childX.length);
            System.arraycopy(parent.childZ, 0, childZ, 0, parent.childZ.length);
            System.arraycopy(parent.children, 0, children, 0, parent.children.length);
            childX[childX.length - 2] = x;
            childZ[childZ.length - 2] = z;
            childX[childX.length - 1] = x;
            childZ[childZ.length - 1] = z;
            children[children.length - 2] = unhovered.id;
            children[children.length - 1] = index;
            parent.childX = childX;
            parent.childZ = childZ;
            parent.children = children;
        }
    
        public static void createHoverButton(final int x, final int z, final int buttonType, final Interface parent, final String unhoveredSprite, final String hoveredSprite, final String option) {
            final Interface unhoveredButton = createSprite(parent.id, unhoveredSprite, unhoveredSprite);
            unhoveredButton.buttonType = buttonType;
            unhoveredButton.option = option;
            final Interface hoveredButton = createSprite(parent.id, hoveredSprite, hoveredSprite);
            hoveredButton.buttonType = buttonType;
            hoveredButton.option = option;
            createHoverButton(x, z, parent, unhoveredButton, hoveredButton);
        }
    
        public static void createHoverButton(final int x, final int z, final int buttonType, final Interface parent, final String spriteGroup, final String option) {
            createHoverButton(x, z, buttonType, parent, spriteGroup + ",0", spriteGroup + ",1", option);
        }
    You may already have some of these functions, such as those that create sprites, etc. Feel free to use whatever your client comes with, if you'd like. The above code assumes you have absolutely zero custom functions in your interface class. The key function here is:

    Code:
    1     public static void createHoverButton(final int x, final int z, final Interface parent, final Interface unhovered, final Interface hovered) {
    2         final int index = getFreeIndex();
    3         if (index < 0) {
    4             throw new IllegalStateException("Interface cache full; expand the size of the array before attempting to create a component!");
    5         }
    6         final Interface container = instances[index] = new Interface();
    7         container.id = index;
    8         container.parent = index;
    9         container.hoverParentIndex = -1;
    10        container.width = hovered.width;
    11        container.height = hovered.height;
    12        container.hidden = true;
    13        container.childX = new int[1];
    14        container.childZ = new int[1];
    15        container.children = new int[]{hovered.id};
    16        unhovered.hoverParentIndex = index;
    17
    18        final int[] childX = new int[parent.childX.length + 2];
    19        final int[] childZ = new int[parent.childZ.length + 2];
    20        final int[] children = new int[parent.children.length + 2];
    21        System.arraycopy(parent.childX, 0, childX, 0, parent.childX.length);
    22        System.arraycopy(parent.childZ, 0, childZ, 0, parent.childZ.length);
    23        System.arraycopy(parent.children, 0, children, 0, parent.children.length);
    24        childX[childX.length - 2] = x;
    25        childZ[childZ.length - 2] = z;
    26        childX[childX.length - 1] = x;
    27        childZ[childZ.length - 1] = z;
    28        children[children.length - 2] = unhovered.id;
    29        children[children.length - 1] = index;
    30        parent.childX = childX;
    31        parent.childZ = childZ;
    32        parent.children = children;
    33    }
    Inside of that function, on line 6, we create a new container interface and add it to the interface array. Afterwards, on line 12, we set the container to be invisible. Then, on line 15, we create an integer array to store the children of the container and add the hovered sprite's index. Next, on line 16, we set the "hoverParentIndex" property, which determines what interface to show upon hovering over an interface, on the unhovered sprite to be the index of the invisible container. Finally, from 18 to 32, we expand the child interface arrays on the parent and add the container and unhovered sprite.

    For those needing the spoon, copy paste everything from the original code block and call this function:

    Code:
    createHoverButton(final int x, final int z, final int buttonType, final Interface parent, final String spriteGroup, final String option)
    籠 Pass it the X position and Z position where you'd like it to display on the screen along with a button type (typically 1), a reference the interface which you'd like to parent the buttons to, the sprite group (the function uses index 0 and 1 of the group, so you should only have two sprites - the unhovered and hovered sprites inside of the group), and the option (tooltip text that'll display when hovering).

    Like, subscribe, 5 star me on yelp, sub to my onlyfans.

    Special thanks:

    Last edited by Omar; 03-03-2021 at 10:12 AM.
    Attached image
    Reply With Quote  
     


  2. #2  
    DESIGNER

    Lynch's Avatar
    Join Date
    Feb 2016
    Age
    25
    Posts
    235
    Thanks given
    35
    Thanks received
    343
    Rep Power
    5000
    awesome guide, good job Omar.
    Reply With Quote  
     

  3. Thankful user:


  4. #3  
    Respected Member


    George's Avatar
    Join Date
    Mar 2009
    Posts
    7,099
    Thanks given
    2,226
    Thanks received
    3,146
    Rep Power
    5000
    Releasing very informative guides as of recently
    Attached image

    Spoiler for Spoilers!:
    Attached image
    Attached image
    Attached image
    Attached image
    Reply With Quote  
     

  5. Thankful user:


  6. #4  
    nice


    Join Date
    Jul 2014
    Posts
    740
    Thanks given
    382
    Thanks received
    562
    Rep Power
    4239
    good tutorial
    Attached image
    Reply With Quote  
     

  7. Thankful user:


  8. #5  
    Registered Member
    Optimum's Avatar
    Join Date
    Apr 2012
    Posts
    3,570
    Thanks given
    871
    Thanks received
    1,745
    Rep Power
    5000
    You’re no longer needed

    Quote Originally Posted by DownGrade View Post
    Don't let these no life creeps get to you, its always the same on here. They'd rather spend hours upon hours in the rune-server spam section then getting laid! ha ha!Its honestly pathetic i haven't seen so many lowlifes in my life its actually insane i wish that this section would just vanish its probably the only way to get these people out of the community...
    PLEASE BE AWARE OF IMPOSTERS MY DISCORD ID: 362240000760348683
    Reply With Quote  
     

  9. Thankful user:


  10. #6  
    Banned

    Join Date
    May 2016
    Age
    55
    Posts
    1,137
    Thanks given
    565
    Thanks received
    600
    Rep Power
    0
    Very clean interface and good tutorial!
    Reply With Quote  
     

  11. #7  
    Extreme Donator

    Benneh's Avatar
    Join Date
    Nov 2015
    Posts
    199
    Thanks given
    133
    Thanks received
    102
    Rep Power
    464
    Good work!
    Quote Originally Posted by Corey View Post
    Vouch for Benneh

    Worked with him for a month. He's professional and always on time with posts, always interested in how the server is doing and how he can can improve and help in any way.
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. [317] Making toggle buttons (checkboxes, etc)
    By Omar in forum Tutorials
    Replies: 9
    Last Post: 01-28-2021, 09:04 PM
  2. [317] Hover buttons with Lin's interface editor
    By conflickd in forum Help
    Replies: 6
    Last Post: 12-30-2018, 01:23 PM
  3. [317] New Hover Buttons
    By Hitten in forum Snippets
    Replies: 8
    Last Post: 06-17-2018, 10:15 AM
  4. Replies: 3
    Last Post: 08-24-2017, 10:45 PM
  5. Replies: 5
    Last Post: 03-23-2016, 03:29 PM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •