Pixel-Composer/scripts/panel_data/panel_data.gml
2023-03-19 15:17:39 +07:00

841 lines
21 KiB
Plaintext

enum ANCHOR {
none = 0,
top = 1,
bottom = 2,
left = 4,
right = 8
}
function Panel(_parent, _x, _y, _w, _h) constructor {
parent = _parent;
if(parent) ds_list_add(parent.childs, self);
padding = ui(2);
content = [];
content_index = 0;
childs = ds_list_create();
anchor = ANCHOR.none;
x = _x;
y = _y;
w = _w;
h = _h;
tx = x;
ty = y;
tw = w;
th = h;
split = "";
tab_width = 0;
tab_height = ui(20);
tab_x = 0;
tab_x_to = 0;
tab_surface = noone;
min_w = ui(40);
min_h = ui(40);
dragging = -1;
drag_sval = 0;
drag_sm = 0;
mouse_active = true;
content_surface = surface_create_valid(w, h);
mask_surface = surface_create_valid(w, h);
tab_holding = noone;
tab_hold_state = 0;
tab_holding_mx = 0;
tab_holding_my = 0;
tab_holding_sx = 0;
tab_holding_sy = 0;
static getContent = function() { return array_safe_get(content, content_index, noone, ARRAY_OVERFLOW._default); }
static hasContent = function() { return bool(array_length(content)); }
function resetMask() {
var tab = array_length(content) > 1;
tx = x; ty = y + tab * ui(tab_height);
tw = w; th = h - tab * ui(tab_height);
content_surface = surface_verify(content_surface, tw, th);
mask_surface = surface_verify(mask_surface, tw, th);
surface_set_target(mask_surface);
draw_clear(c_black);
gpu_set_blendmode(bm_subtract);
draw_sprite_stretched(THEME.ui_panel_bg, 0, padding, padding, tw - padding * 2, th - padding * 2);
gpu_set_blendmode(bm_normal);
surface_reset_target();
}
resetMask();
function setPadding(padding) {
self.padding = padding;
refresh();
}
function refresh() {
resetMask();
for( var i = 0; i < array_length(content); i++ )
content[i].refresh();
for( var i = 0; i < ds_list_size(childs); i++ )
childs[| i].refresh();
}
function move(dx, dy) {
x += dx;
y += dy;
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
_panel.move(dx, dy);
}
for( var i = 0; i < array_length(content); i++ ) {
content[i].x = x;
content[i].y = y;
}
}
function resizable(dw, dh, oppose = ANCHOR.left) {
var tab = array_length(content) > 1;
tx = x; ty = y + tab * ui(tab_height);
tw = w; th = h - tab * ui(tab_height);
var hori = oppose == ANCHOR.left || oppose == ANCHOR.right;
if(hasContent()) {
var res = true;
for( var i = 0; i < array_length(content); i++ )
res &= hori? tw + dw > content[i].min_w : th + dh > content[i].min_h;
return res;
}
var ind = hori? childs[| 1].w > childs[| 0].w : childs[| 1].h > childs[| 0].h;
return childs[| ind].resizable(dw, dh, oppose);
}
function refreshSize(recur = true) { //refresh content surface after resize
//__debug_counter("refresh size");
var tab = array_length(content) > 1;
tx = x; ty = y + tab * ui(tab_height);
tw = w; th = h - tab * ui(tab_height);
for( var i = 0; i < array_length(content); i++ ) {
content[i].w = max(tw, content[i].min_w);
content[i].h = max(th, content[i].min_h);
content[i].onResize();
}
if(ds_list_size(childs) == 2) {
//print("=== Refreshing (" + string(w) + ", " + string(h) + ") " + string(split) + " ===");
var _tw = childs[| 0].w + childs[| 1].w;
var _th = childs[| 0].h + childs[| 1].h;
var fixChild = split == "h"? childs[| 1].x < childs[| 0].x : childs[| 1].y < childs[| 0].y;
childs[| fixChild].x = x;
childs[| fixChild].y = y;
if(split == "h") {
childs[| fixChild].w = round(childs[| fixChild].w / _tw * w);
childs[| fixChild].h = round(h);
childs[| !fixChild].x = x + childs[| fixChild].w;
childs[| !fixChild].y = y;
childs[| !fixChild].w = round(w - childs[| fixChild].w);
childs[| !fixChild].h = round(h);
childs[| fixChild].anchor = ANCHOR.left;
childs[| !fixChild].anchor = ANCHOR.right;
} else if(split == "v") {
childs[| fixChild].w = round(w);
childs[| fixChild].h = round(childs[| fixChild].h / _th * h);
childs[| !fixChild].x = x;
childs[| !fixChild].y = y + childs[| fixChild].h;
childs[| !fixChild].w = round(w);
childs[| !fixChild].h = round(h - childs[| fixChild].h);
childs[| fixChild].anchor = ANCHOR.top;
childs[| !fixChild].anchor = ANCHOR.bottom;
}
if(recur)
for(var i = 0; i < ds_list_size(childs); i++)
childs[| i].refreshSize();
}
refresh();
}
function resize(dw, dh, oppose = ANCHOR.left) {
if(dw == 0 && dh == 0) return;
if(ds_list_size(childs) == 2) {
var hori = oppose == ANCHOR.left || oppose == ANCHOR.right;
var ind = hori? childs[| 1].w > childs[| 0].w : childs[| 1].h > childs[| 0].h;
childs[| ind].resize(dw, dh, oppose);
}
w = max(round(w + dw), min_w);
h = max(round(h + dh), min_h);
refreshSize(false);
}
function setContent(_content = noone, _switch = false) {
if(is_array(_content))
content = array_append(content, _content);
else
array_push(content, _content);
for( var i = 0; i < array_length(content); i++ )
content[i].onSetPanel(self);
if(_switch)
content_index = array_find(content, _content);
refresh();
}
function split_h(_w) {
if(abs(_w) > w) {
print("Error: Split panel larger than size w (" + string(_w) + " > " + string(w) + ")");
return noone;
}
if(_w < 0) _w = w + _w;
var _panelParent = new Panel(parent, x, y, w, h);
_panelParent.anchor = anchor;
_panelParent.split = "h";
var _panelL = self;
ds_list_add(_panelParent.childs, _panelL);
var _panelR = new Panel(_panelParent, x + _w, y, w - _w, h);
_panelR.anchor = ANCHOR.right;
var prev_w = w;
w = _w;
for( var i = 0; i < array_length(content); i++ ) {
content[i].w = w;
content[i].onResize();
}
if(parent == noone)
PANEL_MAIN = _panelParent;
else
ds_list_delete(parent.childs, ds_list_find_index(parent.childs, self));
parent = _panelParent;
anchor = ANCHOR.left;
content = [];
return [ _panelL, _panelR ];
}
function split_v(_h) {
if(abs(_h) > h) {
print("Error: Split panel larger than size h (" + string(_h) + " > " + string(h) + ")");
return noone;
}
if(_h < 0) _h = h + _h;
var _panelParent = new Panel(parent, x, y, w, h);
_panelParent.anchor = anchor;
_panelParent.split = "v";
var _panelT = self;
ds_list_add(_panelParent.childs, _panelT);
var _panelB = new Panel(_panelParent, x, y + _h, w, h - _h);
_panelB.anchor = ANCHOR.bottom;
var prev_h = h;
h = _h;
for( var i = 0; i < array_length(content); i++ ) {
content[i].h = h;
content[i].onResize();
}
if(parent == noone)
PANEL_MAIN = _panelParent;
else
ds_list_delete(parent.childs, ds_list_find_index(parent.childs, self));
parent = _panelParent;
anchor = ANCHOR.top;
content = [];
return [_panelT, _panelB];
}
function stepBegin() {
var con = getContent();
if(con) con.panelStepBegin(self);
if(o_main.panel_dragging != noone) dragging = -1;
if(dragging == 1) {
var _mx = clamp(mouse_mx, ui(16), WIN_W - ui(16));
var dw = round(_mx - drag_sm);
var res = true;
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
switch(_panel.anchor) {
case ANCHOR.left:
res &= _panel.resizable(dw, 0, ANCHOR.left);
break;
case ANCHOR.right:
res &= _panel.resizable(-dw, 0, ANCHOR.right);
break;
}
}
if(res) {
drag_sm = _mx;
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
switch(_panel.anchor) {
case ANCHOR.left:
_panel.resize(dw, 0, ANCHOR.left);
break;
case ANCHOR.right:
_panel.resize(-dw, 0, ANCHOR.right);
_panel.move(dw, 0);
break;
}
}
}
if(mouse_release(mb_left)) {
refreshSize();
dragging = -1;
}
} else if(dragging == 2) {
var _my = clamp(mouse_my, ui(16), WIN_H - ui(16));
var dh = round(_my - drag_sm);
var res = true;
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
switch(_panel.anchor) {
case ANCHOR.top:
res &= _panel.resizable(0, dh, ANCHOR.top);
break;
case ANCHOR.bottom:
res &= _panel.resizable(0, -dh, ANCHOR.bottom);
break;
}
}
if(res) {
drag_sm = _my;
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
switch(_panel.anchor) {
case ANCHOR.top:
_panel.resize(0, dh, ANCHOR.top);
break;
case ANCHOR.bottom:
_panel.resize(0, -dh, ANCHOR.bottom);
_panel.move(0, dh);
break;
}
}
}
if(mouse_release(mb_left)) {
refreshSize();
dragging = -1;
}
} else {
if(con && point_in_rectangle(mouse_mx, mouse_my, x + ui(2), y + ui(2), x + w - ui(4), y + h - ui(4))) {
HOVER = self;
if(mouse_press(mb_any))
setFocus(self);
if(FOCUS == self && con)
FOCUS_STR = con.context_str;
} else {
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
_panel.stepBegin();
}
}
}
}
static step = function() {
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
_panel.step();
}
}
function draw() {
if(hasContent()) {
drawPanel();
return;
}
if(ds_list_empty(childs))
return;
var min_w = ui(32);
var min_h = ui(32);
if(split == "h") {
min_w = childs[| 0].min_w + childs[| 1].min_w;
min_h = max(childs[| 0].min_h + childs[| 1].min_h);
} else {
min_w = max(childs[| 0].min_w, childs[| 1].min_w);
min_h = childs[| 0].min_h + childs[| 1].min_h;
}
for(var i = 0; i < ds_list_size(childs); i++) {
var _panel = childs[| i];
_panel.draw();
if!(HOVER == noone || is_struct(HOVER))
continue;
var p = ui(6 - 1);
switch(_panel.anchor) {
case ANCHOR.left :
if(!point_in_rectangle(mouse_mx, mouse_my, _panel.x + _panel.w - p, _panel.y, _panel.x + _panel.w + p, _panel.y + _panel.h))
break;
CURSOR = cr_size_we;
if(mouse_press(mb_left)) {
dragging = 1;
drag_sval = _panel.w;
drag_sm = mouse_mx;
}
break;
case ANCHOR.top :
if(!point_in_rectangle(mouse_mx, mouse_my, _panel.x, _panel.y + _panel.h - p, _panel.x + _panel.w, _panel.y + _panel.h + p))
break;
CURSOR = cr_size_ns;
if(mouse_press(mb_left)) {
dragging = 2;
drag_sval = _panel.h;
drag_sm = mouse_my;
}
break;
}
}
if(self == PANEL_MAIN && o_main.panel_dragging != noone && key_mod_press(CTRL))
checkHover();
}
function drawTab() {
tab_surface = surface_verify(tab_surface, w - padding * 2 + 1, tab_height + ui(4));
var tsx = x + padding - 1;
var tsy = y;
var msx = mouse_x - tsx;
var msy = mouse_y - tsy;
surface_set_target(tab_surface);
DRAW_CLEAR
var tbx = tab_x;
var tby = 0;
var tabHov = msx < 0 ? 0 : array_length(content) - 1;
tab_x = lerp_float(tab_x, tab_x_to, 5);
tab_width = 0;
draw_set_text(f_p3, fa_left, fa_bottom, COLORS._main_text_sub);
for( var i = 0; i < array_length(content); i++ ) {
var txt = content[i].title;
var tbw = string_width(txt) + ui(16);
var foc = false;
tab_width += tbw + ui(2);
if(msx >= tbx && msy <= tbx + tbw)
tabHov = i;
if(tab_holding == content[i]) {
tbx += tbw + ui(2);
continue;
}
content[i].tab_x = lerp_float(content[i].tab_x, tbx, 5);
var _tbx = content[i].tab_x;
var _hov = point_in_rectangle(msx, msy, _tbx, tby, _tbx + tbw, tab_height);
if(i == content_index) {
foc = FOCUS == self;
draw_set_color(FOCUS == self? COLORS._main_accent : COLORS.panel_bg_clear);
draw_roundrect_ext(_tbx, tby, _tbx + tbw, tby + ui(32), ui(8), ui(8), false);
} else {
draw_set_color(COLORS.panel_bg_clear_inner);
draw_roundrect_ext(_tbx, tby, _tbx + tbw, tby + ui(32), ui(8), ui(8), false);
if(HOVER == self && _hov) {
draw_set_color(COLORS.panel_bg_clear);
draw_roundrect_ext(_tbx, tby, _tbx + tbw, tby + ui(32), ui(8), ui(8), false);
}
}
if(HOVER == self && _hov) {
if(mouse_press(mb_left, FOCUS == self)) {
content_index = i;
tab_holding = content[i];
tab_hold_state = 0;
tab_holding_mx = msx;
tab_holding_my = msy;
tab_holding_sx = tab_holding.tab_x;
}
}
draw_set_text(f_p3, fa_left, fa_bottom, foc? COLORS.panel_bg_clear_inner : COLORS._main_text_sub);
draw_text(_tbx + ui(8), tab_height - ui(2), txt);
tbx += tbw + ui(2);
}
tab_width = max(0, tab_width - w + ui(32));
if(point_in_rectangle(msx, msy, 0, 0, w, tab_height)) {
if(mouse_wheel_up()) tab_x_to = clamp(tab_x_to + ui(64), -tab_width, 0);
if(mouse_wheel_down()) tab_x_to = clamp(tab_x_to - ui(64), -tab_width, 0);
}
if(tab_holding) {
draw_set_font(f_p3);
var _tbx = tab_holding.tab_x;
var txt = tab_holding.title;
var tbw = string_width(txt) + ui(16);
draw_set_color(COLORS._main_accent);
draw_roundrect_ext(_tbx, tby, _tbx + tbw, tby + ui(32), ui(8), ui(8), false);
draw_set_text(f_p3, fa_left, fa_bottom, COLORS.panel_bg_clear_inner);
draw_text(_tbx + ui(8), tab_height - ui(2), txt);
if(tab_hold_state == 0) {
if(point_distance(tab_holding_mx, tab_holding_my, msx, msy) > 8)
tab_hold_state = 1;
} else if(tab_hold_state == 1) {
if(point_in_rectangle(msx, msy, 0, 0, w, tab_height)) {
if(msx < ui(32)) tab_x_to = clamp(tab_x_to + ui(2), -tab_width, 0);
if(msx > w - ui(32)) tab_x_to = clamp(tab_x_to - ui(2), -tab_width, 0);
}
tab_holding.tab_x = clamp(tab_holding_sx + (msx - tab_holding_mx), 1, w - tbw - ui(4));
array_remove(content, tab_holding);
array_insert(content, tabHov, tab_holding);
content_index = array_find(content, tab_holding);
if(abs(msy - tab_holding_my) > ui(32)) {
extract();
tab_holding = noone;
}
}
if(mouse_release(mb_left))
tab_holding = noone;
}
surface_reset_target();
draw_surface(tab_surface, tsx, tsy);
}
function drawPanel() {
if(w <= ui(16)) return;
var tab = array_length(content) > 1;
tx = x; ty = y + tab * ui(tab_height);
tw = w; th = h - tab * ui(tab_height);
if(th < ui(16)) return;
if(tab) drawTab();
var p = ui(6);
var m_in = point_in_rectangle(mouse_mx, mouse_my, tx + p, ty + p, tx + tw - p, ty + th - p);
var m_ot = point_in_rectangle(mouse_mx, mouse_my, tx, ty, tx + tw, ty + th);
mouse_active = m_in;
draw_sprite_stretched(THEME.ui_panel_bg, 0, tx + padding, ty + padding, tw - padding * 2, th - padding * 2);
if(!is_surface(mask_surface)) {
mask_surface = surface_create_valid(tw, th);
refresh();
}
if(!is_surface(content_surface))
content_surface = surface_create_valid(tw, th);
surface_set_target(content_surface);
draw_clear(COLORS.panel_bg_clear);
var con = getContent();
if(con) {
min_w = con.min_w;
min_h = con.min_h;
if(tw >= min_w && th >= min_h)
con.draw(self);
}
gpu_set_blendmode(bm_subtract);
draw_surface_safe(mask_surface, 0, 0);
gpu_set_blendmode(bm_normal);
surface_reset_target();
draw_surface_safe(content_surface, tx, ty);
if(FOCUS == self && parent != noone) {
draw_sprite_stretched_ext(THEME.ui_panel_active, 0, tx + padding, ty + padding, tw - padding * 2, th - padding * 2, COLORS._main_accent, 1);
if(hasContent() && !m_in && m_ot) {
draw_sprite_stretched_ext(THEME.ui_panel_active, 0, tx + padding, ty + padding, tw - padding * 2, th - padding * 2, c_white, 0.4);
if(DOUBLE_CLICK) {
extract();
panel_mouse = 0;
} else if(mouse_press(mb_right)) {
var arr = [
menuItem("Move", function() {
extract();
panel_mouse = 1;
}),
menuItem("Pop out", function() { popWindow(); }, THEME.node_goto),
];
if(instanceof(getContent()) != "Panel_Menu")
array_push(arr, menuItem("Close", function() {
extract();
o_main.panel_dragging = noone;
}, THEME.cross));
menuCall(,, arr);
}
}
}
if(o_main.panel_dragging != noone && m_ot && !key_mod_press(CTRL))
checkHover();
}
function extract() {
var con = getContent();
con.dragSurface = surface_clone(content_surface);
o_main.panel_dragging = con;
array_remove(content, con);
refresh();
content_index = 0;
HOVER = noone;
FOCUS = noone;
if(hasContent()) return;
var ind = !ds_list_find_index(parent.childs, self); //index of the other child
var sib = parent.childs[| ind];
if(!sib.hasContent() && ds_list_size(sib.childs) == 2) { //other child is compound panel
var gparent = parent.parent;
if(gparent == noone) {
sib.x = PANEL_MAIN.x; sib.y = PANEL_MAIN.y;
sib.w = PANEL_MAIN.w; sib.h = PANEL_MAIN.h;
PANEL_MAIN = sib;
sib.parent = noone;
PANEL_MAIN.refreshSize();
} else {
var pind = ds_list_find_index(gparent.childs, parent); //index of parent in grandparent object
gparent.childs[| pind] = sib; //replace parent with sibling
sib.parent = gparent;
gparent.refreshSize();
}
} else if(sib.hasContent()) { //other child is content panel, set parent to content panel
parent.setContent(sib.content);
ds_list_clear(parent.childs);
}
}
function popWindow() {
var con = getContent();
if(con == noone) return;
dialogPanelCall(con);
extract();
o_main.panel_dragging = noone;
}
function checkHover() {
var dx = (mouse_mx - x) / w;
var dy = (mouse_my - y) / h;
var p = ui(8);
draw_set_color(COLORS._main_accent);
o_main.panel_hovering = self;
var x0 = x + p;
var y0 = y + p;
var x1 = x + w - p;
var y1 = y + h - p;
var xc = x + w / 2;
var yc = y + h / 2;
if(point_in_rectangle(mouse_mx, mouse_my, x + w * 1 / 3, y + h * 1 / 3, x + w * 2 / 3, y + h * 2 / 3)) {
o_main.panel_split = 4;
o_main.panel_draw_x0_to = x + w * 1 / 3;
o_main.panel_draw_y0_to = y + h * 1 / 3;
o_main.panel_draw_x1_to = x + w * 2 / 3;
o_main.panel_draw_y1_to = y + h * 2 / 3;
} else {
if(dx + dy > 1) {
if((1 - dx) + dy > 1) {
o_main.panel_draw_x0_to = x0;
o_main.panel_draw_y0_to = yc;
o_main.panel_draw_x1_to = x1;
o_main.panel_draw_y1_to = y1;
o_main.panel_split = 3;
} else {
o_main.panel_draw_x0_to = xc;
o_main.panel_draw_y0_to = y0;
o_main.panel_draw_x1_to = x1;
o_main.panel_draw_y1_to = y1;
o_main.panel_split = 1;
}
} else {
if((1 - dx) + dy > 1) {
o_main.panel_draw_x0_to = x0;
o_main.panel_draw_y0_to = y0;
o_main.panel_draw_x1_to = xc;
o_main.panel_draw_y1_to = y1;
o_main.panel_split = 2;
} else {
o_main.panel_draw_x0_to = x0;
o_main.panel_draw_y0_to = y0;
o_main.panel_draw_x1_to = x1;
o_main.panel_draw_y1_to = yc;
o_main.panel_split = 0;
}
}
}
}
function remove() {
var con = getContent();
array_remove(content, con);
content_index = 0;
refresh();
if(hasContent()) return;
if(parent == noone) {
show_message("What are you trying to do!");
return;
}
ds_list_delete(parent.childs, ds_list_find_index(parent.childs, self));
var otherPanel = parent.childs[| 0];
parent.setContent(otherPanel.content);
ds_list_clear(parent.childs);
}
}
function PanelContent() constructor {
title = "";
context_str = "";
draggable = true;
expandable = true;
panel = noone;
mx = 0;
my = 0;
x = 0;
y = 0;
w = 640;
h = 480;
padding = ui(16);
tab_x = 0;
min_w = ui(40);
min_h = ui(40);
pFOCUS = false;
pHOVER = false;
in_dialog = false;
dragSurface = surface_create(1, 1);
showHeader = true;
function refresh() {
onResize();
}
function onResize() {}
function onFocusBegin() {}
function onFocusEnd() {}
function initSize() {}
function setPanelSize(panel) {
x = panel.tx;
y = panel.ty;
w = panel.tw;
h = panel.th;
}
function onSetPanel(panel) {
self.panel = panel;
setPanelSize(panel);
initSize();
onResize();
}
function panelStepBegin(panel) {
setPanelSize(panel);
onStepBegin();
}
function onStepBegin() {
mx = mouse_mx - x;
my = mouse_my - y;
stepBegin();
}
function stepBegin() {}
function draw(panel) {
pFOCUS = FOCUS == panel && panel.mouse_active;
pHOVER = HOVER == panel && panel.mouse_active;
drawContent(panel);
}
function drawContent(panel) {}
}
function setFocus(target, fstring = noone) {
if(FOCUS != noone && is_struct(FOCUS) && FOCUS.getContent())
FOCUS.getContent().onFocusEnd();
FOCUS = target;
if(fstring != noone)
FOCUS_STR = fstring;
if(FOCUS != noone && is_struct(FOCUS) && FOCUS.getContent())
FOCUS.getContent().onFocusBegin();
}