1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.panels.viewport; 8 import creator.viewport; 9 import creator.widgets; 10 import creator.core; 11 import creator.core.colorbleed; 12 import creator.panels; 13 import creator.actions; 14 import creator; 15 import inochi2d; 16 import inochi2d.core.dbg; 17 import bindbc.imgui; 18 import std.string; 19 import i18n; 20 21 /** 22 A viewport 23 */ 24 class ViewportPanel : Panel { 25 private: 26 ImVec2 lastSize; 27 bool actingInViewport; 28 29 protected: 30 override 31 void onBeginUpdate() { 32 33 ImGuiWindowClass wmclass; 34 wmclass.DockNodeFlagsOverrideSet = ImGuiDockNodeFlagsI.NoTabBar; 35 igSetNextWindowClass(&wmclass); 36 igPushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(1, 2)); 37 igSetNextWindowDockID(incGetViewportDockSpace(), ImGuiCond.Always); 38 super.onBeginUpdate(); 39 } 40 41 override void onEndUpdate() { 42 super.onEndUpdate(); 43 igPopStyleVar(); 44 } 45 46 override 47 void onUpdate() { 48 49 auto io = igGetIO(); 50 auto camera = inGetCamera(); 51 52 // Draw viewport itself 53 ImVec2 currSize; 54 igGetContentRegionAvail(&currSize); 55 56 // We do not want the viewport to be NaN 57 // That will crash the app 58 if (currSize.x.isNaN || currSize.y.isNaN) { 59 currSize = ImVec2(0, 0); 60 } 61 62 // Resize Inochi2D viewport according to frame 63 // Also viewport of 0 is too small, minimum 128. 64 currSize = ImVec2(clamp(currSize.x, 128, float.max), clamp(currSize.y, 128, float.max)); 65 66 67 igBeginChild("##ViewportView", ImVec2(0, -30)); 68 igGetContentRegionAvail(&currSize); 69 currSize = ImVec2( 70 clamp(currSize.x, 128, float.max), 71 clamp(currSize.y, 128, float.max)-4 72 ); 73 74 if (currSize != lastSize) { 75 inSetViewport(cast(int)currSize.x, cast(int)currSize.y); 76 } 77 78 incViewportPoll(); 79 80 // Ignore events within child windows *unless* drag started within 81 // viewport. 82 ImGuiHoveredFlags winFlags = ImGuiHoveredFlags.None; 83 if (actingInViewport) winFlags |= ImGuiHoveredFlags.ChildWindows | ImGuiHoveredFlags.AllowWhenBlockedByActiveItem; 84 if (igIsWindowHovered(winFlags)) { 85 actingInViewport = igIsMouseDown(ImGuiMouseButton.Left) || 86 igIsMouseDown(ImGuiMouseButton.Middle) || 87 igIsMouseDown(ImGuiMouseButton.Right); 88 incViewportUpdate(); 89 } 90 91 auto style = igGetStyle(); 92 inSetClearColor(style.Colors[ImGuiCol.WindowBg].x, style.Colors[ImGuiCol.WindowBg].y, style.Colors[ImGuiCol.WindowBg].z, 1); 93 incViewportDraw(); 94 95 int width, height; 96 inGetViewport(width, height); 97 98 // Render our viewport 99 ImVec2 sPos; 100 ImVec2 sPosA; 101 igGetCursorScreenPos(&sPos); 102 103 igImage( 104 cast(void*)inGetRenderImage(), 105 ImVec2(width, height), 106 ImVec2(0, 1), 107 ImVec2(1, 0), 108 ImVec4(1, 1, 1, 1), ImVec4(0, 0, 0, 0) 109 ); 110 igGetCursorScreenPos(&sPosA); 111 112 // Render our fancy in-viewport buttons 113 igSetCursorScreenPos(ImVec2(sPos.x+8, sPos.y+8)); 114 igSetItemAllowOverlap(); 115 116 igPushStyleVar(ImGuiStyleVar.FrameRounding, 0); 117 igBeginChild("##ViewportMainControls", ImVec2(128, 28 * incGetUIScale())); 118 igPushStyleVar_Vec2(ImGuiStyleVar.FramePadding, ImVec2(6, 6)); 119 incViewportDrawOverlay(); 120 igPopStyleVar(); 121 igEndChild(); 122 igPopStyleVar(); 123 124 igSetCursorScreenPos(sPosA); 125 126 lastSize = currSize; 127 igEndChild(); 128 129 130 // FILE DRAG & DROP 131 if (igBeginDragDropTarget()) { 132 ImGuiPayload* payload = igAcceptDragDropPayload("__PARTS_DROP"); 133 if (payload !is null) { 134 string[] files = *cast(string[]*)payload.Data; 135 import std.path : baseName, extension; 136 import std.uni : toLower; 137 mainLoop: foreach(file; files) { 138 string fname = file.baseName; 139 140 switch(fname.extension.toLower) { 141 case ".png", ".tga", ".jpeg", ".jpg": 142 143 auto tex = new ShallowTexture(file); 144 incColorBleedPixels(tex); 145 inTexPremultiply(tex.data); 146 incAddChildWithHistory( 147 inCreateSimplePart(*tex, null, fname), 148 incSelectedNode(), 149 fname 150 ); 151 152 // We've added new stuff, rescan nodes 153 incActivePuppet().rescanNodes(); 154 155 foreach(Part part; incActivePuppet().getRootParts()) { 156 import std.stdio : writeln; 157 debug writeln(part); 158 } 159 break; 160 161 // Allow dragging PSD in to main window 162 case ".psd": 163 incImportPSD(file); 164 break mainLoop; 165 166 default: break; 167 } 168 } 169 170 // Finish the file drag 171 incFinishFileDrag(); 172 } 173 174 igEndDragDropTarget(); 175 } 176 177 // BOTTOM VIEWPORT CONTROLS 178 igGetContentRegionAvail(&currSize); 179 igBeginChild("##ViewportControls", ImVec2(0, currSize.y), false, flags.NoScrollbar); 180 igPushItemWidth(72); 181 igSpacing(); 182 igSameLine(0, 8); 183 if (igSliderFloat( 184 "##Zoom", 185 &incViewportZoom, 186 incVIEWPORT_ZOOM_MIN, 187 incVIEWPORT_ZOOM_MAX, 188 "%s%%\0".format(cast(int)(incViewportZoom*100)).ptr, 189 ImGuiSliderFlags.NoRoundToFormat) 190 ) { 191 camera.scale = vec2(incViewportZoom); 192 incViewportTargetZoom = incViewportZoom; 193 } 194 if (incViewportTargetZoom != 1) { 195 igPushFont(incIconFont()); 196 igSameLine(0, 8); 197 if (igButton("", ImVec2(0, 0))) { 198 incViewportTargetZoom = 1; 199 } 200 igPopFont(); 201 } 202 igSameLine(0, 8); 203 igSeparatorEx(ImGuiSeparatorFlags.Vertical); 204 205 igSameLine(0, 8); 206 igText("x = %.2f y = %.2f", incViewportTargetPosition.x, incViewportTargetPosition.y); 207 if (incViewportTargetPosition != vec2(0)) { 208 igSameLine(0, 8); 209 igPushFont(incIconFont()); 210 if (igButton("##2", ImVec2(0, 0))) { 211 incViewportTargetPosition = vec2(0, 0); 212 } 213 igPopFont(); 214 } 215 216 217 igPopItemWidth(); 218 igEndChild(); 219 220 // Handle smooth move 221 incViewportZoom = dampen(incViewportZoom, incViewportTargetZoom, deltaTime, 1); 222 camera.scale = vec2(incViewportZoom, incViewportZoom); 223 camera.position = vec2(dampen(camera.position, incViewportTargetPosition, deltaTime, 1.5)); 224 } 225 226 public: 227 this() { 228 super("Viewport", _("Viewport"), true); 229 this.alwaysVisible = true; 230 } 231 232 } 233 234 mixin incPanel!ViewportPanel;