55
66//! Cells: a mini spreadsheet
77
8- use kas:: event :: { Command , FocusSource } ;
9- use kas :: prelude :: * ;
10- use kas :: view :: { DataKey , Driver , MatrixData , MatrixView , SharedData } ;
8+ use kas:: view :: {
9+ DataChanges , DataClerk , DataKey , DataLen , Driver , GridIndex , GridView , TokenChanges ,
10+ } ;
1111use kas:: widgets:: { EditBox , EditField , EditGuard , ScrollBars } ;
12+ use kas:: { prelude:: * , TextOrSource } ;
1213use std:: collections:: HashMap ;
13- use std:: { fmt, iter , ops } ;
14+ use std:: fmt;
1415
1516#[ derive( Copy , Clone , Eq , PartialEq , Debug , Default , Hash ) ]
1617pub struct ColKey ( u8 ) ;
17- type ColKeyIter = iter:: Map < ops:: RangeInclusive < u8 > , fn ( u8 ) -> ColKey > ;
1818impl ColKey {
1919 const LEN : u8 = 26 ;
2020 fn try_from_u8 ( n : u8 ) -> Option < Self > {
2121 if ( b'A' ..=b'Z' ) . contains ( & n) {
22- Some ( ColKey ( n) )
22+ Some ( ColKey ( n - b'A' ) )
2323 } else {
2424 None
2525 }
2626 }
2727 fn from_u8 ( n : u8 ) -> Self {
2828 Self :: try_from_u8 ( n) . expect ( "bad column key" )
2929 }
30- fn iter_keys ( ) -> ColKeyIter {
31- ( b'A' ..=b'Z' ) . map ( ColKey :: from_u8)
32- }
3330}
3431
3532impl fmt:: Display for ColKey {
@@ -39,7 +36,7 @@ impl fmt::Display for ColKey {
3936 }
4037}
4138
42- const MAX_ROW : u8 = 99 ;
39+ const ROW_LEN : u32 = 100 ;
4340
4441#[ derive( Clone , Copy , Debug , Default , PartialEq , Eq , Hash ) ]
4542pub struct Key ( ColKey , u8 ) ;
@@ -265,15 +262,6 @@ impl Cell {
265262 self . input = input;
266263 }
267264
268- /// Get display string
269- fn display ( & self ) -> String {
270- if !self . display . is_empty ( ) {
271- self . display . clone ( )
272- } else {
273- self . input . clone ( )
274- }
275- }
276-
277265 fn try_eval ( & mut self , values : & HashMap < Key , f64 > ) -> Result < Option < f64 > , EvalError > {
278266 if self . parse_error {
279267 // Display the error locally; propegate NaN
@@ -345,60 +333,50 @@ impl CellData {
345333 }
346334}
347335
348- #[ derive( Clone , Debug , Default ) ]
349- struct Item {
350- input : String ,
351- display : String ,
352- error : bool ,
336+ struct Clerk {
337+ empty_cell : Cell ,
353338}
354339
355- impl SharedData for CellData {
340+ impl DataClerk < GridIndex > for Clerk {
341+ type Data = CellData ;
356342 type Key = Key ;
357- type Item = Item ;
358- type ItemRef < ' b > = Self :: Item ;
343+ type Item = Cell ;
344+ type Token = Key ;
359345
360- fn contains_key ( & self , _: & Self :: Key ) -> bool {
361- // we know both sub-keys are valid and that the length is fixed
362- true
346+ fn update ( & mut self , _: & mut ConfigCx < ' _ > , _: Id , _: & Self :: Data ) -> DataChanges {
347+ DataChanges :: Any
363348 }
364349
365- fn borrow ( & self , key : & Self :: Key ) -> Option < Self :: Item > {
366- self . cells
367- . get ( key)
368- . map ( |cell| Item {
369- input : cell. input . clone ( ) ,
370- display : cell. display ( ) ,
371- error : cell. parse_error ,
372- } )
373- . or_else ( || Some ( Item :: default ( ) ) )
374- }
375- }
376-
377- impl MatrixData for CellData {
378- type ColKey = ColKey ;
379- type RowKey = u8 ;
380- type ColKeyIter < ' b > = iter:: Take < iter:: Skip < ColKeyIter > > ;
381- type RowKeyIter < ' b > = iter:: Take < iter:: Skip < ops:: RangeInclusive < u8 > > > ;
382-
383- fn is_empty ( & self ) -> bool {
384- false
385- }
386- fn len ( & self ) -> ( usize , usize ) {
387- ( ColKey :: LEN . cast ( ) , 99 )
350+ fn len ( & self , _: & CellData , _: GridIndex ) -> DataLen < GridIndex > {
351+ DataLen :: Known ( GridIndex {
352+ col : ColKey :: LEN . cast ( ) ,
353+ row : ROW_LEN ,
354+ } )
388355 }
389356
390- fn col_iter_from ( & self , start : usize , limit : usize ) -> Self :: ColKeyIter < ' _ > {
391- ColKey :: iter_keys ( ) . skip ( start) . take ( limit)
392- }
357+ fn update_token (
358+ & self ,
359+ _: & CellData ,
360+ index : GridIndex ,
361+ _: bool ,
362+ token : & mut Option < Key > ,
363+ ) -> TokenChanges {
364+ if index. col >= ColKey :: LEN as u32 || index. row >= ROW_LEN {
365+ * token = None ;
366+ return TokenChanges :: Any ;
367+ }
393368
394- fn row_iter_from ( & self , start : usize , limit : usize ) -> Self :: RowKeyIter < ' _ > {
395- // NOTE: for strict compliance with the 7GUIs challenge the rows should
396- // start from 0, but any other spreadsheet I've seen starts from 1!
397- ( 1 ..=MAX_ROW ) . skip ( start) . take ( limit)
369+ let key = Key ( ColKey ( index. col as u8 ) , index. row as u8 ) ;
370+ if * token == Some ( key) {
371+ TokenChanges :: None
372+ } else {
373+ * token = Some ( key) ;
374+ TokenChanges :: Any
375+ }
398376 }
399377
400- fn make_key ( & self , col : & Self :: ColKey , row : & Self :: RowKey ) -> Self :: Key {
401- Key ( * col , * row )
378+ fn item < ' r > ( & ' r self , data : & ' r CellData , key : & ' r Key ) -> & ' r Cell {
379+ data . cells . get ( key ) . unwrap_or ( & self . empty_cell )
402380 }
403381}
404382
@@ -411,39 +389,42 @@ struct CellGuard {
411389 is_input : bool ,
412390}
413391impl EditGuard for CellGuard {
414- type Data = Item ;
392+ type Data = Cell ;
415393
416- fn update ( edit : & mut EditField < Self > , cx : & mut ConfigCx , item : & Item ) {
417- let mut action = edit. set_error_state ( item. error ) ;
394+ fn update ( edit : & mut EditField < Self > , cx : & mut ConfigCx , item : & Cell ) {
395+ edit. set_error_state ( cx , item. parse_error ) ;
418396 if !edit. has_edit_focus ( ) {
419- action |= edit. set_str ( & item. display ) ;
397+ let text = if !item. display . is_empty ( ) {
398+ & item. display
399+ } else {
400+ & item. input
401+ } ;
402+ edit. set_str ( cx, text) ;
420403 edit. guard . is_input = false ;
421404 }
422- cx. action ( edit, action) ;
423405 }
424406
425- fn activate ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Item ) -> IsUsed {
407+ fn activate ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Cell ) -> IsUsed {
426408 Self :: focus_lost ( edit, cx, item) ;
427409 IsUsed :: Used
428410 }
429411
430- fn focus_gained ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Item ) {
431- cx . action ( edit. id ( ) , edit . set_str ( & item. input ) ) ;
412+ fn focus_gained ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Cell ) {
413+ edit. set_str ( cx , & item. input ) ;
432414 edit. guard . is_input = true ;
433415 }
434416
435- fn focus_lost ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Item ) {
436- let s = edit. get_string ( ) ;
437- if edit. guard . is_input && s != item. input {
438- cx. push ( UpdateInput ( edit. guard . key , s) ) ;
417+ fn focus_lost ( edit : & mut EditField < Self > , cx : & mut EventCx , item : & Cell ) {
418+ if edit. guard . is_input && edit. as_str ( ) != item. input {
419+ cx. push ( UpdateInput ( edit. guard . key , edit. clone_string ( ) ) ) ;
439420 }
440421 }
441422}
442423
443424#[ derive( Debug ) ]
444425struct CellDriver ;
445426
446- impl Driver < Item , CellData > for CellDriver {
427+ impl Driver < Key , Cell > for CellDriver {
447428 // TODO: we should use EditField instead of EditBox but:
448429 // (a) there is currently no code to draw separators between cells
449430 // (b) EditField relies on a parent (EditBox) to draw background highlight on error state
@@ -454,6 +435,15 @@ impl Driver<Item, CellData> for CellDriver {
454435 key : * key,
455436 is_input : false ,
456437 } )
438+ . with_width_em ( 6.0 , 6.0 )
439+ }
440+
441+ fn navigable ( _: & Self :: Widget ) -> bool {
442+ false
443+ }
444+
445+ fn label ( widget : & Self :: Widget ) -> Option < TextOrSource < ' _ > > {
446+ Some ( widget. as_str ( ) . into ( ) )
457447 }
458448}
459449
@@ -470,46 +460,29 @@ pub fn window() -> Window<()> {
470460 cells. insert ( make_key ( "C2" ) , Cell :: new ( "= A2 * A3 * A4" ) ) ;
471461 data. update_values ( ) ;
472462
473- let cells = MatrixView :: new ( CellDriver ) . with_num_visible ( 5 , 20 ) ;
463+ let clerk = Clerk {
464+ empty_cell : Cell :: default ( ) ,
465+ } ;
466+
467+ let cells = GridView :: new ( clerk, CellDriver ) . with_num_visible ( 5 , 20 ) ;
474468
475469 let ui = impl_anon ! {
476- #[ widget {
477- layout = self . cells;
478- } ]
470+ #[ widget]
471+ #[ layout( self . cells) ]
479472 struct {
480473 core: widget_core!( ) ,
481474 data: CellData = data,
482- #[ widget( & self . data) ] cells: ScrollBars <MatrixView < CellData , CellDriver >> =
475+ #[ widget( & self . data) ] cells: ScrollBars <GridView < Clerk , CellDriver >> =
483476 ScrollBars :: new( cells) ,
484477 }
485478 impl Events for Self {
486479 type Data = ( ) ;
487480
488- fn steal_event( & mut self , cx: & mut EventCx , _: & ( ) , _: & Id , event: & Event ) -> IsUsed {
489- match event {
490- Event :: Command ( Command :: Enter , _) => {
491- if let Some ( Key ( col, row) ) = cx. nav_focus( ) . and_then( |id| {
492- Key :: reconstruct_key( self . cells. inner( ) . id_ref( ) , id)
493- } )
494- {
495- let row = if cx. modifiers( ) . shift_key( ) {
496- ( row - 1 ) . max( 1 )
497- } else {
498- ( row + 1 ) . min( MAX_ROW )
499- } ;
500- let id = Key ( col, row) . make_id( self . cells. inner( ) . id_ref( ) ) ;
501- cx. next_nav_focus( Some ( id) , false , FocusSource :: Synthetic ) ;
502- }
503- IsUsed :: Used
504- } ,
505- _ => IsUsed :: Unused
506- }
507- }
508-
509481 fn handle_messages( & mut self , cx: & mut EventCx , _: & ( ) ) {
510482 if let Some ( UpdateInput ( key, input) ) = cx. try_pop( ) {
511483 self . data. cells. entry( key) . or_default( ) . update( input) ;
512484 self . data. update_values( ) ;
485+ cx. update( self . cells. as_node( & self . data) ) ;
513486 }
514487 }
515488 }
0 commit comments