import "luxe: world" for Entity, UIClear, UILayoutMode, UIBehave, UIContain, Assets, Material, UI, UIEvent import "luxe: ui" for Control, UIList, UIWindow, UIButton, UIPanel, UIImage import "luxe: id" for ID import "luxe: draw" for PathStyle import "luxe: math" for Math import "luxe: color" for Color var Color_spaces = [ { "name": "RGB", "components": ["r", "g", "b"], "componentsFull": ["Red", "Green", "Blue"], }, { "name": "HSV", "components": ["h", "s", "v"], "componentsFull": ["Hue", "Saturation", "Value"], }, { "name": "HSL", "components": ["h", "s", "l"], "componentsFull": ["Hue", "Saturation", "Lightness"], }, { "name": "Oklab", "components": ["L", "a", "b"], "componentsFull": ["Lightness", "red/green", "blue/yellow"], } ] var Modes = [ //I wanted to do unicode icons but it doesnt render with the current font { "name": "Triangle", "icon": "tri", //▲ }, { "name": "Square", "icon": "box", //■ }, { "name": "Circle", "icon": "round", //● } ] class ColorPicker{ static create(ui: Entity) : Control{ //setup root var panel = UIWindow.create(ui) Control.set_size(panel, 350, 400) Control.set_id(panel, "panel.%(ID.unique())") Control.set_state_data(panel, [1, 0, 0, 1]) var color_view = Control.create(ui) Control.set_behave(color_view, UIBehave.fill) Control.set_margin(color_view, 0, 40, 0, 0) Control.child_add(panel, color_view) Control.set_id(panel, "color_view.%(ID.unique())") var color_wheel = Control.create(ui) Control.set_size(color_wheel, 200, 200) Control.child_add(color_view, color_wheel) Control.set_state_data(color_wheel, {"ring":null, "triangle":null, "hue": 0}) Control.set_process(color_wheel){|control, state, event, x,y,w,h| if(event.control != control) return if(event.type == UIEvent.move){ x = Control.get_pos_x_abs(control) y = Control.get_pos_y_abs(control) var center = [x + w/2, y + h/2] if(state["ring"] == "captured"){ var diff = [event.x - center.x, event.y - center.y] var angle = Math.atan2(-diff.x, diff.y) + Num.pi var hue = angle / Num.tau var color = Control.get_state_data(panel) var hsv = Color.rgb2hsv(color) hsv[0] = hue state["hue"] = hue color = Color.hsv2rgb(hsv) Control.set_state_data(panel, color) UI.events_emit(control, UIEvent.change, state) UI.events_emit(panel, UIEvent.change, color) } else { var distance = Math.dist2D(center, event) if(distance > 70 && distance < 100){ state["ring"] = "hover" } else { state["ring"] = null } } } else if(event.type == UIEvent.press && event.button == 1) { if(!state["ring"]) return state["ring"] = "captured" UI.capture(control) } else if(event.type == UIEvent.release && event.button == 1) { state["ring"] = null UI.uncapture(control) } } Control.set_allow_input(color_wheel, true) var color_ring = UIImage.create(ui) Control.set_size(color_ring, 200, 200) Control.set_contain(color_ring, UIContain.justify) var color_ring_mat = Material.create("materials/color_ring") UIImage.set_material(color_ring, color_ring_mat) Control.child_add(color_wheel, color_ring) var color_triangle = UIImage.create(ui) Control.set_margin(color_triangle, 30, 30, 0, 0) Control.set_size(color_triangle, 140, 140) Control.set_contain(color_triangle, UIContain.justify) var color_tri_mat = Material.create("materials/color_triangle") UIImage.set_material(color_triangle, color_tri_mat) Control.child_add(color_wheel, color_triangle) Control.set_events(color_wheel) {|event| if(event.type == UIEvent.change){ var hue = event.change["hue"] UIImage.set_angle(color_triangle, hue * -360) Material.set_input(color_tri_mat, "triangle.hue", hue) } } var color_wheel_overlay = Control.create(ui) Control.set_behave(color_wheel_overlay, UIBehave.fill) Control.set_margin(color_wheel_overlay, 0, 0, 0, 0) Control.set_render(color_wheel_overlay){|control, state, x, y, w, h| var depth = UI.draw_depth_of(control, 0) var center = [x + w/2, y + h/2] var style: PathStyle = PathStyle.new() var wheel_state = Control.get_state_data(color_wheel) var hover = wheel_state["ring"] var hue = wheel_state["hue"] var angle = hue * Num.tau var direction = [angle.sin, -angle.cos] style.thickness = 4 style.color = hover ? [0.5,0.5,0.5,1] : [0.22,0.22,0.22,1] var from = [center.x + direction.x * 70, center.y + direction.y * 70] var to = [center.x + direction.x * 100, center.y + direction.y * 100] UI.draw_line(control, from.x, from.y, to.x, to.y, depth, style) style.color = [0.22,0.22,0.22,1] style.thickness = 2 UI.draw_ring(control, center.x, center.y, depth, w/2, h/2, 0, 360, 8, style) UI.draw_ring(control, center.x, center.y, depth, w/2*0.7, h/2*0.7, 0, 360, 8, style) } Control.child_add(color_wheel, color_wheel_overlay) return panel /* //setup colorspace buttons //todo: this should be a dropdown??? var colorspace_list = UIList.create(ui) //could use naked control but logically its a list? Control.child_add(root, colorspace_list) //base button size is 92x32 btw var space_button_height = 30 var space_button_width = 50 for(i in 0...Color_spaces.count){ var space = Color_spaces[i] var colorspace_button = UIButton.create(ui) Control.set_size(colorspace_button, space_button_width, space_button_height) UIList.add(colorspace_list, colorspace_button) UIButton.set_text(colorspace_button, space["name"]) Control.set_pos(colorspace_button, i * space_button_width, 0) //manually set position //todo: add event to actually do stuff here } Control.set_size(colorspace_list, Control.get_width(root).min(space_button_width * Color_spaces.count), space_button_height) //UIList.refresh(colorspace_list) //uilist can only do vertical ordering so far :( //setup uimode buttons //todo: this should be a dropdown??? var mode_list = UIList.create(ui) Control.child_add(root, mode_list) Control.set_pos(mode_list, 0, space_button_height) //base button size is 92x32 btw var mode_button_height = 30 var mode_button_width = 50 for(i in 0...Modes.count){ var mode = Modes[i] var mode_button = UIButton.create(ui) Control.set_size(mode_button, mode_button_width, mode_button_height) UIList.add(mode_list, mode_button) UIButton.set_text(mode_button, mode["icon"]) Control.set_pos(mode_button, i * mode_button_width, 0) //manually set position //todo: add event to actually do stuff here } Control.set_size(mode_list, Control.get_width(root).min(mode_button_width * Modes.count), mode_button_height) //setup main editor var main_editor_root = Control.create(ui) Control.child_add(root, main_editor_root) Control.set_size(main_editor_root, 200, 200) Control.set_pos(main_editor_root, 0, mode_button_height + space_button_height) //todo: configurable default editor build_triangle_editor(ui, main_editor_root) //setup sliders var sliders_root = Control.create(ui) Control.child_add(root, sliders_root) Control.set_size(sliders_root, 300, 140) Control.set_pos(sliders_root, 0, mode_button_height + space_button_height + 200) //setup text input/output var text_io_root = Control.create(ui) Control.child_add(root, text_io_root) Control.set_size(text_io_root, 150, 100) Control.set_pos(text_io_root, 200, 160) //setup preview field (old => new) var preview_root = Control.create(ui) Control.child_add(root, preview_root) Control.set_size(preview_root, 150, 100) Control.set_pos(preview_root, 200, 60) //other stuff? gamma/linear? scene color pick? range toggle (0-1/0-255)? HDR?? //todo return root */ } static build_triangle_editor(ui: Entity, root: Control){ Control.clear(root, UIClear.destroy) } static build_square_editor(ui: Entity, root: Control){ Control.clear(root, UIClear.destroy) } static build_circle_editor(ui: Entity, root: Control){ Control.clear(root, UIClear.destroy) } }