@@ -487,6 +487,7 @@ impl MonitorView { |
| 487 | 487 | } |
| 488 | 488 | |
| 489 | 489 | /// Find the nearest position that makes the rect adjacent to another monitor. |
| 490 | + /// Clamps perpendicular coordinate to ensure overlap (adjacency). |
| 490 | 491 | fn find_nearest_adjacent_position(&self, dragged_idx: usize, dragged: Rect) -> Option<Rect> { |
| 491 | 492 | let mut best: Option<(Rect, i32)> = None; |
| 492 | 493 | |
@@ -499,27 +500,39 @@ impl MonitorView { |
| 499 | 500 | let r_right = r.x + r.width as i32; |
| 500 | 501 | let r_bottom = r.y + r.height as i32; |
| 501 | 502 | |
| 502 | | - // Try 4 adjacent positions, preserving the perpendicular coordinate |
| 503 | + // For horizontal adjacency, clamp y to ensure vertical overlap |
| 504 | + // Valid y range: (r.y - dragged.height + 1) to (r_bottom - 1) |
| 505 | + let clamped_y = dragged.y.clamp( |
| 506 | + r.y - dragged.height as i32 + 1, |
| 507 | + r_bottom - 1, |
| 508 | + ); |
| 509 | + |
| 510 | + // For vertical adjacency, clamp x to ensure horizontal overlap |
| 511 | + // Valid x range: (r.x - dragged.width + 1) to (r_right - 1) |
| 512 | + let clamped_x = dragged.x.clamp( |
| 513 | + r.x - dragged.width as i32 + 1, |
| 514 | + r_right - 1, |
| 515 | + ); |
| 516 | + |
| 517 | + // Try 4 adjacent positions with clamped perpendicular coordinates |
| 503 | 518 | let candidates = [ |
| 504 | | - // Right of other (preserve y) |
| 505 | | - Rect::new(r_right, dragged.y, dragged.width, dragged.height), |
| 506 | | - // Left of other (preserve y) |
| 507 | | - Rect::new(r.x - dragged.width as i32, dragged.y, dragged.width, dragged.height), |
| 508 | | - // Below other (preserve x) |
| 509 | | - Rect::new(dragged.x, r_bottom, dragged.width, dragged.height), |
| 510 | | - // Above other (preserve x) |
| 511 | | - Rect::new(dragged.x, r.y - dragged.height as i32, dragged.width, dragged.height), |
| 519 | + // Right of other (clamped y for vertical overlap) |
| 520 | + Rect::new(r_right, clamped_y, dragged.width, dragged.height), |
| 521 | + // Left of other (clamped y for vertical overlap) |
| 522 | + Rect::new(r.x - dragged.width as i32, clamped_y, dragged.width, dragged.height), |
| 523 | + // Below other (clamped x for horizontal overlap) |
| 524 | + Rect::new(clamped_x, r_bottom, dragged.width, dragged.height), |
| 525 | + // Above other (clamped x for horizontal overlap) |
| 526 | + Rect::new(clamped_x, r.y - dragged.height as i32, dragged.width, dragged.height), |
| 512 | 527 | ]; |
| 513 | 528 | |
| 514 | 529 | for candidate in candidates { |
| 515 | | - // Must be adjacent and not overlap |
| 516 | | - if !Self::rects_adjacent(candidate, r) { |
| 517 | | - continue; |
| 518 | | - } |
| 530 | + // Skip if would overlap with another monitor |
| 519 | 531 | if self.would_overlap(candidate, dragged_idx) { |
| 520 | 532 | continue; |
| 521 | 533 | } |
| 522 | 534 | |
| 535 | + // Calculate distance from original drop position |
| 523 | 536 | let dist = (candidate.x - dragged.x).abs() + (candidate.y - dragged.y).abs(); |
| 524 | 537 | if best.map_or(true, |(_, d)| dist < d) { |
| 525 | 538 | best = Some((candidate, dist)); |