Skip to content

Instantly share code, notes, and snippets.

@boq
Created July 27, 2015 20:17
Show Gist options
  • Select an option

  • Save boq/b5f94fa9410ec05aea31 to your computer and use it in GitHub Desktop.

Select an option

Save boq/b5f94fa9410ec05aea31 to your computer and use it in GitHub Desktop.
-- this program is crude and ugly sometimes ugly. But it's tutorial/demo and not good programming practices tutorial
local args = {...}
side = args[1]
point_num = args[2]
if not point_num or point_num < 1 then
point_num = 8
end
local p = peripheral.wrap(side)
p.clear()
-- constants
INACTIVE_MARKER_COLOR = 0x0000FF
INACTIVE_MARKER_OPACITY = 0.6
ACTIVE_MARKER_COLOR = 0xFF0000
ACTIVE_MARKER_OPACITY = 1
INITIAL_COLOR = 3
DRAW_AREA_WIDTH = 200
DRAW_AREA_HEIGHT = 200
-- we use setZ to control drawing order and more importantly, order of checking component clicks
-- drawing are is separated into few layers:
LAYER_POINT_SELECTORS = 2 -- for clickable point selectors
LAYER_DRAW_AREA = 1 -- for invisible, clickable draw area. It's is needed, since only drawables report coordinates on mouse event
-- components (like THE POLYGON) by default are on layer 0
LAYER_BACKGROUND = -2 -- semi-transparent background, for showing drawing area
-- background
local background = p.addBox(0, 0, DRAW_AREA_WIDTH, DRAW_AREA_HEIGHT, 0x000000, 0.2)
background.setAlignment("middle","middle")
background.setZ(LAYER_BACKGROUND)
-- click capture box (invisible overlay)
local draw_area = p.addBox(0, 0, DRAW_AREA_WIDTH, DRAW_AREA_HEIGHT, 0xFFFFFF, 0.0)
draw_area.setAlignment("middle","middle")
draw_area.setZ(LAYER_DRAW_AREA)
-- color selectors
COLORS = {
0xEB8844,
0xC354CD,
0x6689D3,
0xDECF2A,
0x41CD34,
0xD88198,
0x434343,
0xABABAB,
0x287697,
0x7B2FBE,
0x253192,
0x51301A,
0x3B511A,
0xB3312C,
0x1E1B1B,
0xF0F0F0,
}
-- list of buttons, for updating when point selection changes
local color_buttons = {}
for meta = 1,16 do
local button_x = (meta - 8) * 18
local button_y = 0
local button = p.addIcon(button_x, button_y, "minecraft:wool", meta)
button.setAlignment("middle","bottom")
button.setVisible(false)
button.setUserdata({index = meta, rgb = COLORS[meta]}) -- keeping freeform data so we can later identify what was clicked
color_buttons[meta] = button
end
-- color selection marker (just background box)
local color_marker = p.addBox(0,0,16,16, 0x000000, 0.5)
color_marker.setAlignment("middle","bottom")
color_marker.setZ(LAYER_BACKGROUND)
color_marker.setVisible(false)
-- move color selection marker under selected color
function mark_color(color_selector)
assert(color_selector)
color_marker.setX(color_selector.getX())
color_marker.setY(color_selector.getY())
end
-- toggle color selector visibility
function change_color_selectors_visibility(visibility)
for _,v in pairs(color_buttons) do
v.setVisible(visibility)
end
color_marker.setVisible(visibility)
end
-- just simple method for drawing equilateral triangles
function set_triangle_position(triangle, x, y)
local H = 4
local A = 2 / math.sqrt(3) * H
triangle.setP1({x + 0, y - H * 2/3})
triangle.setP2({x - A/2, y + H * 1/3})
triangle.setP3({x + A/2, y + H * 1/3})
end
-- THE POLYGON
local polygon = p.addGradientPolygon()
polygon.setScreenAnchor("middle","middle")
-- triangles for marking and selecting polygons vertices
local point_markers = {}
for i = 1,point_num do
local angle = 2 * math.pi / point_num * i
local point_x = 80 * math.cos(angle)
local point_y = 80 * math.sin(angle)
-- 'points' table works like native Lua tables - setting value at index that does not exists will expand that list (all new values except last are nulls). During rendering null values are just skipped
polygon.setPoints({point_x, point_y, COLORS[INITIAL_COLOR]}, i)
-- creating marker triangle
local point_marker = p.addTriangle({0,0},{0,0},{0,0}, INACTIVE_MARKER_COLOR, INACTIVE_MARKER_OPACITY)
set_triangle_position(point_marker, point_x, point_y)
point_marker.setZ(LAYER_POINT_SELECTORS)
point_marker.setScreenAnchor("middle","middle")
point_marker.setUserdata({index = i, color_index = INITIAL_COLOR}) -- again, some metadata for handling clicks
point_markers[i] = point_marker
end
-- store intial point configuration for later
-- getPoints() returns full list, but getPoints(index) returns just single value
local initial_points = polygon.getPoints()
local reset_label = p.addText(0,0,"RESET", 0xFF0000)
reset_label.setAlignment("right","bottom")
-- currently selected point
local active_point = 1
-- change colors of all point selectors
function select_point(point_index)
assert(point_index)
active_point = point_index
for _,marker in pairs(point_markers) do
if marker.getUserdata().index == point_index then
marker.setColor(ACTIVE_MARKER_COLOR)
marker.setOpacity(ACTIVE_MARKER_OPACITY)
else
marker.setColor(INACTIVE_MARKER_COLOR)
marker.setOpacity(INACTIVE_MARKER_OPACITY)
end
end
end
-- change color of currently selected point
function set_point_color(component)
assert(component)
local color_userdata = component.getUserdata()
local color_index = color_userdata.index
local rgb = color_userdata.rgb
assert(color_index)
assert(rgb)
-- update polygon point
-- getPoints() returns full list, but getPoints(index) returns just single value
local point = polygon.getPoints(active_point)
point.rgb = rgb
-- same here: setPoints({...}) sets full list, but setPoints(value, index) sets single value
polygon.setPoints(point, active_point)
-- now we needs to update marker triangle color
local point_marker = point_markers[active_point]
local point_userdata = point_marker.getUserdata()
point_userdata.color_index = color_index
point_marker.setUserdata(point_userdata)
end
function sign(val)
if val < 0 then return -1
elseif val > 0 then return 1
else return 0
end
end
function handle_scroll(distance)
if (distance == 0) then return end
local selected_marker = point_markers[active_point]
local userdata = selected_marker.getUserdata()
local current_color = userdata.color_index
local next_color = math.min(math.max(current_color + sign(distance), 1), 16)
local color_selector = color_buttons[next_color]
set_point_color(color_selector)
mark_color(color_selector)
end
-- move currently selected point
function move_point(x, y)
-- change point in polygon...
local point = polygon.getPoints(active_point)
point.x = x
point.y = y
polygon.setPoints(point, active_point)
-- ... and move marker
set_triangle_position(point_markers[active_point], x, y)
end
function reset_polygon()
polygon.setPoints(initial_points) -- restore initial configuration
for i,v in ipairs(point_markers) do -- restore metadata
v.setUserdata({index = i, color_index = INITIAL_COLOR})
set_triangle_position(v, initial_points[i].x, initial_points[i].y)
end
select_point(1)
mark_color(color_buttons[INITIAL_COLOR])
end
mark_color(color_buttons[INITIAL_COLOR])
select_point(1)
p.sync()
function pack(...)
return {...}
end
-- setup done, start event loop
while true do
evt = pack(os.pullEvent())
-- full list of glasses events: https://gist.github.com/boq/9a098b89ee102cbf1b2b
print(evt[1])
if evt[1] == "key" then
break -- exit loop
elseif evt[1] == "glasses_capture" then
-- player uses keyboard
local uuid = evt[4]
local control = p.getCaptureControl(uuid)
control.setBackground(0xFFFFFF, 0)
-- replace hotbar with color selector
control.toggleGuiElements({hotbar = false, crosshairs = false, health = false, armor = false, food = false, experience = false})
change_color_selectors_visibility(true)
elseif evt[1] == "glasses_release" then
change_color_selectors_visibility(false)
elseif evt[1] == "glasses_component_mouse_down" then
-- mouse click
local objectId = evt[5]
local component = p.getObjectById(objectId)
local component_type = component.getType()
local buttonId = evt[9]
if component_type == "triangle" and buttonId == 1 then -- right click triangle to select point
-- point selection
local userdata = component.getUserdata() -- {index, color_index}
select_point(userdata.index)
local color_selector = color_buttons[userdata.color_index]
mark_color(color_selector)
elseif component_type == "item" then -- click wool icon to change color of currect point
mark_color(component)
set_point_color(component)
elseif objectId == draw_area.getId() and buttonId == 0 then -- left click invisible area to move to new position
local clickX = evt[7] - DRAW_AREA_WIDTH / 2
local clickY = evt[8] - DRAW_AREA_HEIGHT / 2
move_point(clickX, clickY)
elseif objectId == reset_label.getId() then
reset_polygon()
end
elseif evt[1] == "glasses_mouse_scroll" then
handle_scroll(evt[5])
elseif evt[1] == "glasses_component_mouse_wheel" then
handle_scroll(evt[9])
end
p.sync()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment