Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/electron.renderer/EditorTypes.hx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum GlobalEvent {
LevelRestoredFromHistory(level:data.Level);
LevelJsonCacheInvalidated(level:data.Level);

WorldLevelSelectionChanged;
WorldLevelMoved(level:data.Level, isFinal:Bool, prevNeighbourIids:Null<Array<String>>);
WorldSettingsChanged;
WorldCreated(w:data.World);
Expand Down Expand Up @@ -309,4 +310,4 @@ enum DebugFlag {
F_MainDebug;
F_IntGridUseCounts;
F_ProjectImgCache;
}
}
160 changes: 141 additions & 19 deletions src/electron.renderer/WorldTool.hx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ class WorldTool extends dn.Process {
var origin : Coords;
var clicked = false;
var dragStarted = false;
var boxSelecting = false;
var activeDragLevels : Array<data.Level> = [];
var dragOriginXs : Map<Int,Int> = new Map();
var dragOriginYs : Map<Int,Int> = new Map();
var dragInitialNeighbours : Map<Int,Array<String>> = new Map();
var worldMode(get,never) : Bool; inline function get_worldMode() return editor.worldMode;

var tmpRender : h2d.Graphics;
Expand Down Expand Up @@ -156,6 +161,11 @@ class WorldTool extends dn.Process {
origin = m;
initialNeighbours = null;
dragStarted = false;
boxSelecting = false;
activeDragLevels = [];
dragOriginXs = new Map();
dragOriginYs = new Map();
dragInitialNeighbours = new Map();
clicked = true;
if( !worldMode && editor.curLevel.inBoundsWorld(m.worldX,m.worldY) )
clickedLevel = null;
Expand All @@ -166,30 +176,51 @@ class WorldTool extends dn.Process {
clickedLevel = null;

if( clickedLevel!=null ) {
if( worldMode && App.ME.isCtrlCmdDown() && !App.ME.isAltDown() ) {
editor.toggleWorldLevelSelection(clickedLevel);
clickedLevel = null;
clicked = false;
ev.cancel = true;
return;
}

levelOriginX = clickedLevel.worldX;
levelOriginY = clickedLevel.worldY;
ev.cancel = true;
clickedSameLevel = editor.curLevel==clickedLevel;
initialNeighbours = clickedLevel.getNeighboursIids();

// Pick level
editor.selectLevel(clickedLevel);
if( worldMode && editor.isWorldLevelSelected(clickedLevel) && editor.countWorldLevelSelection()>1 )
editor.selectLevel(clickedLevel, false, true);
else if( worldMode )
editor.replaceWorldLevelSelection([clickedLevel], clickedLevel);
else
editor.selectLevel(clickedLevel);
}
}

public function onMouseUp(m:Coords) {
tmpRender.clear();

if( boxSelecting ) {
var selected = getLevelsInSelectionBox(m);
if( App.ME.isCtrlCmdDown() )
editor.toggleWorldLevelsInSelection(selected);
else
editor.replaceWorldLevelSelection(selected);
}
else if( clicked && clickedLevel==null && worldMode && !App.ME.isCtrlCmdDown() && origin.getPageDist(m)<=getDragThreshold() )
editor.clearWorldLevelSelection();

if( clickedLevel!=null ) {
if( dragStarted ) {
// Drag complete
var initialX = clickedLevel.worldX;
var initialY = clickedLevel.worldY;

switch curWorld.worldLayout {
case Free, GridVania:
curWorld.applyAutoLevelIdentifiers();
editor.ge.emit( WorldLevelMoved(clickedLevel, true, initialNeighbours) );
for(l in activeDragLevels)
editor.ge.emit( WorldLevelMoved(l, true, dragInitialNeighbours.get(l.uid)) );

case LinearHorizontal:
var i = ui.vp.LevelSpotPicker.getLinearInsertPoint(project, curWorld, m, clickedLevel, levelOriginX);
Expand Down Expand Up @@ -227,14 +258,29 @@ class WorldTool extends dn.Process {
// Cleanup
clickedLevel = null;
dragStarted = false;
boxSelecting = false;
activeDragLevels = [];
dragOriginXs = new Map();
dragOriginYs = new Map();
dragInitialNeighbours = new Map();
clicked = false;
}

inline function getLevelSnapDist() return App.ME.isShiftDown() || App.ME.isCtrlCmdDown() ? 0 : project.getSmartLevelGridSize() / ( editor.camera.adjustedZoom * 0.4 );

function willOverlapAnyDraggedLevel(cur:data.Level, newWorldX:Int, newWorldY:Int) {
for(l in curWorld.levels) {
if( l==cur || activeDragLevels.contains(l) )
continue;
if( dn.Lib.rectangleOverlaps(newWorldX, newWorldY, cur.pxWid, cur.pxHei, l.worldX, l.worldY, l.pxWid, l.pxHei) )
return true;
}
return false;
}

inline function snapLevelX(cur:data.Level, offset:Int, at:Int) {
if( M.fabs(cur.worldX + offset - at) <= getLevelSnapDist() ) {
if( cur.willOverlapAnyLevel(at-offset, cur.worldY) )
if( willOverlapAnyDraggedLevel(cur, at-offset, cur.worldY) )
return false;
else {
cur.worldX = at-offset;
Expand All @@ -247,7 +293,7 @@ class WorldTool extends dn.Process {

inline function snapLevelY(l:data.Level, offset:Int, with:Int) {
if( M.fabs(l.worldY + offset - with) <= getLevelSnapDist() ) {
if( l.willOverlapAnyLevel(l.worldX, with-offset) )
if( willOverlapAnyDraggedLevel(l, l.worldX, with-offset) )
return false;
else {
l.worldY = with-offset;
Expand Down Expand Up @@ -294,19 +340,50 @@ class WorldTool extends dn.Process {
}
if( allow ) {
dragStarted = true;
boxSelecting = clickedLevel==null;
ev.cancel = true;
// if( clickedLevel!=null )
// editor.selectLevel(clickedLevel);

if( clickedLevel!=null && App.ME.isAltDown() && App.ME.isCtrlCmdDown() ) {
var copy = curWorld.duplicateLevel(clickedLevel);
editor.ge.emit( LevelAdded(copy) );
editor.selectLevel(copy);
editor.replaceWorldLevelSelection([copy], copy);
clickedLevel = copy;
}

activeDragLevels = [];
if( clickedLevel!=null ) {
var canMoveGroup = switch curWorld.worldLayout {
case Free, GridVania: true;
case LinearHorizontal, LinearVertical: false;
}
if( canMoveGroup && editor.isWorldLevelSelected(clickedLevel) && editor.countWorldLevelSelection()>1 )
activeDragLevels = editor.getWorldLevelSelection();
else
activeDragLevels = [clickedLevel];

dragOriginXs = new Map();
dragOriginYs = new Map();
dragInitialNeighbours = new Map();
for(l in activeDragLevels) {
dragOriginXs.set(l.uid, l.worldX);
dragOriginYs.set(l.uid, l.worldY);
dragInitialNeighbours.set(l.uid, l.getNeighboursIids());
}
levelOriginX = dragOriginXs.get(clickedLevel.uid);
levelOriginY = dragOriginYs.get(clickedLevel.uid);
}
}
}

if( boxSelecting && dragStarted ) {
renderSelectionBox(m);
App.ME.requestCpu();
ev.cancel = true;
return;
}

// Drag
if( clickedLevel!=null && dragStarted ) {
// Init tmpRender render
Expand All @@ -326,8 +403,6 @@ class WorldTool extends dn.Process {
case LinearHorizontal: false;
case LinearVertical: true;
}
var initialX = clickedLevel.worldX;
var initialY = clickedLevel.worldY;
if( allowX )
clickedLevel.worldX = levelOriginX + ( m.worldX - origin.worldX );
else
Expand All @@ -349,7 +424,7 @@ class WorldTool extends dn.Process {

// Snap to other levels
for(l in curWorld.levels) {
if( l==clickedLevel )
if( l==clickedLevel || activeDragLevels.contains(l) )
continue;

if( clickedLevel.getBoundsDist(l) > getLevelSnapDist() )
Expand Down Expand Up @@ -393,21 +468,68 @@ class WorldTool extends dn.Process {
tmpRender.lineTo(i.coord, curWorld.getWorldHeight(clickedLevel)+100);
}

case LinearVertical:
var i = ui.vp.LevelSpotPicker.getLinearInsertPoint(project, curWorld, m, clickedLevel, levelOriginY);
if( i!=null ) {
tmpRender.moveTo(-100, i.coord);
tmpRender.lineTo(curWorld.getWorldWidth(clickedLevel)+100, i.coord);
}
case LinearVertical:
var i = ui.vp.LevelSpotPicker.getLinearInsertPoint(project, curWorld, m, clickedLevel, levelOriginY);
if( i!=null ) {
tmpRender.moveTo(-100, i.coord);
tmpRender.lineTo(curWorld.getWorldWidth(clickedLevel)+100, i.coord);
}
}

var moveDx = clickedLevel.worldX - dragOriginXs.get(clickedLevel.uid);
var moveDy = clickedLevel.worldY - dragOriginYs.get(clickedLevel.uid);
if( activeDragLevels.length>1 ) {
for(l in activeDragLevels) {
if( l==clickedLevel )
continue;
l.worldX = dragOriginXs.get(l.uid) + moveDx;
l.worldY = dragOriginYs.get(l.uid) + moveDy;
}
}

// Refresh render
editor.ge.emit( WorldLevelMoved(clickedLevel, false, null) );
for(l in activeDragLevels)
editor.ge.emit( WorldLevelMoved(l, false, null) );
App.ME.requestCpu();
ev.cancel = true;
}
}

function getSelectionBox(m:Coords) {
var left = M.imin(origin.worldX, m.worldX);
var top = M.imin(origin.worldY, m.worldY);
var right = M.imax(origin.worldX, m.worldX);
var bottom = M.imax(origin.worldY, m.worldY);
return {
x: left,
y: top,
wid: right-left,
hei: bottom-top,
};
}

function renderSelectionBox(m:Coords) {
var r = getSelectionBox(m);
tmpRender.clear();
tmpRender.lineStyle(2/editor.camera.adjustedZoom, 0x72feff, 0.8);
tmpRender.beginFill(0x72feff, 0.12);
tmpRender.drawRect(r.x, r.y, r.wid, r.hei);
tmpRender.endFill();
}

function getLevelsInSelectionBox(m:Coords) {
var r = getSelectionBox(m);
var out : Array<data.Level> = [];
if( r.wid<=0 || r.hei<=0 )
return out;

for(l in curWorld.levels)
if( l.worldDepth==editor.curWorldDepth && dn.Lib.rectangleOverlaps(r.x, r.y, r.wid, r.hei, l.worldX, l.worldY, l.pxWid, l.pxHei) )
out.push(l);

return out;
}

function getLevelAt(worldX:Int, worldY:Int, ?except:data.Level) {
var i = curWorld.levels.length-1;
var l : data.Level = null;
Expand All @@ -421,4 +543,4 @@ class WorldTool extends dn.Process {

return null;
}
}
}
2 changes: 2 additions & 0 deletions src/electron.renderer/display/LevelRender.hx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class LevelRender extends dn.Process {
updateGridPos();
invalidateGrid();

case WorldLevelSelectionChanged:

case ProjectSaved, BeforeProjectSaving:

case ProjectSelected:
Expand Down
15 changes: 13 additions & 2 deletions src/electron.renderer/display/WorldRender.hx
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ class WorldRender extends dn.Process {
}
}

case WorldLevelSelectionChanged:
for(l in curWorld.levels)
getWorldLevel(l).boundsInvalidated = true;

case ProjectSaved:
invalidateAllLevelFields();
invalidateAllLevelIdentifiers();
Expand Down Expand Up @@ -995,10 +999,12 @@ class WorldRender extends dn.Process {
var wl = getWorldLevel(l);
if( wl!=null ) {
wl.outline.clear();
if( !settings.v.showDetails )
var isCur = l==editor.curLevel;
var isSelected = editor.isWorldLevelSelected(l);
if( !settings.v.showDetails && !isSelected )
return;

var thick = (l==editor.curLevel?3:2)*camera.pixelRatio / camera.adjustedZoom;
var thick = (isCur?3:2)*camera.pixelRatio / camera.adjustedZoom;
var c : dn.Col = l.getSmartColor(false);

var error = l.getFirstError();
Expand All @@ -1007,6 +1013,11 @@ class WorldRender extends dn.Process {
c = 0xff0000;
}

if( isSelected && !isCur && error==NoError ) {
thick = 3*camera.pixelRatio / camera.adjustedZoom;
c = 0x72feff;
}

var pad = 1;
wl.outline.beginFill(c);
wl.outline.drawRect(pad, pad, l.pxWid-pad*2, thick); // top
Expand Down
Loading