@@ -293,18 +293,19 @@ impl DockItem {
293293 icon_button. into ( )
294294 } ;
295295
296+ let icon_origin = iced:: Vector :: new ( app_icon. padding . left , app_icon. padding . top ) ;
296297 let path = desktop_info. path . clone ( ) ;
297298 let icon_button = if dnd_source_enabled && interaction_enabled {
298299 dnd_source ( icon_button)
299300 . window ( window_id)
300- . drag_icon ( move |_ | {
301+ . drag_icon ( move |pointer_offset | {
301302 (
302303 cosmic_icon. clone ( ) . into ( ) ,
303304 iced:: core:: widget:: tree:: State :: None ,
304- iced :: Vector :: ZERO ,
305+ icon_origin - pointer_offset ,
305306 )
306307 } )
307- . drag_threshold ( 16 .)
308+ . drag_threshold ( 0 .)
308309 . drag_content ( move || DndPathBuf ( path. clone ( ) ) )
309310 . on_start ( Some ( Message :: StartDrag ( * id) ) )
310311 . on_cancel ( Some ( Message :: DragFinished ) )
@@ -319,6 +320,15 @@ impl DockItem {
319320 icon_button. into ( )
320321 }
321322 }
323+
324+ fn as_draged_item ( & self , applet : & Context ) -> Element < ' _ , Message > {
325+ let app_icon = AppletIconData :: new ( applet) ;
326+
327+ container ( horizontal_space ( ) )
328+ . width ( app_icon. icon_size as f32 + app_icon. padding . left + app_icon. padding . right )
329+ . height ( app_icon. icon_size as f32 + app_icon. padding . top + app_icon. padding . bottom )
330+ . into ( )
331+ }
322332}
323333
324334#[ derive( Debug , Clone , Default ) ]
@@ -344,6 +354,7 @@ struct CosmicAppList {
344354 desktop_entries : Vec < DesktopEntry > ,
345355 active_list : Vec < DockItem > ,
346356 pinned_list : Vec < DockItem > ,
357+ dragged_item : Option < DockItem > ,
347358 dnd_source : Option < ( window:: Id , DockItem , DndAction , Option < usize > ) > ,
348359 config : AppListConfig ,
349360 wayland_sender : Option < Sender < WaylandRequest > > ,
@@ -404,40 +415,21 @@ enum Message {
404415}
405416
406417fn index_in_list (
407- mut list_len : usize ,
418+ list_len : usize ,
408419 item_size : f32 ,
409- divider_size : f32 ,
420+ center_threshold : f32 ,
410421 existing_preview : Option < usize > ,
411422 pos_in_list : f32 ,
412423) -> usize {
413- if existing_preview. is_some ( ) {
414- list_len += 1 ;
415- }
424+ let current_index = existing_preview. unwrap_or ( 0 ) ;
425+ let current_center = current_index as f32 * item_size + item_size / 2.0 ;
416426
417- let index = if ( list_len == 0 ) || ( pos_in_list < item_size / 2.0 ) {
418- 0
427+ if pos_in_list > current_center + item_size - center_threshold {
428+ ( current_index + 1 ) . min ( list_len)
429+ } else if pos_in_list < current_center - item_size + center_threshold {
430+ current_index. saturating_sub ( 1 )
419431 } else {
420- let mut i = 1 ;
421- let mut pos = item_size / 2.0 ;
422- while i < list_len {
423- let next_pos = pos + item_size + divider_size;
424- if pos < pos_in_list && pos_in_list < next_pos {
425- break ;
426- }
427- pos = next_pos;
428- i += 1 ;
429- }
430- i
431- } ;
432-
433- if let Some ( existing_preview) = existing_preview {
434- if index >= existing_preview {
435- index. saturating_sub ( 1 )
436- } else {
437- index
438- }
439- } else {
440- index
432+ current_index
441433 }
442434}
443435
@@ -1083,8 +1075,18 @@ impl cosmic::Application for CosmicAppList {
10831075 } )
10841076 {
10851077 let icon_id = window:: Id :: unique ( ) ;
1078+ if let Some ( pinned_pos) = pos {
1079+ let entry = self . pinned_list . remove ( pinned_pos) ;
1080+ if !entry. toplevels . is_empty ( ) {
1081+ self . dragged_item = Some ( entry) ;
1082+ }
1083+ }
10861084 self . dnd_source =
10871085 Some ( ( icon_id, toplevel_group. clone ( ) , DndAction :: empty ( ) , pos) ) ;
1086+ self . dnd_offer = Some ( DndOffer {
1087+ dock_item : Some ( toplevel_group) ,
1088+ preview_index : pos. unwrap_or ( self . pinned_list . len ( ) ) ,
1089+ } ) ;
10881090 }
10891091 }
10901092 Message :: DragFinished => {
@@ -1127,14 +1129,20 @@ impl cosmic::Application for CosmicAppList {
11271129 } ;
11281130 let num_pinned = self . pinned_list . len ( ) ;
11291131 let index = index_in_list ( num_pinned, item_size as f32 , 4.0 , None , pos_in_list) ;
1130- self . dnd_offer = Some ( DndOffer {
1131- preview_index : index,
1132- ..DndOffer :: default ( )
1133- } ) ;
11341132 if let Some ( dnd_source) = self . dnd_source . as_ref ( ) {
1135- self . dnd_offer . as_mut ( ) . unwrap ( ) . dock_item = Some ( dnd_source. 1 . clone ( ) ) ;
1133+ let source_id = dnd_source. 1 . desktop_info . id ( ) . to_string ( ) ;
1134+ self . pinned_list
1135+ . retain ( |p| p. desktop_info . id ( ) != source_id) ;
1136+
1137+ self . dnd_offer = Some ( DndOffer {
1138+ preview_index : index,
1139+ dock_item : Some ( dnd_source. 1 . clone ( ) ) ,
1140+ } ) ;
11361141 } else {
1137- // TODO dnd
1142+ self . dnd_offer = Some ( DndOffer {
1143+ preview_index : index,
1144+ ..DndOffer :: default ( )
1145+ } ) ;
11381146 return peek_dnd :: < DndPathBuf > ( )
11391147 . map ( Message :: DndData )
11401148 . map ( cosmic:: Action :: App ) ;
@@ -1160,17 +1168,9 @@ impl cosmic::Application for CosmicAppList {
11601168 }
11611169 }
11621170 Message :: DndLeave => {
1163- if let Some ( ( _, toplevel_group, _, pinned_pos) ) = self . dnd_source . as_ref ( ) {
1164- let mut pos = 0 ;
1165- self . pinned_list . retain_mut ( |pinned| {
1166- let matched_id =
1167- pinned. desktop_info . id ( ) == toplevel_group. desktop_info . id ( ) ;
1168- let pinned_match = pinned_pos. is_some_and ( |pinned_pos| pinned_pos == pos) ;
1169- let ret = !matched_id || pinned_match;
1170-
1171- pos += 1 ;
1172- ret
1173- } ) ;
1171+ if let Some ( dragged_item) = self . dragged_item . take ( ) {
1172+ self . active_list . push ( dragged_item) ;
1173+ self . dragged_item = None ;
11741174 }
11751175 self . dnd_offer = None ;
11761176 }
@@ -1768,18 +1768,7 @@ impl cosmic::Application for CosmicAppList {
17681768 {
17691769 favorites. insert (
17701770 index. min ( favorites. len ( ) ) ,
1771- item. as_icon (
1772- & self . core . applet ,
1773- None ,
1774- false ,
1775- self . config . enable_drag_source ,
1776- self . gpus . as_deref ( ) ,
1777- item. toplevels
1778- . iter ( )
1779- . any ( |y| focused_item. contains ( & y. 0 . foreign_toplevel ) ) ,
1780- dot_radius,
1781- self . core . main_window_id ( ) . unwrap ( ) ,
1782- ) ,
1771+ item. as_draged_item ( & self . core . applet ) ,
17831772 ) ;
17841773 } else if self . is_listening_for_dnd && self . pinned_list . is_empty ( ) {
17851774 // show star indicating pinned_list is drag target
0 commit comments