[attachment=1303:widget_screenshot.png]
Example of my mob spawner controller. Note the sliders, buttons and labels are nicely (and automatically) arranged. I apologize that the screen shot is too small. I uploaded a larger image, and I'm not sure how to make it larger on the forum. If anyone has advice, I'd be happy to hear it.
Documentation:
[attachment=1305:widget_doc.pdf]
1 Features
• ease of use; few and simple commands to create and customize widgets
• automatic positioning of widgets means less work and better looking widgets; They also look good on different screen sizes
• myriad of widget types:
– buttons
– sliders
– toggles
– chooser (think drop-down combo box)
– labels
– progress bars
– and more
• object oriented framework makes adding new widgets easy; typically 10-15
minutes for me
• documentation and quick-start guide
2 Installation
Download widget from http://pastebin.com/PSmSpaLk . Place file in either rom/apis or your directly to your ComputerCraft computer.
Alternatively if you're running Minecraft v1.6 you can download and install the resource pack
[attachment=1306:widget.zip]
At least I think so. I'm running 1.5 myself so I haven't been able to test resource packs.
Load with the command
os.loadAPI("widget")
3 Quick Start
Spoiler
The first step to creating a GUI is to load the widget library with the code
os.loadAPI("widget")
The second is to create the widgets which will compose your interface. The simplest widget is the button. To create a button, use something like this code:
exampleButton=widget.newButton("press me")
This will create a button labeled “press me”. There are a number of different widgets (see section 5) such as sliders, progress bars, and choosers (which function like drop-down comboboxes). Lets add a new slider as well.
exampleSlider=widget.newSlider(1,10)
And a button to quit is always a good idea (you can use control-t, but its awkward).
quitButton=widget.newButton("quit")
Then we need to tell the system how to arrange our various widgets. We do this by placing them in rows or columns with code like
exampleColumn=widget.newColumn()
exampleColumn:add(exampleButton)
exampleColumn:add(exampleSlider)
exampleColumn:add(quitButton)
This adds the widget to our column. Note that the operator ‘:’ is used between the name of the variable and the function name. The function add is a member function of the variable exampleColumn. Basically its a function inside of the variable. To access it, use the semicolon (‘:’) after the variable name. This library uses a lot of member functions, so watch out for them.The column will now give its space to the widgets you’ve added. In this case it will split the space evenly (or as evenly as possible) between the two buttons and the slider. Its important to note that rows and columns are widgets too. That means you can have rows of columns or columns of rows. My mob spawner controller has a column of rows with columns in it.
Next, we should tell the computer what to do when the button is pressed. For example, if we wanted to print the value of the slider, then we would use the code
function exampleButton.onClick(button)
exampleButton:blink()
print("The slider has a value of " .. tostring(exampleSlider.value))
end
function quitButton.onClick(button)
exampleColumn.run=false
end
Now we just need to tell the computer we’re ready to run the GUI.
exampleColumn:run()
This will display the GUI and process mouse clicks in-game. Note that you can adjust the slider by right-clicking on it.4 Configuring the API
Spoiler
For the most part no configuration is necessary.4.1 Changing the color scheme
If you want to change the color scheme, set the following variables:
- widget.defaultButtonBackground
- widget.defaultButtonForeground
- widget.terminalBackground
- widget.defaultSliderForeground
- widget.defaultSliderBackground
- widget.defaultFlagMonitorForeground
- widget.defaultProgressBarForeground
Normally the attached advanced monitor is automatically detected. However, there are two situations in which you would want to set the monitor manually. The first is if there are more than one advanced monitors adjacent to your computer and it is autodetecting the wrong one. In that case, use something like
widget.setMonitor(peripheral.wrap("bottom"))
The other possibility is that you want your GUI to appear not on an advanced monitor, but on the advanced computer itself. Again this is usually handled automatically, but if there is an advanced monitor attached it will try to display there unless you set the monitor to the terminal manually with the command
widget.setMonitor(term)
5 widget API for GUI designers
Spoiler
5.1 widgetConstructor:
example=widget.newWidget()
This sets up an empty widget called example with does nothing.Functions and Fields:
example:run()
runs the GUI with this widget as the screen; stops when widget.quit is trueexample:onClick()
defines what the widget does when clicked; by default does nothingexample:draw()
draws the widget; This is useful if the widget needs to be redrawn. by default does nothingexample:processEvent(event,side,x,y)
processes an event, ignoring events other than monitor touch and mouse clickexample.vWeight
specifies the height of the widget compared to a standard widget; For example, if vWeight was 0.5, this widget would ask for half as much room as a vWeight=1 widget.example.hWeight
specifies the width of the widget compared to a standard widget One might ask why this even exists, since it is a blank widget which does nothing. The answer is that all other interface elements (buttons, progress bars, et c.) are also widgets, and get to run these functions as well. In programmer terminology all widget classes (such as button) derive from this class. So while you’ll probably never use the newWidget function, every widget you create will have access to the run and onClick functions. And you can overwrite the onClick function of any widget to make it do whatever you want when you click it.5.2 row
Constructor:
example=widget.newRow()
Functions and Fields:example:add(widget)
adds a widget to the rowexample.hSpacingWeight
specifies how large the horizontal spacing should be relative to a standard widget; only affects rows5.3 column
Constructor:
example=widget.newColumn()
Functions and Fields:example:add(widget)
adds a widget to the columnexample.vSpacingWeight
specifies how large the vertical spacing should be relative to a standard widget; only affects columns5.4 button
Constructor:
example=widget.newButton(”label”)
where “label” should be the label of the button.Functions and Fields:
example:drawFull()
draws the button as a solid, labeled blockexample:drawOutline()
draws the button a hollow, labeled blockexample:blink()
draws the button as an outline, then solid again a moment later; This can give feedback to the user that the button was really clicked.example.label
the label of the button5.5 toggle button
Constructor:
example=newToggleButton(”label”)
A toggle button is derived from button, and so can use all of a button’s functions and field. In addition it will either draw as a solid or outline depending on its state.Functions and Fields:
example:toggle()
switched the button between the on and off statesexample.state
true iff the button is on5.6 label
Constructor:
example=widget.newLabel(”text”)
This creates a label called example which displays the word “text”. Functions and Fields:example.text
what text the label is displaying5.7 slider
Constructor:
example=widget.newSlider(1,10)
creates a slider called example which goes between 1 and 10 inclusiveFunctions and Fields:
example.value
the value of the sliderexample.foregroundColor
the color of the filled slider portionexample.backgroundColor
the color of the unfilled slider portion5.8 flag monitor
Constructor:
example=widget.newFlagMonitor(”top”)
creates a flag monitor called example which monitors and sets the redstone bundled signal out the top of the computer:Functions and Fields:
example:get(i)
returns the i’th color of the outputexample:set(i,value)
sets the i’th color of the output to value; if value is absent or nil, it is treated as trueexample:clear(i)
sets the i’th color of the output to offexample:toggle(i)
sets the i’th color of the output to whatever it was not before; If it was on previously, it will be off. If it was off previously, it will be on.example.flags
a 16-bit integer representing the state of the bundled output5.9 chooser
Constructor:
example=widget.newChooser(”axe”,”pick”,”axe”,”fish”)
will create a chooser called example which allows the user to pick between “pick”, “axe” and “fish”. It will initially be set to “axe”. Note that chooser derives from button, so it has all the functionality of a button as well.Functions and Fields:
example:choose
brings up a page to allow the user to choose one of the possible choicesexample.label
the current choice5.10 progress bar
Constructor:
example=newProgressBar(15)
will create a progress bar called example which will be full when it reaches a value of 15.Functions and Fields:
example.value
the current value of the progress barexample.foreground
the color of the filled portionexample.background
the color of the unfilled portion6 Possible future features
• a variable widget which can change between different widget types
• a tab widget which switches between multiple interface pages
• multimonitor support
• documentation for adding new widgets
7 example application: keypad
Spoiler
redstone.setOutput("right",false) -- lock the door
os.loadAPI("widget")
-- a button to operate a lock via a keypad advanced monitor
-- which means no control-t or control-r override
-- create the widgets
button1=widget.newButton("1")
button2=widget.newButton("2")
button3=widget.newButton("3")
button4=widget.newButton("4")
button5=widget.newButton("5")
button6=widget.newButton("6")
button7=widget.newButton("7")
button8=widget.newButton("8")
button9=widget.newButton("9")
button0=widget.newButton("0")
backspaceButton=widget.newButton("<-")
clearButton=widget.newButton("reset")
-- arrange the widgets
row1=widget.newRow()
row1:add(button7)
row1:add(button8)
row1:add(button9)
row2=widget.newRow()
row2:add(button4)
row2:add(button5)
row2:add(button6)
row3=widget.newRow()
row3:add(button1)
row3:add(button2)
row3:add(button3)
row4=widget.newRow()
row4:add(backspaceButton)
row4:add(button0)
row4:add(clearButton)
main=widget.newColumn()
main:add(row1)
main:add(row2)
main:add(row3)
main:add(row4)
-- program variables
passcode="1337"
entry=""
-- configure the widgets
function clearButton.onClick(button)
entry=""
end
function backspaceButton.onClick(button)
if (entry:len()>0) then
entry=entry:sub(1,entry:len()-1)
end
end
function button0.onClick(button)
entry=entry .. button.label
if (entry==passcode) then
print("access granted " .. os.time())
redstone.setOutput("right",true) -- open the door
os.sleep(4) -- let someone through
redstone.setOutput("right",false) -- automatically lock the door a
entry=""
end
end
-- all the buttons should do the same thing
-- append their label to entry
-- and check if the code is entered
-- so we can just copy the onClick function
-- instead of rewriting it
button1.onClick=button0.onClick
button2.onClick=button0.onClick
button3.onClick=button0.onClick
button4.onClick=button0.onClick
button5.onClick=button0.onClick
button6.onClick=button0.onClick
button7.onClick=button0.onClick
button8.onClick=button0.onClick
button9.onClick=button0.onClick
-- display the GUI
main:run()
8 Licensing