@@ -172,16 +172,18 @@ pub fn grid_ui_interactive(
172172 let mut drag_started_index: Option < usize > = None ;
173173 let mut thumbnail_requests: Vec < PathBuf > = Vec :: new ( ) ;
174174 let mut right_clicked = false ;
175+ let mut pending_rename_rect: Option < egui:: Rect > = None ;
176+ let mut pending_rename_font: f32 = 11.0 ;
175177
176178 // The visible grid pane rect (used for hit-testing pointer vs grid area)
177179 let grid_pane_rect = ui. max_rect ( ) ;
178180
179181 egui:: ScrollArea :: vertical ( )
180182 . id_salt ( "asset_grid" )
181183 . auto_shrink ( [ false , false ] )
184+ . drag_to_scroll ( false )
182185 . show ( ui, |ui| {
183- ui. add_space ( 4.0 ) ;
184-
186+ ui. add_space ( 5.0 ) ;
185187 let grid = TileGrid :: new ( theme)
186188 . zoom ( zoom)
187189 . available_width ( ui. available_width ( ) ) ;
@@ -228,33 +230,9 @@ pub fn grid_ui_interactive(
228230 // Inline rename UI
229231 let is_renaming = state. renaming_asset . as_ref ( ) == Some ( & entry. path ) ;
230232 if is_renaming {
231- // Draw rename TextEdit in the label area
232- let rename_rect = tile. label_rect ;
233- let rename_id = ui. id ( ) . with ( "rename_input" ) ;
234- let mut text = state. rename_buffer . clone ( ) ;
235- let resp = ui. put (
236- rename_rect,
237- egui:: TextEdit :: singleline ( & mut text)
238- . font ( FontId :: proportional ( tile. font_size ) )
239- . desired_width ( rename_rect. width ( ) )
240- . id ( rename_id) ,
241- ) ;
242- state. rename_buffer = text;
243-
244- if !state. rename_focus_set {
245- resp. request_focus ( ) ;
246- state. rename_focus_set = true ;
247- }
248-
249- // Enter to confirm rename
250- if resp. lost_focus ( ) && ui. input ( |i| i. key_pressed ( egui:: Key :: Enter ) ) {
251- let new_name = state. rename_buffer . trim ( ) . to_string ( ) ;
252- if !new_name. is_empty ( ) && new_name != entry. name {
253- state. pending_rename = Some ( ( entry. path . clone ( ) , new_name) ) ;
254- }
255- state. renaming_asset = None ;
256- }
257- // Escape handled above
233+ // Stash rename info to render outside the grid layout
234+ pending_rename_rect = Some ( tile. label_rect ) ;
235+ pending_rename_font = tile. font_size ;
258236 }
259237
260238 // Try to render an image thumbnail for supported file types
@@ -330,6 +308,46 @@ pub fn grid_ui_interactive(
330308 }
331309 }
332310
311+ // --- Inline rename (rendered outside grid layout to avoid breaking flow) ---
312+ if let Some ( rename_rect) = pending_rename_rect {
313+ let rename_id = egui:: Id :: new ( "asset_grid_rename_input" ) ;
314+ let mut text = state. rename_buffer . clone ( ) ;
315+ let area_resp = egui:: Area :: new ( rename_id. with ( "area" ) )
316+ . fixed_pos ( rename_rect. min )
317+ . order ( egui:: Order :: Foreground )
318+ . show ( & ctx, |ui| {
319+ ui. set_max_width ( rename_rect. width ( ) ) ;
320+ ui. add (
321+ egui:: TextEdit :: singleline ( & mut text)
322+ . font ( FontId :: proportional ( pending_rename_font) )
323+ . desired_width ( rename_rect. width ( ) - 8.0 )
324+ . id ( rename_id) ,
325+ )
326+ } ) ;
327+ let resp = area_resp. inner ;
328+ state. rename_buffer = text;
329+
330+ if !state. rename_focus_set {
331+ resp. request_focus ( ) ;
332+ state. rename_focus_set = true ;
333+ }
334+
335+ if resp. lost_focus ( ) {
336+ if ctx. input ( |i| i. key_pressed ( egui:: Key :: Enter ) ) {
337+ // Confirm rename
338+ let new_name = state. rename_buffer . trim ( ) . to_string ( ) ;
339+ if let Some ( ref renaming) = state. renaming_asset {
340+ let old_name = renaming. file_name ( ) . and_then ( |n| n. to_str ( ) ) . unwrap_or ( "" ) ;
341+ if !new_name. is_empty ( ) && new_name != old_name {
342+ state. pending_rename = Some ( ( renaming. clone ( ) , new_name) ) ;
343+ }
344+ }
345+ }
346+ // Cancel on click-away or Escape — discard changes
347+ state. renaming_asset = None ;
348+ }
349+ }
350+
333351 if right_clicked {
334352 state. context_menu_pos = ctx. pointer_latest_pos ( ) ;
335353 }
0 commit comments