ID:84560
 
Here is the documentation for the overhauled library.

HDK HUD Buttons

______________________________________________________

The Buttons Within
______________________________________________________

I find it much easier to show how to use the library here rather than in the library itself. Thus, the lack of easy-to-read documentation.

The five predefined types of buttons are as follows:
Button
Head
Sub
Group
Drag
Simple
Non


______________________________________________________

Menu Buttons
______________________________________________________

Head
Head is a menu button. Press down on it to open its menu. You can also press down on it and drag your mouse over objects in its menu to highlight them. If the object is a Sub button, it will open the submenu for it. If you let up your mouse over itself or a Sub button in its menu, it will leave the menu open as it is. If you let up your mouse over a Group button in its menu, it will and do whatever the Group button has been defined to do.

Sub
Sub is a sub-menu button under head. Drag your mouse over it from its Head button or click on it to open it's sub-menu.

Group
Group is a menu item button. It may be under a Head button or a Sub button. Drag your mouse over it from its Head button or Sub button or just click on it to activate it.

______________________________________________________

Draggable Buttons
______________________________________________________

Drag
Drag is a simple button. Click on it for effect. By setting a Drag button's 'draggable' variable to 1, a Drag button becomes much more complex. This allows a simple button to be dragged around on the screen. The button's "pixeldrag" variable allows you to define whether or not you woud like to use the pixel movement system or the tile movement system when dragging it around. It also has a list of "dragalongs", which is a list of other Drag, Simple, or Non buttons that can be dragged along with it. And don't worry, you will not be able to accidentally drag a button, or part of a button, 'off screen', I've made sure of that.

Simple
Simple is a standalone button. Press it down, let it go for effect. It can be added to a Drag button's list of "dragalongs".

Non
Non is simply not a button. It is just a blank screen object that can be used for things like backgrounds or displays. It can be added to a Drag button's list of "dragalongs".

______________________________________________________

Creating The Buttons
______________________________________________________

Let's start with creating buttons. This is the general format for defining buttons.
GeneralButton
parent_type = /Button/Non
name = "General Button"
state = "gen"
columns = 1
rows = 1
xx = 1
yy = 1

The format for calling New() is a little different however. For buttons, it must be called like this.
new/GeneralButton(1,client)
The "client" in the New() is the client on whose screen the button will be created. The "1" in the call to New() tells it to skip normal procedure to check for and create multi-tiled buttons.

This means that all you have to do to create and enormously large button would be:
BigAssButton
parent_type = /Button/Non
name = "Big Ass Button"
state = "big"
columns = 15
rows = 15
xx = 1
yy = 1
This example would create a 15x15 tile button. You only have to define this first button and New() would take care of the other 224 for you. It is important to note that the "xx,yy" coordinates that you specify for a multi-tiled object will be the bottom left of the overall button.

This shows how the vars of the other five buttons should be defined.
HeadButton
parent_type = /Button/Head
menu = "Menu"

SubButton
parent_type = /Button/Sub
menu = "Menu"
submenu = "Submenu

GroupButton
parent_type = /Button/Group
menu = "Menu"
submenu = "Submenu" //only necessary if it is actually in a sub-menu
Effect()
//do some stuff here

SimpleButton
parent_type = /Button/Simple
Effect()
//do some more stuff here

DragButton
parent_type = /Button/Drag
draggable = 1 //set this to 1 to allow dragging
dragalongs = list("That Other Button") //enter the names of other buttons to have them move with this one
Effect()
//do some other stuff here


______________________________________________________

Creating The Icon States
______________________________________________________

First of all, start by defining the icon file for buttons somewhere in your code:
Button/icon = 'buttons.dmi'

In order for you to be able to see your buttons, you must set up each button's icon_state correctly. Every button has the state variable to determine its icon_state.

Each type of button requires different icon_states for their functions.
-Non only requires one icon_state.
-Head, Simple, and Drag require icon_states for up and down.
-Sub and Group require icon_states for up, over, and down.

The letters "u", "o", and "d" are appended to the icon_state for up, over, and down, respectively.
ButtonOne
parent_type = /Button/Sub
state = "one"
This button will need three icon_states; "oneu", "oneo", and "oned".

If a button is multi-tiled, it will need its part number appended to its icon_state, directly after its state.
ButtonTwo
parent_type = /Button/Group
state = "two"
columns = 2
rows = 2
This button will need twelve icon_states; "one1u", "one1o", "one1d", "one2u", "one2o", "one2d", "one3u", "one3o", "one3d", "one4u", "one4o", and "one4d".

The order in which to name the icon_states with part numbers is just like a book; left to right, next line, repeat.

______________________________________________________

The Pixel System
______________________________________________________

Currently, the pixel system I use is inherently slow due to its use of JavaScript in lieu of BYOND's lack of mouse interaction.

There are a bunch of variables to use with the pixel system, but the results are fantastic. The pixel system allows for objects of literally any size to be placed and dragged around on your screen, provided it fits on your screen. The first thing you need to know in order to use it though, is when a client logs in, you need to call:
client.ChangeView(X,Y)
This proc is necessary because it will change the view for you and grab the size of the view in pixels for usage in the pixel related procs.

If you want to use the full 32x23 pixel icons, you only need to define the buttons like you normally would. If you wish to create buttons of different sizes, you must define a few more variables. First of all, you will need to make sure that all of your icons for pixel related buttons start in the bottom right of the 32x32 gird. Next:
Button
pixeldrag = 1 //Turns on the pixel system for this and attached buttons.
lastx //This defines how many pixels wide the icons on the far right of your button are.
lasty //This defines how many pixels wide the icons on the top of your button are.
The default is 32. These are necessary for accurate bounds checking.

So:
    columns = 1
rows = 1
lastx = 16
lasty = 16
This will create a 48x48 pixel button.

For pixel based buttons, you may also define pixel offsets for the starting location on screen.
    px = 16
py = 16
This will offset your button North and East by 16 pixels each. Note that if you set these for buttons that use the tile system, they will be canceled out as soon as you move the button, otherwise, it is okay to use for other buttons too.

______________________________________________________

Button Procedures
______________________________________________________

For this next part, I will just quote the library itself.

In order to change the icon state of a button, you must call the Parts() proc.
Parts proc

Format:
Parts(D, client/C)

Args:
D: the status of the button you wish to change "u" for up, "o" for open, "d" for down
client/C: the client on whose screen the button belongs

Example:
Parts("u", usr.client)

This example will first check to see if the Button is multi-tiled and if so, search the usr's screen for all buttons with the same name, e.g., multi-tiled buttons, and change the icon state according their own state and part number, if any.
______________________________________________________

In order to change the a variable of a button, you should make a proc to do so. There are already two procs built-in that change the variables, "pressed" and "opened". At the moment, these are the only variables that need to be changed when working with buttons normally.
Parts proc && Opened proc

Formats:
Pressed(num, client/C)
Opened(num, client/C)

Args:
num: the number you wish to change the button's variable to.
client/C: the client on whose screen the button belongs

Example:
Opened(1, client/C)

This example will first check to see if the Button is multi-tiled and if so, search the usr's screen for all buttons with the same name, and change their variable, "opened" to 1.

______________________________________________________

Menus
______________________________________________________

There are two menu related client variables in this library.

client.menusopen
-This is a list of menus currently opened. This is to be maintained by you in client.OpenMenu() and client.CloseMenu().

client.menuloc
-Set this variable to 1 to prevent interaction with menus.

In order for the menu buttons to work, you must first define how their menu works under client.OpenMenu() and client.CloseMenu(). Here is slightly longer example showing how they work.
Menu
parent_type = /Button/Head
menu = "Menu"

SubMenu1
parent_type = /Button/Sub
menu = "Menu"
submenu = "SubMenu1"
SubMenu2
parent_type = /Button/Sub
menu = "Menu"
submenu = "SubMenu2"

MenuItem1
parent_type = /Button/Group
menu = "Menu"
submenu = "SubMenu1"
Effect(client/C) //The client is automatically passed to the Effect() proc from the mouse procs
//as to give easy access to the client responsible.
world << "Yes."
C.CloseMenu("[menu]") //Closes the menu this belongs to.
MenuItem2
parent_type = /Button/Group
menu = "Menu"
submenu = "SubMenu2"
Effect(client/C)
world << "No."
C.CloseMenu("[menu]")
MenuItem3
parent_type = /Button/Group
menu = "Menu"
submenu = "SubMenu3"
Effect(client/C)
world << "Maybe."
C.CloseMenu("[menu]")
MenuItem4
parent_type = /Button/Group
menu = "Menu"
submenu = "SubMenu4"
Effect(client/C)
world << "I don't know."
C.CloseMenu("[menu]")
MenuItem5
parent_type = /Button/Group
menu = "Menu"
submenu = "SubMenu5"
Effect(client/C)
world << "Can you repeat the question?"
C.CloseMenu("[menu]")

client
OpenMenu(menu)
switch(menu)
if("Menu")
CloseAll() //This is generally called for top level menus as to close all the other
//menus that are open. This only works by calling CloseMenu() for all the
//menus currently listed in client.menusopen. It is important to call this
//before "..()" so that you don't accidentally close the menu you're opening.
..() //This will add the name of the menu to the client's "menusopen" variable.
//It is important to call this for top level menus in order to properly
//keep track of what menus are open.
new/SubMenu1
new/SubMenu2
new/MenuItem1(1,src)
if("SubMenu1")
CloseMenu("Submenu2") //Closes the other sub-menu when this one is opened.
new/MenuItem2(1,src) //Creates the menu items under the sub-menu.
new/MenuItem3(1,src)
if("SubMenu2")
CloseMenu("Submenu1")
new/MenuItem4(1,src)
new/MenuItem5(1,src)
CloseMenu(menu)
..()
switch(menu)
if("Menu")
for(var/Button/Sub/B in screen) //Finds all Sub buttons..
if(B.menu == "Menu") //under this menu...
del B //and deletes them..
for(var/Button/Group/B in screen) //then does the same for Group buttons.
if(B.menu == "Menu")
del B
for(var/Button/Head/B in screen) //Finds all Menu buttons...
if(B.menu == "Menu") //for this menu...
B.Parts("u", src) //and returns their icon_state to the upright position...
B.Opened(0, src) //then sets their "opened" variable to 0.
//This is an important step. If "opened" isn't 0, it will still
//think that the button is opened and attempt to close it when
//you press it.
if("SubMenu1")
for(var/Button/Group/B in screen)
if(B.submenu == "SubMenu1")
del B
for(var/Button/Sub/B in screen)
if(B.submenu == "SubMenu1")
B.Parts("u", src)
B.Opened(0, src)
if("SubMenu2")
for(var/Button/Group/B in screen)
if(B.submenu == "SubMenu2")
del B
for(var/Button/Sub/B in screen)
if(B.submenu == "SubMenu2")
B.Parts("u", src)
B.Opened(0, src)
This is a functional menu with a menu item, two sub-menus, and two items in each sub-menu. Each of the menu items will output their own message before closing the menu.

______________________________________________________

Extras
______________________________________________________

There are five more miscellaneous features in the library:

client.buttonloc
-Set this to 1 to restrict all interactions with buttons.

client.menuloc
-Set this to 1 to restrict all interactions with the menu buttons. Other buttons that open menus will still work, though. If it is necessary, I will change that.

client.maxview
-The maximum view size in which client.ChangeView() will work.

client.minview
-The minimum view size in which client.ChangeView() will work.

client.ResetDrag()
-Calling this will reset all buttons back to their original position.

______________________________________________________

Fin
______________________________________________________