I've never written an API before so I thought I'd give it a whirl. The result is buttonBuddy - a basic button API that is reasonably flexible and relatively easy to use.

Not only can you create, draw, and parse buttons; you can group them, and edit every aspect of them live. buttonBuddy supports full color and monochrome in addition to gray scale for newer versions of ComputerCraft.

And it makes shapes! Well, two of them anyway (mostly squarish things and obvious rectangles).

SpoilerValues in square brackets '[ ]' are optional. When passing arguments to buttonBuddy, optional arguments that aren't used should be populated with nils (unless the argument(s) is/are the last argument(s) in the call; in which case the field(s) can be left out of the command entirely).

buttonBuddy is designed to be loaded with doFile()
local button = dofile("buttonBuddy.api")
Once loaded, all methods are called via button.method(arguments)

BASIC METHODS
SpoilerCreates a new button with the specified parameters. buttonBuddy does it's best to ensure buttons will fit onscreen and be drawn onscreen, however it does not compensate for buttons overlaping each other.

Returns success state (boolean) and button ID (number - or nil if creation is unsuccessful)


[local success, buttonID = ] button.create(text, [group,] x, y, width, height, [mouseButton,] active [, function] [, textColor] [, bgColor] [, inactiveTextColor] [, inactiveBgColor])
- or -
if button.create(text, [group,] x, y, width, height, [mouseButton,] active [, function] [, textColor] [, bgColor] [, inactiveTextColor] [, inactiveBgColor]) then...

text (string) = The text displayed on the button.
group (string) = The group the button is assigned to (use this for multiple screens with different buttons) - buttons assigned to no group will be drawn and parsed with all groups.
x (number) = The left-most coordinate of the button.
y (number) = The top-most coordinate of the button.
width (number) = The width of the button (this can be set to 1 to let buttonBuddy automatically determine the optimum width based on text length - so you don't have to count).
height (number) = The height of the button.
mouseButton (number) = The mouse button required to activate the buttonBuddy button (valid values: 1-3 and nil; this can be set to nil in order to accept all mouse buttons).
active (boolean) = whether the button is active and pressable or not.
function (function) = function to execute upon button press (if not specified or an invalid function is provided, the button will simply return success and its ID on each press and do nothing else).
textColor (number) = color of the button text (will be set to black if not specified).
bgColor (number) = color of the button face (will be set to white if not specified).
inactiveTextColor (number) = color of the button text when the button is inactive (will be set to light gray if not specified - or white if not on an advanced device).
inactiveBgColor (number) = color of the button body when the button is inactive (will be set to gray if not specified - or black if not on an advanced device).

SpoilerCheck to see if a button was pressed and carry out the assigned function for the pressed button. If a group is not specified then only non-grouped buttons will be parsed. Non-grouped buttons are also parsed with all groups.

The mouse button only needs to be passed if any buttonBuddy buttons have been configured to require a specific mouse button or you wish that information to be passed by buttonBuddy to the function associated with the button pressed. When executing the function associated with any button, buttonBuddy passes the button's ID and the mouse button pressed to the function for further use in parsing. If the function returns any data in addition to a success indicator (true/false) then that data will be passed back to the program for further parsing.

Returns success state (boolean), button ID (number - or nil if no button is matched), and returned data from the function executed (if it returns data)


[local success, buttonID, returnData = ] button.check(x, y [, mouseButton] [, group]) --# if the function called by the button pressed doesn't return false (to indicate failure), then buttonBuddy will assume and indicate success by returning true.  If the function returns any data in addition to a success indicator (true/false) then that data will be passed back to the user for further parsing.
- or -
if button.check(x, y [, mouseButton] [, group]) then... --# if the function called by the button pressed doesn't return false (to indicate failure), then buttonBuddy will assume and indicate success by returning true.

x (number) = The x coordinate of the user input.
y (number) = The y coordinate of the user input.
mouseButton (number) = the mouse button pressed (only required if any buttonBuddy buttons have been configured to require a specific mouse button or you wish buttonBuddy to pass that information on to the function called by the button pressed).
group (string) = The button group to be parsed. Skip this if you wish to parse *only* non-grouped buttons. Non-grouped buttons are also parsed with all groups.

SpoilerDraw buttons to the screen. If a button ID or group is not specified then only non-grouped buttons will be drawn. Non-grouped buttons are also drawn with all groups, unless 'groupOnly' is set to true. Non-grouped buttons are not drawn with single button calls.

Returns success state (boolean) and number of buttons drawn (number)


[local success, numberRendered = ] button.render([target] [, groupOnly])
- or -
if button.render([target] [, groupOnly]) then...

target (string/number) = The buttonBuddy button id (to draw a single button) or group name (to draw a group of buttons). Skip this if you wish to draw *only* non-grouped buttons. Non-grouped buttons are also drawn with all groups, unless 'groupOnly' is set to true. Non-grouped buttons are not drawn with single button calls.
groupOnly (boolean) = Only draw the specified group, do not draw un-grouped buttons.

ADVANCED METHODS
SpoilerSet the single mouse button required to activate the buttonBuddy button (if set to nil, all mouse buttons will work).

Returns success state (boolean) and assigned mouseButton (number)


[local success, mButton = ] button.setMouseButton(buttonID [, mouseBtn])
- or -
if button.setMouseButton(buttonID [, mouseBtn]) then...

buttonID (number) = The ID of the buttonBuddy button to receive a new mouse button assignment.
mouseBtn (number) = The mouse button to be required in order to activate the function assigned to the buttonBuddy button (must be 1-3 or nil).

SpoilerSet the function to be executed when the specific button is pressed.

Returns success state (boolean)


[local success = ] button.setFunction(buttonID [, function])
- or -
if button.setFunction(buttonID [, function]) then...

buttonID (number) = The ID of the button to receive a new function.
function (function) = the function to be executed when the button is pressed - if set to nil or an invalid function is provided the button will simply return true and it's ID on each press and do nothing else.

SpoilerChange a specific button's text. Text will be truncated, if necessary, to ensure button fits onscreen.

Returns success state (boolean), text as recorded - including truncation (text), button width (number) (which could change if text length is longer than button width - this is set internally automatically and is provided if you happen to track button widths externally of buttonBuddy)


[local success, newText, buttonWidth = ] button.setText(buttonID, text)
- or -
if button.setText(buttonID, text) then...

buttonID (number) = The ID of the button to assign text.
text (string) = The text displayed on the button.

SpoilerGet a specific button's text.

Returns text of button (string)


local text = button.getText(buttonID)

buttonID (number) = The ID of the button to be queried.

SpoilerChange a specific button's coordinates. Coords will be automatically adjusted, if necessary, to ensure entire button is drawn onscreen.

Returns success state (boolean), X coordinate (number, Y coordinate (number)


[local succes, xCoord, yCoord = ] button.setCoords(buttonID, x, y)
- or -
if button.setCoords(buttonID, x, y) then...

buttonID (number) = The ID of the button to be moved.
x (number) = The left-most coordinate of the button.
y (number) = The top-most coordinate of the button.

SpoilerGet a specific button's coordinates.

Returns coordinates of top/left corner of button (numbers)


local x, y = button.getCoords(buttonID)

buttonID (number) = The ID of the button to be queried.

SpoilerChange a specific button's size. Size will be automatically adjusted down, if necessary, to ensure button fits onscreen.

Returns success state (boolean), button width (number), button height (number)


[local success, bWidth, bHeight = ] button.setSize(buttonID, width, height)
- or -
if button.setSize(buttonID, width, height) then...

buttonID (number) = The ID of the button to be resized.
width (number) = The width of the button.
height (number) = The height of the button.

SpoilerGet a specific button's size.

Returns width and height of button (numbers)


local w, h = button.getSize(buttonID)

buttonID (number) = The ID of the button to be queried.

SpoilerChange a specific button's or and entire group's active/inactive text color and/or body color.

Returns success state (boolean) and the number of colors changed (number). Returns true if any color set is successful when multiple colors are set in a single call. Any value set to nil will be ignored and the present button value will be retained.


[local success, numColorsChanged = ] button.setColors(target [, textColor] [, bgColor] [, inactiveTextColor] [, inactiveBgColor])
- or -
if button.setColors(target [, textColor] [, bgColor] [, inactiveTextColor] [, inactiveBgColor]) then...

target (string/number) = The Group Name or Button ID of the group or button to assign colors.
textColor (number) = color of the button text when the button is active.
bgColor (number) = color of the button body when the button is active.
inactiveTextColor (number) = color of the button text when the button is inactive.
inactiveBgColor (number) = color of the button body when the button is inactive.

SpoilerGet a specific button's active and inactive text and body colors.

Returns the active and inactive text and body colors of button (numbers)


local txtCol, bgCol, inactiveTxtCol, inactiveBgCol = button.getColors(buttonID)

buttonID (number) = The ID of the button to be queried.

SpoilerSet a specific button or group of buttons to active (pressable) or inactive (not pressable).

Returns success state (boolean) and number of buttons activated/deactivated (number)


[local success, buttonsSwitched = ] button.setActive(target, boolean)
- or -
if button.setActive(target, boolean) then...

target (string/number) = The buttonBuddy button id (to activate/deactivate a single button) or group name (to activate/deactivate a group of buttons). Non-grouped buttons are activated/deactivated if target is set to nil. Non-grouped buttons are not activated/deactivated with single or group button calls.

SpoilerGet a specific button's active state.

Returns button's active status (boolean)


local status = button.getActiveStaus(buttonID)
- or -
if button.getActiveStatus(buttonID) then...

buttonID (number) = The ID of the button to be queried.

SpoilerReassign a specific button to a different or new group. Leave [group] blank to assign the button to no group.

Returns success state (boolean)


[local success = ] button.setGroup(buttonID, group)
- or -
if button.setGroup(buttonID, group) then...

buttonID (number) = The ID of the button to be assigned.
group (string) = The group the button is to be assigned to. Skip this if you wish to assign the button to no group.

SpoilerGet the group that a specific button is assigned to.

Returns group button is assigned to (string or nil)


local group = button.getGroup(buttonID)

buttonID (number) = The ID of the button to be queried.

SpoilerGet the total number of buttons in service.

Returns the number of buttons in the buttons table (number)


local buttonCount = button.getButtonCount()
- or -
for i = 1, button.getButtonCount() do...

SpoilerDelete a specific button or group of buttons.

Returns success state (boolean) and number of buttons deleted (number)


[local success, numberDeleted = ] button.delete(target)
- or -
if button.delete(target) then...

target (string/number) = The buttonBuddy button id (to delete a single button) or group name (to delete a group of buttons). Non-grouped buttons are deleted if target is set to nil. Non-grouped buttons are not deleted with single or group button calls.

SpoilerDelete all buttons.

Returns success state (boolean) and number of buttons deleted (number)


[local success, deleteCount = ] button.deleteAll()
- or -
if button.deleteAll() then...

DEPRECATED METHODS
SpoilerDelete a specific button.

Returns success state (boolean)


[local success = ] button.deleteButton(buttonID)
- or -
if button.deleteButton(buttonID) then...

buttonID (number) = The ID of the button to be deleted.

SpoilerDelete all buttons in a specific group. Specify no group to delete all un-grouped buttons.

Returns success state (boolean) and number of buttons deleted (number)


[local success, deleteCount = ] button.deleteGroup([group])
- or -
if button.deleteGroup([group]) then...

group (string) = The group of buttons to be deleted.

SpoilerbuttonBuddy is designed to be loaded with dofile()
local button = dofile("buttonBuddy.api")
Once loaded, all methods are called via button.method(arguments)

Please note that all these examples require an advanced computer, although buttonBuddy does not.

Single button, no groupsA single button assigned to no group, at (1, 1) with auto-assigned width and a height of 3, activated, a simple function to exit, white text with red button face and no custom inactive colors. Advanced computer required.

if not term.isColor() or pocket or turtle then error("Advanced computer required!", 0) end --# Ensure the program is running on an advanced computer
term.setBackgroundColor(colors.black) --# set the current background color to black
term.clear() --# clear the screen
local button = dofile("buttonBuddy.api") --# load buttonBuddy

button.create(" QUIT ", nil, 1, 1, 1, 3, 1, true, function() error() end, colors.white, colors.red) --# this button uses a simple function that calls error() in order to exit the program when clicked with mouse button 1
button.render() --# draw the button

while true do
  local event, data, x, y = os.pullEvent() --# wait for an event
  if event == "mouse_click" then --# if a mouse button was clicked
    button.check(x, y, data) --# check to see if a buttonBuddy button was pressed and carry out its function
  end
end

Multiple buttons, with groups, assigned functions, and mouse scrollingMultiple buttons in two groups, one ungrouped, at various x, y positions, all with auto-assigned width and heights of 1 or 3, all buttons activated, various functions, with various text colors and button face colors and no custom inactive colors. Advanced computer required.

if not term.isColor() or pocket or turtle then error("Advanced computer required!", 0) end --# Ensure the program is running on an advanced computer
term.setBackgroundColor(colors.black) --# set the current background color to black
term.clear() --# clear the screen
local button = dofile("buttonBuddy.api") --# load buttonBuddy
local activeGroup = "page1" --# the active button group
local pageNum, numPages = 1, 2 --# the current page number (1) and maximum number of pages (2)

--# Functions for buttons
local function buttonClicked(id) --# this function makes use of the button id provided by buttonBuddy to take action on a specified button
  local clicked = button.getText(id) == " Clicked! " --# determine the state of the button based on it's text
  if button.setText(id, clicked and " Click Me" or " Clicked! ") then --# Set the button's text depending on the current state of the button, and proceed based on the success state of the call
    if activeGroup == "page1" then --# if the active group is 'page1' then...
      return button.setColors(id, clicked and colors.white or colors.black, clicked and colors.orange or colors.cyan) --# Set the button's text and face colors depending on the current state of the button and return the success status returned by setColors() 
    elseif activeGroup == "page2" then --# if the active group is 'page2' then...
      return button.setColors(id, nil, clicked and colors.green or colors.purple) --# Set the button's face color only (leaving the text color as is) depending on the current state of the button and return the success status returned by setColors()
    end
  end
  return false --# return false to indicate to buttonBuddy that the function was not carried out (this is optional, but be aware that buttonBuddy will assume and signal success if it doesn't recieve a false)
end

local function oneTime(id) --# this function makes use of the button id provided by buttonBuddy to take action on a specified button
  return button.setActive(id, not button.getActiveStatus(id)) --# Toggle the button's activation status and return the success state returned by setActive()
end

local function colorChange(id) --# this function makes use of the button id provided by buttonBuddy to take action on a specified button
  return button.setColors(id, nil, 2 ^ math.random(1, 14)) --# change the button color to a random color (not including white [0] and black [15]), leaving the text color as is, and return the success state returned by setColors()
end

local function nextPage() --# this function doesn't care who called it and does no button manipulation
  pageNum = math.min(pageNum + 1, numPages) --# increment the page number (if appropriate)
  activeGroup = "page" .. tostring(pageNum) --# set the active group to the next group
  return true --# return true to indicate success (or false to indicate failure) to buttonBuddy (this is optional - buttonBuddy will assume and signal success if it doesn't recieve a false)
end

local function prevPage() --# this function doesn't care who called it and does no button manipulation
  pageNum = math.max(pageNum - 1, 1) --# decrement the page number (if appropriate)
  activeGroup = "page" .. tostring(pageNum) --# set the active group to the prior group
  return true --# return true to indicate success (or false to indicate failure) to buttonBuddy (this is optional - buttonBuddy will assume and signal success if it doesn't recieve a false)
end
--# End functions for buttons

--# Create buttons
button.create(" Click Me ", "page1", 2, 2, 1, 3, 1, true, buttonClicked, colors.white, colors.orange) --# this button assigns the buttonClicked() function to be carried out on click of mouse button 1
button.create(" C o l o r ", "page1", 25, 2, 1, 3, nil, true, colorChange, colors.white, colors.cyan) --# this button assigns the colorChange() function to be carried out on click of any mouse button
button.create(" Next Page ", "page1", 2, 6, 1, 1, 1, true, nextPage, colors.white, colors.blue) --# this button assigns the nextPage() function to be carried out on click of mouse button 1
button.create(" Click Me ", "page2", 2, 2, 1, 3, 1, true, buttonClicked, colors.white, colors.green) --# this button assigns the buttonClicked() function to be carried out on click of mouse button 1
button.create(" One  Time ", "page2", 25, 2, 1, 3, 2, true, oneTime, colors.red, colors.white) --# this button assigns the oneTime() function to be carried out on click of mouse button 2
button.create(" Prev Page ", "page2", 2, 6, 1, 1, 1, true, prevPage, colors.white, colors.blue) --# this button assigns the prevPage() function to be carried out on click of mouse button 1
button.create(" QUIT ", nil, 2, 10, 1, 3, 1, true, function() error() end, colors.white, colors.red) --# this button is assigned to no group and uses a simple function that calls error() on click of mouse button 1 in order to exit the program
button.render(activeGroup) --# this draws the buttons in the currently active group (and all ungrouped buttons)

--# Main loop
while true do
  local event, data, x, y = os.pullEvent() --# wait for an event
  if event == "mouse_click" then --# if a mouse button was clicked then...
    local success, id = button.check(x, y, data, activeGroup) --# parse all buttonBuddy buttons in the active group (and non-grouped buttons) to see if one was pressed and carry out its function; capture the success state and button ID in variables
    if success then --# if a button was pressed and successfully acted on then...
      if button.getText(id):find("Page") then --# if one of the page change buttons was pressed then...
        button.render(activeGroup, true) --# this draws the buttons in the currently active group (and skips ungrouped buttons)
      else --# otherwise if any of the other buttons was pressed...
        button.render(id) --# this redraws the button that was pressed
      end
    end
  elseif event == "mouse_scroll" then --# if the mouse wheel was scrolled then...
    if data == 1 then --# if the wheel is scrolled down then...
      nextPage() --# change pages
    else --# otherwise if the wheel is scrolled up then...
      prevPage() --# change pages the other way
    end
    button.render(activeGroup, true) --# this draws the buttons in the currently active group (and skips ungrouped buttons)
  end
end

SpoilerThis creates buttons for each side of the computer and allows the user to easily toggle redstone on each side. Advanced computer required.

if not term.isColor() or pocket or turtle then error("Advanced computer required!", 0) end --# Ensure the program is running on an advanced computer
term.setBackgroundColor(colors.black) --# set the background color to black
term.clear() --# clear the screen
local button = dofile("buttonBuddy.api") --# load buttonBuddy

--# Function called by buttons
local function changeOutput(id) --# change redstone output based on button id provided by buttonBuddy
  rs.setOutput(button.getText(id), not rs.getOutput(button.getText(id))) --# toggle the redstone output
  button.setColors(id, nil, rs.getOutput(button.getText(id)) and colors.green or colors.red) --# set the button face color to red for off, green for on - do not change text color
  return true --# return true to indicate success (or false to indicate failure) to buttonBuddy (this is optional - buttonBuddy will assume and signal success if it doesn't recieve a false)
end

--# Create buttons
local yPos = 0 --# set the initial y position
for _, side in pairs(rs.getSides()) do --# loop through the list of computer sides
  yPos = yPos + 2 --# increment the y position
  button.create(side, nil, 2, yPos, 8, 1, 1, true, changeOutput, colors.white, rs.getOutput(side) and colors.green or colors.red) --# create a button (no group) for the current side of the computer that is specified by the loop (requires mouse button 1)
end
button.create(" QUIT ", nil, 2, yPos + 4, 8, 3, 1, true, function() error() end, colors.white, colors.orange) --# create a quit button (no group) that uses a simple function to call error() in order to exit the program (requires mouse button 1)
button.render() --# render the buttons

--# Main loop
while true do --# start an infinite loop
  local event, data, x, y = os.pullEvent() --# wait for an event
  if event == "mouse_click" then --# if a mouse button is clicked then...
    local success, id = button.check(x, y, data) --# parse the buttons to see if one was pressed - if one was pressed, execute its assigned function
    if success then --# the action was successful then...
      button.render(id) --# re-draw the button that was pressed
    end
  end
end

SpoilerThis makes use of the data passed from buttonBuddy to the function called by a button, then further uses the data returned by the button's function. Advanced computer required.

if not term.isColor() or pocket or turtle then error("Advanced computer required!, 0") end --# Ensure the program is running on an advanced computer
term.setBackgroundColor(colors.black) --# set the background color to black
term.setTextColor(colors.white) --# set the text color to white
term.clear() --# clear the screen
local button = dofile("buttonBuddy.api") --# load buttonBuddy

--# Function to be called by one of the buttons
local function swapData(id, mouseBtn) --# function called by our button - it uses the buttonBuddy button ID and mouse button that are passed to the function by buttonBuddy
  local returnData = tostring(id) .. " * " .. tostring(mouseBtn) .. " = " .. tostring(id * mouseBtn) --# create new data from the passed data
  return true, returnData --# return true (to indicate success) and our new return data
end

--# Create buttons
button.create(" QUIT ", nil, 25, 2, 1, 3, nil, true, function() error() end, colors.white, colors.orange) --# no group, (25, 2) with height of 3 and auto-width, any mouse button, activated, error() called to exit, white text, orange button face
button.create(" Click Me ", nil, 2, 2, 1, 3, nil, true, swapData, colors.white, colors.purple) --# no group, (2, 2) with height of 3 and auto-width, any mouse button, activated, swapData() called on press, white text, purple button face
button.render() --# render the buttons

--# Main loop
while true do
  local event, data, x, y = os.pullEvent() --# capture events
  if event == "mouse_click" then --# if the event is a mouse click then...
    local success, buttonID, returnData = button.check(x, y, data) --# parse the buttonBuddy buttons and capture the buttonID and return data for further processing...
    if success then --# if a button was pressed then...
      term.setCursorPos(2, 10) --# set the cursor position
      term.setBackgroundColor(colors.black) --# set the background color to black
      if term.isColor() then term.setTextColor(2 ^ math.random(0, 14)) end --# set the text color to a random color (skipping black [15])
      term.write(returnData) --# write the return data to the screen
    end
  end
end

Bundled Cable Switch PanelThis makes use of both buttonBuddy and cableBuddy to create a basic bundled cable switcher. Each side is represented in a column, with each column populated with buttons for each color for the respective side. Advanced computer required.


if not term.isColor() or pocket or turtle then error("Advanced computer required!, 0") end --# Ensure the program is running on an advanced computer
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
local button = dofile("buttonBuddy.api") --# load buttonBuddy API
local cable = dofile("cableBuddy.api") --# load cableBuddy API
local validColors = { [1] = true; [2] = true; [4] = true; [8] = true; [16] = true; [32] = true; [64] = true; [128] = true; [256] = true; [512] = true; [1024] = true; [2048] = true; [4096] = true; [8192] = true; [16384] = true, [32768] = true; }
local colorNames = { [1] = "White"; [2] = "Orange"; [4] = "Magenta"; [8] = "L. Blue"; [16] = "Yellow"; [32] = "Lime"; [64] = "Pink"; [128] = "Gray"; [256] = "L. Gray"; [512] = "Cyan"; [1024] = "Purple"; [2048] = "Blue"; [4096] = "Brown"; [8192] = "Green"; [16384] = "Red", [32768] = "Black"; }
local xPos, yPos = -7, 0 --# Cursor position values

--# Function to be carried out on button press
local function buttonPress(id) --# This function takes advantage of the buttonBuddy button ID passed from buttonBuddy
  if button.getText(id) == " QUIT " then --# If the button is the quit button then...
    term.setBackgroundColor(colors.black)
    term.setCursorPos(1, 1)
    term.clear()
    error() --# Exit the program
  end
  local colorAssignment --# Declare colorAssignment variable (for holding the color value of the cable output)
  for num, name in pairs(colorNames) do --# Cycle through the color names table
    if button.getText(id) == name then colorAssignment = num break end --# set colorAssignment based on button text
  end
  if cable.findOutputColor(button.getGroup(id), colorAssignment) then --# if the selected color is on then...
    cable.remove(button.getGroup(id), colorAssignment) --# remove the appropriate color (side chosen by group)
  else --# otherwise...
    cable.add(button.getGroup(id), colorAssignment) --# add the appropriate color (side chosen by group)
  end
  button.setColors(id, nil, cable.findOutputColor(button.getGroup(id), colorAssignment) and colors.green or colors.red) --# Set the button's color (green = active, red = inactive)
end

--# Create buttons and write side labels to screen
for _, side in pairs(rs.getSides()) do --# Cycle through the computer's sides
  xPos, yPos = xPos + 8, 1 --# Set xPos & yPos values for each column
  term.setBackgroundColor(colors.black)
  term.setCursorPos(math.floor(xPos + ((7 - #side) / 2)), yPos) --# Position the cursor to center the side (column) label
  term.write(side) --# label for each side (column)
  for value in pairs(validColors) do --# Cycle through the valid colors table
    yPos = yPos + 1 --# Increment the yPos value
    button.create(colorNames[value], side, xPos, yPos, 7, 1, 1, true, buttonPress, colors.white, cable.findOutputColor(side, value) and colors.green or colors.red) --# create button for each color on each side (green = active, red = inactive)
  end
end
button.create(" QUIT ", nil, 1, 18, 1, 1, 1, true, buttonPress, colors.white, colors.orange) --# QUIT button near bottom left of screen

--# Render buttons
for _, side in pairs(rs.getSides()) do --# Cycle through the computer's sides
  button.render(side, true) --# render all our groups (sides), skipping ungrouped buttons (in this case, the quit button)
end
button.render() --# render only ungrouped buttons (in this case, the quit button)

--# Main loop
while true do --# start an infinite loop
  local event, data, x, y = os.pullEvent() --# wait for an event
  if event == "mouse_click" then
    for _, side in pairs(rs.getSides()) do --# Cycle through the computer's sides
      local success, id = button.check(x, y, data, side) --# Parse buttonBuddy buttons to see if any were clicked and catch the return results in variable
      if success then button.render(id) break end --# If a buttonBuddy button was pressed and successfully carried out its function, redraw the button
    end
  end
end

SpoilerbuttonBuddy is designed to be loaded with dofile()
local button = dofile("buttonBuddy.api")
Once loaded, all methods are called via button.method(arguments)

Pastebin: zkB39pr7
ComputerCraft: pastebin get zkB39pr7 buttonBuddy.api

As always, thank you to everyone who helped make this possible!

p.s. Woohoo! 1,000th post!