Skip to content

Commit

Permalink
Add anchor to elements
Browse files Browse the repository at this point in the history
  • Loading branch information
Zerthox committed Jan 12, 2025
1 parent 5877e9a commit 6768629
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,59 @@
use nexus::imgui::Ui;
use crate::render_util::{enum_combo, impl_static_variants};
use nexus::imgui::{ComboBoxFlags, Ui};
use serde::{Deserialize, Serialize};
use strum::{AsRefStr, EnumIter, VariantArray};

/// Anchor point.
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
EnumIter,
AsRefStr,
Serialize,
Deserialize,
)]
pub enum Anchor {
#[default]
Parent,

Screen(ScreenAnchor),
}

impl_static_variants!(Anchor);

impl Anchor {
/// Calculates the root position.
pub fn root(ui: &Ui) -> [f32; 2] {
ScreenAnchor::Center.calc_pos(ui)
}

/// Calculates the anchor position.
pub fn pos(&self, ui: &Ui, parent: [f32; 2]) -> [f32; 2] {
match self {
Self::Parent => parent,
Self::Screen(screen) => screen.calc_pos(ui),
}
}

pub fn render_select(&mut self, ui: &Ui) {
enum_combo(ui, "Anchor", self, ComboBoxFlags::empty());

match self {
Self::Parent => {}
Self::Screen(screen) => {
enum_combo(ui, "Screen Anchor", screen, ComboBoxFlags::empty());
}
}
}
}

/// Screen anchor point.
#[derive(
Debug,
Expand Down Expand Up @@ -65,3 +117,9 @@ impl ScreenAnchor {
}
}
}

impl From<ScreenAnchor> for Anchor {
fn from(screen: ScreenAnchor) -> Self {
Self::Screen(screen)
}
}
23 changes: 16 additions & 7 deletions reffect/src/elements/common.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Element, ElementType, RenderState, ELEMENT_ID};
use super::{Anchor, Element, ElementType, RenderState, ScreenAnchor, ELEMENT_ID};
use crate::{
action::ChildElementAction,
context::{Context, EditState},
Expand All @@ -7,6 +7,7 @@ use crate::{
render_util::{
helper_slider, input_pos, push_alpha_change, slider_percent, EnumStaticVariants, Rect,
},
serde::migrate,
trigger::ProgressTrigger,
};
use nexus::imgui::{Condition, MenuItem, MouseButton, StyleVar, Ui, Window};
Expand All @@ -25,6 +26,8 @@ pub struct Common {

pub name: String,

#[serde(deserialize_with = "migrate::<_, _, ScreenAnchor>")]
pub anchor: Anchor,
pub pos: [f32; 2],

pub opacity: f32,
Expand All @@ -47,23 +50,23 @@ impl Common {
self.enabled || ctx.edit.is_edited_or_parent(self.id)
}

pub fn pos(&self, state: &RenderState) -> [f32; 2] {
state.pos.add(self.pos)
pub fn pos(&self, ui: &Ui, parent_pos: [f32; 2]) -> [f32; 2] {
self.anchor.pos(ui, parent_pos).add(self.pos)
}

pub fn render_initial(
pub fn render_root(
&mut self,
ui: &Ui,
ctx: &Context,
edit: bool,
pos: [f32; 2],
contents: impl FnOnce(RenderState),
) {
if self.visible(ctx) {
let edit = edit || ctx.edit.is_edited(self.id);
self.trigger.update(ctx, edit, None);

let _style = push_alpha_change(ui, self.opacity);
let pos = self.pos(ui, Anchor::root(ui));
let state = RenderState::initial(edit, pos, self);
contents(state);
}
Expand All @@ -82,20 +85,21 @@ impl Common {
self.trigger.update(ctx, edit, parent_active);

let _style = push_alpha_change(ui, self.opacity);
let state = parent.for_child(ctx, self);
let state = parent.for_child(ui, ctx, self);
contents(state);
}
}

/// Renders the element edit indicators.
///
/// Updates the position if moved.
pub fn render_edit_indicators(&mut self, ui: &Ui, anchor: [f32; 2], bounds: Rect) {
pub fn render_edit_indicators(&mut self, ui: &Ui, parent_pos: [f32; 2], bounds: Rect) {
const ANCHOR_SIZE: f32 = 5.0;
const ANCHOR_OFFSET: [f32; 2] = [0.5 * ANCHOR_SIZE, 0.5 * ANCHOR_SIZE];
const COLOR: [f32; 4] = colors::WHITE;
const COLOR_DRAG: [f32; 4] = colors::YELLOW;

let anchor = self.pos(ui, parent_pos);
let (min, max) = bounds;
let min = anchor.add(min);
let max = anchor.add(max);
Expand Down Expand Up @@ -213,6 +217,7 @@ impl RenderOptions for Common {

ui.input_text("Name", &mut self.name).build();

self.anchor.render_select(ui);
input_pos(&mut self.pos);

slider_percent(ui, "Opacity", &mut self.opacity);
Expand All @@ -227,6 +232,8 @@ impl RenderOptions for Common {
impl RenderDebug for Common {
fn render_debug(&mut self, ui: &Ui, ctx: &Context) {
ui.text(format!("Id: {}", self.id));
ui.text(format!("Pos: {:?}", self.pos(ui, Anchor::root(ui))));

self.trigger.render_debug(ui, ctx);
}
}
Expand All @@ -237,6 +244,7 @@ impl Default for Common {
enabled: true,
id: ELEMENT_ID.generate(),
name: "Unnamed".into(),
anchor: Anchor::default(),
pos: [0.0, 0.0],
opacity: 1.0,
trigger: ProgressTrigger::default(),
Expand All @@ -251,6 +259,7 @@ impl Clone for Common {
enabled: self.enabled,
id: ELEMENT_ID.generate(), // we want a fresh id for the clone
name: self.name.clone(),
anchor: self.anchor.clone(),
pos: self.pos,
opacity: self.opacity,
trigger: self.trigger.clone(),
Expand Down
3 changes: 1 addition & 2 deletions reffect/src/elements/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ impl Element {
});

if ctx.edit.is_edited(self.common.id) {
let pos = self.common.pos(state);
let bounds = self.kind.bounds(ui, ctx);
self.common.render_edit_indicators(ui, pos, bounds);
self.common.render_edit_indicators(ui, state.pos, bounds);
}
}

Expand Down
4 changes: 2 additions & 2 deletions reffect/src/elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod icon;
pub mod list;
pub mod text;

mod anchor;
mod animation;
mod common;
mod direction;
Expand All @@ -13,10 +14,10 @@ mod group;
mod pack;
mod props;
mod render_state;
mod screen_anchor;
mod unit;

pub use self::{
anchor::*,
animation::*,
bar::Bar,
common::*,
Expand All @@ -29,7 +30,6 @@ pub use self::{
pack::*,
props::*,
render_state::*,
screen_anchor::*,
text::Text,
unit::*,
};
Expand Down
43 changes: 26 additions & 17 deletions reffect/src/elements/pack/mod.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
use super::{Common, Element, ScreenAnchor};
use super::{Anchor, Common, Element, ScreenAnchor};
use crate::{
context::{Context, EditState},
render::{colors, Bounds, ComponentWise, RenderDebug, RenderOptions},
render::{colors, Bounds, RenderDebug, RenderOptions},
render_util::{
delete_confirm_modal, enum_combo, item_context_menu, style_disabled, style_disabled_if,
delete_confirm_modal, item_context_menu, style_disabled, style_disabled_if,
tree_select_empty,
},
schema::Schema,
tree::{FontReloader, Loader, TreeNode, VisitMut},
};
use nexus::imgui::{ComboBoxFlags, MenuItem, StyleColor, Ui};
use nexus::imgui::{MenuItem, StyleColor, Ui};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Pack {
#[serde(flatten)]
pub common: Common,

pub anchor: ScreenAnchor,
pub layer: i32,
pub elements: Vec<Element>,

Expand Down Expand Up @@ -63,18 +62,16 @@ impl Pack {
/// Renders the pack.
pub fn render(&mut self, ui: &Ui, ctx: &Context) {
let edit = ctx.edit.show_all && ctx.edit.is_edited_or_parent(self.common.id);
let anchor_pos = self.anchor.calc_pos(ui);
self.common
.render_initial(ui, ctx, edit, anchor_pos, |state| {
for element in &mut self.elements {
element.render(ui, ctx, &state);
}
});
self.common.render_root(ui, ctx, edit, |state| {
for element in &mut self.elements {
element.render(ui, ctx, &state);
}
});

if ctx.edit.is_edited(self.common.id) {
let pos = anchor_pos.add(self.common.pos);
let bounds = Bounds::combined_bounds(self.elements.iter(), ui, ctx);
self.common.render_edit_indicators(ui, pos, bounds)
self.common
.render_edit_indicators(ui, Anchor::root(ui), bounds)
}
}

Expand Down Expand Up @@ -146,8 +143,6 @@ impl Pack {

ui.spacing();

enum_combo(ui, "Anchor", &mut self.anchor, ComboBoxFlags::empty());

{
// TODO: layer input
let _style = style_disabled(ui);
Expand Down Expand Up @@ -184,3 +179,17 @@ impl TreeNode for Pack {
Some(&mut self.elements)
}
}

impl Default for Pack {
fn default() -> Self {
Self {
common: Common {
anchor: Anchor::Screen(ScreenAnchor::default()),
..Common::default()
},
layer: 0,
elements: Vec::new(),
file: PathBuf::new(),
}
}
}
14 changes: 7 additions & 7 deletions reffect/src/elements/render_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::Common;
use crate::{context::Context, render::ComponentWise, trigger::ProgressActive};
use nexus::imgui::Ui;

// TODO: as visitor?
// TODO: add tint + opacity as color, scale, use instead of imgui globals?
Expand All @@ -21,25 +22,24 @@ pub struct RenderState<'a> {
}

impl<'a> RenderState<'a> {
/// Creates a new initial render state.
pub fn initial(edit: bool, pos: [f32; 2], common: &'a Common) -> Self {
Self {
edit,
pos: pos.add(common.pos),
common,
}
Self { edit, pos, common }
}

pub fn for_child<'b>(&'a self, ctx: &Context, common: &'b Common) -> RenderState<'b>
/// Creates a new render state for a child.
pub fn for_child<'b>(&'a self, ui: &Ui, ctx: &Context, common: &'b Common) -> RenderState<'b>
where
'a: 'b,
{
RenderState {
edit: self.edit || ctx.edit.is_edited(common.id),
pos: common.pos(self),
pos: common.pos(ui, self.pos),
common,
}
}

/// Creates a new the render state with a poisition offset.
pub fn with_offset(&'a self, offset: [f32; 2]) -> Self {
// TODO: positive offset always towards center of screen? need direction/anchor here probably
Self {
Expand Down

0 comments on commit 6768629

Please sign in to comment.