@@ -38,13 +38,13 @@ pub struct Column<'col> {
3838 pub id : usize ,
3939}
4040
41- impl < ' col > Hash for Column < ' col > {
41+ impl < ' col > Hash for Column < ' col > {
4242 fn hash < H : Hasher > ( & self , state : & mut H ) {
4343 self . name . hash ( state)
4444 }
4545}
4646
47- impl < ' col > Column < ' col > {
47+ impl < ' col > Column < ' col > {
4848 pub fn new ( name : String , value_type : ValueType ) -> Self {
4949 Self {
5050 name : Cow :: from ( name) ,
@@ -57,22 +57,22 @@ impl <'col>Column<'col> {
5757 }
5858}
5959
60- impl < ' col > Eq for Column < ' col > { }
60+ impl < ' col > Eq for Column < ' col > { }
6161
62- impl < ' col > PartialEq < Self > for Column < ' col > {
62+ impl < ' col > PartialEq < Self > for Column < ' col > {
6363 fn eq ( & self , other : & Self ) -> bool {
6464 self . name . eq ( & other. name )
6565 }
6666}
6767
6868
69- impl < ' col > PartialOrd < Self > for Column < ' col > {
69+ impl < ' col > PartialOrd < Self > for Column < ' col > {
7070 fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
7171 Some ( self . cmp ( other) )
7272 }
7373}
7474
75- impl < ' col > Ord for Column < ' col > {
75+ impl < ' col > Ord for Column < ' col > {
7676 fn cmp ( & self , other : & Self ) -> Ordering {
7777 match other. seen_count . cmp ( & self . seen_count ) {
7878 Ordering :: Equal => other. order . cmp ( & self . order ) ,
@@ -127,14 +127,24 @@ pub struct ArrayTable<'array> {
127127 pub matching_column_selected : usize ,
128128 pub scroll_to_column : String ,
129129 pub scroll_to_row : String ,
130+ pub scroll_to_row_number : usize ,
131+ pub scroll_to_column_number : usize ,
130132 pub scroll_to_row_mode : ScrollToRowMode ,
131133 pub focused_cell : Option < CellLocation > ,
132134
135+ // Visibility information
136+ pub first_visible_index : usize ,
137+ pub last_visible_index : usize ,
138+ pub first_visible_offset : f32 ,
139+ pub last_visible_offset : f32 ,
140+
133141 // Handle interaction
134142 pub next_frame_reset_scroll : bool ,
135143 pub changed_scroll_to_column_value : bool ,
136144 pub changed_matching_column_selected : bool ,
137145 pub changed_matching_row_selected : bool ,
146+ pub changed_arrow_horizontal_scroll : bool ,
147+ pub changed_arrow_vertical_scroll : bool ,
138148
139149 #[ cfg( not( target_arch = "wasm32" ) ) ]
140150 pub changed_scroll_to_row_value : Option < std:: time:: Instant > ,
@@ -149,7 +159,7 @@ pub struct ArrayTable<'array> {
149159}
150160
151161
152- impl < ' array > super :: View < ArrayResponse > for ArrayTable < ' array > {
162+ impl < ' array > super :: View < ArrayResponse > for ArrayTable < ' array > {
153163 fn ui ( & mut self , ui : & mut egui:: Ui ) -> ArrayResponse {
154164 use egui_extras:: { Size , StripBuilder } ;
155165 let mut array_response = ArrayResponse :: default ( ) ;
@@ -189,6 +199,15 @@ impl <'array>super::View<ArrayResponse> for ArrayTable<'array> {
189199 }
190200 }
191201
202+ if self . changed_arrow_horizontal_scroll {
203+ self . changed_arrow_horizontal_scroll = false ;
204+ if !( self . first_visible_index < self . scroll_to_column_number && self . scroll_to_column_number < self . last_visible_index ) {
205+ if let Some ( offset) = self . columns_offset . get ( self . scroll_to_column_number ) {
206+ scroll_to_x = Some ( * offset) ;
207+ }
208+ }
209+ }
210+
192211 if self . changed_matching_column_selected {
193212 self . changed_matching_column_selected = false ;
194213 if !self . matching_columns . is_empty ( ) {
@@ -239,7 +258,7 @@ impl Hash for CachePointerKey {
239258 }
240259}
241260
242- impl < ' array > crate :: components:: cache:: ComputerMut < ( & Column < ' array > , & String ) , & Vec < JsonArrayEntries < String > > , IndexSet < String > > for CacheFilterOptions {
261+ impl < ' array > crate :: components:: cache:: ComputerMut < ( & Column < ' array > , & String ) , & Vec < JsonArrayEntries < String > > , IndexSet < String > > for CacheFilterOptions {
243262 fn compute ( & mut self , ( column, parent_pointer) : ( & Column < ' array > , & String ) , nodes : & Vec < JsonArrayEntries < String > > ) -> IndexSet < String > {
244263 let mut unique_values = IndexSet :: new ( ) ;
245264 if ArrayTable :: is_filterable ( column) {
@@ -272,7 +291,7 @@ impl <'array> crate::components::cache::ComputerMut<(&Column<'array>, &String),
272291}
273292
274293
275- impl < ' array > crate :: components:: cache:: ComputerMut < CachePointerKey , & ArrayTable < ' array > , Option < usize > > for CacheGetPointer {
294+ impl < ' array > crate :: components:: cache:: ComputerMut < CachePointerKey , & ArrayTable < ' array > , Option < usize > > for CacheGetPointer {
276295 fn compute ( & mut self , cache_pointer_key : CachePointerKey , table : & ArrayTable < ' array > ) -> Option < usize > {
277296 let columns = if cache_pointer_key. pinned_column_table { & table. column_pinned } else { & table. column_selected } ;
278297 ArrayTable :: get_pointer_index ( & table. parent_pointer , columns, & table. nodes ( ) [ cache_pointer_key. row_index ] . entries ( ) , cache_pointer_key. index , cache_pointer_key. row_index )
@@ -281,7 +300,7 @@ impl <'array>crate::components::cache::ComputerMut<CachePointerKey, &ArrayTable<
281300
282301pub const NON_NULL_FILTER_VALUE : & str = "__non_null" ;
283302
284- impl < ' array > ArrayTable < ' array > {
303+ impl < ' array > ArrayTable < ' array > {
285304 pub fn new ( parse_result : Option < ParseResult < String > > , nodes : Vec < JsonArrayEntries < String > > , all_columns : Vec < Column < ' array > > , depth : u8 , parent_pointer : PointerKey ) -> Self {
286305 let last_parsed_max_depth = parse_result. as_ref ( ) . map_or ( depth, |p| p. parsing_max_depth ) ;
287306 Self {
@@ -311,13 +330,21 @@ impl <'array>ArrayTable<'array> {
311330 columns_filter : HashMap :: new ( ) ,
312331 scroll_to_row_mode : ScrollToRowMode :: RowNumber ,
313332 scroll_to_row : "" . to_string ( ) ,
333+ scroll_to_row_number : 0 ,
334+ scroll_to_column_number : 0 ,
314335 changed_scroll_to_row_value : None ,
315336 changed_matching_row_selected : false ,
316337 changed_matching_column_selected : false ,
338+ changed_arrow_horizontal_scroll : false ,
339+ changed_arrow_vertical_scroll : false ,
317340 editing_index : RefCell :: new ( None ) ,
318341 editing_value : RefCell :: new ( String :: new ( ) ) ,
319342 is_sub_table : false ,
320343 focused_cell : None ,
344+ first_visible_index : 0 ,
345+ last_visible_index : 0 ,
346+ first_visible_offset : 0.0 ,
347+ last_visible_offset : 0.0 ,
321348 cache : Default :: default ( ) ,
322349 opened_windows : Default :: default ( ) ,
323350 search_replace_panel : Default :: default ( ) ,
@@ -470,6 +497,10 @@ impl <'array>ArrayTable<'array> {
470497 }
471498 }
472499 }
500+ if self . changed_arrow_vertical_scroll {
501+ self . changed_arrow_vertical_scroll = false ;
502+ table = table. scroll_to_row ( self . scroll_to_row_number , Some ( Align :: Center ) ) ;
503+ }
473504 if self . changed_matching_row_selected {
474505 self . changed_matching_row_selected = false ;
475506 table = table. scroll_to_row ( self . matching_rows [ self . matching_row_selected ] , Some ( Align :: Center ) ) ;
@@ -503,19 +534,23 @@ impl <'array>ArrayTable<'array> {
503534 } else {
504535 None
505536 } ;
506- let table_scroll_output = table
537+ let table_response = table
507538 . header ( text_height * 2.0 , |header| {
508539 self . header ( pinned_column_table, header) ;
509540 } )
510541 . body ( self . hovered_row_index , search_highlight_row, self . focused_cell , |body| {
511542 self . body ( text_height, pinned_column_table, & mut array_response, request_repaint, body) ;
512543 } ) ;
513-
544+ let table_scroll_output = table_response . scroll_area_output ;
514545 if self . scroll_y != table_scroll_output. state . offset . y {
515546 self . scroll_y = table_scroll_output. state . offset . y ;
516547 }
517548 if !pinned_column_table {
518- self . columns_offset = table_scroll_output. inner ;
549+ self . columns_offset = table_response. columns_offset ;
550+ self . first_visible_index = table_response. first_visible_index ;
551+ self . first_visible_offset = table_response. first_visible_offset ;
552+ self . last_visible_index = table_response. last_visible_index ;
553+ self . last_visible_offset = table_response. last_visible_offset ;
519554 }
520555 if request_repaint {
521556 ui. ctx ( ) . request_repaint ( ) ;
@@ -682,7 +717,7 @@ impl <'array>ArrayTable<'array> {
682717 * self . editing_value . borrow_mut ( ) = value. clone ( ) ;
683718 * editing_index = Some ( ( col_index, row_index, pinned_column_table) ) ;
684719 }
685- if response. secondary_clicked ( ) {
720+ if response. secondary_clicked ( ) || response . clicked ( ) {
686721 focused_cell = Some ( CellLocation { column_index : col_index, row_index : table_row_index, is_pinned_column_table : pinned_column_table } ) ;
687722 focused_changed = true ;
688723 }
@@ -750,12 +785,6 @@ impl <'array>ArrayTable<'array> {
750785 }
751786 } ) ;
752787
753- if let Some ( focused_cell_location) = self . focused_cell {
754- if focused_cell_location. is_pinned_column_table == pinned_column_table && focused_cell_location. row_index == table_row_index && focused_cell_location. column_index == col_index && !response. context_menu_opened ( ) {
755- focused_cell = None ;
756- focused_changed = true ;
757- }
758- }
759788 if response. hovered ( ) {
760789 ui. ctx ( ) . set_cursor_icon ( CursorIcon :: Cell ) ;
761790 }
@@ -780,7 +809,7 @@ impl <'array>ArrayTable<'array> {
780809 * editing_index = Some ( ( col_index, row_index, pinned_column_table) ) ;
781810 }
782811
783- if response. secondary_clicked ( ) {
812+ if response. secondary_clicked ( ) || response . clicked ( ) {
784813 focused_cell = Some ( CellLocation { column_index : col_index, row_index : table_row_index, is_pinned_column_table : pinned_column_table } ) ;
785814 focused_changed = true ;
786815 }
@@ -818,12 +847,7 @@ impl <'array>ArrayTable<'array> {
818847 }
819848 } ) ;
820849
821- if let Some ( focused_cell_location) = self . focused_cell {
822- if focused_cell_location. is_pinned_column_table == pinned_column_table && focused_cell_location. row_index == table_row_index && focused_cell_location. column_index == col_index && !response. context_menu_opened ( ) {
823- focused_cell = None ;
824- focused_changed = true ;
825- }
826- }
850+
827851 if response. hovered ( ) {
828852 ui. ctx ( ) . set_cursor_icon ( CursorIcon :: Cell ) ;
829853 }
@@ -906,22 +930,25 @@ impl <'array>ArrayTable<'array> {
906930 let substring_len = substring_len + ( i. checked_ilog10 ( ) . unwrap_or ( 0 ) + 1 ) as usize ;
907931 let new_prefix = concat_string ! ( self . parent_pointer. pointer, "/" , ( i+1 ) . to_string( ) ) ;
908932 self . nodes [ i] . entries . iter_mut ( ) . for_each ( |e| {
909- e. pointer . pointer = concat_string ! ( new_prefix, e. pointer. pointer[ substring_len..] ) ;
933+ e. pointer . pointer = concat_string ! ( new_prefix, e. pointer. pointer[ substring_len..] ) ;
910934 } )
911935 }
912936 let new_entry_pointer = concat_string ! ( self . parent_pointer. pointer, "/" , new_index. to_string( ) ) ;
913937 self . nodes . insert ( new_index, JsonArrayEntries {
914938 entries : vec ! [
915939 row_number_entry( new_index, 0 , new_entry_pointer. as_str( ) ) ,
916- FlatJsonValue { pointer: PointerKey {
917- pointer: new_entry_pointer,
918- value_type: ValueType :: Object ( true , 0 ) ,
919- depth,
920- position: 0 ,
921- column_id: 0 ,
922- } , value: Some ( "{}" . to_string( ) ) }
940+ FlatJsonValue {
941+ pointer: PointerKey {
942+ pointer: new_entry_pointer,
943+ value_type: ValueType :: Object ( true , 0 ) ,
944+ depth,
945+ position: 0 ,
946+ column_id: 0 ,
947+ } ,
948+ value: Some ( "{}" . to_string( ) )
949+ }
923950 ] ,
924- index : new_index
951+ index : new_index,
925952 } ) ;
926953 self . filtered_nodes . insert ( table_row_index + above_or_below as usize , new_index) ;
927954 self . cache . borrow_mut ( ) . evict ( ) ;
@@ -966,7 +993,7 @@ impl <'array>ArrayTable<'array> {
966993
967994 let value_changed = Self :: update_row ( & mut self . nodes [ row_index] . entries , updated_entry, self . is_sub_table , self . last_parsed_max_depth ) ;
968995 if value_changed {
969- self . cache . borrow_mut ( ) . evict ( ) ;
996+ self . cache . borrow_mut ( ) . evict ( ) ;
970997 }
971998 value_changed
972999 }
@@ -1100,6 +1127,40 @@ impl <'array>ArrayTable<'array> {
11001127 fn handle_shortcut ( & mut self , ui : & mut Ui , array_response : & mut ArrayResponse ) {
11011128 let mut copied_value = None ;
11021129 ui. input_mut ( |i| {
1130+ if let Some ( focused_cell) = self . focused_cell . as_mut ( ) {
1131+ if i. key_pressed ( Key :: ArrowLeft ) {
1132+ if !focused_cell. is_pinned_column_table && focused_cell. column_index > 0 {
1133+ focused_cell. column_index = focused_cell. column_index - 1 ;
1134+ self . scroll_to_column_number = focused_cell. column_index ;
1135+ self . changed_arrow_horizontal_scroll = true ;
1136+ } else if focused_cell. is_pinned_column_table && focused_cell. column_index > 1 {
1137+ focused_cell. column_index = focused_cell. column_index - 1 ;
1138+ }
1139+ }
1140+ if i. key_pressed ( Key :: ArrowRight ) {
1141+ if !focused_cell. is_pinned_column_table && focused_cell. column_index < self . column_selected . len ( ) - 1 {
1142+ focused_cell. column_index = focused_cell. column_index + 1 ;
1143+ self . scroll_to_column_number = focused_cell. column_index ;
1144+ self . changed_arrow_horizontal_scroll = true ;
1145+ } else if focused_cell. is_pinned_column_table && focused_cell. column_index < self . column_pinned . len ( ) - 1 {
1146+ focused_cell. column_index = focused_cell. column_index + 1 ;
1147+ }
1148+ }
1149+ if i. key_pressed ( Key :: ArrowUp ) {
1150+ if focused_cell. row_index > 0 {
1151+ focused_cell. row_index = focused_cell. row_index - 1 ;
1152+ self . scroll_to_row_number = focused_cell. row_index ;
1153+ self . changed_arrow_vertical_scroll = true ;
1154+ }
1155+ }
1156+ if i. key_pressed ( Key :: ArrowDown ) {
1157+ if focused_cell. row_index < self . nodes . len ( ) - 1 {
1158+ focused_cell. row_index = focused_cell. row_index + 1 ;
1159+ self . scroll_to_row_number = focused_cell. row_index ;
1160+ self . changed_arrow_vertical_scroll = true ;
1161+ }
1162+ }
1163+ }
11031164 if i. consume_shortcut ( & SHORTCUT_DELETE ) {
11041165 i. events . push ( egui:: Event :: Key {
11051166 key : Key :: Delete ,
@@ -1116,15 +1177,15 @@ impl <'array>ArrayTable<'array> {
11161177 for event in i. events . iter ( ) . filter ( |e| match e {
11171178 egui:: Event :: Copy => hovered_cell. is_some ( ) ,
11181179 egui:: Event :: Paste ( _) => hovered_cell. is_some ( ) ,
1119- egui:: Event :: Key { key : Key :: Delete , ..} => hovered_cell. is_some ( ) ,
1180+ egui:: Event :: Key { key : Key :: Delete , .. } => hovered_cell. is_some ( ) ,
11201181 _ => false ,
11211182 } ) {
11221183 let cell_location = hovered_cell. unwrap ( ) ;
11231184 let row_index = self . filtered_nodes [ cell_location. row_index ] ;
11241185 let index = self . get_pointer_index_from_cache ( cell_location. is_pinned_column_table , & & self . nodes [ row_index] , cell_location. column_index ) ;
11251186
11261187 match event {
1127- egui:: Event :: Key { key : Key :: Delete , ..} => {
1188+ egui:: Event :: Key { key : Key :: Delete , .. } => {
11281189 let columns = self . columns ( cell_location. is_pinned_column_table ) ;
11291190 let pointer = Self :: pointer_key ( & self . parent_pointer . pointer , row_index, columns. get ( cell_location. column_index ) . as_ref ( ) . unwrap ( ) . name . as_str ( ) ) ;
11301191 let flat_json_value = FlatJsonValue :: < String > {
@@ -1148,7 +1209,7 @@ impl <'array>ArrayTable<'array> {
11481209 } ;
11491210 match flat_json_value. pointer . value_type {
11501211 // When we paste an object it should not be considered as parsed
1151- ValueType :: Object ( ..) => { flat_json_value. pointer . value_type = ValueType :: Object ( false , 0 ) }
1212+ ValueType :: Object ( ..) => { flat_json_value. pointer . value_type = ValueType :: Object ( false , 0 ) }
11521213 _ => { }
11531214 }
11541215 self . edit_cell ( array_response, flat_json_value, row_index) ;
0 commit comments