mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 22:21:59 +00:00
Recolor Artwork: the Prominent Colors bar keeps the Edit tab's height
- With art, the bar is 10 pt tall and the Edit tab leaves out the gaps above the wheel and above the sliders. The dialog is as tall on the Edit tab as on the Assign tab, and all of it but the color chips fits a 1024 by 576 screen. - recolor.weigh counts a use for the first row that is not excluded when an excluded row lists the same color first.
This commit is contained in:
@@ -70,7 +70,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Prominent Colors",
|
||||
[],
|
||||
None,
|
||||
"{map: rows [{from, to, …}] or {current: new} as recolor.apply, weights?: [numbers ≥ 0, one per row; an excluded row's is ignored, and at least one other must be above 0], ids?: as recolor.colors} → {map: the rows as given, each with its current colours (from) moved as below, shares: [one per row: its percent of the uses (recolor.colors' count) of the current colours of the rows that aren't excluded; 0 for an excluded row]} for Recolor Artwork's Prominent Colors (VectorCraft's own rule): without weights the rows stay as they are. With weights, current colours move one at a time between the rows that aren't excluded and have a new colour (to), while a move brings each row's share of the uses nearer its share of the weights, first the colour nearest in Lab to the first colour of the row it goes to compared with the row it leaves; a row's first colour stays in it, the tints of one global swatch in a row move together, a colour that another row with a new colour lists first stays where it is, the other rows with a new colour drop their entries for a colour that moves, and a use counts for the row recolor.apply recolors it with (rows with a new colour first, an exact colour before a hex one, the first row that lists it), else for the first other row that lists it. The colours that can move are compared with the rows at most 50,000,000 times in all, and when they times the rows that aren't excluded pass that, none move. Changes nothing",
|
||||
"{map: rows [{from, to, …}] or {current: new} as recolor.apply, weights?: [numbers ≥ 0, one per row; an excluded row's is ignored, and at least one other must be above 0], ids?: as recolor.colors} → {map: the rows as given, each with its current colours (from) moved as below, shares: [one per row: its percent of the uses (recolor.colors' count) of the current colours of the rows that aren't excluded; 0 for an excluded row]} for Recolor Artwork's Prominent Colors (VectorCraft's own rule): without weights the rows stay as they are. With weights, current colours move one at a time between the rows that aren't excluded and have a new colour (to), while a move brings each row's share of the uses nearer its share of the weights, first the colour nearest in Lab to the first colour of the row it goes to compared with the row it leaves; a row's first colour stays in it, the tints of one global swatch in a row move together, a colour that another row with a new colour lists first stays where it is, the other rows with a new colour drop their entries for a colour that moves, and a use counts for the row recolor.apply recolors it with (rows with a new colour first, an exact colour before a hex one, the first row that lists it), else for the first other row that isn't excluded and lists it. The colours that can move are compared with the rows at most 50,000,000 times in all, and when they times the rows that aren't excluded pass that, none move. Changes nothing",
|
||||
has_doc,
|
||||
weigh
|
||||
),
|
||||
@@ -1126,14 +1126,14 @@ fn weigh(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
// Each current colour's uses and global swatch. A use counts where recolor.apply recolors it:
|
||||
// rows with a new colour first, exact colours before hex colours, the first row that lists it;
|
||||
// then the other rows, in the same way. `owner` holds the row and entry that took each colour,
|
||||
// then the other rows that aren't excluded, in the same way. `owner` holds the row and entry that took each colour,
|
||||
// and `shadows` the entries of rows with a new colour whose colours other entries took.
|
||||
let mut owner: Vec<Option<(usize, usize)>> = vec![None; used.len()];
|
||||
let mut shadows: Vec<(usize, usize, Vec<usize>)> = vec![];
|
||||
let mut found: Vec<Vec<(usize, Option<String>)>> = rows.iter().map(|r| vec![(0, None); r.from.len()]).collect();
|
||||
for recolors in [true, false] {
|
||||
for hex in [false, true] {
|
||||
for (r, row) in rows.iter().enumerate().filter(|(_, r)| r.new_color().is_some() == recolors) {
|
||||
for (r, row) in rows.iter().enumerate().filter(|(_, r)| !r.exclude && r.new_color().is_some() == recolors) {
|
||||
for (e, m) in row.from.iter().enumerate().filter(|(_, m)| matches!(m, Match::Hex(_)) == hex) {
|
||||
let hits: Vec<usize> = match m {
|
||||
Match::Key(k) => by_key.get(k).copied().into_iter().collect(),
|
||||
|
||||
@@ -1375,6 +1375,9 @@ fn weigh_gives_each_rows_share_of_the_uses() {
|
||||
// An excluded row has no share, and the others share the uses.
|
||||
let excl = json!([{"from": [RED, PURPLE], "to": null}, {"from": [BLUE], "to": null, "exclude": true}]);
|
||||
assert_eq!(run(&mut s, "recolor.weigh", json!({"map": excl}))["shares"], json!([100.0, 0.0]));
|
||||
// An excluded row before another that lists the same colour doesn't take its uses.
|
||||
let first = json!([{"from": [RED], "exclude": true}, {"from": [RED]}, {"from": [BLUE, PURPLE]}]);
|
||||
assert_eq!(run(&mut s, "recolor.weigh", json!({"map": first}))["shares"], json!([0.0, 50.0, 50.0]));
|
||||
// A current colour that no art uses counts nothing, and a use counts for the first row only.
|
||||
let twice = json!({"map": [{"from": [RED, "#123456"]}, {"from": [RED, PURPLE, BLUE]}]});
|
||||
assert_eq!(run(&mut s, "recolor.weigh", twice)["shares"], json!([50.0, 50.0]));
|
||||
|
||||
@@ -88,6 +88,9 @@ const WHEEL: f32 = 220.0;
|
||||
/// Height of the Edit tab's color bars area (the wheel with its Brightness slider), and of a bar.
|
||||
const BARS_H: f32 = WHEEL + 31.0;
|
||||
const BAR_H: f32 = 22.0;
|
||||
/// Without the Prominent Colors bar, the Edit tab's gaps above the wheel and above the sliders.
|
||||
const WHEEL_GAP: f32 = 8.0;
|
||||
const SLIDERS_GAP: f32 = 6.0;
|
||||
/// Height of the rows table, and of either tab (so switching tabs doesn't resize the dialog).
|
||||
const TABLE_H: f32 = 182.0;
|
||||
const TAB_H: f32 = 400.0;
|
||||
@@ -237,8 +240,9 @@ const SHARES: &str = "__shares";
|
||||
const SHARES_OF: &str = "__sharesOf";
|
||||
const BAR_DRAG: &str = "__barDrag";
|
||||
const SAVE_GROUP: &str = "__saveGroup";
|
||||
/// Height of the Prominent Colors bar, and the smallest share of it a drag leaves a part.
|
||||
const PROMINENT_H: f32 = 18.0;
|
||||
/// Height of the Prominent Colors bar, and the smallest share of it a drag leaves a part. With the
|
||||
/// bar the Edit tab leaves out [`WHEEL_GAP`] and [`SLIDERS_GAP`], which keeps the tab's height.
|
||||
const PROMINENT_H: f32 = 10.0;
|
||||
const MIN_PART: f64 = 0.01;
|
||||
/// The ids of the bar's part `n` and of the edge after part `k`, with `n` or `k`.
|
||||
const PROMINENT_PART: &str = "recolor-prominent-part";
|
||||
@@ -1282,7 +1286,12 @@ fn edit_tab(app: &VectorcraftApp, ui: &mut Ui, d: &mut Dialog, rows: &mut [Value
|
||||
mode_menu(ui, d, &target, true);
|
||||
});
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
// With art the Prominent Colors bar has the room of the two gaps, so the tab is no taller with
|
||||
// it: on a short screen all of the tab but the chips has to fit.
|
||||
let art = d.bool("__art");
|
||||
if !art {
|
||||
ui.add_space(WHEEL_GAP);
|
||||
}
|
||||
let colors: Vec<Color> = active.iter().filter_map(|&i| to_color(&rows[i])).collect();
|
||||
let marked = base.and_then(|b| active.iter().position(|&i| i == b));
|
||||
let display = d.str("display");
|
||||
@@ -1308,8 +1317,7 @@ fn edit_tab(app: &VectorcraftApp, ui: &mut Ui, d: &mut Dialog, rows: &mut [Value
|
||||
});
|
||||
});
|
||||
// Prominent Colors: the art's new colors, each as wide as its share of the art.
|
||||
if d.bool("__art") {
|
||||
ui.add_space(6.0);
|
||||
if art {
|
||||
prominent_bar(ui, d, rows);
|
||||
}
|
||||
if let Some(k) = w.pressed {
|
||||
@@ -1335,7 +1343,9 @@ fn edit_tab(app: &VectorcraftApp, ui: &mut Ui, d: &mut Dialog, rows: &mut [Value
|
||||
if !ui.input(|i| i.pointer.any_down()) {
|
||||
d.fields.remove(DRAG);
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
if !art {
|
||||
ui.add_space(SLIDERS_GAP);
|
||||
}
|
||||
if d.str("sliderMode") == GLOBAL {
|
||||
let sample = base.and_then(|b| to_color(&rows[b])).unwrap_or(Color::rgb(0.8, 0.45, 0.25));
|
||||
global_sliders(ui, d, sample);
|
||||
|
||||
+2
-2
@@ -3723,8 +3723,8 @@ excluded take the palette as their new colors in row order, the colors repeating
|
||||
returns them as `map`, each with `from` as a list, and `shares`: for each row, its percent of the uses (the `count` of
|
||||
`recolor.colors`) of the current colors of the rows that are not excluded, and 0 for an excluded row. A use counts for
|
||||
the row that `recolor.apply` recolors it with (rows with a new color first, an exact color before a hex color, then
|
||||
the first row that lists it), and otherwise for the first other row that lists it. A current color that no art uses
|
||||
counts nothing. Without `weights` the
|
||||
the first row that lists it), and otherwise for the first other row that is not excluded and lists it. A current
|
||||
color that no art uses counts nothing. Without `weights` the
|
||||
rows come back unchanged. `weights` holds one number of 0 or more per row; an excluded row's weight is ignored, and
|
||||
at least one other row needs a weight above 0. As VectorCraft's own rule, current colors then move one at a time
|
||||
between the rows that are not excluded and have a new color (`to`), as long as a move brings each row's share of the uses nearer its share of the
|
||||
|
||||
Reference in New Issue
Block a user