#region funtion calls function __fnInit_Preview() { __registerFunction("preview_focus_content", panel_preview_focus_content); __registerFunction("preview_save_current_frame", panel_preview_save_current_frame); __registerFunction("preview_saveCurrentFrameToFocus", panel_preview_saveCurrentFrameToFocus); __registerFunction("preview_save_all_current_frame", panel_preview_save_all_current_frame); __registerFunction("preview_preview_window", panel_preview_preview_window); __registerFunction("preview_toggle_grid", panel_preview_toggle_grid); __registerFunction("preview_pan", panel_preview_pan); __registerFunction("preview_zoom", panel_preview_zoom); } function panel_preview_focus_content() { CALL("preview_focus_content"); PANEL_PREVIEW.fullView(); } function panel_preview_save_current_frame() { CALL("preview_save_current_frame"); PANEL_PREVIEW.saveCurrentFrame(); } function panel_preview_saveCurrentFrameToFocus() { CALL("preview_saveCurrentFrameToFocus"); PANEL_PREVIEW.saveCurrentFrameToFocus(); } function panel_preview_save_all_current_frame() { CALL("preview_save_all_current_frame"); PANEL_PREVIEW.saveAllCurrentFrames(); } function panel_preview_preview_window() { CALL("preview_preview_window"); PANEL_PREVIEW.create_preview_window(PANEL_PREVIEW.getNodePreview()); } function panel_preview_toggle_grid() { CALL("preview_toggle_grid"); PROJECT.previewGrid.show = !PROJECT.previewGrid.show; } function panel_preview_pan() { CALL("preview_pan"); PANEL_PREVIEW.canvas_dragging_key = true; } function panel_preview_zoom() { CALL("preview_zoom"); PANEL_PREVIEW.canvas_zooming_key = true; } function panel_preview_3d_view_front() { CALL("preview_3d_view_front"); PANEL_PREVIEW.d3_view_action_front(); } function panel_preview_3d_view_back() { CALL("preview_3d_view_back"); PANEL_PREVIEW.d3_view_action_back(); } function panel_preview_3d_view_right() { CALL("preview_3d_view_right"); PANEL_PREVIEW.d3_view_action_right(); } function panel_preview_3d_view_left() { CALL("preview_3d_view_left"); PANEL_PREVIEW.d3_view_action_left(); } function panel_preview_3d_view_top() { CALL("preview_3d_view_top"); PANEL_PREVIEW.d3_view_action_top(); } function panel_preview_3d_view_bottom() { CALL("preview_3d_view_bottom"); PANEL_PREVIEW.d3_view_action_bottom(); } #endregion function Panel_Preview() : PanelContent() constructor { title = __txt("Preview"); context_str = "Preview"; icon = THEME.panel_preview_icon; last_focus = noone; #region ---- canvas control & sample ---- function initSize() { canvas_x = w / 2; canvas_y = h / 2; } run_in(1, function() { initSize() }); canvas_x = 0; canvas_y = 0; canvas_s = 1; canvas_w = ui(128); canvas_h = ui(128); canvas_a = 0; canvas_bg = -1; do_fullView = false; canvas_hover = true; canvas_dragging_key = false; canvas_dragging = false; canvas_drag_key = 0; canvas_drag_mx = 0; canvas_drag_my = 0; canvas_drag_sx = 0; canvas_drag_sy = 0; canvas_zooming_key = false; canvas_zooming = false; canvas_zoom_mx = 0; canvas_zoom_my = 0; canvas_zoom_m = 0; canvas_zoom_s = 0; view_pan_tool = false; view_zoom_tool = false; sample_color = noone; sample_x = noone; sample_y = noone; #endregion #region ---- preview ---- locked = false; preview_node = [ noone, noone ]; preview_surfaces = [ 0, 0 ]; preview_surface = [ 0, 0 ]; tile_surface = surface_create(1, 1); preview_x = 0; preview_x_to = 0; preview_x_max = 0; preview_sequence = [ 0, 0 ]; _preview_sequence = preview_sequence; preview_rate = 10; right_menu_x = 0; right_menu_y = 8; mouse_on_preview = 0; _mouse_on_preview = 0; resetViewOnDoubleClick = true; splitView = 0; splitPosition = 0.5; splitSelection = 0; splitViewDragging = false; splitViewStart = 0; splitViewMouse = 0; tileMode = 0; bg_color = COLORS.panel_bg_clear; mouse_pos_string = ""; show_info = true; show_view_control = 1; #endregion #region ---- tool ---- tool_x = 0; tool_x_to = 0; tool_x_max = 0; tool_y = 0; tool_y_to = 0; tool_y_max = 0; tool_ry = 0; tool_ry_to = 0; tool_ry_max = 0; tool_current = noone; toolbar_width = ui(40); toolbar_height = ui(40); tool_hovering = noone; tool_side_draw_l = false; tool_side_draw_r = false; overlay_hovering = false; view_hovering = false; sbChannel = new scrollBox([], function(index) { #region var node = getNodePreview(); if(node == noone) return; node.preview_channel = array_safe_get_fast(sbChannelIndex, index); }); #endregion sbChannelIndex = []; sbChannel.font = f_p1; sbChannel.align = fa_left; #endregion #region ---- 3d ---- d3_active = false; _d3_active = false; d3_active_transition = 0; d3_surface = noone; d3_surface_normal = noone; d3_surface_depth = noone; d3_surface_outline = noone; d3_surface_bg = noone; d3_preview_channel = 0; d3_deferData = noone; global.SKY_SPHERE = new __3dUVSphere(0.5, 16, 8, true); #region camera d3_view_camera = new __3dCamera(); d3_camW = 1; d3_camH = 1; d3_view_camera.setFocusAngle(135, 45, 4); d3_camLerp = 0; d3_camLerp_x = 0; d3_camLerp_y = 0; d3_camTarget = new __vec3(); d3_camPanning = false; d3_camPan_mx = 0; d3_camPan_my = 0; d3_zoom_speed = 0.2; d3_pan_speed = 2; #endregion #region scene d3_scene = new __3dScene(d3_view_camera, "Preview panel"); d3_scene.lightAmbient = $404040; d3_scene.cull_mode = cull_counterclockwise; d3_scene_preview = d3_scene; d3_scene_light_enabled = true; d3_scene_light0 = new __3dLightDirectional(); d3_scene_light0.transform.position.set(-1, -2, 3); d3_scene_light0.color = $FFFFFF; d3_scene_light0.shadow_active = false; d3_scene_light0.shadow_map_scale = 4; d3_scene_light1 = new __3dLightDirectional(); d3_scene_light1.transform.position.set(1, 2, -3); d3_scene_light1.color = $505050; #endregion #region tool d3_tool_snap = false; d3_tool_snap_position = 1; d3_tool_snap_rotation = 15; #endregion #region view channel d3ChannelNames = [ "Rendered", "Normal", "Depth" ]; d3Channel = new scrollBox(d3ChannelNames, function(index) { d3_preview_channel = index; }); d3Channel.align = fa_left; #endregion #endregion tb_framerate = new textBox(TEXTBOX_INPUT.number, function(val) { preview_rate = real(val); }); #region ++++ hotkey ++++ addHotkey("Preview", "Focus content", "F", MOD_KEY.none, panel_preview_focus_content); addHotkey("Preview", "Save current frame", "S", MOD_KEY.shift, panel_preview_save_current_frame); addHotkey("Preview", "Save to focused file", "", MOD_KEY.none, panel_preview_saveCurrentFrameToFocus); addHotkey("Preview", "Save all current frame", "", MOD_KEY.none, panel_preview_save_all_current_frame); addHotkey("Preview", "Preview window", "P", MOD_KEY.ctrl, panel_preview_preview_window); addHotkey("Preview", "Toggle grid", "G", MOD_KEY.ctrl, panel_preview_toggle_grid); addHotkey("Preview", "Pan", "", MOD_KEY.ctrl, panel_preview_pan); addHotkey("Preview", "Zoom", "", MOD_KEY.alt | MOD_KEY.ctrl, panel_preview_zoom); addHotkey("Preview", "3D Front view", vk_numpad1, MOD_KEY.none, panel_preview_3d_view_front); addHotkey("Preview", "3D Back view", vk_numpad1, MOD_KEY.alt, panel_preview_3d_view_back); addHotkey("Preview", "3D Right view ", vk_numpad3, MOD_KEY.none, panel_preview_3d_view_right); addHotkey("Preview", "3D Left view ", vk_numpad3, MOD_KEY.alt, panel_preview_3d_view_left); addHotkey("Preview", "3D Top view", vk_numpad7, MOD_KEY.none, panel_preview_3d_view_top); addHotkey("Preview", "3D Bottom view", vk_numpad7, MOD_KEY.alt, panel_preview_3d_view_bottom); #endregion #region ++++ toolbars & actions ++++ topbar_height = ui(32); toolbar_height = ui(40); toolbars = [ [ THEME.icon_reset_when_preview, function() { return resetViewOnDoubleClick; }, function() { return resetViewOnDoubleClick? __txtx("panel_preview_center_canvas_on_preview", "Center canvas on preview") : __txtx("panel_preview_keep_canvas_on_preview", "Keep canvas on preview"); }, function() { resetViewOnDoubleClick = !resetViewOnDoubleClick; } ], [ THEME.icon_split_view, function() { return splitView; }, function() { switch(splitView) { case 0 : return __txtx("panel_preview_split_view_off", "Split view off"); case 1 : return __txtx("panel_preview_horizontal_split_view", "Horizontal split view"); case 2 : return __txtx("panel_preview_vertical_split_view", "Vertical split view"); } return __txtx("panel_preview_split_view", "Split view"); }, function() { splitView = (splitView + 1) % 3; } ], [ THEME.icon_tile_view, function() { var t = [3, 0, 1, 2]; return array_safe_get_fast(t, tileMode); }, function() { switch(tileMode) { case 0 : return __txtx("panel_preview_tile_off", "Tile off"); case 1 : return __txtx("panel_preview_tile_horizontal", "Tile horizontal"); case 2 : return __txtx("panel_preview_tile_vertical", "Tile vertical"); case 3 : return __txtx("panel_preview_tile_both", "Tile both"); } return __txtx("panel_preview_tile_mode", "Tile mode"); }, function(data) { menuCall("preview_tile_menu", data.x + ui(28), data.y + ui(28), [ menuItem(__txtx("panel_preview_tile_off", "Tile off"), function() { tileMode = 0; }), menuItem(__txtx("panel_preview_tile_horizontal", "Tile horizontal"), function() { tileMode = 1; }), menuItem(__txtx("panel_preview_tile_vertical", "Tile vertical"), function() { tileMode = 2; }), menuItem(__txtx("panel_preview_tile_both", "Tile both"), function() { tileMode = 3; }), ]); } ], [ THEME.icon_grid_setting, function() { return 0; }, function() { return __txtx("grid_title", "Grid setting") }, function(param) { var dia = dialogPanelCall(new Panel_Preview_Grid_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); } ], [ THEME.onion_skin, function() { return 0; }, function() { return __txt("Onion Skin") }, function(param) { var dia = dialogPanelCall(new Panel_Preview_Onion_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); } ], ]; toolbars_3d = [ [ THEME.d3d_preview_settings, function() { return 0; }, function() { return __txt("3D Preview Settings") }, function(param) { var dia = dialogPanelCall(new Panel_Preview_3D_Setting(self), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); } ], [ THEME.d3d_snap_settings, function() { return 0; }, function() { return __txt("3D Snap Settings") }, function(param) { var dia = dialogPanelCall(new Panel_Preview_Snap_Setting(self), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); } ], ]; tooltip_center = new tooltipHotkey(__txtx("panel_preview_center_canvas", "Center canvas"), "Preview", "Focus content"); tooltip_export = new tooltipHotkey(__txtx("panel_preview_export_canvas", "Export canvas"), "Preview", "Save current frame"); actions = [ [ THEME.lock, __txtx("panel_preview_lock_preview", "Lock previewing node"), function() { locked = !locked; }, function() { return !locked; }, ], [ THEME.icon_preview_export, tooltip_export, function() { saveCurrentFrame(); }, function() { return 0; }, ], [ THEME.icon_center_canvas, tooltip_center, function() { fullView(); }, function() { return 0; }, ], [ THEME.icon_visibility, __txtx("graph_visibility_title", "Visibility settings"), function(param) { dialogPanelCall(new Panel_Preview_View_Setting(self), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); }, function() { return 0; }, ], ]; static d3_view_action_front = function() { d3_camLerp = 1; d3_camLerp_x = 0; d3_camLerp_y = 0; } static d3_view_action_back = function() { d3_camLerp = 1; d3_camLerp_x = 180; d3_camLerp_y = 0; } static d3_view_action_right = function() { d3_camLerp = 1; d3_camLerp_x = 90; d3_camLerp_y = 0; } static d3_view_action_left = function() { d3_camLerp = 1; d3_camLerp_x = -90; d3_camLerp_y = 0; } static d3_view_action_bottom = function() { d3_camLerp = 1; d3_camLerp_x = 0; d3_camLerp_y = -89; } static d3_view_action_top = function() { d3_camLerp = 1; d3_camLerp_x = 0; d3_camLerp_y = 89; } #endregion ////============ DATA ============ function setNodePreview(node) { #region if(locked) return; if(resetViewOnDoubleClick) do_fullView = true; if(is_instanceof(node, Node) && node.getPreviewingNode != noone) node = node.getPreviewingNode(); preview_node[splitView? splitSelection : 0] = node; } #endregion function removeNodePreview(node) { #region if(locked) return; if(preview_node[0] == node) preview_node[0] = noone; if(preview_node[1] == node) preview_node[1] = noone; } #endregion function resetNodePreview() { #region preview_node = [ noone, noone ]; locked = false; } #endregion function getNodePreview() { return preview_node[splitView? splitSelection : 0]; } function getNodePreviewSurface() { return preview_surfaces[splitView? splitSelection : 0]; } function getNodePreviewSequence() { return preview_sequence[splitView? splitSelection : 0]; } function getPreviewData() { #region preview_surfaces = [ noone, noone ]; preview_sequence = [ noone, noone ]; for( var i = 0; i < 2; i++ ) { var node = preview_node[i]; if(node == noone) continue; if(!node.active) { resetNodePreview(); return; } var value = node.getPreviewValues(); if(is_array(value)) { preview_sequence[i] = value; canvas_a = array_length(value); } else { preview_surfaces[i] = value; canvas_a = 0; } if(preview_sequence[i] != noone) { if(array_length(preview_sequence[i]) == 0) return; preview_surfaces[i] = preview_sequence[i][safe_mod(node.preview_index, array_length(preview_sequence[i]))]; } } var prevS = getNodePreviewSurface(); if(is_surface(prevS)) { canvas_w = surface_get_width_safe(prevS); canvas_h = surface_get_height_safe(prevS); } } #endregion function onFocusBegin() { PANEL_PREVIEW = self; } ////============ VIEW ============ function dragCanvas() { #region if(canvas_dragging) { if(!MOUSE_WRAPPING) { var dx = mx - canvas_drag_mx; var dy = my - canvas_drag_my; canvas_x += dx; canvas_y += dy; } canvas_drag_mx = mx; canvas_drag_my = my; setMouseWrap(); if(mouse_release(canvas_drag_key)) { canvas_dragging = false; view_pan_tool = false; } } if(canvas_zooming) { if(!MOUSE_WRAPPING) { var dy = -(my - canvas_zoom_m) / 200; var _s = canvas_s; canvas_s = clamp(canvas_s * (1 + dy), 0.10, 64); if(_s != canvas_s) { var dx = (canvas_s - _s) * ((canvas_zoom_mx - canvas_x) / _s); var dy = (canvas_s - _s) * ((canvas_zoom_my - canvas_y) / _s); canvas_x -= dx; canvas_y -= dy; } } canvas_zoom_m = my; setMouseWrap(); if(mouse_release(canvas_drag_key)) { canvas_zooming = false; view_zoom_tool = false; } } if(pHOVER && canvas_hover) { var _doDragging = false; var _doZooming = false; if(mouse_press(PREFERENCES.pan_mouse_key, pFOCUS)) { _doDragging = true; canvas_drag_key = PREFERENCES.pan_mouse_key; } else if(mouse_press(mb_left, pFOCUS) && canvas_dragging_key) { _doDragging = true; canvas_drag_key = mb_left; } else if(mouse_press(mb_left, pFOCUS) && canvas_zooming_key) { _doZooming = true; canvas_drag_key = mb_left; } if(_doDragging) { canvas_dragging = true; canvas_drag_mx = mx; canvas_drag_my = my; canvas_drag_sx = canvas_x; canvas_drag_sy = canvas_y; } if(_doZooming) { canvas_zooming = true; canvas_zoom_mx = mx; canvas_zoom_my = my; canvas_zoom_m = my; canvas_zoom_s = canvas_s; } var _canvas_s = canvas_s; var inc = 0.1; if(canvas_s > 16) inc = 2; else if(canvas_s > 8) inc = 1; else if(canvas_s > 3) inc = 0.5; else if(canvas_s > 1) inc = 0.25; if(mouse_wheel_down() && !key_mod_press_any()) canvas_s = max(round(canvas_s / inc) * inc - inc, 0.10); if(mouse_wheel_up() && !key_mod_press_any()) canvas_s = min(round(canvas_s / inc) * inc + inc, 1024); if(_canvas_s != canvas_s) { var dx = (canvas_s - _canvas_s) * ((mx - canvas_x) / _canvas_s); var dy = (canvas_s - _canvas_s) * ((my - canvas_y) / _canvas_s); canvas_x -= dx; canvas_y -= dy; } } canvas_dragging_key = false; canvas_zooming_key = false; canvas_hover = point_in_rectangle(mx, my, 0, toolbar_height, w, h - toolbar_height); } #endregion function dragCanvas3D() { #region if(d3_camLerp) { d3_view_camera.focus_angle_x = lerp_float(d3_view_camera.focus_angle_x, d3_camLerp_x, 3, 1); d3_view_camera.focus_angle_y = lerp_float(d3_view_camera.focus_angle_y, d3_camLerp_y, 3, 1); if(d3_view_camera.focus_angle_x == d3_camLerp_x && d3_view_camera.focus_angle_y == d3_camLerp_y) d3_camLerp = false; } if(d3_camPanning) { if(!MOUSE_WRAPPING) { var dx = mx - d3_camPan_mx; var dy = my - d3_camPan_my; var px = d3_view_camera.focus_angle_x; var py = d3_view_camera.focus_angle_y; var ax = px + dx * 0.2 * d3_pan_speed; var ay = py + dy * 0.1 * d3_pan_speed; //if(py < 90 && ay >= 90) ax -= 180; //if(py > 90 && ay <= 90) ax += 180; //print($"{ax},\t{ay}"); d3_view_camera.focus_angle_x = ax; d3_view_camera.focus_angle_y = ay; } d3_camPan_mx = mx; d3_camPan_my = my; setMouseWrap(); if(mouse_release(canvas_drag_key)) { d3_camPanning = false; view_pan_tool = false; } } if(canvas_zooming) { if(!MOUSE_WRAPPING) { var dy = -(my - canvas_zoom_m) / 200; d3_view_camera.focus_dist = clamp(d3_view_camera.focus_dist + dy, 1, 1000); } canvas_zoom_m = my; setMouseWrap(); if(mouse_release(canvas_drag_key)) { canvas_zooming = false; view_zoom_tool = false; } } if(pHOVER && canvas_hover) { var _doDragging = false; var _doZooming = false; if(mouse_press(PREFERENCES.pan_mouse_key, pFOCUS)) { _doDragging = true; canvas_drag_key = PREFERENCES.pan_mouse_key; } else if(mouse_press(mb_left, pFOCUS) && canvas_dragging_key) { _doDragging = true; canvas_drag_key = mb_left; } else if(mouse_press(mb_left, pFOCUS) && canvas_zooming_key) { _doZooming = true; canvas_drag_key = mb_left; } if(_doDragging) { d3_camPanning = true; d3_camPan_mx = mx; d3_camPan_my = my; } if(_doZooming) { canvas_zooming = true; canvas_zoom_m = my; } if(mouse_wheel_up()) d3_view_camera.focus_dist = max( 1, d3_view_camera.focus_dist * (1 - d3_zoom_speed)); if(mouse_wheel_down()) d3_view_camera.focus_dist = min(1000, d3_view_camera.focus_dist * (1 + d3_zoom_speed)); } canvas_dragging_key = false; canvas_zooming_key = false; canvas_hover = point_in_rectangle(mx, my, 0, toolbar_height, w, h - toolbar_height); } #endregion function fullView() { #region var bbox = noone; var node = getNodePreview(); if(node != noone) bbox = node.getPreviewBoundingBox(); if(bbox == noone) bbox = BBOX().fromWH(0, 0, PROJECT.attributes.surface_dimension[0], PROJECT.attributes.surface_dimension[1]); var tl = tool_side_draw_l * 40; var tr = tool_side_draw_r * 40; var ss = min((w - 32 - tl - tr) / bbox.w, (h - 32 - toolbar_height * 2) / bbox.h); canvas_s = ss; canvas_x = w / 2 - bbox.w * canvas_s / 2 - bbox.x0 * canvas_s + (tl - tr) / 2; canvas_y = h / 2 - bbox.h * canvas_s / 2 - bbox.y0 * canvas_s; } #endregion function drawNodeChannel(_x, _y) { #region var _node = getNodePreview(); if(_node == noone) return; if(ds_list_size(_node.outputs) < 2) return; var chName = []; sbChannelIndex = []; var currName = _node.outputs[| _node.preview_channel].name; draw_set_text(sbChannel.font, fa_center, fa_center); var ww = 0; var hh = TEXTBOX_HEIGHT - ui(2); for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { if(_node.outputs[| i].type != VALUE_TYPE.surface) continue; array_push(chName, _node.outputs[| i].name); array_push(sbChannelIndex, i); ww = max(ww, string_width(_node.outputs[| i].name) + ui(40)); } if(!array_empty(chName)) { sbChannel.data_list = chName; sbChannel.setFocusHover(pFOCUS, pHOVER); sbChannel.draw(_x - ww, _y - hh / 2, ww, hh, currName, [mx, my], x, y); right_menu_y += ui(40); } } #endregion function drawNodeChannel3D(_x, _y) { #region var _node = getNodePreview(); if(_node == noone) return; var ww = ui(128); var hh = toolbar_height - ui(12); d3Channel.setFocusHover(pFOCUS, pHOVER); d3Channel.draw(_x - ww, _y - hh / 2, ww, hh, d3ChannelNames[d3_preview_channel], [mx, my], x, y); right_menu_y += ui(40); } #endregion static onFullScreen = function() { run_in(1, fullView); } ////============ DRAW ============ function drawOnionSkin(node, psx, psy, ss) { #region var _surf = preview_surfaces[0]; var _rang = PROJECT.onion_skin.range; var _alph = PROJECT.onion_skin.alpha; var _colr = PROJECT.onion_skin.color; var _step = PROJECT.onion_skin.step; var _top = PROJECT.onion_skin.on_top; var fr = CURRENT_FRAME; var st = min(_rang[0], _rang[1]); var ed = max(_rang[0], _rang[1]); st = sign(st) * floor(abs(st) / _step) * _step; ed = sign(ed) * floor(abs(ed) / _step) * _step; st += fr; ed += fr; var surf, aa, cc; if(!_top) { draw_surface_ext_safe(_surf, psx, psy, ss, ss); BLEND_ADD } for( var i = st; i <= ed; i += _step ) { surf = node.getCacheFrame(i); if(!is_surface(surf)) continue; aa = power(_alph, abs((i - fr) / _step)); cc = c_white; if(i < fr) cc = _colr[0]; else if(i > fr) cc = _colr[1]; draw_surface_ext_safe(surf, psx, psy, ss, ss, 0, cc, aa); } BLEND_NORMAL if(_top) draw_surface_ext_safe(_surf, psx, psy, ss, ss); } #endregion function drawNodePreview() { #region var ss = canvas_s; var psx = 0, psy = 0; var psw = 0, psh = 0; var pswd = 0, pshd = 0; var psx1 = 0, psy1 = 0; var ssx = 0, ssy = 0; var ssw = 0, ssh = 0; if(is_surface(preview_surfaces[0])) { psx = canvas_x + preview_node[0].preview_x * ss; psy = canvas_y + preview_node[0].preview_y * ss; psw = surface_get_width_safe(preview_surfaces[0]); psh = surface_get_height_safe(preview_surfaces[0]); pswd = psw * ss; pshd = psh * ss; psx1 = psx + pswd; psy1 = psy + pshd; } if(is_surface(preview_surfaces[1])) { var ssx = canvas_x + preview_node[1].preview_x * ss; var ssy = canvas_y + preview_node[1].preview_y * ss; var ssw = surface_get_width_safe(preview_surfaces[1]); var ssh = surface_get_height_safe(preview_surfaces[1]); } var _node = getNodePreview(); if(_node) title = _node.renamed? _node.display_name : _node.name; #region >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Draw Surfaces <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< var _ps0 = is_surface(preview_surfaces[0]); var _ps1 = is_surface(preview_surfaces[1]); if(_ps0) { var _sw = surface_get_width_safe(preview_surfaces[0]); var _sh = surface_get_height_safe(preview_surfaces[0]); preview_surface[0] = surface_verify(preview_surface[0], _sw, _sh); surface_set_shader(preview_surface[0], PROJECT.attributes.palette_fix? sh_posterize_palette : sh_sample); shader_set_f("palette", PROJECT.palettes); shader_set_i("keys", array_length(PROJECT.attributes.palette)); shader_set_i("alpha", 1); draw_surface_safe(preview_surfaces[0]); surface_reset_shader(); } if(_ps1) { var _sw = surface_get_width_safe(preview_surfaces[1]); var _sh = surface_get_height_safe(preview_surfaces[1]); preview_surface[1] = surface_verify(preview_surface[1], _sw, _sh); surface_set_shader(preview_surface[1], PROJECT.attributes.palette_fix? sh_posterize_palette : sh_sample); shader_set_f("palette", PROJECT.palettes); shader_set_i("keys", array_length(PROJECT.attributes.palette)); shader_set_i("alpha", 1); draw_surface_safe(preview_surfaces[1]); surface_reset_shader(); } switch(splitView) { case 0 : if(_ps0) { preview_node[0].previewing = 1; switch(tileMode) { case 0 : if(PROJECT.onion_skin.enabled) drawOnionSkin(_node, psx, psy, ss); else draw_surface_ext(preview_surface[0], psx, psy, ss, ss, 0, c_white, preview_node[0].preview_alpha); break; case 1 : tile_surface = surface_verify(tile_surface, w, surface_get_height_safe(preview_surface[0]) * ss); surface_set_target(tile_surface); DRAW_CLEAR draw_surface_tiled_ext_safe(preview_surface[0], psx, 0, ss, ss, 0, c_white, 1); surface_reset_target(); draw_surface_safe(tile_surface, 0, psy); break; case 2 : tile_surface = surface_verify(tile_surface, surface_get_width_safe(preview_surface[0]) * ss, h); surface_set_target(tile_surface); DRAW_CLEAR draw_surface_tiled_ext_safe(preview_surface[0], 0, psy, ss, ss, 0, c_white, 1); surface_reset_target(); draw_surface_safe(tile_surface, psx, 0); break; case 3 : draw_surface_tiled_ext_safe(preview_surface[0], psx, psy, ss, ss, 0, c_white, 1); break; } } break; case 1 : var sp = splitPosition * w; if(_ps0) { preview_node[0].previewing = 2; var maxX = min(sp, psx1); var sW = min(psw, (maxX - psx) / ss); if(sW > 0) draw_surface_part_ext_safe(preview_surface[0], 0, 0, sW, psh, psx, psy, ss, ss, 0, c_white, 1); } if(_ps1) { preview_node[1].previewing = 3; var minX = max(ssx, sp); var sX = (minX - ssx) / ss; var spx = max(sp, ssx); if(sX >= 0 && sX < ssw) draw_surface_part_ext_safe(preview_surface[1], sX, 0, ssw - sX, ssh, spx, ssy, ss, ss, 0, c_white, 1); } break; case 2 : var sp = splitPosition * h; if(_ps0) { preview_node[0].previewing = 4; var maxY = min(sp, psy1); var sH = min(psh, (maxY - psy) / ss); if(sH > 0) draw_surface_part_ext_safe(preview_surface[0], 0, 0, psw, sH, psx, psy, ss, ss, 0, c_white, 1); } if(_ps1) { preview_node[1].previewing = 5; var minY = max(ssy, sp); var sY = (minY - ssy) / ss; var spy = max(sp, ssy); if(sY >= 0 && sY < ssh) draw_surface_part_ext_safe(preview_surface[1], 0, sY, ssw, ssh - sY, ssx, spy, ss, ss, 0, c_white, 1); } break; } #endregion if(!instance_exists(o_dialog_menubox)) { #region color sample sample_color = noone; sample_x = noone; sample_y = noone; if(mouse_on_preview && (mouse_press(mb_right) || key_mod_press(CTRL))) { var _sx = sample_x; var _sy = sample_y; sample_x = floor((mx - canvas_x) / canvas_s); sample_y = floor((my - canvas_y) / canvas_s); var surf = getNodePreviewSurface(); sample_color = surface_get_pixel_ext(surf, sample_x, sample_y); //print($"{dec_to_hex(sample_color)}: {color_get_alpha(int64(sample_color))}"); } } #endregion if(is_surface(preview_surfaces[0])) { #region outline if(PROJECT.previewGrid.pixel && canvas_s >= 16) { var gw = pswd / canvas_s; var gh = pshd / canvas_s; var cx = canvas_x; var cy = canvas_y; draw_set_color(PROJECT.previewGrid.color); draw_set_alpha(PROJECT.previewGrid.opacity * 0.5 * clamp((canvas_s - 16) / 16, 0, 1)); for( var i = 1; i < gw; i++ ) { var _xx = cx + i * canvas_s; draw_line(_xx, cy, _xx, cy + pshd); } for( var i = 1; i < gh; i++ ) { var _yy = cy + i * canvas_s; draw_line(cx, _yy - 1, cx + pswd, _yy - 1); } draw_set_alpha(1); } if(PROJECT.previewGrid.show) { var _gw = PROJECT.previewGrid.size[0] * canvas_s; var _gh = PROJECT.previewGrid.size[1] * canvas_s; var gw = pswd / _gw; var gh = pshd / _gh; var cx = canvas_x; var cy = canvas_y; draw_set_color(PROJECT.previewGrid.color); draw_set_alpha(PROJECT.previewGrid.opacity); for( var i = 1; i < gw; i++ ) { var _xx = cx + i * _gw; draw_line(_xx, cy, _xx, cy + pshd); } for( var i = 1; i < gh; i++ ) { var _yy = cy + i * _gh; draw_line(cx, _yy, cx + pswd, _yy); } draw_set_alpha(1); } draw_set_color(COLORS.panel_preview_surface_outline); draw_rectangle(psx, psy, psx + pswd - 1, psy + pshd - 1, true); } #endregion } #endregion function draw3DPolygon(_node) { #region surface_depth_disable(false); _node.previewing = 1; d3_scene_preview = struct_has(_node, "scene")? _node.scene : d3_scene; d3_scene_preview.camera = d3_view_camera; #region view var _pos, targ, _blend = 1; targ = d3_camTarget; _pos = d3d_PolarToCart(targ.x, targ.y, targ.z, d3_view_camera.focus_angle_x, d3_view_camera.focus_angle_y, d3_view_camera.focus_dist); if(d3_active_transition == 1) { var _up = new __vec3(0, 0, -1); d3_view_camera.position._lerp_float(_pos, 5, 0.1); d3_view_camera.focus._lerp_float( targ, 5, 0.1); d3_view_camera.up._lerp_float( _up, 5, 0.1); if(d3_view_camera.position.equal(_pos) && d3_view_camera.focus.equal(targ)) d3_active_transition = 0; } else if(d3_active_transition == -1) { var _pos = new __vec3(0, 0, 8); var targ = new __vec3(0, 0, 0); var _up = new __vec3(0, 1, 0); d3_view_camera.position._lerp_float(_pos, 5, 0.1); d3_view_camera.focus._lerp_float( targ, 5, 0.1); d3_view_camera.up._lerp_float( _up, 5, 0.1); _blend = d3_view_camera.position.distance(_pos) / 2; _blend = clamp(_blend, 0, 1); if(d3_view_camera.position.equal(_pos) && d3_view_camera.focus.equal(targ)) d3_active_transition = 0; } else { d3_view_camera.position.set(_pos); d3_view_camera.focus.set(targ); } d3_view_camera.setViewSize(w, h); d3_view_camera.setMatrix(); #endregion #region background surface_free_safe(d3_surface_bg); if(d3_scene_preview != d3_scene) d3_surface_bg = d3_scene_preview.renderBackground(w, h); #endregion #region shadow if(d3_scene_preview == d3_scene) { d3_scene_light0.shadow_map_scale = d3_view_camera.focus_dist * 2; var _prev_obj = _node.getPreviewObject(); if(_prev_obj != noone) { d3_scene_light0.submitShadow(d3_scene_preview, _prev_obj); _prev_obj.submitShadow(d3_scene_preview, _prev_obj); } } #endregion d3_surface = surface_verify(d3_surface, w, h); d3_surface_normal = surface_verify(d3_surface_normal, w, h); d3_surface_depth = surface_verify(d3_surface_depth, w, h); d3_surface_outline = surface_verify(d3_surface_outline, w, h); #region defer var _prev_obj = _node.getPreviewObject(); if(_prev_obj) d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); #endregion #region grid surface_set_target_ext(0, d3_surface); surface_set_target_ext(1, d3_surface_normal); surface_set_target_ext(2, d3_surface_depth); draw_clear_alpha(bg_color, 0); d3_view_camera.applyCamera(); gpu_set_ztestenable(true); gpu_set_zwriteenable(false); if(OS != os_macosx) { gpu_set_cullmode(cull_noculling); shader_set(sh_d3d_grid_view); var _dist = round(d3_view_camera.focus.distance(d3_view_camera.position)); var _tx = round(d3_view_camera.focus.x); var _ty = round(d3_view_camera.focus.y); var _scale = _dist * 2; while(_scale > 32) _scale /= 2; shader_set_f("axisBlend", _blend); shader_set_f("scale", _scale); shader_set_f("shift", _tx / _dist / 2, _ty / _dist / 2); draw_sprite_stretched(s_fx_pixel, 0, _tx - _dist, _ty - _dist, _dist * 2, _dist * 2); shader_reset(); } gpu_set_zwriteenable(true); #endregion #region draw d3_scene_preview.reset(); gpu_set_cullmode(cull_counterclockwise); var _prev_obj = _node.getPreviewObjects(); if(d3_scene_preview == d3_scene) { if(d3_scene_light_enabled) { d3_scene_preview.addLightDirectional(d3_scene_light0); d3_scene_preview.addLightDirectional(d3_scene_light1); } } for( var i = 0, n = array_length(_prev_obj); i < n; i++ ) { var _prev = _prev_obj[i]; if(_prev == noone) continue; _prev.submitShader(d3_scene_preview); } d3_scene_preview.apply(d3_deferData); for( var i = 0, n = array_length(_prev_obj); i < n; i++ ) { var _prev = _prev_obj[i]; if(_prev == noone) continue; _prev.submitUI(d3_scene_preview); } gpu_set_cullmode(cull_noculling); surface_reset_target(); draw_clear(bg_color); switch(d3_preview_channel) { case 0 : if(d3_scene_preview.draw_background) draw_surface_safe(d3_surface_bg); draw_surface_safe(d3_surface); if(is_struct(d3_deferData)) { BLEND_MULTIPLY draw_surface_safe(d3_deferData.ssao); BLEND_NORMAL } break; case 1 : draw_surface_safe(d3_surface_normal); break; case 2 : draw_surface_safe(d3_surface_depth); break; } #endregion #region outline var inspect_node = PANEL_INSPECTOR.getInspecting(); if(inspect_node && inspect_node.is_3D == NODE_3D.polygon) { var _inspect_obj = inspect_node.getPreviewObjectOutline(); surface_set_target(d3_surface_outline); draw_clear(c_black); d3_scene_preview.camera.applyCamera(); gpu_set_ztestenable(false); for( var i = 0, n = array_length(_inspect_obj); i < n; i++ ) { if(_inspect_obj[i] == noone) continue; _inspect_obj[i].submitSel(d3_scene_preview); } surface_reset_target(); shader_set(sh_d3d_outline); shader_set_dim("dimension", d3_surface_outline); shader_set_color("outlineColor", COLORS._main_accent); draw_surface_safe(d3_surface_outline); shader_reset(); } #endregion d3_scene_preview.camera.resetCamera(); surface_depth_disable(true); } #endregion function draw3DSdf(_node) { #region _node.previewing = 1; var _env = _node.environ; var _obj = _node.object; d3_scene_preview = d3_scene; d3_scene_preview.camera = d3_view_camera; #region view d3_view_camera.fov = max(1, _env.fov * 1.23); var _pos, targ, _blend = 1; targ = d3_camTarget; _pos = d3d_PolarToCart(targ.x, targ.y, targ.z, d3_view_camera.focus_angle_x, d3_view_camera.focus_angle_y, d3_view_camera.focus_dist); if(d3_active_transition == 1) { var _up = new __vec3(0, 0, -1); d3_view_camera.position._lerp_float(_pos, 5, 0.1); d3_view_camera.focus._lerp_float( targ, 5, 0.1); d3_view_camera.up._lerp_float( _up, 5, 0.1); if(d3_view_camera.position.equal(_pos) && d3_view_camera.focus.equal(targ)) d3_active_transition = 0; } else if(d3_active_transition == -1) { var _pos = new __vec3(0, 0, 8); var targ = new __vec3(0, 0, 0); var _up = new __vec3(0, 1, 0); d3_view_camera.position._lerp_float(_pos, 5, 0.1); d3_view_camera.focus._lerp_float( targ, 5, 0.1); d3_view_camera.up._lerp_float( _up, 5, 0.1); _blend = d3_view_camera.position.distance(_pos) / 2; _blend = clamp(_blend, 0, 1); if(d3_view_camera.position.equal(_pos) && d3_view_camera.focus.equal(targ)) d3_active_transition = 0; } else { d3_view_camera.position.set(_pos); d3_view_camera.focus.set(targ); } d3_view_camera.setViewSize(w, h); d3_view_camera.setMatrix(); #endregion draw_clear(bg_color); gpu_set_texfilter(true); shader_set(sh_rm_primitive); var zm = 4 / d3_view_camera.focus_dist; shader_set_f("camRotation", [ d3_view_camera.focus_angle_y, -d3_view_camera.focus_angle_x, 0 ]); shader_set_f("camScale", zm); shader_set_f("camRatio", w / h); shader_set_i("shapeAmount", 0); _env.apply(); if(_obj) _obj.apply(); shader_set_i("drawBg", 0); shader_set_f("depthInt", 0); var _scale = zm / 2; var _step = 1; while(_scale > 32) { _scale /= 2; _step /= 2; } shader_set_i("drawGrid", true); shader_set_f("gridStep", _step); shader_set_f("gridScale", zm / 2); shader_set_f("axisBlend", 1.); shader_set_f("viewRange", [ d3_view_camera.view_near, d3_view_camera.view_far ]); draw_sprite_stretched(s_fx_pixel, 0, 0, 0, w, h); shader_reset(); gpu_set_texfilter(false); } #endregion function draw3D() { #region var _node = getNodePreview(); if(_node == noone) return; switch(_node.is_3D) { case NODE_3D.polygon : draw3DPolygon(_node); break; case NODE_3D.sdf : draw3DSdf(_node); break; } } #endregion function drawPreviewOverlay() { #region right_menu_y = toolbar_height - ui(4); if(show_view_control == 2) { if(d3_active) right_menu_y += ui(72); else right_menu_y += ui(40); } toolbar_draw = false; var _node = getNodePreview(); #region status texts (top right) draw_set_text(f_p2, fa_right, fa_top, COLORS._main_text); var _lh = line_get_height(); if(right_menu_x == 0) right_menu_x = w - ui(8); if(show_info) { if(PANEL_PREVIEW == self) { draw_set_color(COLORS._main_text_accent); draw_text(right_menu_x, right_menu_y, __txt("Active")); right_menu_y += _lh; } var txt = $"{__txt("fps")} {fps}"; if(PREFERENCES.panel_preview_show_real_fps) txt += $" / {FPS_REAL}"; draw_set_color(fps >= PROJECT.animator.framerate? COLORS._main_text_sub : COLORS._main_value_negative); draw_text(right_menu_x, right_menu_y, txt); right_menu_y += _lh; draw_set_color(COLORS._main_text_sub); draw_text(right_menu_x, right_menu_y, $"{__txt("Frame")} {CURRENT_FRAME + 1}/{TOTAL_FRAMES}"); if(!d3_active) { right_menu_y += _lh; draw_text(right_menu_x, right_menu_y, $"x{canvas_s}"); if(pHOVER) { right_menu_y += _lh; var mpx = floor((mx - canvas_x) / canvas_s); var mpy = floor((my - canvas_y) / canvas_s); draw_text(right_menu_x, right_menu_y, $"[{mpx}, {mpy}]"); if(mouse_pos_string != "") { right_menu_y += _lh; draw_text(right_menu_x, right_menu_y, $"{mouse_pos_string}"); } } if(_node != noone) { right_menu_y += _lh; var txt = $"{canvas_w} x {canvas_h}px"; if(canvas_a) txt = $"{canvas_a} x {txt}"; draw_text(right_menu_x, right_menu_y, txt); right_menu_x = w - ui(8); right_menu_y += _lh; } } mouse_pos_string = ""; } right_menu_x = w - ui(8); #endregion var pseq = getNodePreviewSequence(); if(pseq == noone) return; if(!array_equals(pseq, _preview_sequence)) { _preview_sequence = pseq; preview_x = 0; preview_x_to = 0; } var prev_size = ui(48); preview_x = lerp_float(preview_x, preview_x_to, 4); if(pHOVER && my > h - toolbar_height - prev_size - ui(16) && my > toolbar_height) { canvas_hover = false; if(mouse_wheel_down() && !key_mod_press_any()) preview_x_to = clamp(preview_x_to - prev_size * SCROLL_SPEED, - preview_x_max, 0); if(mouse_wheel_up() && !key_mod_press_any()) preview_x_to = clamp(preview_x_to + prev_size * SCROLL_SPEED, - preview_x_max, 0); } #region surface array preview_x_max = 0; if(array_length(pseq) > 1) { var _xx = tool_side_draw_l * ui(40); var xx = _xx + preview_x + ui(8); var yy = h - toolbar_height - prev_size - ui(8); if(my > yy - 8) mouse_on_preview = 0; var hoverable = pHOVER && point_in_rectangle(mx, my, _xx, ui(32), w, h - toolbar_height); for(var i = 0; i < array_length(pseq); i++) { var prev = pseq[i]; if(is_instanceof(prev, __d3dMaterial)) prev = prev.surface; if(!is_surface(prev)) continue; var prev_w = surface_get_width_safe(prev); var prev_h = surface_get_height_safe(prev); var ss = prev_size / max(prev_w, prev_h); var prev_sw = prev_w * ss; draw_set_color(COLORS.panel_preview_surface_outline); draw_rectangle(xx, yy, xx + prev_w * ss, yy + prev_h * ss, true); if(hoverable && point_in_rectangle(mx, my, xx, yy, xx + prev_sw, yy + prev_h * ss)) { if(mouse_press(mb_left, pFOCUS)) { _node.preview_index = i; _node.onValueUpdate(0); if(resetViewOnDoubleClick) do_fullView = true; } draw_surface_ext_safe(prev, xx, yy, ss, ss, 0, c_white, 1); } else { draw_surface_ext_safe(prev, xx, yy, ss, ss, 0, c_white, 0.5); } if(i == _node.preview_index) { draw_set_color(COLORS._main_accent); draw_rectangle(xx, yy, xx + prev_sw, yy + prev_h * ss, true); } xx += prev_sw + ui(8); preview_x_max += prev_sw + ui(8); } } #endregion preview_x_max = max(preview_x_max - ui(100), 0); } #endregion function drawViewController() { if(!show_view_control) return; var _side = show_view_control == 1? 1 : -1; var _view_x = show_view_control == 1? tool_side_draw_l * toolbar_width + ui(8) : w - tool_side_draw_r * toolbar_width - ui(8); var _view_y = topbar_height + ui(8); var _hab = pHOVER && tool_hovering == noone && !view_pan_tool && !view_zoom_tool; view_hovering = false; if(d3_active) { var d3_view_wr = ui(32); var _d3x = _view_x + d3_view_wr * _side; var _d3y = _view_y + d3_view_wr; var _hv = false; if(_hab && point_in_circle(mx, my, _d3x, _d3y, d3_view_wr)) { _hv = true; view_hovering = true; if(mouse_press(mb_left, pFOCUS)) { canvas_drag_key = mb_left; d3_camPanning = true; d3_camPan_mx = mx; d3_camPan_my = my; view_pan_tool = true; } } if(view_pan_tool) _hv = true; draw_circle_ui(_d3x, _d3y, d3_view_wr, _hv? 0 : 0.02, COLORS._main_icon, 0.3); var _qview = new BBMOD_Quaternion().FromEuler(d3_view_camera.focus_angle_y, -d3_view_camera.focus_angle_x, 0); var _as = [ new BBMOD_Vec3(-1, 0, 0), new BBMOD_Vec3(0, 0, 1), new BBMOD_Vec3(0, -1, 0), ]; for(var i = 0; i < 3; i++) { _as[i] = _qview.Rotate(_as[i]); draw_set_color(COLORS.axis[i]); draw_line_round(_d3x, _d3y, _d3x + _as[i].X * (d3_view_wr * 0.75), _d3y + _as[i].Y * (d3_view_wr * 0.75), 3); } var d3_view_wz = ui(16); var _d3x = _view_x + (d3_view_wr * 2 + ui(20)) * _side; var _d3y = _view_y + d3_view_wz; var _hv = false; if(_hab && point_in_circle(mx, my, _d3x, _d3y, d3_view_wz)) { _hv = true; view_hovering = true; if(mouse_press(mb_left, pFOCUS)) { canvas_drag_key = mb_left; canvas_zooming = true; canvas_zoom_m = my; view_zoom_tool = true; } } if(view_zoom_tool) _hv = true; draw_circle_ui(_d3x, _d3y, d3_view_wz, _hv? 0 : 0.04, COLORS._main_icon, 0.3); draw_sprite_ui(THEME.view_zoom, 0, _d3x, _d3y, 1, 1, 0, view_zoom_tool? COLORS._main_accent : COLORS._main_icon, 1); } else { var d3_view_wz = ui(16); var _d3x = _view_x + d3_view_wz * _side; var _d3y = _view_y + d3_view_wz; var _hv = false; if(_hab && point_in_circle(mx, my, _d3x, _d3y, d3_view_wz)) { _hv = true; view_hovering = true; if(mouse_press(mb_left, pFOCUS)) { canvas_drag_key = mb_left; canvas_dragging = true; canvas_drag_mx = mx; canvas_drag_my = my; canvas_drag_sx = canvas_x; canvas_drag_sy = canvas_y; view_pan_tool = true; } } if(view_pan_tool) _hv = true; draw_circle_ui(_d3x, _d3y, d3_view_wz, _hv? 0 : 0.04, COLORS._main_icon, 0.3); draw_sprite_ui(THEME.view_pan, 0, _d3x, _d3y, 1, 1, 0, view_pan_tool? COLORS._main_accent : COLORS._main_icon, 1); _d3x += (d3_view_wz + ui(4) + d3_view_wz) * _side; _d3y = _view_y + d3_view_wz; _hv = false; if(_hab && point_in_circle(mx, my, _d3x, _d3y, d3_view_wz)) { _hv = true; view_hovering = true; if(mouse_press(mb_left, pFOCUS)) { canvas_drag_key = mb_left; canvas_zooming = true; canvas_zoom_mx = w / 2; canvas_zoom_my = h / 2; canvas_zoom_m = my; canvas_zoom_s = canvas_s; view_zoom_tool = true; } } if(view_zoom_tool) _hv = true; draw_circle_ui(_d3x, _d3y, d3_view_wz, _hv? 0 : 0.04, COLORS._main_icon, 0.3); draw_sprite_ui(THEME.view_zoom, 0, _d3x, _d3y, 1, 1, 0, view_zoom_tool? COLORS._main_accent : COLORS._main_icon, 1); } } function drawNodeTools(active, _node) { #region var _mx = mx; var _my = my; var overHover = pHOVER && mouse_on_preview == 1; var tool_size = ui(32); var cx = canvas_x + _node.preview_x * canvas_s; var cy = canvas_y + _node.preview_y * canvas_s; var _snx = 0, _sny = 0; tool_side_draw_l = _node.tools != -1; tool_side_draw_r = _node.rightTools != -1; if(_node.tools != -1 && point_in_rectangle(_mx, _my, 0, 0, toolbar_width, h)) { overHover = false; mouse_on_preview = 0; } overHover &= !view_hovering; overHover &= tool_hovering == noone && !overlay_hovering; overHover &= !(view_pan_tool || view_zoom_tool); overHover &= point_in_rectangle(mx, my, (_node.tools != -1) * toolbar_width, toolbar_height, w, h - toolbar_height); var overActive = active && overHover; var _dragging = key_mod_press(CTRL) && !key_mod_press(SHIFT) && !key_mod_press(ALT); overActive &= !_dragging; var params = { w, h, toolbar_height }; var mouse_free = false; if(_node.is_3D == NODE_3D.none) { if(key_mod_press(CTRL)) { _snx = PROJECT.previewGrid.show? PROJECT.previewGrid.size[0] : 1; _sny = PROJECT.previewGrid.show? PROJECT.previewGrid.size[1] : 1; } else if(PROJECT.previewGrid.snap) { _snx = PROJECT.previewGrid.size[0]; _sny = PROJECT.previewGrid.size[1]; } mouse_free = _node.drawOverlay(overHover, overActive, cx, cy, canvas_s, _mx, _my, _snx, _sny, params); } else { if(key_mod_press(CTRL) || d3_tool_snap) { _snx = d3_tool_snap_position; _sny = d3_tool_snap_rotation; } mouse_free = _node.drawOverlay3D(overActive, d3_scene, _mx, _my, _snx, _sny, params); } #region node overlay overlay_hovering = false; if(_node.drawPreviewToolOverlay(pHOVER, pFOCUS, _mx, _my, { x, y, w, h, toolbar_height, x0: _node.tools == -1? 0 : ui(40), x1: w, y0: toolbar_height - ui(8), y1: h - toolbar_height })) { canvas_hover = false; overlay_hovering = true; } #endregion var _tool = tool_hovering; tool_hovering = noone; if(_node.tools == -1) { tool_current = noone; return; } var aa = d3_active? 0.8 : 1; draw_sprite_stretched_ext(THEME.tool_side, 1, 0, ui(32), toolbar_width, h - toolbar_height - ui(32), c_white, aa); tool_y_max = 0; tool_y = lerp_float(tool_y, tool_y_to, 5); var xx = ui(1) + toolbar_width / 2; var yy = ui(34) + tool_size / 2 + tool_y; var pd = 2; var thov = pHOVER && point_in_rectangle(mx, my, 0, toolbar_height, toolbar_width, h - toolbar_height); if(thov) canvas_hover = false; for(var i = 0; i < array_length(_node.tools); i++) { #region left tools var tool = _node.tools[i]; var _x0 = xx - tool_size / 2; var _y0 = yy - tool_size / 2; var _x1 = xx + tool_size / 2; var _y1 = yy + tool_size / 2; if(tool == -1) { draw_set_color(COLORS._main_icon_dark); draw_line_round(xx + ui(8), _y0 + ui(3), xx - ui(9), _y0 + ui(3), 2); yy += ui(8); tool_y_max += ui(8); continue; } if(thov && point_in_rectangle(_mx, _my, _x0, _y0 + 1, _x1, _y1 - 1)) tool_hovering = tool; if(tool.subtools > 0 && _tool == tool) { #region hovering subtools var s_ww = tool_size * tool.subtools; var s_hh = tool_size; draw_sprite_stretched(THEME.menu_bg, 0, _x0 - pd, _y0 - pd, s_ww + pd * 2, s_hh + pd * 2); var stool = tool.spr; for( var j = 0; j < array_length(stool); j++ ) { var _sxx = xx + j * tool_size; var _syy = yy; var _sx0 = _sxx - tool_size / 2; var _sy0 = _syy - tool_size / 2; var _sx1 = _sxx + tool_size / 2; var _sy1 = _syy + tool_size / 2; if(point_in_rectangle(_mx, _my, _sx0, _sy0 + 1, _sx1, _sy1 - 1)) { TOOLTIP = tool.getDisplayName(j); draw_sprite_stretched(THEME.button_hide, 1, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2); if(mouse_press(mb_left, pFOCUS)) tool.toggle(j); } if(tool_current == tool && tool.selecting == j) { draw_sprite_stretched_ext(THEME.button_hide, 2, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS.panel_preview_grid, 1); draw_sprite_stretched_ext(THEME.button_hide, 3, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS._main_accent, 1); } draw_sprite_colored(stool[j], 0, _sxx, _syy); } if(point_in_rectangle(_mx, _my, _x0, _y0 + 1, _x0 + s_ww, _y1 - 1)) tool_hovering = tool; #endregion } else { #region single tools if(tool_hovering == tool) { draw_sprite_stretched(THEME.button_hide, 1, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2); TOOLTIP = tool.getDisplayName(); if(mouse_press(mb_left, pFOCUS)) tool.toggle(); } if(pFOCUS && WIDGET_CURRENT == noone) { var _key = tool.checkHotkey(); if(keyboard_check_pressed(ord(string(i + 1))) || (_key != noone && _key.isPressing())) tool.toggleKeyboard(); } if(tool_current == tool) { draw_sprite_stretched_ext(THEME.button_hide, 2, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS.panel_preview_grid, 1); draw_sprite_stretched_ext(THEME.button_hide, 3, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS._main_accent, 1); } if(tool.subtools > 0) draw_sprite_colored(tool.spr[tool.selecting], 0, xx, yy); else draw_sprite_colored(tool.spr, 0, xx, yy); #endregion } yy += tool_size; tool_y_max += tool_size; } #endregion var _h = _node.drawTools == noone? 0 : _node.drawTools(_mx, _my, xx, yy - tool_size / 2, tool_size, thov, pFOCUS); yy += _h; tool_y_max += _h; tool_y_max = max(0, tool_y_max - h + toolbar_height * 2); if(thov && !key_mod_press_any()) { if(mouse_wheel_up()) tool_y_to = clamp(tool_y_to + ui(64) * SCROLL_SPEED, -tool_y_max, 0); if(mouse_wheel_down()) tool_y_to = clamp(tool_y_to - ui(64) * SCROLL_SPEED, -tool_y_max, 0); } if(_node.rightTools != -1) { right_menu_x = w - toolbar_width - ui(8); tool_ry_max = 0; tool_ry = lerp_float(tool_ry, tool_ry_to, 5); var _tbx = w - toolbar_width; var xx = _tbx + toolbar_width / 2; var yy = ui(34) + tool_size / 2 + tool_ry; var _sw = -toolbar_width / sprite_get_width(THEME.tool_side); var _sh = h - toolbar_height - ui(32) / sprite_get_height(THEME.tool_side); draw_sprite_ext(THEME.tool_side, 1, w + 1, ui(32), _sw, _sh, 0, c_white, aa); var thov = pHOVER && point_in_rectangle(mx, my, _tbx, toolbar_height, w, h - toolbar_height); if(thov) canvas_hover = false; for(var i = 0; i < array_length(_node.rightTools); i++) { #region right tools var tool = _node.rightTools[i]; var _x0 = xx - tool_size / 2; var _y0 = yy - tool_size / 2; var _x1 = xx + tool_size / 2; var _y1 = yy + tool_size / 2; if(tool == -1) { draw_set_color(COLORS._main_icon_dark); draw_line_round(xx + ui(8), _y0 + ui(3), xx - ui(9), _y0 + ui(3), 2); yy += ui(8); tool_ry_max += ui(8); continue; } if(thov && point_in_rectangle(_mx, _my, _x0, _y0 + 1, _x1, _y1 - 1)) tool_hovering = tool; if(tool.subtools > 0 && _tool == tool) { #region hovering subtools var stool = tool.spr; var s_ww = tool_size * tool.subtools; var s_hh = tool_size; var tx = _x0 - s_ww + tool_size; draw_sprite_stretched(THEME.menu_bg, 0, tx - pd, _y0 - pd, s_ww + pd * 2, s_hh + pd * 2); var _am = array_length(stool); for( var j = 0; j < _am; j++ ) { var _sind = _am - 1 - j; var _sxx = tx + j * tool_size + tool_size / 2; var _syy = yy; var _sx0 = _sxx - tool_size / 2; var _sy0 = _syy - tool_size / 2; var _sx1 = _sxx + tool_size / 2; var _sy1 = _syy + tool_size / 2; draw_sprite_colored(stool[_sind], 0, _sxx, _syy); if(point_in_rectangle(_mx, _my, _sx0, _sy0 + 1, _sx1, _sy1 - 1)) { TOOLTIP = tool.getDisplayName(_sind); draw_sprite_stretched(THEME.button_hide, 1, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2); if(mouse_press(mb_left, pFOCUS)) tool.toggle(_sind); } if(tool_current == tool && tool.selecting == _sind) { draw_sprite_stretched_ext(THEME.button_hide, 2, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS.panel_preview_grid, 1); draw_sprite_stretched_ext(THEME.button_hide, 3, _sx0 + pd, _sy0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS._main_accent, 1); } } if(point_in_rectangle(_mx, _my, tx, _y0 + 1, tx + s_ww, _y1 - 1)) tool_hovering = tool; #endregion } else { #region single tools if(tool_hovering == tool) { draw_sprite_stretched(THEME.button_hide, 1, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2); TOOLTIP = tool.getDisplayName(); if(mouse_press(mb_left, pFOCUS)) tool.toggle(); } if(pFOCUS && WIDGET_CURRENT == noone) { var _key = tool.checkHotkey(); if(keyboard_check_pressed(ord(string(i + 1))) || (_key != noone && _key.isPressing())) tool.toggleKeyboard(); } if(tool_current == tool) { draw_sprite_stretched_ext(THEME.button_hide, 2, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS.panel_preview_grid, 1); draw_sprite_stretched_ext(THEME.button_hide, 3, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS._main_accent, 1); } if(tool.subtools > 0) draw_sprite_colored(tool.spr[tool.selecting], 0, xx, yy); else draw_sprite_colored(tool.spr, 0, xx, yy); #endregion } yy += tool_size; tool_ry_max += tool_size; } #endregion tool_ry_max = max(0, tool_ry_max - h + toolbar_height * 2); if(thov && !key_mod_press_any()) { if(mouse_wheel_up()) tool_ry_to = clamp(tool_ry_to + ui(64) * SCROLL_SPEED, -tool_ry_max, 0); if(mouse_wheel_down()) tool_ry_to = clamp(tool_ry_to - ui(64) * SCROLL_SPEED, -tool_ry_max, 0); } } } #endregion function drawToolBar(_tool) { #region var ty = h - toolbar_height; var aa = d3_active? 0.8 : 1; draw_sprite_stretched_ext(THEME.toolbar, 1, 0, 0, w, topbar_height, c_white, aa); draw_sprite_stretched_ext(THEME.toolbar, 0, 0, ty, w, toolbar_height, c_white, aa); if(_tool && tool_current != noone) { #region tool settings var settings = array_merge(_tool.getToolSettings(), tool_current.settings); tool_x = lerp_float(tool_x, tool_x_to, 5); var tolx = tool_x + ui(8); var toly = ui(8); var tolw = ui(48); var tolh = toolbar_height - ui(20); var tol_max_w = ui(16); for( var i = 0, n = array_length(settings); i < n; i++ ) { var sett = settings[i]; var nme = sett[0]; var wdg = sett[1]; var key = sett[2]; var atr = sett[3]; if(nme != "") { tolx += ui(8) + bool(i == 0) * ui(8); tol_max_w += ui(8) + bool(i == 0) * ui(8); } draw_set_text(f_p2, fa_left, fa_center, COLORS._main_text_sub); if(nme != "") { draw_text(tolx, toolbar_height / 2 - ui(2), nme); tolx += string_width(nme) + ui(8); tol_max_w += string_width(nme) + ui(8); } wdg.setFocusHover(pFOCUS, pHOVER); var _tool_font = f_p3; switch(instanceof(wdg)) { case "textBox" : tolw = ui(40); if(wdg.side_button != noone) tolw += tolh + ui(8); break; case "buttonGroup": case "checkBoxGroup" : tolw = tolh * wdg.size; break; case "checkBox" : tolw = tolh; break; case "scrollBox" : tolw = ui(96); _tool_font = f_p2; break; case "buttonClass" : tolw = wdg.text == ""? tolh : tolw; break; } var params = new widgetParam(tolx, toly, tolw, tolh, atr[$ key],, [ mx, my ]) params.s = tolh; params.font = _tool_font; wdg.drawParam(params); tolx += tolw + ui(8); tol_max_w += tolw + ui(8); } tol_max_w = max(0, tol_max_w - w); if(point_in_rectangle(mx, my, 0, 0, w, toolbar_height) && !key_mod_press_any()) { if(mouse_wheel_up()) tool_x_to = clamp(tool_x_to + ui(64) * SCROLL_SPEED, -tol_max_w, 0); if(mouse_wheel_down()) tool_x_to = clamp(tool_x_to - ui(64) * SCROLL_SPEED, -tol_max_w, 0); } #endregion } else { #region color sampler var cx = ui(8); var cy = ui(8); var cw = ui(32); var ch = topbar_height - ui(16); if(sample_color != noone) { draw_set_color(sample_color); draw_set_alpha(1); draw_rectangle(cx, cy, cx + cw, cy + ch, false); } draw_set_color(COLORS.panel_toolbar_outline); draw_rectangle(cx, cy, cx + cw, cy + ch, true); if(sample_color != noone) { var tx = cx + cw + ui(16); var hx = color_get_hex(sample_color); draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text); draw_text(tx, cy + ch / 2, hx); tx += string_width(hx) + ui(8); draw_set_color(COLORS._main_text_sub); draw_text(tx, cy + ch / 2, $"({color_get_alpha(sample_color)})"); } #endregion } var tbx = toolbar_height / 2; var tby = ty + toolbar_height / 2; var _toolbars = d3_active? toolbars_3d : toolbars; for( var i = 0, n = array_length(_toolbars); i < n; i++ ) { var tb = _toolbars[i]; var tbSpr = tb[0]; var tbInd = tb[1](); var tbTooltip = tb[2](); var tbActive = tb[3]; var b = buttonInstant(THEME.button_hide, tbx - ui(14), tby - ui(14), ui(28), ui(28), [mx, my], pFOCUS, pHOVER, tbTooltip, tbSpr, tbInd); if(b == 2) tbActive( { x: x + tbx - ui(14), y: y + tby - ui(14) } ); tbx += ui(32); } tbx = w - toolbar_height / 2; for( var i = 0, n = array_length(actions); i < n; i++ ) { var tb = actions[i]; var tbSpr = tb[0]; var tbTooltip = tb[1]; var tbIndex = tb[3](); var b = buttonInstant(THEME.button_hide, tbx - ui(14), tby - ui(14), ui(28), ui(28), [mx, my], pFOCUS, pHOVER, tbTooltip, tbSpr, tbIndex); if(b == 2) tb[2]( { x: x + tbx - ui(14), y: y + tby - ui(14) } ); tbx -= ui(32); } draw_set_color(COLORS.panel_toolbar_separator); draw_line_width(tbx + ui(12), tby - toolbar_height / 2 + ui(8), tbx + ui(12), tby + toolbar_height / 2 - ui(8), 2); if(d3_active) drawNodeChannel3D(tbx, tby); else drawNodeChannel(tbx, tby); } #endregion function drawSplitView() { #region if(splitView == 0) return; draw_set_color(COLORS.panel_preview_split_line); if(splitViewDragging) { if(splitView == 1) { var cx = splitViewStart + (mx - splitViewMouse); splitPosition = clamp(cx / w, .1, .9); } else if(splitView == 2) { var cy = splitViewStart + (my - splitViewMouse); splitPosition = clamp(cy / h, .1, .9); } if(mouse_release(mb_left)) splitViewDragging = false; } if(splitView == 1) { var sx = w * splitPosition; if(mouse_on_preview && point_in_rectangle(mx, my, sx - ui(4), 0, sx + ui(4), h)) { draw_line_width(sx, 0, sx, h, 2); if(mouse_press(mb_left, pFOCUS)) { splitViewDragging = true; splitViewStart = sx; splitViewMouse = mx; } } else draw_line_width(sx, 0, sx, h, 1); draw_sprite_ui_uniform(THEME.icon_active_split, 0, splitSelection? sx + ui(16) : sx - ui(16), toolbar_height + ui(16),, COLORS._main_accent); if(mouse_on_preview && mouse_press(mb_left, pFOCUS)) { if(point_in_rectangle(mx, my, 0, 0, sx, h)) splitSelection = 0; else if(point_in_rectangle(mx, my, sx, 0, w, h)) splitSelection = 1; } } else { var sy = h * splitPosition; if(mouse_on_preview && point_in_rectangle(mx, my, 0, sy - ui(4), w, sy + ui(4))) { draw_line_width(0, sy, w, sy, 2); if(mouse_press(mb_left, pFOCUS)) { splitViewDragging = true; splitViewStart = sy; splitViewMouse = my; } } else draw_line_width(0, sy, w, sy, 1); draw_sprite_ui_uniform(THEME.icon_active_split, 0, ui(16), splitSelection? sy + ui(16) : sy - ui(16),, COLORS._main_accent); if(mouse_on_preview && mouse_press(mb_left, pFOCUS)) { if(point_in_rectangle(mx, my, 0, 0, w, sy)) splitSelection = 0; else if(point_in_rectangle(mx, my, 0, sy, w, h)) splitSelection = 1; } } } #endregion function drawContent(panel) { #region >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MAIN DRAW <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< mouse_on_preview = pHOVER && point_in_rectangle(mx, my, 0, topbar_height, w, h - toolbar_height); if(do_fullView) run_in(1, fullView); do_fullView = false; var _prev_node = getNodePreview(); d3_active = _prev_node != noone && _prev_node.is_3D != NODE_3D.none; bg_color = lerp_color(bg_color, d3_active? COLORS.panel_3d_bg : COLORS.panel_bg_clear, 0.3); draw_clear(bg_color); if(canvas_bg == -1) { if(canvas_s >= 0.1) draw_sprite_tiled_ext(s_transparent, 0, canvas_x, canvas_y, canvas_s, canvas_s, COLORS.panel_preview_transparent, 1); } else draw_clear(canvas_bg); draw_set_color(COLORS._main_icon_dark); draw_line_width(canvas_x, 0, canvas_x, h, 1); draw_line_width(0, canvas_y, w, canvas_y, 1); title = __txt("Preview"); getPreviewData(); if(_prev_node) { if(d3_active) { dragCanvas3D(); draw3D(); } else { dragCanvas(); drawNodePreview(); } } else dragCanvas(); drawPreviewOverlay(); var inspect_node = PANEL_INSPECTOR.getInspecting(); var tool = noone; drawViewController(); tool_side_draw_l = false; tool_side_draw_r = false; if(PANEL_PREVIEW == self) { if(inspect_node) { tool = inspect_node.getTool(); if(tool) drawNodeTools(pFOCUS, tool); } else tool_current = noone; } if(!d3_active) drawSplitView(); drawToolBar(tool); if(mouse_on_preview && mouse_press(mb_right, pFOCUS) && !key_mod_press(SHIFT)) { menuCall("preview_context_menu",,, [ menuItem(__txtx("panel_graph_preview_window", "Send to preview window"), function() { create_preview_window(getNodePreview()); }, noone, ["Preview", "Preview window"]), -1, menuItem(__txtx("panel_preview_save", "Save current preview as") + "...", function() { saveCurrentFrame(); }, noone, ["Preview", "Save current frame"]), menuItem(__txtx("panel_preview_save_all", "Save all current previews as") + "...", function() { saveAllCurrentFrames(); }, noone, ["Preview", "Save all current frame"]), -1, menuItem($"{__txtx("panel_preview_copy_image", "Copy image")}", function() { copyCurrentFrame(); }, THEME.copy), menuItem($"{__txtx("panel_preview_copy_color", "Copy color")} [{sample_color}]", function() { clipboard_set_text(sample_color); }), menuItem($"{__txtx("panel_preview_copy_hex", "Copy hex")} [{color_get_hex(sample_color)}]", function() { clipboard_set_text(color_get_hex(sample_color)); }), ],, getNodePreview()); } ////////////////////////////////// File drop ////////////////////////////////// if(pHOVER) { var _node = getNodePreview(); if(_node && _node.dropPath != noone) { if(DRAGGING && DRAGGING.type == "Asset") { draw_sprite_stretched_ext(THEME.ui_panel_selection, 0, 8, 8, w - 16, h - 16, COLORS._main_value_positive, 1); if(mouse_release(mb_left)) _node.dropPath(DRAGGING.data.path); } if(FILE_IS_DROPPING) draw_sprite_stretched_ext(THEME.ui_panel_selection, 0, 8, 8, w - 16, h - 16, COLORS._main_value_positive, 1); if(FILE_DROPPED && !array_empty(FILE_DROPPING)) _node.dropPath(FILE_DROPPING[0]); } } } #endregion ////=========== ACTION =========== function copyCurrentFrame() { #region var prevS = getNodePreviewSurface(); if(!is_surface(prevS)) return; var buff = buffer_create(surface_get_width_safe(prevS) * surface_get_height_safe(prevS) * 4, buffer_fixed, 1); var s = surface_create(surface_get_width_safe(prevS), surface_get_height_safe(prevS)); surface_set_target(s); shader_set(sh_BGR); draw_surface_safe(prevS); shader_reset(); surface_reset_target(); buffer_get_surface(buff, s, 0); surface_free(s); clipboard_set_bitmap(buffer_get_address(buff), surface_get_width_safe(prevS), surface_get_height_safe(prevS)); } #endregion function saveCurrentFrameToFocus() { #region var prevS = getNodePreviewSurface(); if(!is_surface(prevS)) return; if(!is_struct(PANEL_FILE)) return; var _fileO = PANEL_FILE.file_focus; if(_fileO == noone) return; var path = _fileO.path; if(path == "") return; if(filename_ext(path) != ".png") path += ".png"; surface_save_safe(prevS, path); _fileO.refreshThumbnail(); } #endregion function saveCurrentFrame() { #region var prevS = getNodePreviewSurface(); var _node = getNodePreview(); if(_node == noone) return; if(!is_surface(prevS)) return; var path = get_save_filename_pxc("image|*.png;*.jpg", _node.display_name == ""? "export" : _node.display_name, "Save surface as"); key_release(); if(path == "") return; if(filename_ext(path) != ".png") path += ".png"; surface_save_safe(prevS, path); } #endregion function saveAllCurrentFrames() { #region var _node = getNodePreview(); if(_node == noone) return; var path = get_save_filename_pxc("image|*.png;*.jpg", _node.display_name == ""? "export" : _node.display_name, "Save surfaces as"); key_release(); if(path == "") return; var ext = ".png"; var name = string_replace_all(path, ext, ""); var ind = 0; var pseq = getNodePreviewSequence(); for(var i = 0; i < array_length(pseq); i++) { var prev = pseq[i]; if(!is_surface(prev)) continue; var _name = name + string(ind) + ext; surface_save_safe(prev, _name); ind++; } } #endregion //// =========== Serialize =========== static serialize = function() { return { name: instanceof(self), preview_node : [ node_get_id(preview_node[0]), node_get_id(preview_node[1]) ], canvas_x, canvas_y, canvas_s, locked, }; } static deserialize = function(data) { if(struct_has(data, "preview_node")) preview_node = [ node_from_id(data.preview_node[0]), node_from_id(data.preview_node[1]) ]; canvas_x = struct_try_get(data, "canvas_x", canvas_x); canvas_y = struct_try_get(data, "canvas_y", canvas_y); canvas_s = struct_try_get(data, "canvas_s", canvas_s); locked = struct_try_get(data, "locked", locked); run_in(1, fullView) return self; } }