egui::TextEdit::singleline with macroquad - not able to edit text - user-interface

Trying to experiment with egui and macroquad, but can't get elements enabled for edit.
From the standard example:
use macroquad::prelude::*;
#[macroquad::main("")]
async fn main() {
loop {
clear_background(BLACK);
egui_macroquad::ui(|egui_ctx| {
egui_macroquad::egui::Window::new("egui ❤ macroquad").show(egui_ctx, |ui| {
ui.colored_label(egui_macroquad::egui::Color32::WHITE, "Test");
ui.add(egui_macroquad::egui::TextEdit::singleline(&mut "ku").text_color(egui_macroquad::egui::Color32::RED));
});
});
egui_macroquad::draw();
next_frame().await
}
}
In Cargo.toml:
[dependencies]
macroquad = "0.3.25"
egui-macroquad = "0.12.0"
As result:
I see the TextEdit::singleline widget, but can't edit it.
Should I enable it somehow or something else?

Found the solution. Mutable "String" variable must be defined and used for TextEdit::singleline:
use macroquad::prelude::*;
#[macroquad::main("")]
async fn main() {
let mut kuku: String = "ku".to_string();
loop {
clear_background(BLACK);
egui_macroquad::ui(|egui_ctx| {
egui_macroquad::egui::Window::new("egui ❤ macroquad").show(egui_ctx, |ui| {
ui.colored_label(egui_macroquad::egui::Color32::WHITE, "Test");
ui.add(egui_macroquad::egui::TextEdit::singleline(&mut kuku).text_color(egui_macroquad::egui::Color32::RED));
});
});
egui_macroquad::draw();
next_frame().await
}
}
Now it works, because it takes the values from the widget and assign them to the variable "kuku".

Related

Prae:Wrapper: need to use iter_mut of interior Vec but Prae:Wrapper only provides immutable access

I'm using the prae crate for validation and the following function gives me errors:
fn advance_rotors(&mut self) {
self.rotors.get()[0].rotate();
let mut iterhandle = self.rotors.iter_mut().peekable(); // Error at iter_mut() #0599
while let Some(el) = iterhandle.next() {
match iterhandle.peek_mut() {
Some(next_rotor) => match el.should_advance_next() {
true => {
next_rotor.rotate(); // This line requires mutable access to next_rotor
}
false => (),
},
None => (),
}
}
}
and the definition of my struct here:
pub struct Enigma {
reflector: Reflector,
rotors: RotorConfig, // Only mutable via getter and setter functions
}
the struct of interest here is RotorConfig which is generated using the define! macro from prae. Here's the code:
prae::define! {
#[derive(Debug)]
RotorConfig: Vec<Rotor>; // I need to be able to call the rotate method of each rotor in this vec. This requires mutability
validate(RotorConfigError) |config| {
match config.len(){
3..=4 => (),
_ => return Err(RotorConfigError::Size)
}
match config.iter().unique().count(){
3..=4 =>(),
_ => return Err(RotorConfigError::Duplicate)
}
Ok(())
};
}
the issue stems from the fact that prae only allows for immutable access to the internal representation via getter and setter functions so as to ensure the validity of the values inside. As you can see in my advance_rotors function I wrote before implementing validation I'm getting an error because I need to call rotor.rotate mutably. I'm at a loss as to how to accomplish this
After posting this I realized that I can simply provide interior mutability by using the following impl block
impl RotorConfig{
fn advance_rotors(&mut self)
{
self.0[0].rotate();
let mut iterhandle = self.0.iter_mut().peekable();
while let Some(el) = iterhandle.next() {
match iterhandle.peek_mut() {
Some(next_rotor) => match el.should_advance_next() {
true => {
next_rotor.rotate();
}
false => (),
},
None => (),
}
}
}
}
As you can see the function largely remains unchanged except that we replace self.rotors with self.0

How to Filter out a Vec of Strings From a Vec of Structs Rust

I have a working solution to filtering out an input vec of strings compared to a vector of a struct. However, my code seems complicated and I tried simplify the code using a iter::filter(https://doc.rust-lang.org/stable/std/iter/struct.Filter.html). This caused issues because the iterator gave back values that were references and could not be directly used. It seems like my understanding of the iter and what can be done in a structs vector needs refreshing. Below is the simplified filtering code that works:
#[derive(Debug)]
pub struct Widget {
name: String,
pin: u16,
}
impl Widget{
pub fn new(widget_name: String, widget_pin: String) -> Widget {
let widget_pin_u16 = widget_pin.parse::<u16>().expect("Unable to parse");
let nw = Widget {
name: widget_name,
pin: widget_pin_u16
};
return nw
}
}
pub struct WidgetHolder {
widgets: Vec<Widget>,
widget_holder_name: String
}
impl WidgetHolder {
fn add_widgets(&mut self, valid_widgets_found: Vec<String>) {
let mut widgets_to_add: Vec<String> = Vec::new();
for widget in valid_widgets_found {
// The string musy be compared to pin field, so we're converting
let widget_offset = widget
.clone()
.parse::<u16>()
.expect("Unable to parse widget base into int.");
// If it doesnt exist in our widgetHolder widgets vector, then lets add it.
let mut widget_exists = false;
for existing_widget in &self.widgets {
if widget_offset == existing_widget.pin {
widget_exists = true;
break;
}
}
if !widget_exists {
widgets_to_add.push(widget.clone());
}
}
if widgets_to_add.is_empty() {
return;
}
for widget in widgets_to_add {
let loaded_widget = Widget::new(self.widget_holder_name.clone(), widget);
self.widgets.push(loaded_widget);
}
}
}
pub fn main() {
let init_vec = Vec::new();
let mut wh = WidgetHolder {
widgets: init_vec,
widget_holder_name: "MyWidget".to_string()
};
let vec1 = vec!["1".to_string(), "2".to_string(), "3".to_string()];
wh.add_widgets(vec1);
println!("{:?}", wh.widgets);
let vec2 = vec!["2".to_string(), "3".to_string(), "4".to_string()];
wh.add_widgets(vec2);
println!("{:?}", wh.widgets);
}
Is there a way I can clean up this code without having to use so many data structures and loops? The filter api looks clean but does it work with a vector inside of a struct that I am trying to mutate(append to it)?
EDIT
After trying to get a stack trace, I actually got the filter to work...
fn add_widgets(&mut self, valid_widgets_found: Vec<String>) {
let widgets_to_add: Vec<String> = valid_widgets_found.into_iter()
.filter(|widget_pin| {
let widget_offset = widget_pin.clone().parse::<u16>().expect("Unable to parse widget base into int.");
let mut widget_exists = false;
for existing_widget in &self.widgets {
if widget_offset == existing_widget.pin {
widget_exists = true;
break;
}
}
!widget_exists
})
.collect();
if widgets_to_add.is_empty() {
return;
}
for widget in widgets_to_add {
let loaded_widget = Widget::new(self.widget_holder_name.clone(), widget);
self.widgets.push(loaded_widget);
}
}
I figured out the answer. Seemed like a syntax error when I initially tried it. For anyone who's looking for a filter example in the future:
fn add_widgets(&mut self, valid_widgets_found: Vec<String>) {
let widgets_to_add: Vec<String> = valid_widgets_found.into_iter()
.filter(|widget_pin| {
let widget_offset = widget_pin.clone().parse::<u16>().expect("Unable to parse widget base into int.");
let mut widget_exists = false;
for existing_widget in &self.widgets {
if widget_offset == existing_widget.pin {
widget_exists = true;
break;
}
}
!widget_exists
})
.collect();
if widgets_to_add.is_empty() {
return;
}
for widget in widgets_to_add {
let loaded_widget = Widget::new(self.widget_holder_name.clone(), widget);
self.widgets.push(loaded_widget);
}
}

Handling commands from the viewmodel to the UI

The peculiarity of this application is that every time a user does something (except common things like typing) the application must check with an authority that they are indeed allowed to perform that action.
For example, let us say that the user wishes to see their profile (which is on the top bar)
the Composable screen looks something like this:
#Composable
fun HomeScreen(
navController: NavController,
vm: HomeViewModel = hiltViewModel()
) {
val state = vm.state.value
val scaffoldState = rememberScaffoldState()
HomeScreen(state, scaffoldState, vm::process)
}
#Composable
fun HomeScreen(state: HomeState, scaffoldState: ScaffoldState, event: (HomeEvent) -> Unit) {
Scaffold(
scaffoldState = scaffoldState,
modifier = Modifier.fillMaxSize(),
topBar = {
TopAppBar(
title = {
Text("Hello world")
},
actions = {
IconButton(onClick = {
event.invoke(HomeEvent.ShowProfile)
}) {
Icon(
painter = painterResource(id = R.drawable.ic_person),
contentDescription = stringResource(id = R.string.profile)
)
}
}
)
}
) {
}
}
the view model receives it like so:
#HiltViewModel
class HomeViewModel #Inject constructor(app: Application, private val checkAllowed: CheckAllowed): AndroidViewmodel(app) {
val state = mutableStateOf(HomeState.Idle)
fun process(event:HomeEvent) {
when(event) {
HomeEvent.ShowProfile -> {
state.value = HomeState.Loading
viewModelScope.launch {
try {
val allowed = checkAllowed(Permission.SeeProfile) //use case that checks if the action is allowed
if (allowed) {
} else {
}
} finally {
state.value = HomeState.Idle
}
}
}
}
}
}
I now have to send a command to the ui, to either show a snackbar with the error or navigate to the profile page.
I have read a number of articles saying that compose should have a state, and the correct way to do this is make a new state value, containing the response, and when the HomeScreen receives it , it will act appropriately and send a message back that it is ok
I assume something like this :
in the viewmodel
val command = mutableStateOf<HomeCommand>(HomeCommand.Idle)
fun commandExecuted() {
command.value = HomeCommand.Idle
}
and inside the HomeScreen
val command = vm.command.value
try {
when (command) {
is HomeCommand.ShowProfile -> navController.navigate("profile_screen")
is HomeCommand.ShowSnackbar -> scaffoldState.snackbarHostState.showSnackbar(command.message, "Dismiss", SnackbarDuration.Indefinite)
}
}finally {
vm.commandExecuted()
}
but the way I did it is using flows like so:
inside the viewmodel:
private val _commands = MutableSharedFlow<HomeCommand>(0, 10, BufferOverflow.DROP_LATEST)
val commands: Flow<HomeCommand> = _commands
and inside the HomeScreen:
LaunchedEffect(key1 = vm) {
this#ExecuteCommands.commands.collectLatest { command ->
when (command) {
is HomeCommand.ShowProfile -> navController.navigate("profile_screen")
is HomeCommand.ShowSnackbar -> scaffoldState.snackbarHostState.showSnackbar(command.message, "Dismiss", SnackbarDuration.Indefinite)
}
}
This seems to work, but I am afraid there may be a memory leak or something I'm missing that could cause problems
Is my approach correct? Should I change it to state as in the first example? can I make it better somehow?

How do I write an asynchronous function which polls a resource and returns when it's ready or otherwise retries in a few seconds?

I want to write an asynchronous function which repeatedly polls a resource from the web and returns when it's ready. I am implementing it using future::poll_fn:
#![feature(async_await)]
/*
[dependencies]
rand = "0.7.0"
futures-preview = "=0.3.0-alpha.18"
*/
use futures::future;
use rand;
use std::task::Poll;
enum ResourceStatus {
Ready,
NotReady,
}
use ResourceStatus::*;
// Mocking the function requesting a web resource
fn poll_web_resource() -> ResourceStatus {
if rand::random::<f32>() < 0.1 {
Ready
} else {
NotReady
}
}
async fn async_get_resource() {
// do other works
future::poll_fn(|ctx| match poll_web_resource() {
Ready => Poll::Ready(()),
NotReady => Poll::Pending,
})
.await
}
fn main() {
futures::executor::block_on(async_get_resource());
}
It doesn't work because the task gets parked forever when poll_web_resource() returns NotReady. One way to solve it is to wake the task every time it returns Pending:
future::poll_fn(|ctx| match poll_web_resource() {
Ready => Poll::Ready(()),
NotReady => {
ctx.waker().wake_by_ref();
Poll::Pending
}
})
.await
This creates loads of unnecessary requests. For my use case, the ideal situation would be request the resource every few seconds when it's not ready. Here's my current workaround:
future::poll_fn(|ctx| match poll_web_resource() {
Ready => Poll::Ready(()),
NotReady => {
let waker = ctx.waker().clone();
thread::spawn(move || {
thread::sleep(Duration.from_millis(5000));
waker.wake();
});
Poll::Pending
}
})
.await
This works, but it uses an extra thread just for tracking the timeout. I think there should be a better way to do it. How can I achieve the same goal more idiomatically?
Since you are using async / await keywords, write a loop that exits when the resource is available, or waits when it's not. Waiting can be accomplished with Tokio's Delay:
#![feature(async_await)]
use futures; // 0.3.0-alpha.17
use rand; // 0.7.0
use std::time::Duration;
use tokio::timer; // 0.2.0-alpha.1
enum ResourceStatus {
Ready,
NotReady,
}
use ResourceStatus::*;
async fn async_get_resource() {
const SLEEP_TIME: Duration = Duration::from_secs(1);
loop {
match poll_web_resource() {
Ready => return,
NotReady => {
// Don't actually use println in production async code.
println!("Waiting...");
timer::Delay::new(tokio::clock::now() + SLEEP_TIME).await;
}
}
}
}
fn poll_web_resource() -> ResourceStatus {
if rand::random::<f32>() < 0.1 {
Ready
} else {
NotReady
}
}
fn main() {
let runtime = tokio::runtime::Runtime::new().expect("Unable to create the runtime");
let _resource = runtime.block_on(async_get_resource());
}

What is the idiomatic way to handle/unwrap nested Result types?

I read that using unwrap on a Result is not a good practice in Rust and that it's better to use pattern matching so any error that occurred can be handled appropriately.
I get the point, but consider this snippet that reads a directory and prints the accessed time for each entry:
use std::fs;
use std::path::Path;
fn main() {
let path = Path::new(".");
match fs::read_dir(&path) {
Ok(entries) => {
for entry in entries {
match entry {
Ok(ent) => {
match ent.metadata() {
Ok(meta) => {
match meta.accessed() {
Ok(time) => {
println!("{:?}", time);
},
Err(_) => panic!("will be handled")
}
},
Err(_) => panic!("will be handled")
}
},
Err(_) => panic!("will be handled")
}
}
},
Err(_) => panic!("will be handled")
}
}
I want to handle every possible error in the code above (the panic macro is just a placeholder). While the code above works, I think it's ugly. What is the idiomatic way to handle a case like this?
I read that using unwrap on a Result is not a good practice in Rust.
It's not that easy. For example, read my answer here to learn a bit more. Now to your main problem:
Reduce right shift by passing Ok value to the outside
One big issue with your code is the right shift: for example, the meta.accessed() call is indented a whole lot. We can avoid this by passing the value we want to work with out of the match:
let entries = match fs::read_dir(&path) {
Ok(entries) => entries, // "return" from match
Err(_) => panic!("will be handled"),
};
for entry in entries { // no indentation! :)
// ...
}
That's already a very good way to make the code more readable.
Using the ? operator to pass the error to the calling function
Your function could return a Result<_, _> type in order to pass the error to the calling function (yes, even main() can return Result). In this case you can use the ? operator:
use std::{fs, io};
fn main() -> io::Result<()> {
for entry in fs::read_dir(".")? {
println!("{:?}", entry?.metadata()?.accessed()?);
}
Ok(())
}
Use helper methods of Result
There are also many helper methods, like map() or and_then(), for the Result type. and_then is helpful if you want to do something, if the result is Ok and this something will return a result of the same type. Here is your code with and_then() and manual handling of the error:
fn main() {
let path = Path::new(".");
let result = fs::read_dir(&path).and_then(|entries| {
for entry in entries {
let time = entry?.metadata()?.accessed()?;
println!("{:?}", time);
}
Ok(())
});
if let Err(e) = result {
panic!("will be handled");
}
}
There really isn't only one way to do this kind of error handling. You have to get to know all the tools you can use and then need to choose the best for your situation. However, in most situations, the ? operator is the right tool.
Result happens to have a lot of convenience methods for these kinds of things:
use std::fs;
use std::path::Path;
fn main() {
let path = Path::new(".");
match fs::read_dir(&path) {
Ok(entries) => {
for entry in entries {
match entry.and_then(|e| e.metadata()).map(|m| m.accessed()) {
Ok(time) => {
println!("{:?}", time);
},
Err(_) => panic!("will be handled")
}
}
},
Err(_) => panic!("will be handled")
}
}
And usually you will not have so much logic in main and will simply be able to use ? or try! in another function:
use std::fs;
use std::path::Path;
fn print_filetimes(path: &Path) -> Result<(), std::io::Error> {
for entry in fs::read_dir(&path)? {
let time = entry.and_then(|e| e.metadata()).map(|m| m.accessed())?;
println!("{:?}", time);
}
Ok(())
}
fn main() {
let path = Path::new(".");
match print_filetimes(path) {
Ok(()) => (),
Err(_) => panic!("will be handled"),
}
}

Resources