【rust/egui】(十)使用painter绘制一些图形—connections

说在前面

  • rust新手,egui没啥找到啥教程,这里自己记录下学习过程
  • 环境:windows11 22H2
  • rust版本:rustc 1.71.1
  • egui版本:0.22.0
  • eframe版本:0.22.0
  • 上一篇:这里

绘制连接

  • 在上一节我们使用painter绘制了一个可以拖拽的小方块,现在我们来用painter将两个小方块连接起来,类似这种:
    【rust/egui】(十)使用painter绘制一些图形—connections_第1张图片
  • 首先我们需要在我们的方块上添加一个连接点,这是为了区分方块本体和连接点之间的拖拽事件:
    let port_rect = egui::Rect::from_center_size(body_rect.min, egui::vec2(10.0, 10.0));
    let port_resp = ui.allocate_rect(port_rect, egui::Sense::click_and_drag());
    ui.painter()
    	.circle(port_rect.center(), 5.0, egui::Color32::BLUE, egui::Stroke::NONE);
    
    结果如下:
    【rust/egui】(十)使用painter绘制一些图形—connections_第2张图片
  • 上述代码同时返回了拖拽事件,然后我们就需要对拖拽事件进行处理,进而在连接点与鼠标光标之间绘制一条线,以下是绘制函数:
    fn draw_connection(painter: &egui::Painter, src_pos: egui::Pos2, dst_pos: egui::Pos2, color: egui::Color32) {
        let connection_stroke = egui::Stroke { width: 5.0, color };
    
        let control_scale = ((dst_pos.x - src_pos.x) / 2.0).max(30.0);
        let src_control = src_pos + egui::Vec2::X * control_scale;
        let dst_control = dst_pos - egui::Vec2::X * control_scale;
    
    	// 贝塞尔曲线
        let bezier = egui::epaint::CubicBezierShape::from_points_stroke(
            [src_pos, src_control, dst_control, dst_pos],
            false,
            egui::Color32::TRANSPARENT,
            connection_stroke,
        );
    
        painter.add(bezier);
    }
    
  • 所以我们的目标是确定connection起点终点,起点自然是方块的连接点,终点则是光标的位置:
    let cursor_pos = ui
    	.ctx()
        .input(|i| i.pointer.hover_pos().unwrap_or(egui::Pos2::ZERO));
    
  • 同时,这个connection只有在我们开始拖拽,以及拖拽过程中才会有:
    if port_resp.drag_started() {
    	self.in_drag_port = true;
    } else if port_resp.drag_released() {
    	self.in_drag_port = false;
    }
    
    if self.in_drag_port {
    	draw_connection(ui.painter(), cursor_pos,port_rect.center(),  egui::Color32::BROWN);
    }
    
  • 最终的结果如下
    【rust/egui】(十)使用painter绘制一些图形—connections_第3张图片

建立连接

  • 如果有多个方块,那我们就可以将方块连接起来,这里为了简化,我们将另一个方块只保留连接点:
    let fix_port_rect =
    	egui::Rect::from_center_size(egui::pos2(500.0, 500.0), egui::vec2(10.0, 10.0));
    ui.painter().circle(
    	fix_port_rect.center(),
        5.0,
        egui::Color32::GRAY,
        egui::Stroke::NONE,
    );
    
    【rust/egui】(十)使用painter绘制一些图形—connections_第4张图片
  • 然后,我们需要在将connection的终点接近固定点后,将连接状态记录下来,这样就可以在之后的update中,通过这个连接状态把connection绘制出来
    if port_resp.drag_started() {
    	self.in_drag_port = true;
    	// 方块连接点拖拽开始时将连接取消
        self.connected = false;
    } else if port_resp.drag_released() {
        self.in_drag_port = false;
    	// 如果光标足够接近固定点时,建立连接,记录状态
        self.connected = if let Some(pointer_pos) = ui.ctx().pointer_hover_pos() {
        	fix_port_rect.center().distance(pointer_pos) < 10.0
        } else {
        	false
        };
    }
    
    // 如果建立了连接 直接绘制
    if self.connected {
    	draw_connection(
            ui.painter(),
            fix_port_rect.center(),
            port_rect.center(),
            egui::Color32::BROWN,
        );
    }
    
    结果如下
    【rust/egui】(十)使用painter绘制一些图形—connections_第5张图片

参考

  • egui_node_graph

你可能感兴趣的:(Rust,rust,开发语言,后端)