Skip to content

Instantly share code, notes, and snippets.

@antonhornquist
Created October 2, 2019 20:25
Show Gist options
  • Save antonhornquist/071cd9a62ae3eb4145c7f1d9a8bc0d95 to your computer and use it in GitHub Desktop.
Save antonhornquist/071cd9a62ae3eb4145c7f1d9a8bc0d95 to your computer and use it in GitHub Desktop.
(
var imgui_prev;
var imgui = ();
var ui_begin = {
ui_clear.value; // TODO: perhaps possible to fix via property?
imgui.inside_item = nil;
Pen.font = imgui.font;
Pen.fillColor = Color.black;
Pen.strokeColor = Color.black;
if (imgui_prev.notNil) {
if (imgui.mouse_is_down and: imgui_prev.mouse_is_down.not) {
imgui.mouse_was_pressed = true;
} {
imgui.mouse_was_pressed = false;
};
if (imgui.mouse_is_down.not and: imgui_prev.mouse_is_down) {
imgui.mouse_was_released = true;
} {
imgui.mouse_was_released = false;
};
};
};
var ui_end = {
imgui.mousedeltax = 0;
imgui.mousedeltay = 0;
imgui.keys_pressed = [];
imgui.keys_released = [];
imgui_prev = imgui.copy;
};
var ui_clear = {
Pen.fillColor = Color.white; // Color.new(0xff/0xff, 0xa5/0xff, 0);
Pen.addRect(Rect(0, 0, v.bounds.width, v.bounds.height));
Pen.fill;
};
var ui_clip_rect = { |x, y, width, height|
var left = x;
var top = y;
var right = x+width;
var bottom = y+height;
Pen.moveTo(left@top);
Pen.lineTo(right@top);
Pen.lineTo(right@bottom);
Pen.lineTo(left@bottom);
Pen.lineTo(left@top);
Pen.clip;
imgui.active_clip_area = (left: left, top: top, right: right, bottom: bottom);
};
var do_text = { |string, x, y, width, height|
var id = ['text', string, x, y];
var result = false;
width = width ? (imgui.button_xpad * 2) + get_text_width.value(string);
height = height ? imgui.button_ypad * 2 + imgui.fontsize + 5;
draw_text_widget.value(id, string, x, y, width, height);
};
var do_button = { |string, x, y, width, height|
var id = ['button', string, x, y];
var result = false;
var is_inside, is_active, is_hot;
width = width ? (imgui.button_xpad * 2) + get_text_width.value(string);
height = height ? imgui.button_ypad * 2 + imgui.fontsize + 5;
is_inside = is_inside_clipped_rect.value(x, y, x+width, y+height, imgui.mousex, imgui.mousey);
is_active = imgui.active_item == id;
is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
if (is_hot) {
postln("pressed " ++ id ++ ": " ++ string);
result = true;
};
imgui.active_item = nil;
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
};
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_button.value(id, string, x, y, width, height);
result;
};
var do_checkbox = { |id, string, container, x, y, width, height|
var is_inside, is_active, is_hot;
width = width ? imgui.button_xpad + imgui.checkbox_size + imgui.button_xpad + get_text_width.value(string) + imgui.button_xpad;
height = height ? imgui.button_ypad * 2 + imgui.fontsize + 5;
is_inside = is_inside_clipped_rect.value(x, y, x+width, y+height, imgui.mousex, imgui.mousey);
is_active = imgui.active_item == id;
is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
if (is_hot) {
postln("pressed " ++ id ++ ": " ++ string);
container.ref = container.ref.not;
};
imgui.active_item = nil;
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
};
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_checkbox.value(id, string, container, x, y, width, height);
};
var do_modules = { |modules|
modules.do { |module, i|
do_module.value(module);
};
};
var do_module = { |module|
var id = ['module', module];
var result = false;
var pos = module.pos;
var string = module.name;
var x = pos.x;
var y = pos.y;
var width = get_module_width.value(module);
var height = get_module_height.value(module);
var is_inside = is_inside_clipped_rect.value(x+1, y+1, x+width-2, y+height-2, imgui.mousex, imgui.mousey);
var is_active = imgui.active_item == id;
var is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
if (is_hot) {
postln("pressed " ++ id ++ ": " ++ string);
result = true;
};
imgui.active_item = nil;
} {
if ((imgui.mousedeltax != 0) or: (imgui.mousedeltay != 0)) {
pos.x = pos.x+imgui.mousedeltax;
pos.y = pos.y+imgui.mousedeltay;
};
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
};
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_module.value(id, module, x, y);
result;
};
var do_module_in_and_outlets = { |modules|
modules.do { |module|
module.inlets.do { |index|
do_inlet.value(module, index);
};
module.outlets.do { |index|
do_outlet.value(module, index);
};
};
};
var do_inlet = { |module, index|
var id = ['inlet', module, index];
var pos = get_module_inlet_pos.value(module, index);
var bounds = Rect(pos.x - (imgui.inoutlet_width/2), pos.y, imgui.inoutlet_width, 3);
var detect_within_bounds = bounds.insetBy(-5);
var is_inside = is_inside_clipped_rect2.value(detect_within_bounds, imgui.mousex, imgui.mousey);
var is_active = imgui.active_item == id;
var is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
if (is_hot) {
postln("pressed" + id);
// result = true;
};
imgui.active_item = nil;
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
} {
if (is_inside) {
if (imgui.mouse_was_released) {
if (imgui.possible_connection.notNil) {
var from = imgui.possible_connection.key;
var to = imgui.possible_connection.value;
if (outlet_is_connected_to_inlet.value(from, to).not) {
var outlet_module = from[1];
var outlet_index = from[2];
var inlet_module = to[1];
var inlet_index = to[2];
outlet_module['connections'] = outlet_module['connections'].add([outlet_index, [inlet_module.name, inlet_index]]);
};
}
}
}
}
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_inlet.value(id, bounds);
};
var do_outlet = { |module, index|
var id = ['outlet', module, index];
var pos = get_module_outlet_pos.value(module, index);
var bounds = Rect(pos.x - (imgui.inoutlet_width/2), pos.y-3, imgui.inoutlet_width, 3);
var detect_within_bounds = bounds.insetBy(-5);
var is_inside = is_inside_clipped_rect2.value(detect_within_bounds, imgui.mousex, imgui.mousey);
var is_active = imgui.active_item == id;
var is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
if (is_hot) {
postln("pressed" + id);
// result = true;
};
imgui.active_item = nil;
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
} {
if (is_inside) {
if (imgui.mouse_was_released) {
if (imgui.possible_connection.notNil) {
var from = imgui.possible_connection.key;
var to = imgui.possible_connection.value;
if (outlet_is_connected_to_inlet.value(from, to).not) {
var outlet_module = from[1];
var outlet_index = from[2];
var inlet_module = to[1];
var inlet_index = to[2];
outlet_module['connections'] = outlet_module['connections'].add([outlet_index, [inlet_module.name, inlet_index]]);
};
}
}
}
}
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_outlet.value(id, bounds);
};
var do_connections = { |modules|
var connections = modules.collect { |module, i|
module.connections.collect { |arr|
var dest = arr[1];
[[module, arr[0]], [modules.detect { |module| module.name == dest[0] }, dest[1]]]
};
}.flatten.reject { |conn| conn.isNil };
connections.do { |conn|
do_connection.value(conn[0][0], conn[0][1], conn[1][0], conn[1][1]);
};
};
var do_connection = { |src_module, src_index, dest_module, dest_index|
var id = ['connection', src_module, src_index, dest_module, dest_index];
var from = get_module_outlet_pos.value(src_module, src_index);
var to = get_module_inlet_pos.value(dest_module, dest_index);
var is_inside = is_inside_connection.value(from, to, imgui.mousex, imgui.mousey);
var is_active = imgui.active_item == id;
var is_hot = imgui.hot_item == id;
if (is_active) {
if (imgui.mouse_was_released) {
imgui.selection = id;
/*
if (is_hot) {
postln("pressed " ++ id ++ ": " ++ string);
result = true;
};
*/
imgui.active_item = nil;
}
} {
if (is_hot) {
if (imgui.mouse_was_pressed) {
imgui.active_item = id;
};
};
};
if (is_inside and: imgui.inside_item.isNil) {
imgui.inside_item = id;
if (imgui.active_item.isNil) {
imgui.hot_item = id;
}
} {
if (is_hot) {
imgui.hot_item = nil;
};
};
draw_connection.value(id, from, to);
};
var do_tips = { |modules|
var positions = all_in_and_outlet_positions.value(modules);
var pos_to_inlet;
if ((pos_to_inlet = positions.detect { |position| ((imgui.mousex@imgui.mousey) dist: position.key) < 10 }).notNil) {
var pos = pos_to_inlet.key;
var module_inlet = pos_to_inlet.value;
var type = module_inlet[0];
var module = module_inlet[1];
var inlet = module_inlet[2];
if (type == 'inlet') {
do_text.value(1234124, "Inlet " ++ inlet, pos.x-(imgui.inoutlet_width/2), pos.y-imgui.fontsize-10);
} {
do_text.value(1234124, "Outlet " ++ inlet, pos.x-(imgui.inoutlet_width/2), pos.y+(imgui.fontsize/2));
};
};
};
var draw_text_widget = { |id, string, x, y, width, height|
draw_text.value(string, x, y);
};
var draw_button = { |id, string, x, y, width, height|
if (imgui.active_item == id) {
Pen.width = 3;
} {
Pen.width = 2;
};
draw_text.value(string, x+imgui.button_xpad, y+imgui.button_ypad);
draw_rect.value(x, y, width, height);
};
var draw_module = { |id, module, x, y|
if (imgui.active_item == id) {
Pen.width = 3;
} {
if (imgui.hot_item == id) {
Pen.width = 1;
} {
Pen.width = 2;
}
};
//fill_rect.value(x, y, get_module_width.value(module), get_module_height.value(module), Color.yellow);
draw_rect.value(x, y, get_module_width.value(module), get_module_height.value(module));
Pen.fillColor = Color.black;
draw_text.value(module.name, x+imgui.button_xpad, y+imgui.button_ypad);
};
var draw_checkbox = { |id, string, container, x, y, width, height|
if (imgui.active_item == id) {
Pen.width = 3;
} {
Pen.width = 2;
};
if (container.ref) {
fill_rect.value(x+imgui.button_xpad, y+imgui.button_ypad, imgui.checkbox_size, imgui.checkbox_size);
} {
draw_rect.value(x+imgui.button_xpad, y+imgui.button_ypad, imgui.checkbox_size, imgui.checkbox_size);
};
draw_text.value(string, x+imgui.button_xpad+imgui.checkbox_size+imgui.button_xpad, y+imgui.button_ypad);
draw_rect.value(x, y, width, height);
};
var draw_text = { |string, x, y|
Pen.stringAtPoint(string, x@y);
};
var draw_rect = { |x, y, width, height|
Pen.strokeColor = Color.black;
Pen.strokeRect(Rect(x, y, width, height));
};
var draw_inlet = { |id, bounds|
var is_inside = imgui.inside_item == id;
var focused = case
{ imgui.active_item.notNil and: is_inside } {
if (imgui.active_item.first == 'outlet') {
outlet_is_connected_to_inlet.value(imgui.active_item, id).not
}
}
{ is_inside } { true } ? false;
draw_in_and_outlet.value(id, bounds, focused);
};
var draw_outlet = { |id, bounds|
var is_inside = imgui.inside_item == id;
var focused = case
{ imgui.active_item.notNil and: is_inside } {
if (imgui.active_item.first == 'inlet') {
outlet_is_connected_to_inlet.value(id, imgui.active_item).not
}
}
{ is_inside } { true } ? false;
draw_in_and_outlet.value(id, bounds, focused);
};
var draw_in_and_outlet = { |id, bounds, focused|
var is_inside = imgui.inside_item == id;
fill_rect.value(bounds.left, bounds.top, bounds.width, bounds.height, Color.black);
if (focused) {
fill_oval.value(bounds.insetBy(-5));
};
};
var draw_connection = { |id, from, to|
var is_selected = imgui.selection == id;
Pen.strokeColor = case
{ is_selected } {Color.grey}
{ true } {Color.black};
Pen.width = case
{ is_selected } {6}
{ imgui.active_item == id } {6}
{ imgui.hot_item == id } {4}
{ true } {2};
Pen.moveTo(from);
Pen.lineTo(to);
Pen.stroke;
};
var outlet_is_connected_to_inlet = { |outlet, inlet|
var outlet_module = outlet[1];
var outlet_index = outlet[2];
var inlet_module = inlet[1];
var inlet_index = inlet[2];
var conn = [outlet_index, [inlet_module.name, inlet_index]];
// conn.debug(\conn);
outlet_module['connections'].any { |actual_conn|
actual_conn/* .debug(\actual) */ == conn
};
};
var is_inside_clipped_rect2 = { |bounds, x, y|
is_inside_clipped_rect.value(bounds.left, bounds.top, bounds.right, bounds.bottom, x, y);
};
var is_inside_clipped_rect = { |left, top, right, bottom, x, y|
var clip = imgui.active_clip_area;
if (clip.notNil) {
(clip.left <= x) and: (x <= clip.right) and: (clip.top <= y) and: (y <= clip.bottom) and: (left <= x) and: (x <= right) and: (top <= y) and: (y <= bottom)
} {
(left <= x) and: (x <= right) and: (top <= y) and: (y <= bottom)
};
};
var get_module_inlet_pos = { |module, index|
var span = get_module_width.value(module) - imgui.inoutlet_width;
var div = span / ((module.inlets-1) max: 1);
( module.pos.x+(imgui.inoutlet_width/2)+(div*index) ) @ (module.pos.y);
};
var get_module_outlet_pos = { |module, index|
var span = get_module_width.value(module) - imgui.inoutlet_width;
var div = span / ((module.outlets-1) max: 1);
( module.pos.x+(imgui.inoutlet_width/2)+(div*index) ) @ (module.pos.y + get_module_height.value(module));
};
var get_module_width = { |module|
(imgui.button_xpad * 2) + get_text_width.value(module.name);
};
var get_module_height = { |module|
(imgui.button_ypad * 2) + imgui.fontsize + 4;
};
var fill_oval = { |bounds|
Pen.strokeColor = Color.grey;
Pen.strokeOval(bounds);
};
var fill_rect = { |x, y, width, height, colour|
Pen.fillColor = colour ? Color.red;
Pen.fillRect(Rect(x, y, width, height));
};
var get_text_width = { |text|
text.bounds(imgui.font).width+3;
};
var all_in_and_outlet_positions = { |modules|
modules.collect { |module, i|
module.inlets.collect { |inlet|
get_module_inlet_pos.value(module, inlet) -> ['inlet', module, inlet]
} ++
module.outlets.collect { |inlet|
get_module_outlet_pos.value(module, inlet) -> ['outlet', module, inlet]
};
}.flatten;
};
// TODO: does not respect clip
var is_inside_connection = { |from, to, mousex, mousey, sensitivity = 5|
var mouse_pos = mousex@mousey;
var diff = to-from;
var delta = diff/from.dist(to);
var points = from.dist(to).round.asInteger;
points.collect { |index, i|
(from+(delta*index)) dist: mouse_pos
}.minItem < sensitivity;
};
var dump = { |id|
switch (id.first)
{ 'inlet' } {
"Inlet:" ++ id[1].name ++ "/" ++ id[2] + get_module_inlet_pos.value(id[1], id[2])
}
{ 'outlet' } {
"Outlet:" ++ id[1].name ++ "/" ++ id[2] + get_module_outlet_pos.value(id[1], id[2])
} ? id
};
imgui.window_width = 640;
imgui.window_height = 480;
imgui.hot_item = nil;
imgui.active_item = nil;
imgui.inoutlet_width = 18;
imgui.button_xpad = 10;
imgui.button_ypad = 5;
imgui.fontsize = 18;
imgui.checkbox_size = imgui.fontsize;
imgui.font = Font("Consolas", imgui.fontsize);
//imgui.font = Font("Akkurat-Mono", imgui.fontsize);
imgui.mousex = 0;
imgui.mousey = 0;
imgui.mouse_is_down = false;
imgui.mouse_was_pressed = false;
imgui.mouse_was_released = false;
imgui.mousedeltax = 0;
imgui.mousedeltay = 0;
imgui.keys_pressed = [];
imgui.keys_released = [];
imgui.selection = nil;
{
var x = 300;
var y = 50;
var col_width = 0;
var row_height = 45;
~modules = [
(
name: "FreqGate",
pos: Point(x+(col_width*0), y+(row_height*0)),
inlets: 0,
outlets: 1,
connections: [
//[0, ["Osc", 0]],
//[0, ["Envelope", 0]],
]
),
(
name: "Osc",
pos: Point(x+(col_width*0), y+(row_height*1)),
inlets: 1,
outlets: 1,
connections: [
//[0, ["Filter", 0]],
]
),
(
name: "Filter",
pos: Point(x+(col_width*1), y+(row_height*2)),
inlets: 3,
outlets: 1,
connections: [
//[0, ["Amp", 0]],
]
),
(
name: "Envelope",
pos: Point(x+110+(col_width*2), y+(row_height*1)),
inlets: 1,
outlets: 1,
connections: [
//[0, ["Amp", 1]],
//[0, ["Filter", 1]],
]
),
(
name: "Amp",
pos: Point(x+(col_width*2), y+(row_height*3)),
inlets: 2,
outlets: 1,
connections: [
//[0, ["Pan", 0]],
]
),
(
name: "Pan",
pos: Point(x+(col_width*3), y+(row_height*4)),
inlets: 1,
outlets: 2,
connections: [
//[0, ["Out", 0]],
//[1, ["Out", 1]],
]
),
(
name: "Out",
pos: Point(x+(col_width*3), y+(row_height*5)),
inlets: 2,
outlets: 0,
)
];
}.value;
w = Window.new("", Rect(100, 100, imgui.window_width, imgui.window_height)).front;
v = UserView(w, Rect(0, 0, imgui.window_width, imgui.window_height));
v.resize = 5;
v.drawFunc = {
ui_begin.value;
do_module_in_and_outlets.value(~modules);
do_connections.value(~modules);
do_modules.value(~modules);
if (imgui.active_item.notNil) {
var type = imgui.active_item.first;
Pen.width = 2;
switch (type)
{ 'outlet' } {
var module = imgui.active_item[1];
var index = imgui.active_item[2];
var pos = get_module_outlet_pos.value(module, index);
Pen.moveTo(pos);
if (imgui.inside_item.notNil) {
if (imgui.inside_item.first == 'inlet') {
if (outlet_is_connected_to_inlet.value(imgui.active_item, imgui.inside_item).not) {
Pen.lineTo(get_module_inlet_pos.value(imgui.inside_item[1], imgui.inside_item[2]));
imgui.possible_connection = imgui.active_item -> imgui.inside_item;
}
};
} ?? {
Pen.lineTo(imgui.mousex@imgui.mousey);
imgui.possible_connection = nil;
};
}
{ 'inlet' } {
var module = imgui.active_item[1];
var index = imgui.active_item[2];
var pos = get_module_inlet_pos.value(module, index);
Pen.moveTo(pos);
if (imgui.inside_item.notNil) {
if (imgui.inside_item.first == 'outlet') {
if (outlet_is_connected_to_inlet.value(imgui.inside_item, imgui.active_item).not) {
Pen.lineTo(get_module_outlet_pos.value(imgui.inside_item[1], imgui.inside_item[2]));
imgui.possible_connection = imgui.inside_item -> imgui.active_item;
};
};
} ?? {
Pen.lineTo(imgui.mousex@imgui.mousey);
imgui.possible_connection = nil;
};
};
Pen.stroke;
};
if (imgui.active_item.isNil and: imgui.mouse_was_pressed) {
imgui.selection = nil;
};
//do_tips.value(~modules);
do_text.value("Mouse: "++(imgui.mousex@imgui.mousey), 10, 340);
do_text.value("Inside Item: "++(dump.value(imgui.inside_item) ? "None"), 10, 360);
do_text.value("Hot Item: "++(dump.value(imgui.hot_item) ? "None"), 10, 380);
do_text.value("Active Item: "++(dump.value(imgui.active_item) ? "None"), 10, 400);
if (imgui.selection.notNil) {
if (imgui.keys_pressed.includes($s)) {
imgui.selection = nil;
};
if (imgui.keys_pressed.includes($d)) {
var outlet_module = imgui.selection[1];
var outlet_index = imgui.selection[2];
var inlet_module = imgui.selection[3];
var inlet_index = imgui.selection[4];
outlet_module['connections'] = outlet_module['connections'].reject { |conn| conn == [outlet_index, [inlet_module.name, inlet_index]] };
imgui.selection = nil;
};
};
ui_end.value;
};
w.acceptsMouseOver = true;
v.mouseOverAction = { |view, x, y|
imgui.mousedeltax = x-imgui.mousex;
imgui.mousedeltay = y-imgui.mousey;
imgui.mousex = x;
imgui.mousey = y;
v.refresh;
};
v.mouseMoveAction = v.mouseOverAction;
v.mouseDownAction = { |...args|
imgui.mouse_is_down = true;
v.refresh;
};
v.mouseUpAction = { |...args|
imgui.mouse_is_down = false;
v.refresh;
};
v.keyDownAction = { |view, char, mod, unicode, keycode, key|
imgui.keys_pressed = imgui.keys_pressed.add(char);
};
v.keyUpAction = { |view, char, mod, unicode, keycode, key|
imgui.keys_released = imgui.keys_released.add(char);
};
v.animate = true; // TODO: invalidate on request instead
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment