Drag cards out into columns, and columns among and into columns
The user wants to drag a card out between columns to make a new column, and to drag columns to reorder them or put them inside other columns. Their pick for where: the row of titles, the gaps between columns and the space past the last one are among the columns. Something dragged there becomes a column, before the column under the mouse on its left half and after it on its right half, after the one to the left in a gap. Anywhere else it goes into the column under the mouse by the card rules, so a column dragged down into another one becomes a card, its own cards its block. A column's title no longer means "its first card"; the top half of its first card does that. The root's column stays first and can't be dragged (the user's pick): it says so. The board holds still around a drag. Besides the kept widths, the room a dragged column took stays empty while it isn't a column (Drag.room): without it, the columns to its right slid left under the mouse each time it stopped being one, and the card landed a column too far. Dropping it back in that room makes it that column again. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
38eca3c8c3
commit
09f8b048d6
4 files changed
+210
-34
No files matched your search
@@ -362,13 +362,22 @@ lines.
|
|||||||
at its end; a column's own node trades places with the column beside
|
at its end; a column's own node trades places with the column beside
|
||||||
(the root's stays first). Enter is done, one undo step. Every move goes
|
(the root's stays first). Enter is done, one undo step. Every move goes
|
||||||
through the tree.
|
through the tree.
|
||||||
- A drag moves the card live, as the canvas does (the user's pick): it goes
|
- A drag moves a card, or a column by its title, live, as the canvas does
|
||||||
through the board as the mouse goes, by the row the mouse is on in the
|
(the user's pick); the whole drag is one undo step. The row of titles,
|
||||||
column under it. On a card's top half it goes before that card; on its
|
the gaps between columns and the space past the last one are among the
|
||||||
|
columns (the user's pick): there it becomes a column, before the column
|
||||||
|
under the mouse on its left half, after it on its right half, after the
|
||||||
|
one to the left in a gap. Anywhere else it goes into the column under
|
||||||
|
the mouse, as a card, by the row: on a card's top half before it; on its
|
||||||
bottom half after it, or into its block as the first card; on a block's
|
bottom half after it, or into its block as the first card; on a block's
|
||||||
foot, after the block; on a column's title, first; below the cards,
|
foot, after the block; below the cards, last. So a card dragged out
|
||||||
last. The whole drag is one undo step. The columns keep their widths
|
becomes a column, and a column dragged into another one becomes a card,
|
||||||
while a card is dragged, so the one under the mouse stays put.
|
its cards its block. The root's column stays first and can't be dragged
|
||||||
|
(the user's pick: it's the document's root).
|
||||||
|
- The board holds still around a drag: the columns keep the widths they
|
||||||
|
had, and the room a dragged column took stays empty while it isn't one
|
||||||
|
(dropping it there makes it that column again). Otherwise the columns
|
||||||
|
beside would slide under the mouse, and the card would chase them.
|
||||||
- In visual mode the board selects in reading order, as the outline does.
|
- In visual mode the board selects in reading order, as the outline does.
|
||||||
|
|
||||||
**Views, panes and popups** (settled in stage 7)
|
**Views, panes and popups** (settled in stage 7)
|
||||||
@@ -568,9 +577,11 @@ pans up and down, and sideways with a wheel that tilts, a touchpad, or the
|
|||||||
wheel with Shift or Alt held (Alt for terminals that keep Shift for selecting
|
wheel with Shift or Alt held (Alt for terminals that keep Shift for selecting
|
||||||
text), Ctrl+drag selects a rectangle, Ctrl+click adds or removes one node,
|
text), Ctrl+drag selects a rectangle, Ctrl+click adds or removes one node,
|
||||||
right-click opens a menu built from the same actions as the keys. Zoom is on
|
right-click opens a menu built from the same actions as the keys. Zoom is on
|
||||||
the `+` and `-` keys. On the board, dragging a card moves it through the
|
the `+` and `-` keys. On the board, dragging a card, or a column by its
|
||||||
tree as the mouse goes: before or after the card under it (by which half),
|
title, moves it through the tree as the mouse goes: before or after the
|
||||||
into a block, out at its foot, or to a column's top or end.
|
card under it (by which half), into a block, out at its foot, to a
|
||||||
|
column's end, or among the columns (on the titles' row or in a gap) as a
|
||||||
|
column of its own.
|
||||||
|
|
||||||
## Modes and keys
|
## Modes and keys
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ The plan for the everyday keys (all of them are in DESIGN.md):
|
|||||||
| `<Space>o` | this branch out, into a document of its own, with a portal in its place (`:branchout`) |
|
| `<Space>o` | this branch out, into a document of its own, with a portal in its place (`:branchout`) |
|
||||||
| Enter or `gf` `gu` | through a portal / up to the portals that lead here |
|
| Enter or `gf` `gu` | through a portal / up to the portals that lead here |
|
||||||
| `<Space>` | the action menu: `c` color, `t` tags, `b` documents, `i` inbox, `vo` outline, `vn` note, `vb` board… |
|
| `<Space>` | the action menu: `c` color, `t` tags, `b` documents, `i` inbox, `vo` outline, `vn` note, `vb` board… |
|
||||||
| board | `<Space>vb` or `:board`: a column per node without a parent, its children as cards, a card with children wrapping them as Scratch's loop blocks do; `j` `k` cards, `h` `l` columns, `M` then `hjkl` (or a drag) moves a card |
|
| board | `<Space>vb` or `:board`: a column per node without a parent, its children as cards, a card with children wrapping them as Scratch's loop blocks do; `j` `k` cards, `h` `l` columns, `M` then `hjkl` (or a drag) moves a card; drag a card onto the titles' row or into a gap to make it a column, and a column by its title to reorder it or put it in another column |
|
||||||
| `Ctrl-w v` `Ctrl-w s` | split the pane side by side / stacked (`Ctrl-w hjkl` to move between them) |
|
| `Ctrl-w v` `Ctrl-w s` | split the pane side by side / stacked (`Ctrl-w hjkl` to move between them) |
|
||||||
| `gt` `gT` | the next / previous document |
|
| `gt` `gT` | the next / previous document |
|
||||||
| `:` `?` | command line, help (search it with `/`, Enter runs the key or command) |
|
| `:` `?` | command line, help (search it with `/`, Enter runs the key or command) |
|
||||||
|
|||||||
+111
-5
@@ -165,11 +165,92 @@ fn a_dragged_card_goes_into_blocks_out_of_them_and_onto_columns() {
|
|||||||
drag_to(&mut h, kitchen, (col, row + 2));
|
drag_to(&mut h, kitchen, (col, row + 2));
|
||||||
assert_eq!(h.children("Watering"), ["Rain barrel", "Drip line"]);
|
assert_eq!(h.children("Watering"), ["Rain barrel", "Drip line"]);
|
||||||
assert_eq!(h.children("Garden plans").last().map(String::as_str), Some("Kitchen"));
|
assert_eq!(h.children("Garden plans").last().map(String::as_str), Some("Kitchen"));
|
||||||
// A column's title: its first card.
|
// Below a column's cards: its last card.
|
||||||
let compost = h.find("ask about compost");
|
let (col, row) = h.find("Basil");
|
||||||
drag_to(&mut h, kitchen, compost);
|
drag_to(&mut h, kitchen, (col, row + 3));
|
||||||
let_go(&mut h, compost);
|
let_go(&mut h, (col, row + 3));
|
||||||
assert_eq!(h.children("ask about compost"), ["Kitchen"]);
|
assert_eq!(h.children("Seeds to order"), ["Tomatoes", "Basil", "Kitchen"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The titles of the columns, left to right.
|
||||||
|
fn columns(h: &Harness) -> Vec<String> {
|
||||||
|
h.doc().top_level().map(|id| h.title(id)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cells on the left and the right half of a column's title row (its top
|
||||||
|
/// border), found by the corner its title follows (`╭`, `┌`, `┏`).
|
||||||
|
fn title_halves(h: &Harness, corner_and_title: &str) -> ((u16, u16), (u16, u16)) {
|
||||||
|
let (col, row) = h.find(corner_and_title);
|
||||||
|
let cells: Vec<char> = h.rows()[usize::from(row)].chars().collect();
|
||||||
|
let end = (usize::from(col) + 1..cells.len()).find(|&at| matches!(cells[at], '╮' | '┐' | '┓')).unwrap();
|
||||||
|
((col + 1, row), (u16::try_from(end).unwrap() - 1, row))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_card_dragged_among_the_columns_is_a_column_of_its_own() {
|
||||||
|
let mut h = Harness::new();
|
||||||
|
h.type_keys("<Space>vb");
|
||||||
|
// Past the last column: the last column.
|
||||||
|
let tomatoes = pick_up(&mut h, "Tomatoes");
|
||||||
|
let (_, row) = h.find("Tomatoes");
|
||||||
|
let past = (h.rows()[0].chars().count() as u16 - 4, row + 2);
|
||||||
|
drag_to(&mut h, tomatoes, past);
|
||||||
|
let_go(&mut h, past);
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "Seeds to order", "ask about compost", "Tomatoes"]);
|
||||||
|
assert!(h.screen().contains("┏ Tomatoes "), "a column, with the cursor:\n{}", h.screen());
|
||||||
|
// Onto the right half of a column's title: a column after it.
|
||||||
|
let soil = pick_up(&mut h, "Soil");
|
||||||
|
let (_, right) = title_halves(&h, "┌ Seeds to order");
|
||||||
|
drag_to(&mut h, soil, right);
|
||||||
|
let_go(&mut h, right);
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "Seeds to order", "Soil", "ask about compost", "Tomatoes"]);
|
||||||
|
// Into the gap between two columns: a column between them.
|
||||||
|
let basil = pick_up(&mut h, "Basil");
|
||||||
|
let (col, row) = h.find("┌ Seeds to order");
|
||||||
|
drag_to(&mut h, basil, (col - 1, row + 4));
|
||||||
|
let_go(&mut h, (col - 1, row + 4));
|
||||||
|
assert_eq!(
|
||||||
|
columns(&h),
|
||||||
|
["Garden plans", "Basil", "Seeds to order", "Soil", "ask about compost", "Tomatoes"]
|
||||||
|
);
|
||||||
|
assert!(h.children("Seeds to order").is_empty());
|
||||||
|
h.type_keys("u");
|
||||||
|
assert_eq!(h.children("Seeds to order"), ["Basil"], "one drag, one undo step");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_column_is_dragged_by_its_title_among_and_into_columns() {
|
||||||
|
let mut h = Harness::new();
|
||||||
|
h.type_keys("<Space>vb");
|
||||||
|
// Onto the left half of another column's title: before it.
|
||||||
|
let (compost, _) = title_halves(&h, "┌ ask about compost");
|
||||||
|
let at = Cell { col: compost.0, row: compost.1 };
|
||||||
|
h.mouse(Gesture::Press { at, ctrl: false });
|
||||||
|
let (left, _) = title_halves(&h, "┌ Seeds to order");
|
||||||
|
drag_to(&mut h, at, left);
|
||||||
|
let_go(&mut h, left);
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "ask about compost", "Seeds to order"]);
|
||||||
|
// Down into another column's cards: a card there, its cards its block.
|
||||||
|
let (seeds, _) = title_halves(&h, "┌ Seeds to order");
|
||||||
|
let at = Cell { col: seeds.0, row: seeds.1 };
|
||||||
|
h.mouse(Gesture::Press { at, ctrl: false });
|
||||||
|
let watering = bottom_half(&h, "Watering");
|
||||||
|
drag_to(&mut h, at, watering);
|
||||||
|
let_go(&mut h, watering);
|
||||||
|
assert_eq!(h.children("Watering"), ["Seeds to order", "Rain barrel", "Drip line"]);
|
||||||
|
assert_eq!(h.children("Seeds to order"), ["Tomatoes", "Basil"]);
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "ask about compost"]);
|
||||||
|
let (col, row) = h.find("Seeds to order");
|
||||||
|
assert_eq!(h.rows()[usize::from(row) + 1].chars().nth(usize::from(col) - 2), Some('┣'), "a block now");
|
||||||
|
// The root's column stays where it is.
|
||||||
|
let (root, _) = title_halves(&h, "╭ Garden plans");
|
||||||
|
let at = Cell { col: root.0, row: root.1 };
|
||||||
|
h.mouse(Gesture::Press { at, ctrl: false });
|
||||||
|
let (_, right) = title_halves(&h, "┌ ask about compost");
|
||||||
|
drag_to(&mut h, at, right);
|
||||||
|
let_go(&mut h, right);
|
||||||
|
assert_eq!(h.message(), "the root's column stays first");
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "ask about compost"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -186,3 +267,28 @@ fn cards_are_typed_in_and_selected_in_reading_order() {
|
|||||||
h.type_keys("d");
|
h.type_keys("d");
|
||||||
assert_eq!(h.message(), "deleted 3 nodes · u to undo");
|
assert_eq!(h.message(), "deleted 3 nodes · u to undo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_columns_hold_still_under_a_drag() {
|
||||||
|
let mut h = Harness::new();
|
||||||
|
h.type_keys("<Space>vb");
|
||||||
|
// Through the gap: Soil is a column for now, and Seeds moves over.
|
||||||
|
let soil = pick_up(&mut h, "Soil");
|
||||||
|
let (col, row) = h.find("┌ Seeds to order");
|
||||||
|
drag_to(&mut h, soil, (col - 1, row + 4));
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "Soil", "Seeds to order", "ask about compost"]);
|
||||||
|
let seeds = h.find("┌ Seeds to order");
|
||||||
|
// On into Seeds: the room Soil's column took stays empty, so Seeds
|
||||||
|
// stays under the mouse instead of sliding away from it.
|
||||||
|
let tomatoes = bottom_half(&h, "Tomatoes");
|
||||||
|
drag_to(&mut h, soil, tomatoes);
|
||||||
|
assert_eq!(h.children("Seeds to order"), ["Tomatoes", "Soil", "Basil"]);
|
||||||
|
assert_eq!(h.find("┌ Seeds to order"), seeds, "Seeds held still:\n{}", h.screen());
|
||||||
|
// Back into that room: a column there again.
|
||||||
|
drag_to(&mut h, soil, (col + 2, row + 4));
|
||||||
|
assert_eq!(columns(&h), ["Garden plans", "Soil", "Seeds to order", "ask about compost"]);
|
||||||
|
let_go(&mut h, (col + 2, row + 4));
|
||||||
|
assert_eq!(h.find("┏ Soil ").0, col, "where the room was:\n{}", h.screen());
|
||||||
|
h.type_keys("u");
|
||||||
|
assert_eq!(h.children("Garden plans")[0], "Soil", "one undo step");
|
||||||
|
}
|
||||||
+78
-19
@@ -28,9 +28,10 @@
|
|||||||
//! column beside. In move mode (`M`) the card moves instead (the user's
|
//! column beside. In move mode (`M`) the card moves instead (the user's
|
||||||
//! pick): `h` and `l` take it to the end of the column beside (a column
|
//! pick): `h` and `l` take it to the end of the column beside (a column
|
||||||
//! itself trades places with it), `j` and `k` past the cards around it,
|
//! itself trades places with it), `j` and `k` past the cards around it,
|
||||||
//! into and out of the blocks. A drag moves it live, as the canvas does
|
//! into and out of the blocks. A drag moves a card, or a column by its
|
||||||
//! (the user's pick). Every move goes through the tree, so every other view
|
//! title, live, as the canvas does (the user's pick): dragged among the
|
||||||
//! follows.
|
//! columns it becomes one, dragged into a column it becomes a card. Every
|
||||||
|
//! move goes through the tree, so every other view follows.
|
||||||
|
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
@@ -110,15 +111,26 @@ struct Editing {
|
|||||||
at: (i32, i32),
|
at: (i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A card being dragged. It moves through the board as the mouse goes, all
|
/// A card or column being dragged. It moves through the board as the mouse
|
||||||
/// one undo step, and the columns keep at least the widths they had when
|
/// goes, all one undo step, and the board holds still around it: the
|
||||||
/// it was picked up: when a card left a column and it narrowed, the columns
|
/// columns keep at least the widths they had when it was picked up, and
|
||||||
/// beside would slide under the mouse, and the card would chase them.
|
/// when it stops being a column, the room its column took stays empty.
|
||||||
|
/// Otherwise the columns beside would slide under the mouse each time, and
|
||||||
|
/// the card would chase them.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Drag {
|
struct Drag {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
group: Group,
|
group: Group,
|
||||||
widths: Vec<(NodeId, i32)>,
|
widths: Vec<(NodeId, i32)>,
|
||||||
|
/// The room it took the last time it was a column.
|
||||||
|
room: Option<Room>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Where a column was, and how wide: after which column.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Room {
|
||||||
|
after: NodeId,
|
||||||
|
width: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The board view.
|
/// The board view.
|
||||||
@@ -151,6 +163,11 @@ impl BoardView {
|
|||||||
(self.columns, self.cards, self.editing) = (Vec::new(), Vec::new(), None);
|
(self.columns, self.cards, self.editing) = (Vec::new(), Vec::new(), None);
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
let mut bottom = 0;
|
let mut bottom = 0;
|
||||||
|
// While a drag goes on: the room it took as a column, kept empty
|
||||||
|
// while it isn't one, and found again while it is.
|
||||||
|
let dragged = self.drag.as_ref().map(|drag| (drag.id, doc.parent(drag.id).is_none()));
|
||||||
|
let mut room = self.drag.as_ref().and_then(|drag| drag.room);
|
||||||
|
let mut previous = None;
|
||||||
for top in doc.top_level() {
|
for top in doc.top_level() {
|
||||||
let Some(node) = doc.node(top) else { continue };
|
let Some(node) = doc.node(top) else { continue };
|
||||||
let first_card = self.cards.len();
|
let first_card = self.cards.len();
|
||||||
@@ -175,6 +192,17 @@ impl BoardView {
|
|||||||
self.columns.push(Column { id: top, rect, order, title: lines.join(" "), tags, badge });
|
self.columns.push(Column { id: top, rect, order, title: lines.join(" "), tags, badge });
|
||||||
bottom = bottom.max(height);
|
bottom = bottom.max(height);
|
||||||
x += width + GAP;
|
x += width + GAP;
|
||||||
|
match (dragged, room) {
|
||||||
|
(Some((id, true)), _) if id == top => {
|
||||||
|
room = previous.map(|after| Room { after, width });
|
||||||
|
}
|
||||||
|
(Some((_, false)), Some(empty)) if empty.after == top => x += empty.width + GAP,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
previous = Some(top);
|
||||||
|
}
|
||||||
|
if let Some(drag) = &mut self.drag {
|
||||||
|
drag.room = room;
|
||||||
}
|
}
|
||||||
self.size = (x, bottom);
|
self.size = (x, bottom);
|
||||||
}
|
}
|
||||||
@@ -396,17 +424,44 @@ impl BoardView {
|
|||||||
Some(vec![Action::edit_in(EditOp::MoveTo { id, spot }, grab.group)])
|
Some(vec![Action::edit_in(EditOp::MoveTo { id, spot }, grab.group)])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where the `dragged` card goes with the mouse on a board cell. It goes
|
/// Where the `dragged` card or column goes with the mouse on a board
|
||||||
/// by the row, in the column the mouse is over: on a card's top half,
|
/// cell. The row of titles, the gaps and the space past the last column
|
||||||
/// before it; on its bottom half, after it, or into its block as the
|
/// are among the columns (the user's pick): there it becomes a column
|
||||||
/// first card; on a block's foot, after the block; on the column's
|
/// itself. Anywhere else it goes into the column under the mouse, as a
|
||||||
/// title, first; below its cards, last. Nowhere over the card itself or
|
/// card.
|
||||||
/// its own cards, so a card that's caught up with the mouse stays put.
|
|
||||||
fn drop_spot(&self, doc: &Document, dragged: NodeId, (x, y): (i32, i32)) -> Option<Spot> {
|
fn drop_spot(&self, doc: &Document, dragged: NodeId, (x, y): (i32, i32)) -> Option<Spot> {
|
||||||
let column =
|
let column =
|
||||||
self.columns.iter().find(|column| (column.rect.left()..column.rect.right()).contains(&x))?;
|
self.columns.iter().find(|column| (column.rect.left()..column.rect.right()).contains(&x));
|
||||||
if y <= column.rect.top() {
|
match column {
|
||||||
return Some(Spot::FirstChildOf(column.id));
|
Some(column) if y > column.rect.top() => self.in_column(doc, dragged, column, y),
|
||||||
|
_ => self.among_columns(doc, x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Among the columns: before the column under the mouse on its left
|
||||||
|
/// half, after it on its right half, and in a gap or past the last
|
||||||
|
/// column, after the one to its left. Nothing goes before the root's
|
||||||
|
/// column, so its left half counts as its right.
|
||||||
|
fn among_columns(&self, doc: &Document, x: i32) -> Option<Spot> {
|
||||||
|
let column = self.columns.iter().rev().find(|column| column.rect.left() <= x)?;
|
||||||
|
let rect = column.rect;
|
||||||
|
let left_half = x < rect.right() && (x - rect.left()) * 2 < i32::from(rect.size.width);
|
||||||
|
Some(if left_half && column.id != doc.root() {
|
||||||
|
Spot::Before(column.id)
|
||||||
|
} else {
|
||||||
|
Spot::After(column.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Into a column, by the row: on a card's top half, before it; on its
|
||||||
|
/// bottom half, after it, or into its block as the first card; on a
|
||||||
|
/// block's foot, after the block; below the cards, last. Nowhere over
|
||||||
|
/// what's dragged itself or its own cards (a whole column, when it's a
|
||||||
|
/// column that's dragged), so a card that's caught up with the mouse
|
||||||
|
/// stays put.
|
||||||
|
fn in_column(&self, doc: &Document, dragged: NodeId, column: &Column, y: i32) -> Option<Spot> {
|
||||||
|
if column.id == dragged {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
for card in self.cards.iter().filter(|card| column.order.contains(&card.id)) {
|
for card in self.cards.iter().filter(|card| column.order.contains(&card.id)) {
|
||||||
let its_own = card.id == dragged || doc.is_inside(card.id, dragged);
|
let its_own = card.id == dragged || doc.is_inside(card.id, dragged);
|
||||||
@@ -709,20 +764,24 @@ impl View for BoardView {
|
|||||||
if ctrl {
|
if ctrl {
|
||||||
return vec![Action::App(AppAction::ToggleSelected(id))];
|
return vec![Action::App(AppAction::ToggleSelected(id))];
|
||||||
}
|
}
|
||||||
// Cards can be dragged; in connect mode a click only aims.
|
// Cards and columns can be dragged; in connect mode a click
|
||||||
if matches!(target, Target::Card(_)) && !matches!(ctx.mode, Mode::Connect(_)) {
|
// only aims.
|
||||||
|
if !matches!(ctx.mode, Mode::Connect(_)) {
|
||||||
let widths = self
|
let widths = self
|
||||||
.columns
|
.columns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|column| (column.id, i32::from(column.rect.size.width)))
|
.map(|column| (column.id, i32::from(column.rect.size.width)))
|
||||||
.collect();
|
.collect();
|
||||||
self.drag = Some(Drag { id, group: Group::new(), widths });
|
self.drag = Some(Drag { id, group: Group::new(), widths, room: None });
|
||||||
}
|
}
|
||||||
actions.push(Action::cursor(id));
|
actions.push(Action::cursor(id));
|
||||||
actions
|
actions
|
||||||
}
|
}
|
||||||
Gesture::Drag { at, .. } => {
|
Gesture::Drag { at, .. } => {
|
||||||
let (Some(drag), Some(at)) = (&self.drag, self.local(at)) else { return Vec::new() };
|
let (Some(drag), Some(at)) = (&self.drag, self.local(at)) else { return Vec::new() };
|
||||||
|
if drag.id == ctx.doc.root() {
|
||||||
|
return vec![Action::say(Message::info("the root's column stays first"))];
|
||||||
|
}
|
||||||
match self.drop_spot(ctx.doc, drag.id, at) {
|
match self.drop_spot(ctx.doc, drag.id, at) {
|
||||||
Some(spot) if !stays(ctx.doc, drag.id, spot) => {
|
Some(spot) if !stays(ctx.doc, drag.id, spot) => {
|
||||||
vec![Action::edit_in(EditOp::MoveTo { id: drag.id, spot }, drag.group)]
|
vec![Action::edit_in(EditOp::MoveTo { id: drag.id, spot }, drag.group)]
|
||||||
|
|||||||
Reference in new issue
Block a user