Problem when resizing the window

This uwindow.rs modified code

use crate::uwidgets::uwidget::UWidget;
use crate::uwidgets::uwidgetype::WidgetType;
use crate::uwidgets::button::Button;
use crate::uthemes::utheme::{UTheme, UThmTrait};
use crate::uthemes::default::ThmDefault;
use std::num::NonZeroU32;
use softbuffer::{Context, Surface};
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{WindowBuilder, Window};
use skia_safe::{surfaces,Color, Canvas, ImageInfo, ColorType, AlphaType, ColorSpace, SurfaceProps, Paint, PaintStyle};
use rand::{self, Rng};

enum RedrawRequestReason {
    DueUControl,
    DueUWindow
}


pub struct UWindow{
    pub window : WindowBuilder,
    theme : Vec<Box<dyn UThmTrait>>,
    children: Vec<UWidget>,
    children_screenoff_color: Vec<Color>,
    event_handler: Option<Box<dyn FnMut(Event<()>, &mut Self)>>,
    redraw_request_reason: RedrawRequestReason,
}


impl UWindow{

    pub fn new(event_handler: impl FnMut(Event<()>, &mut Self) + 'static)->UWindow{

        let window = WindowBuilder::new();

        return UWindow {
            window: window,
            theme: vec![Box::new(ThmDefault::new()) as Box<dyn UThmTrait>],
            children: Vec::new(),
            children_screenoff_color: Vec::new(),
            event_handler: Some(Box::new(event_handler)),
            redraw_request_reason: RedrawRequestReason::DueUWindow,
        }
    }


    pub fn run(mut self, an_event_loop: EventLoop<()>, mut event_handler: impl FnMut(Event<()>, &mut Self)){
        
        let mut resizing_window = false; // Flag to track window resizing
        let mut surface_redrawing = false;

        let w =self.window.build(&an_event_loop).unwrap();
        let context = unsafe { Context::new(&w) }.unwrap();
        let mut surface = unsafe { Surface::new(&context, &w) }.unwrap();
        let mut last_pixel = Color::from_argb(0 , 0 , 0 , 0);
        let mut _current_pixel  = Color::from_argb(0 , 0 , 0 , 0);
        let mut current_index: usize = 0;
        let mut last_index: usize = 0;
        
        let (width, height) = {
            let size = w.inner_size();
            (size.width, size.height)
        };
            
        let mut ii = ImageInfo::new((width as i32,height as i32), ColorType::RGBA8888, AlphaType::Premul, ColorSpace::new_srgb());
        let mut visible_buffer = surfaces::raster(&ii,(0) as usize, Some(&SurfaceProps::default())).expect("surface");
        let mut screenoff_buffer = surfaces::raster(&ii,(0) as usize, Some(&SurfaceProps::default())).expect("surface");


        an_event_loop.run(move |event, _, control_flow| {

            *control_flow = ControlFlow::Wait;
        
            match event {

                Event::RedrawRequested(window_id) if window_id == w.id() => {
                    surface_redrawing = true;
                    let (width, height) = {
                        let size =w.inner_size();
                        (size.width, size.height)
                    };
                    surface
                        .resize(
                            NonZeroU32::new(width).unwrap(),
                            NonZeroU32::new(height).unwrap(),
                        )
                        .unwrap();


                    let iii = ImageInfo::new((width as i32,height as i32), ColorType::RGBA8888, AlphaType::Premul, ColorSpace::new_srgb());
                    visible_buffer = surfaces::raster(&iii,(0) as usize, Some(&SurfaceProps::default())).expect("surface");
                    screenoff_buffer = surfaces::raster(&iii, 0, Some(&SurfaceProps::default())).expect("surface");
                    visible_buffer.canvas().clear(Color::WHITE);
                    screenoff_buffer.canvas().clear(Color::WHITE);
                                        
                    for i in 0..self.children.len() {
                        if let Some(theme) = self.theme.get_mut(0){
                            match &self.children[i].wdgt {
                                WidgetType::Button(button) =>{
                                self.children[i].rect_position = ((width / 2) as f32, (height / 2) as f32);
                                theme.draw_btn(visible_buffer.canvas(), screenoff_buffer.canvas(), &self.children_screenoff_color[i], self.children[i].rect_position.0, self.children[i].rect_position.1, 300.0, 100.0);
                            }
                        }
                    }
                }

                
                    let pixmap = visible_buffer.peek_pixels().unwrap().bytes().unwrap();
                    let mut buffer = surface.buffer_mut().unwrap();

                    for index in 0..(width * height) as usize {
                        buffer[index] = pixmap[index * 4 + 2] as u32
                            | (pixmap[index * 4 + 1] as u32) << 8
                            | (pixmap[index * 4] as u32) << 16;
                    }
                    buffer.present().unwrap();
                    surface_redrawing = false;
                }
    
            Event::WindowEvent { event, .. } => match event {
                // Close the software when window closed
                WindowEvent::CloseRequested => control_flow.set_exit(),
                WindowEvent::CursorMoved { position,device_id , modifiers } 
                    => {
                        let x = position.x as i32;
                        let y = position.y as i32;
                        
                        if (x <=  screenoff_buffer.image_info().bounds().width()) &&(y <= screenoff_buffer.image_info().bounds().height()) && (x>0) && (y>0){
                            _current_pixel = screenoff_buffer.peek_pixels().unwrap().get_color((x,y));
                        }
                        if last_pixel != _current_pixel && !resizing_window && !surface_redrawing{
                            last_pixel = _current_pixel;
                            println!("mouse pixel: {last_pixel:?}");
                            if self.children_screenoff_color.contains(&_current_pixel){
                                let cindex = self.children_screenoff_color.iter().position(|&c| c == _current_pixel).unwrap();
                                    if let Some(theme) = self.theme.get_mut(0){
                                        match &self.children[cindex].wdgt {
                                            WidgetType::Button(button) => {
                                                theme.draw_on_hover_btn(visible_buffer.canvas(), screenoff_buffer.canvas(), &self.children_screenoff_color[cindex], self.children[cindex].rect_position.0, self.children[cindex].rect_position.1, 300.0, 100.0);
                                                // Run on_hover function
                                                (button.on_hover)(&self.children[cindex]);

                                                current_index = cindex;

                                                let pixmap = visible_buffer.peek_pixels().unwrap().bytes().unwrap();
                                                let mut buffer = surface.buffer_mut().unwrap();

                                                for index in 0..(width * height) as usize {
                                                    buffer[index] = pixmap[index * 4 + 2] as u32
                                                        | (pixmap[index * 4 + 1] as u32) << 8
                                                        | (pixmap[index * 4] as u32) << 16;
                                                }
                                                buffer.present().unwrap();

                                            }
                                            // Add other branches for different widget types if needed
                                        }
                                    }
                            } 

                            else if !self.children_screenoff_color.contains(&_current_pixel) || current_index != last_index {
                                if let Some(theme) = self.theme.get_mut(0){
                                    match &self.children[last_index].wdgt {
                                        WidgetType::Button(button) => {
                                            theme.draw_btn(visible_buffer.canvas(), screenoff_buffer.canvas(), &self.children_screenoff_color[last_index], self.children[last_index].rect_position.0, self.children[last_index].rect_position.1, 300.0, 100.0);

                                            let pixmap = visible_buffer.peek_pixels().unwrap().bytes().unwrap();
                                            let mut buffer = surface.buffer_mut().unwrap();

                                            for index in 0..(width * height) as usize {
                                                buffer[index] = pixmap[index * 4 + 2] as u32
                                                    | (pixmap[index * 4 + 1] as u32) << 8
                                                    | (pixmap[index * 4] as u32) << 16;
                                            }
                                            buffer.present().unwrap();

                                        }
                                        // Add other branches for different widget types if needed
                                    }
                            }


                        }
                    };
                    
                }
                // Handle resizing events to prevent pixel checking during resizing
                WindowEvent::Resized(_) => {
                resizing_window = false;
                }
                // Reset resizing_window to false after resizing is completed
                WindowEvent::Resized(size) => {
                    resizing_window = true;
                }
            _ => {}
        }_ => {}
    
        }; 
        });


    }

    pub fn add_child(&mut self, child: UWidget) {
        self.children.push(child);

        // Generate a random unique color
        let mut rng = rand::thread_rng();
        let mut new_color;
        loop {
            new_color = Color::from_rgb(rng.gen::<u8>(), rng.gen::<u8>(), rng.gen::<u8>());
            if !self.children_screenoff_color.contains(&new_color) {
                break;
            }
        }

        // Add the unique color to UWindow.children_screenoff_color
        self.children_screenoff_color.push(new_color);
    }

    pub fn set_theme(&mut self, theme: Box<dyn UThmTrait>) {
        self.theme.clear(); // Clear the existing themes
        self.theme.push(theme); // Add the new theme
    }
}

I modified it because of the problem I was having

, however, I still get the error message:

thread 'main' panicked at 'index out of bounds: the len is 1914404 but the index is 1914406',/my_gui_v0.01/src/uwindow.rs:149:69
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Please always set this environment variable to get a complete backtrace so we can where the problem is occurring, and post the complete error from cargo run in the terminal.

Also please post and/or link to the code you're currently working with that produces the error. You posted one version and linked to another. It isn't clear which version of the code you're working with.

If you use clippy, it will warn about unreachable code in the following:

// Handle resizing events to prevent pixel checking during resizing
WindowEvent::Resized(_) => {
    resizing_window = false;
}
// Reset resizing_window to false after resizing is completed
WindowEvent::Resized(size) => {
    resizing_window = true;  // <- Unreachable
}

The patterns in these arms match on the same thing (every WindowEvent::Resized event), so only the first arm is ever reached. That means resizing_window will always be false.

Note that the Resized event fires after the resize, so there is no concept of 'a resize is happening' anyway. In a similar way, I don't the the surface_redrawing variable does anything because the event handlers are not run in parallel.

I think the solution is to use the WindowEvent::Resized handler to recalculate the surface size and set up the buffers. Right now you're doing this at the top of the WindowEvent::RedrawRequested handler, but it should happen in the WindowEvent::Resized handler so all the other handlers can access the recalculated dimensions (e.g. WindowEvent::CursorMoved).

2 Likes
  • RUST_BACKTRACE=1
thread 'main' panicked at 'index out of bounds: the len is 77064 but the index is 77066', /my_gui_v0.01/src/uwindow.rs:149:69
stack backtrace:
   0: rust_begin_unwind
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5
   1: core::panicking::panic_fmt
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14
   2: core::panicking::panic_bounds_check
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:162:5
   3: my_gui_v0_0_1::uwindow::UWindow::run::{{closure}}
             at ./src/uwindow.rs:149:69
   4: winit::platform_impl::platform::x11::EventLoop<T>::drain_events::{{closure}}::{{closure}}
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:522:29
   5: winit::platform_impl::platform::sticky_exit_callback
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/mod.rs:884:9
   6: winit::platform_impl::platform::x11::EventLoop<T>::drain_events::{{closure}}
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:513:17
   7: winit::platform_impl::platform::x11::event_processor::EventProcessor<T>::process_event
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/event_processor.rs:905:29
   8: winit::platform_impl::platform::x11::EventLoop<T>::drain_events
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:512:13
   9: winit::platform_impl::platform::x11::EventLoop<T>::run_return::single_iteration
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:343:13
  10: winit::platform_impl::platform::x11::EventLoop<T>::run_return
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:483:27
  11: winit::platform_impl::platform::x11::EventLoop<T>::run
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/x11/mod.rs:498:25
  12: winit::platform_impl::platform::EventLoop<T>::run
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/platform_impl/linux/mod.rs:792:56
  13: winit::event_loop::EventLoop<T>::run
             at home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.28.7/src/event_loop.rs:305:9
  14: my_gui_v0_0_1::uwindow::UWindow::run
             at ./src/uwindow.rs:70:9
  15: simple_window::main
             at ./src/examples/simple_window.rs:26:5
  16: core::ops::function::FnOnce::call_once
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
  • I have placed the modified part here, as it is not much different. I have set two additional conditions in order to prevent the pixels from being read before the surface or buffer becomes the same size as the screen, but it did not work.

I will try that