Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer does not update while widget is focused, other CosmicEditBundle components lag without input #145

Open
databasedav opened this issue Jun 5, 2024 · 3 comments

Comments

@databasedav
Copy link
Contributor

repro, modifying the basic_ui example

use bevy::prelude::*;
use bevy_cosmic_edit::*;

fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) {
    let camera_bundle = Camera2dBundle {
        camera: Camera {
            clear_color: ClearColorConfig::Custom(Color::PINK),
            ..default()
        },
        ..default()
    };
    commands.spawn(camera_bundle);

    let mut attrs = Attrs::new();
    attrs = attrs.family(Family::Name("Victor Mono"));
    attrs = attrs.color(CosmicColor::rgb(0x94, 0x00, 0xD3));

    let cosmic_edit = commands
        .spawn((CosmicEditBundle {
            buffer: CosmicBuffer::new(&mut font_system, Metrics::new(20., 20.)).with_rich_text(
                &mut font_system,
                vec![("Banana", attrs)],
                attrs,
            ),
            max_lines: MaxLines(1),
            ..default()
        },))
        .id();

    commands
        .spawn(
            // Use buttonbundle for layout
            // Includes Interaction and UiImage which are used by the plugin.
            ButtonBundle {
                style: Style {
                    width: Val::Percent(100.),
                    height: Val::Percent(100.),
                    ..default()
                },
                ..default()
            },
        )
        // point editor at this entity.
        // Plugin looks for UiImage and sets it's
        // texture to the editor's rendered image
        .insert(CosmicSource(cosmic_edit));

    commands.insert_resource(FocusedWidget(Some(cosmic_edit)));
}

#[derive(Component)]
struct Pressed;

#[derive(Component)]
struct Entered;

fn set_buffer_to_black_bananas(
    buffer: &mut CosmicBuffer,
    font_system: &mut CosmicFontSystem,
) {
    let mut attrs = Attrs::new();
    attrs = attrs.family(Family::Name("Victor Mono"));
    attrs = attrs.color(Color::BLACK.to_cosmic());
    buffer.set_text(
        font_system,
        "Bananas",
        attrs,
    );
}

fn change_on_click(
    mut commands: Commands,
    mut interaction_query: Query<
        (Entity, &Interaction, &CosmicSource),
        (Changed<Interaction>, Without<Pressed>),
    >,
    mut cosmic_q: Query<&mut CosmicBuffer>,
    mut font_system: ResMut<CosmicFontSystem>,
) {
    for (entity, interaction, source) in interaction_query.iter_mut() {
        if let Interaction::Pressed = interaction {
            commands.entity(entity).insert(Pressed);
            if let Ok(mut buffer) = cosmic_q.get_mut(source.0) {
                set_buffer_to_black_bananas(&mut buffer, &mut font_system);
                commands.entity(source.0).insert(CosmicBackgroundColor(Color::DARK_GRAY));
                println!("pressed");
            }
        }
    }
}

fn change_on_enter(
    mut commands: Commands,
    mut cosmic_q: Query<(Entity, &mut CosmicBuffer), Without<Entered>>,
    mut font_system: ResMut<CosmicFontSystem>,
    keys: Res<ButtonInput<KeyCode>>,
) {
    if keys.just_pressed(KeyCode::Enter) {
        if let Ok((entity, mut buffer)) = cosmic_q.get_single_mut() {
            commands.entity(entity).insert(Entered);
            set_buffer_to_black_bananas(&mut buffer, &mut font_system);
            commands.entity(entity).insert(CosmicBackgroundColor(Color::DARK_GRAY));
            println!("entered");
        }
    }
}

fn main() {
    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
    let font_config = CosmicFontConfig {
        fonts_dir_path: None,
        font_bytes: Some(vec![font_bytes]),
        load_system_fonts: true,
    };

    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                position: WindowPosition::Centered(MonitorSelection::Primary),
                ..default()
            }),
            ..default()
        }))
        .add_plugins(CosmicEditPlugin {
            font_config,
            ..default()
        })
        .add_systems(Startup, setup)
        .add_systems(
            Update,
            (
                print_editor_text,
                change_active_editor_ui,
                deselect_editor_on_esc,
                change_on_click,
                change_on_enter,
            ),
        )
        .run();
}

clicking or pressing enter does not change the text to "Bananas" with a black color

additionally, clicking or pressing does change the fill color to grey, but only after a second or two, unless one adds some mouse clicking/dragging

both these behaviors disappear when the widget is unfocused (e.g. by pressing escape), and the buffer and fill color update as expected

this is problematic for consumers that react to the FocusedWidget resource to modify the state of the widget, e.g. if one wants to modify the text/fill color of a just focused widget, they can't because that would require knowing which widget were focused before resource_changed::<FocusedWidget> could be reacted to, at which point the target widget is already focused and can't be modified

@databasedav
Copy link
Contributor Author

if we want to maintain the invariant that focused widgets cannot be modified, we can emulate a lock with components/events to give consumers a chance to react to an imminent focused widget before the focus is applied

although i would rather just allow the buffer to be modified 😅

@bytemunch
Copy link
Collaborator

bytemunch commented Jun 5, 2024

Yeah currently the "focused" buffer is separate to the editor buffer (borrow checker skill issue reasons lol) and keeping them synchronised currently only works one-way, on unfocus.

Guess I didn't have programmatic editing of a focused editor buffer in mind when I designed around the 0.11 version of cosmic-text, but now you've pointed that out there's definitely utility there!

In an ideal world the editor would work directly on the buffer contained in the bevy entity rather than cloning it.

It seems like cosmic-text is designed to do this with it's BufferRef enum, but when I tried I couldn't get it to play nice with a bevy component. (again, borrow checker skill issue)

Making this change would simplify a whole lot of the code in this plugin! If you wanna have a look, the offending line is

let mut editor = Editor::new(b.0.clone());

If that clone could become a mutable borrow or an Arc then the separate buffers issue would be solved, though such a change might also need a fair bit of refactoring all over the place to allow functions to understand the new buffer layout.

This change would also fix #138, which I think is caused by the same underlying issue

@bytemunch
Copy link
Collaborator

bytemunch commented Jun 5, 2024

Tested the repro in the linked PR, seems to work :)

On closer inspection, background works when focused, but changing text still only works unfocused 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants