feat: transformation buttons

This commit is contained in:
2025-04-01 21:00:31 +02:00
parent c15db2847d
commit bd8b0fecf1
2 changed files with 63 additions and 22 deletions

View File

@@ -23,21 +23,37 @@ impl Pattern {
} }
#[must_use] #[must_use]
pub fn apply_transformation(&self, transformation: Transformation) -> Self { pub fn shift_left(&self, shift: u64) -> Option<Self> {
let mut holds = self.clone(); // Out of bounds check
if transformation.shift_right > 0 { if let Some(min_col) = self.pattern.iter().map(|(hold_position, _)| hold_position.col).min() {
holds = holds.shift_right(transformation.shift_right); if shift > min_col {
return None;
}
} }
if transformation.mirror {
holds = holds.mirror(); let pattern: BTreeMap<HoldPosition, HoldRole> = self
} .pattern
holds .iter()
.map(|(hold_position, hold_role)| {
let mut hold_position = hold_position.clone();
hold_position.col -= shift;
(hold_position, *hold_role)
})
.collect();
Some(Self { pattern })
} }
#[must_use] #[must_use]
pub fn shift_right(&self, shift: u64) -> Self { pub fn shift_right(&self, wall_dimensions: WallDimensions, shift: u64) -> Option<Self> {
let mut pattern = self.clone(); // Out of bounds check
pattern.pattern = pattern if let Some(max_col) = self.pattern.iter().map(|(hold_position, _)| hold_position.col).max() {
if max_col + shift >= wall_dimensions.cols {
return None;
}
}
let pattern: BTreeMap<HoldPosition, HoldRole> = self
.pattern .pattern
.iter() .iter()
.map(|(hold_position, hold_role)| { .map(|(hold_position, hold_role)| {
@@ -46,7 +62,8 @@ impl Pattern {
(hold_position, *hold_role) (hold_position, *hold_role)
}) })
.collect(); .collect();
pattern
Some(Self { pattern })
} }
#[must_use] #[must_use]

View File

@@ -187,7 +187,6 @@ fn View() -> impl IntoView {
<Separator /> <Separator />
<div class="flex flex-row justify-around"> <div class="flex flex-row justify-around">
<Transformations />
<NextProblemButton /> <NextProblemButton />
</div> </div>
</Section> </Section>
@@ -196,7 +195,8 @@ fn View() -> impl IntoView {
<Section title="Current problem"> <Section title="Current problem">
{move || ctx.problem.get().map(|problem| view! { <ProblemInfo problem /> })} {move || ctx.problem.get().map(|problem| view! { <ProblemInfo problem /> })}
<Separator /> <AttemptRadioGroup /> <Separator /> <History /> <Separator /> <Transformations /> <Separator /><AttemptRadioGroup />
<Separator /> <History />
</Section> </Section>
</div> </div>
@@ -214,25 +214,49 @@ fn Transformations() -> impl IntoView {
let ctx = use_context::<Context>().unwrap(); let ctx = use_context::<Context>().unwrap();
let on_left = Callback::new(move |()| { let left = Signal::derive(move || {
tracing::debug!("left"); let mut problem = ctx.problem.get()?;
let new_pattern = problem.pattern.shift_left(1)?;
problem.pattern = new_pattern;
Some(problem)
}); });
let on_mirror = Callback::new(move |()| {
let right = Signal::derive(move || {
let mut problem = ctx.problem.get()?;
let wall_dimensions = ctx.wall.read().wall_dimensions;
let new_pattern = problem.pattern.shift_right(wall_dimensions, 1)?;
problem.pattern = new_pattern;
Some(problem)
});
let on_click_left = Callback::new(move |()| {
tracing::debug!("left");
if let Some(problem) = left.get() {
ctx.cb_set_problem.run(problem);
}
});
let on_click_mirror = Callback::new(move |()| {
tracing::debug!("mirror"); tracing::debug!("mirror");
if let Some(mut problem) = ctx.problem.get() { if let Some(mut problem) = ctx.problem.get() {
problem.pattern = problem.pattern.mirror(); problem.pattern = problem.pattern.mirror();
ctx.cb_set_problem.run(problem); ctx.cb_set_problem.run(problem);
} }
}); });
let on_right = Callback::new(move |()| { let on_click_right = Callback::new(move |()| {
tracing::debug!("right"); tracing::debug!("right");
if let Some(problem) = right.get() {
ctx.cb_set_problem.run(problem);
}
}); });
let left_disabled = Signal::derive(move || left.read().is_none());
let right_disabled = Signal::derive(move || right.read().is_none());
view! { view! {
<div class="flex flex-row gap-2 justify-center"> <div class="flex flex-row gap-2 justify-center">
<Button icon=Icon::ChevronLeft disabled=true on_click=on_left /> <Button icon=Icon::ChevronLeft disabled=left_disabled on_click=on_click_left />
<Button icon=Icon::CodeBracketSquare on_click=on_mirror /> <Button icon=Icon::CodeBracketSquare on_click=on_click_mirror />
<Button icon=Icon::ChevronRight on_click=on_right /> <Button icon=Icon::ChevronRight disabled=right_disabled on_click=on_click_right />
</div> </div>
} }
} }
@@ -261,7 +285,7 @@ fn NextProblemButton() -> impl IntoView {
let ctx = use_context::<Context>().unwrap(); let ctx = use_context::<Context>().unwrap();
let on_click = Callback::new(move |_| ctx.cb_next_problem.run(())); let on_click = Callback::new(move |_| ctx.cb_next_problem.run(()));
view! { <Button icon=Icon::ArrowPath text="Next problem" on_click color=Gradient::PurpleBlue /> } view! { <Button icon=Icon::ArrowPath text="Randomize" on_click color=Gradient::PurpleBlue /> }
} }
#[component] #[component]