Can't set button color - rust

Based on this UI example I've add a custom button at the end of on_start method. But when I run the game the button body is invisible, only its text is shown ("1234567").
The code I added to the example:
// ...
use amethyst::assets::AssetStorage;
use amethyst::assets::Handle;
use amethyst::assets::Loader;
use amethyst::renderer::loaders::load_from_srgba;
use amethyst::renderer::palette::Srgba;
use amethyst::renderer::Texture;
use amethyst::renderer::types::TextureData;
use amethyst::ui::Anchor;
use amethyst::ui::UiButtonBuilder;
use amethyst::ui::UiImage;
// ...
impl SimpleState for Example {
fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
// ...
let texture_handle: Handle<Texture> = {
let loader = world.read_resource::<Loader>();
let texture_assets = world.read_resource::<AssetStorage<Texture>>();
let texture_builder = load_from_srgba(Srgba::new(0.8, 0.6, 0.3, 1.0));
loader.load_from_data(TextureData::from(texture_builder), (), &texture_assets)
};
let button = UiButtonBuilder::<(), u32>::new("1234567".to_string())
.with_id(666)
.with_font_size(12.0)
.with_position(64.0, -64.0)
.with_size(64.0 * 3.0, 64.0)
.with_anchor(Anchor::TopMiddle)
// HAS NO EFFECT
.with_image(texture_handle)
// HAS NO EFFECT
.with_hover_image(UiImage::SolidColor([0.1, 0.1, 0.1, 0.5]))
.with_layer(12.0)
.build_from_world(&world);
world.insert(button);
}
}
// ...
What is the proper way to create a button on the fly with custom color?
I'm using amethyst v0.15.

There is a bug with the UiButtonBuilder. I just created this issue: https://github.com/amethyst/amethyst/issues/2298

Related

How do I keep window's size constant while resizing host window on imgui with Rust?

I want contents' size in a imgui window looks always same, but on resizing OS window, imgui window size and its contents scale too. Actually contents looks 'wrong' when resized, this is scaled down figure of 'hello world' example from imgui-rs repository.
I think I should achieve it by using glViewport, but it looks like I have no access to the function or equivalent things, and ContextWrapper::resize has no effect.
Event::NewEvents(_) => {
let now = Instant::now();
imgui.io_mut().update_delta_time(now - last_frame);
last_frame = now;
}
Event::MainEventsCleared => {
let gl_window = display.gl_window();
platform
.prepare_frame(imgui.io_mut(), gl_window.window())
.expect("Failed to prepare frame");
gl_window.window().request_redraw();
}
Event::RedrawRequested(_) => {
let ui = imgui.new_frame();
let mut run = true;
run_ui(&mut run, ui);
if !run {
*control_flow = ControlFlow::Exit;
}
let gl_window = display.gl_window();
let mut target = display.draw();
target.clear_color_srgb(1.0, 1.0, 1.0, 1.0);
platform.prepare_render(ui, gl_window.window());
let draw_data = imgui.render();
renderer
.render(&mut target, draw_data)
.expect("Rendering failed");
target.finish().expect("Failed to swap buffers");
}
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
display.gl_window().resize(size);
}
What should I do to keep contents' size constant and to render things correctly?
I'm using imgui with glium and winit.

x and y parameters of x11 library don't have any effect on window

I'm using the x11cb library, used to interact with the x11 server using Rust.
use std::error::Error;
use x11rb::connection::Connection;
use x11rb::protocol::xproto::*;
use x11rb::COPY_DEPTH_FROM_PARENT;
fn main() -> Result<(), Box<dyn Error>> {
// Open the connection to the X server. Use the DISPLAY environment variable.
let (conn, screen_num) = x11rb::connect(None)?;
// Get the screen #screen_num
let screen = &conn.setup().roots[screen_num];
// Ask for our window's Id
let win = conn.generate_id()?;
// Create the window
conn.create_window(
COPY_DEPTH_FROM_PARENT, // depth (same as root)
win, // window Id
screen.root, // parent window
200, // x
200, // y
150, // width
150, // height
10, // border width
WindowClass::INPUT_OUTPUT, // class
screen.root_visual, // visual
&Default::default(),
)?; // masks, not used yet
// Map the window on the screen
conn.map_window(win)?;
// Make sure commands are sent before the sleep, so window is shown
conn.flush()?;
std::thread::sleep(std::time::Duration::from_secs(10));
Ok(())
}
The window resizes if I change the width and height parameters. However, the window doesn't change positions if I modify the x and y parameters.
What could be the reason?
Rust Playground
Note: I'm using Ubuntu 22.10 with X11 and NVIDIA propetary drivers.
Update:
For some reason, this successfully repositions the window (but don't know why modifying x and y in create_window doesn't):
let values = ConfigureWindowAux::default().x(500).y(200);
conn.configure_window(win, &values)?;

GTK-rs getting input from GTK::Entry

I have a small gtk-rs application where I am trying to display an input field and get the input from the user. At the moment I can't get the input from the input field when the user clicks the button. I know button.connect_clicked is where I need to do this but I don't know how?
My build_ui method:
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Button, Orientation};
pub fn build_ui(app: &Application) {
let button = Button::builder()
.label("Submit")
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();
let input = gtk::Entry::builder()
.placeholder_text("input")
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();
let gtk_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.build();
gtk_box.append(&input);
gtk_box.append(&button);
button.connect_clicked(move | _button| {
println!("{}", input.display());
});
let window = ApplicationWindow::builder()
.application(app)
.title("gtk-app")
.child(&gtk_box)
.default_height(720)
.default_width(360)
.build();
window.present();
}
main.rs:
const APP_ID: &str = "org.my-gtk-app";
fn main() {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(home::build_ui);
// Run the application
app.run();
}
I have found this question which is almost exactly the same however when I try and implement the solution all of the .add methods throw an error stating:
the following trait bounds were not satisfied: `ApplicationWindow: IsA<CellArea>` which is required by `ApplicationWindow: gtk4::prelude::CellAreaExt`
EDIT:
Also Gtk::Entry does not have a .get_text() method according to the compiler. After doing a bit more googling around this it seems that GTK3 had a get_text method for Gtk::Entry however Gtk4 does not.
So does anyone know how to get the text from a Gtk::Entry object when using Gtk4?
EDIT 2:
I think I needed to use the .display() method however when I run the code now I don't get the text input from the user. input.display() just returns an empty string. I have updated the code samples to reflect these changes.
The Entry does have a text() method which gives you a GString (because Entry implements Editable), that can be converted to a rust str using as_str().
So in order to get the current text from an entry, you can do the following:
let my_input_value = my_input.text().as_str();
For completeness, here is the updated build_ui function:
pub fn build_ui(app: &Application) {
let button = Button::builder()
.label("Submit")
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();
let input = gtk::Entry::builder()
.placeholder_text("input")
.margin_top(12)
.margin_bottom(12)
.margin_start(12)
.margin_end(12)
.build();
let gtk_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.build();
gtk_box.append(&input);
gtk_box.append(&button);
button.connect_clicked(move | _button| {
println!("{}", input.text().as_str());
});
let window = ApplicationWindow::builder()
.application(app)
.title("gtk-app")
.child(&gtk_box)
.default_height(720)
.default_width(360)
.build();
window.present();
}
Edit
Because GString implements Display the following works as well:
println!("{}", input.text());

what's the easy way to make a simple window and catch key presses in Rust?

I am a blind Rust learner and i'm trying to make a simple audiogame engine for blind people but in rust.
Now I'm trying to make a simple window. A game for blind uses only audio and keyboard, so i have a question.
I'm trying to create an empty window and catch key presses to be able to make a self voiced user interface and game interaction using keyboard only, without mouce. what's the best solution for that?
I tryed to use winit and winit input helper, but maybe there is a better way to do that?
use winit::event::VirtualKeyCode;
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit_input_helper::WinitInputHelper;
pub fn show_window() {
let mut input = WinitInputHelper::new();
let event_loop = EventLoop::new();
let _window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
// Pass every event to the WindowInputHelper.
// It will return true when the last event has been processed and it is time to run your application logic.
if input.update(&event) {
// query keypresses this update
if input.key_pressed_os(VirtualKeyCode::A) {
println!("The 'A' key was pressed on the keyboard (OS repeating)");
}
if input.key_pressed(VirtualKeyCode::A) {
println!("The 'A' key was pressed on the keyboard");
}
if input.key_released(VirtualKeyCode::Q) || input.quit() {
*control_flow = ControlFlow::Exit;
return;
}
}
});
}

How to let Gtk CellRendererText display newlines during edit?

My Gtk app currently reads data from an external database/file, then add it to a Gtk Treeview. One of the columns allows newlines, which is correctly displayed in the Treeview when single-paragraph-mode is false.
However, when I double click to edit, the cell turns into a single line entry box where a carriage return symbol (like ⤶) replaces the newlines.
This makes it impossible to edit a cell with lots of newlines because they appear as one single line. Is it possible to render the newlines as actual newlines during editing? In other words, I want single-paragraph-mode=false to apply to the cell when it is being edited
I've read the documentation for CellRendererText and CellRenderer, but it is rather lacking. Things like max-width-chars apply to the cell whether editing or not.
This code demonstrates what I mean. (It uses gtk-rs but an answer using C is fine too):
use gtk::glib;
use gtk::prelude::*;
fn main() {
let application = gtk::Application::new(
Some("com.example.xyz"),
Default::default(),
);
application.connect_activate(build_ui);
application.run();
}
fn build_ui(application: &gtk::Application) {
let window = gtk::ApplicationWindow::new(application);
window.set_title(Some("App"));
window.set_default_size(800, 800);
let grid = gtk::Grid::builder()
.column_spacing(5)
.row_spacing(10)
.build();
window.set_child(Some(&grid));
let (treeview, _treestore) = build_treeview();
let sw = gtk::ScrolledWindow::builder()
.child(&treeview)
.vexpand(false)
.vexpand_set(false)
.max_content_height(10)
.build();
// column, row, width, height
grid.attach(&sw, 0, 0, 1, 1);
window.show();
}
fn build_treeview() -> (gtk::TreeView, gtk::TreeStore) {
let treestore = gtk::TreeStore::new(&[glib::Type::STRING].repeat(4));
let treeview = gtk::TreeView::builder()
.hexpand(true)
.vexpand(true)
.enable_grid_lines(gtk::TreeViewGridLines::Both)
.model(&treestore)
.build();
for (i, title) in ["Title", "Description", "Path1", "Path2"]
.iter()
.enumerate()
{
let cell_renderer = gtk::CellRendererText::builder()
.editable(true)
.xalign(0.0)
.single_paragraph_mode(false)
.build();
treeview.insert_column_with_attributes(
i.try_into().unwrap(),
title,
&cell_renderer,
&[(&"text", i.try_into().unwrap())],
);
let ts = treestore.clone();
cell_renderer.connect_edited(move |_renderer, row, text| {
ts.set_value(
&ts.iter(&row).unwrap(),
i.try_into().unwrap(),
&text.to_value()
);
});
}
treestore.insert_with_values(
None,
None,
&[
(0, &"one"),
(1, &"two\ntwo\ntwo\ntwo"),
(2, &"three"),
(3, &"four"),
],
);
(treeview, treestore)
}

Resources