all repos — taro @ df6e8dd49ba08550d36ddaaaa2a3bc2166815a61

mblaze frontend in uxn + crystal

taro-ls.tal (raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
( taro-ls: list mail, navigate mailboxes, and perform actions on mail )

( message types )

%MBOX_LIST { #00 }
%GET_MBOX { #01 }
%MAIL_LIST { #02 }
%MARK_ALL_READ { #03 }
%SEARCH_MAIL { #05 }
%REFILE_MAIL { #07 }
%TRASH_MAIL { #09 }
%READ_MAIL { #0b }
%COMPOSE_MAIL { #0d }
%UPDATE_UI { #0f }

( UI constants )

%TOP_SECTION { #0040 }
%MID_SEPARATOR { #0008 }
%BOTTOM_SECTION { #0040 }

( listbox helper macros )

%LB_DATA { #02 ADD }
%LB_LEN { #04 ADD }
%LB_OFFSET { #06 ADD }
%LB_ELEM_OFFSET { #08 ADD }
%LB_TOP { #09 ADD }
%LB_HEIGHT { #0b ADD }
%LB_SELECT_IDX { #0c ADD }
%LB_SELECT_LEN { #0e ADD }
%SB_LEN { #10 ADD }
%SB_POS { #11 ADD }
%SB_STEP { #13 ADD }

( entry modes )

%ENTRY_OFF { #00 }
%ENTRY_REFILE { #01 }
%ENTRY_SEARCH { #02 }

|00 @System     &vector $2 &wst      $1 &rst    $1 &eaddr  $2 &ecode  $1 &pad     $1 &r       $2 &g      $2 &b     $2 &debug  $1 &halt $1
|10 @Console    &vector $2 &read     $1 &pad    $5 &write  $1 &error  $1
|20 @Screen     &vector $2 &width    $2 &height $2 &auto   $1 &pad    $1 &x       $2 &y       $2 &addr   $2 &pixel $1 &sprite $1
|30 @Audio0     &vector $2 &position $2 &output $1 &pad    $3 &adsr   $2 &length  $2 &addr    $2 &volume $1 &pitch $1
|40 @Audio1     &vector $2 &position $2 &output $1 &pad    $3 &adsr   $2 &length  $2 &addr    $2 &volume $1 &pitch $1
|50 @Audio2     &vector $2 &position $2 &output $1 &pad    $3 &adsr   $2 &length  $2 &addr    $2 &volume $1 &pitch $1
|60 @Audio3     &vector $2 &position $2 &output $1 &pad    $3 &adsr   $2 &length  $2 &addr    $2 &volume $1 &pitch $1
|80 @Controller &vector $2 &button   $1 &key    $1 &func   $1
|90 @Mouse      &vector $2 &x        $2 &y      $2 &state  $1 &pad    $3 &scrollx $2 &scrolly $2
|a0 @File0      &vector $2 &success  $2 &stat   $2 &delete $1 &append $1 &name    $2 &length  $2 &read   $2 &write $2
|b0 @File1      &vector $2 &success  $2 &stat   $2 &delete $1 &append $1 &name    $2 &length  $2 &read   $2 &write $2
|c0 @DateTime   &year   $2 &month    $1 &day    $1 &hour   $1 &minute $1 &second  $1 &dotw    $1 &doty   $2 &isdst $1

( variables )

|0000

@refresh [ &mboxes $1 &list $1 &fg $1 &btns $1 &textbox $1 &etc $1 ]
@resizing [ $1 &x $2 &y $2 &dx $2 &dy $2 ]
@decoding [ $1 &msg_type $1 &counting $1 &count $1 &count2 $1 &processed $2 ]
@textbox [ &mode $1 &len $1 &cursor $1 &msg $2 &searching $1 ]
@mboxes [ &bytes $2 &data $2 &len $2 &offset $2 &elem_offset $1
          &top $2 &height $1 &select_index $2 &select_len $2
          &sb_len $1 &sb_pos $2 &sb_step $2 ]
@list   [ &bytes $2 &data $2 &len $2 &offset $2 &elem_offset $1
          &top $2 &height $1 &select_index $2 &select_len $2
          &sb_len $1 &sb_pos $2 &sb_step $2 ]
@btn_colors [ &compose $1 &refresh $1 &read_all $1 &search $1 &refile $1 &trash $1 ]
@btn_fns    [ &compose $2 &refresh $2 &read_all $2 &search $2 &refile $2 &trash $2 ]
@pending_ops [ $1 ]

( program )

|0100 ( -> )

  ;metadata #06 DEO2

  ( default theme ) 
  #028d .System/r DEO2 
  #0a8d .System/g DEO2 
  #098d .System/b DEO2
  
  load_theme
  load_font

  #0280 .Screen/width DEO2
  #01c0 .Screen/height DEO2
  
  ;list_data .list/data STZ2
  ;mbox_data .mboxes/data STZ2
  #0001 .list/select_len STZ2
  #0001 .mboxes/select_len STZ2
  
  .Screen/height DEI2 TOP_SECTION BOTTOM_SECTION ADD2 MID_SEPARATOR ADD2 SUB2 #03 SFT2 NIP .list/height STZ
  TOP_SECTION #03 SFT2 NIP .mboxes/height STZ
  
  #01 .refresh/btns STZ
  #01 .refresh/fg STZ
  #01 .refresh/etc STZ
  
  #03 .btn_colors/compose STZ
  #03 .btn_colors/refresh STZ
  #03 .btn_colors/read_all STZ
  #03 .btn_colors/search STZ
  #03 .btn_colors/refile STZ
  #03 .btn_colors/trash STZ
  
  ;send_compose .btn_fns/compose STZ2
  ;send_get_mbox .btn_fns/refresh STZ2
  ;send_mark_all_read .btn_fns/read_all STZ2
  ;enter_search_mode .btn_fns/search STZ2
  ;enter_refile_mode .btn_fns/refile STZ2
  ;send_trash .btn_fns/trash STZ2


  ;on_screen .Screen/vector DEO2
  ;on_mouse .Mouse/vector DEO2
  ;on_stdin .Console/vector DEO2
  ;on_key .Controller/vector DEO2
  
BRK

( -== message in ==- )

@on_stdin ( -> )

  .decoding LDZ #01 EQU ,&must_decode JCN
  #01 .decoding STZ
  #01 .decoding/counting STZ
  
  .Console/read DEI .decoding/msg_type STZ
  BRK
  
  &must_decode
  .decoding/counting LDZ #01 EQU ,&count_1 JCN
  .decoding/counting LDZ #02 EQU ,&count_2 JCN
  
  ( decode data )
  .Console/read DEI
  .decoding/msg_type LDZ
  DUP MBOX_LIST NEQ ,&no_mbox_list JCN
    POP ;mbox_data .decoding/processed LDZ2 ADD2 STA
    decode_inc_count .mboxes/bytes STZ2
    ,&count JMP
  &no_mbox_list
  DUP MAIL_LIST NEQ ,&no_mail_list JCN
    POP ;list_data .decoding/processed LDZ2 ADD2 STA
    decode_inc_count .list/bytes STZ2
    ,&count JMP
  &no_mail_list
  POP
  
  &count
  decode_is_done ,&done JCN
  BRK
  
  &done
  #0000 DUP2 .decoding/count STZ2 .decoding/processed STZ2 #00 .decoding STZ
  BRK
  
  &count_1
  .Console/read DEI .decoding/count STZ
  #02 .decoding/counting STZ
  BRK
  
  &count_2
  .Console/read DEI .decoding/count2 STZ
  #00 .decoding/counting STZ
  
  ( handle empty payload )
  .decoding/count LDZ2 #0000 NEQ2 ,&has_data JCN
    .decoding/msg_type LDZ
    DUP MBOX_LIST NEQ ,&no_mbox_empty JCN
      POP #0000 .mboxes/bytes STZ2 decode_is_done POP
      ,&done JMP
    &no_mbox_empty
    DUP MAIL_LIST NEQ ,&no_mail_empty JCN
      POP
      #0000 .list/bytes STZ2 decode_is_done POP
      ,&done JMP
    &no_mail_empty
    POP
  &has_data

BRK

@decode_inc_count ( -- current* )

  .decoding/processed LDZ2 INC2 DUP2 .decoding/processed STZ2
  
JMP2r

@decode_is_done ( -- bit )

  .decoding/processed LDZ2 .decoding/count LDZ2 EQU2 DUP ,&refresh_ui JCN
  JMP2r
  
  &refresh_ui
    ( we may erroneously decrement if we have a pending operation
      AND we close a reader/compose window but this is rare )
    .pending_ops LDZ #00 EQU ,&no_dec_pending JCN
      .pending_ops LDZ #01 SUB .pending_ops STZ
      #01 .refresh/etc STZ
    &no_dec_pending
    .list/bytes LDZ2 .decoding/count LDZ2 NEQ2 ,&no_list JCN
    #01 .refresh/list STZ
  &no_list
    .mboxes/bytes LDZ2 .decoding/count LDZ2 NEQ2 ,&no_mbox JCN
    #01 .refresh/mboxes STZ
  &no_mbox
  
JMP2r

( -== message out ==- )

@send_get_mbox ( -- )

  #01 .Console/write DEO
  ;selected_mbox strlen SWP .Console/write DEO .Console/write DEO
  ;selected_mbox send_str

  #0000 .list/select_index STZ2
  #0001 .list/select_len STZ2
  #0000 .list/top STZ2
  
  .list update_sb_pos
  
  pending_ops++
  #00 .textbox/searching STZ
  #01 .refresh/etc STZ
  
JMP2r

@send_mark_all_read ( -- )

  MARK_ALL_READ .Console/write DEO
  #00 .Console/write DEOk DEO
  ( message size is 0, no payload )
  
  pending_ops++
  #01 .refresh/etc STZ
  
JMP2r

@send_search ( -- )

  SEARCH_MAIL .Console/write DEO
  ;textbox_text strlen SWP .Console/write DEO .Console/write DEO
  ;textbox_text send_str
  
  #0000 .list/select_index STZ2
  #0001 .list/select_len STZ2
  #0000 .list/top STZ2

  .list update_sb_pos
  
  pending_ops++
  #01 .textbox/searching STZ
  #01 .refresh/etc STZ
  
JMP2r

@send_refile ( -- )

  REFILE_MAIL .Console/write DEO
  #0004 ;textbox_text strlen ADD2 SWP .Console/write DEO .Console/write DEO
  .list selection_to_range
  SWP .Console/write DEO .Console/write DEO
  SWP .Console/write DEO .Console/write DEO
  ;textbox_text send_str
  
  pending_ops++
  #01 .refresh/etc STZ
  
JMP2r

@send_trash ( -- )

  TRASH_MAIL .Console/write DEO
  #0004 SWP .Console/write DEO .Console/write DEO
  .list selection_to_range
  SWP .Console/write DEO .Console/write DEO
  SWP .Console/write DEO .Console/write DEO
  
  pending_ops++
  #01 .refresh/etc STZ
  
JMP2r

@send_reader ( -- )
  
  ( reset the mouse state since if a window opens over the uxn window mid-click
    and steals focus, the click never releases until we click the button again )
  #00 .Mouse/state DEO
  
  READ_MAIL .Console/write DEO
  #0002 SWP .Console/write DEO .Console/write DEO
  .list LB_SELECT_IDX LDZ2 INC2 SWP .Console/write DEO .Console/write DEO
  
JMP2r

@send_compose ( -- )

  ( reset the mouse state since if a window opens over the uxn window mid-click
    and steals focus, the click never releases until we click the button again )
  #00 .Mouse/state DEO
  
  COMPOSE_MAIL .Console/write DEO
  #00 .Console/write DEOk DEO
  ( message size is 0, no payload )
  
JMP2r

@send_str ( str* -- )

	&while
		LDAk .Console/write DEO
		INC2 LDAk ,&while JCN
	POP2

JMP2r

@selection_to_range ( listbox -- end* start* )

  DUP LB_SELECT_IDX LDZ2 INC2 STH2
  LB_SELECT_LEN LDZ2 #0001 SUB2 STH2kr ADD2 
  STH2r

JMP2r

@pending_ops++ ( -- )

  .pending_ops LDZk INC SWP STZ

JMP2r

( -== input ==- )

@on_key ( -> )

  .textbox/mode LDZ #00 EQU ,&no_text_entry JCN
    handle_textbox
    BRK
  &no_text_entry
  
  ( check keys for shortcuts )
  .Controller/key DEI
  DUP #7f NEQ ,&no_del JCN
    send_trash
  &no_del
  DUP #2f NEQ ,&no_search JCN
    enter_search_mode
  &no_search
  DUP #72 NEQ ,&no_refresh JCN
    send_get_mbox
  &no_refresh
  DUP #6d NEQ ,&no_refile JCN
    enter_refile_mode
  &no_refile
  DUP #6e NEQ ,&no_compose JCN
    send_compose
  &no_compose
  DUP #2e NEQ ,&no_all_read JCN
    send_mark_all_read
  &no_all_read
  DUP #0d NEQ ,&no_reader JCN
    send_reader
  &no_reader
  DUP #09 NEQ ,&no_tab JCN
    ;mbox_select_handler .mboxes [ .Controller/button DEI #04 AND ] nav_list_by_key
  &no_tab
  POP
  
  ( check buttons (LRUD, tab, shift, alt) for shortcuts )
  .Controller/button DEI
  DUP #10 NEQ ,&no_up JCN
    ;noop_list_click .list #01 nav_list_by_key
  &no_up
  DUP #20 NEQ ,&no_down JCN
    ;noop_list_click .list #00 nav_list_by_key
  &no_down
  DUP #14 NEQ ,&no_select_up JCN
    #01 change_select_len_by_key
    #01 .refresh/list STZ
  &no_select_up
  DUP #24 NEQ ,&no_select_down JCN
    #00 change_select_len_by_key
    #01 .refresh/list STZ
  &no_select_down
  DUP #12 NEQ ,&no_dec_y JCN
    #10 resize_by_keyboard
  &no_dec_y
  DUP #22 NEQ ,&no_inc_y JCN
    #20 resize_by_keyboard
  &no_inc_y
  DUP #42 NEQ ,&no_dec_x JCN
    #40 resize_by_keyboard
  &no_dec_x
  DUP #82 NEQ ,&no_inc_x JCN
    #80 resize_by_keyboard
  &no_inc_x
  POP
  
BRK

@resize_by_keyboard ( dir -- )

  DUP #10 NEQ ,&no_up JCN
    .Screen/height DEI2 #0100 EQU2 ,&no_down JCN
    .Screen/height DEI2 #0008 SUB2 .Screen/height DEO2
  &no_up
  DUP #20 NEQ ,&no_down JCN
    .Screen/height DEI2 #0008 ADD2 .Screen/height DEO2
  &no_down
  DUP #40 NEQ ,&no_left JCN
    .Screen/width DEI2 #0100 EQU2 ,&no_down JCN
    .Screen/width DEI2 #0008 SUB2 .Screen/width DEO2
  &no_left
  DUP #80 NEQ ,&no_right JCN
    .Screen/width DEI2 #0008 ADD2 .Screen/width DEO2
  &no_right
  POP
  
  #01 .refresh/list STZ
  #01 .refresh/mboxes STZ
  #01 .refresh/textbox STZ
  #01 .refresh/btns STZ
  #01 .refresh/etc STZ
  #01 .refresh/fg STZ
  
JMP2r

@change_select_len_by_key ( up? -- )

  ,&back JCN
  ( fwd )
    .list/select_index LDZ2 .list/select_len LDZ2 ADD2 .list/len LDZ2 LTH2 ,&inc_sel_len JCN
    JMP2r &inc_sel_len
    .list/select_len LDZ2 INC2 .list/select_len STZ2
    .list/top LDZ2 #00 .list/height LDZ ADD2 .list/select_index LDZ2 .list/select_len LDZ2 ADD2 LTH2 ,&scroll_down JCN
    JMP2r &scroll_down
    .list/top LDZ2 INC2 .list/top STZ2
    JMP2r
    
  &back  
    .list/select_len LDZ2 #0001 GTH2 ,&dec_sel_len JCN
    JMP2r &dec_sel_len
    .list/select_len LDZ2 #0001 SUB2 .list/select_len STZ2
    .list/top LDZ2 INC2 .list/select_index LDZ2 .list/select_len LDZ2 ADD2 GTH2 ,&scroll_up JCN
    JMP2r &scroll_up
    .list/top LDZ2 #0001 SUB2 .list/top STZ2
    
JMP2r

@nav_list_by_key ( onchange* list up? -- )

  ,&back JCN
  ( fwd )
    STHk LB_SELECT_IDX LDZ2 INC2 STHkr LB_LEN LDZ2 NEQ2 ,&can_go_fwd JCN
    ( jump to first )
      #0000 STHkr LB_SELECT_IDX STZ2
      #0000 STHkr LB_TOP STZ2
      ,&no_scroll_down JMP
    &can_go_fwd
    STHkr LB_SELECT_IDX LDZ2 INC2 STHkr LB_SELECT_IDX STZ2
    STHkr LB_SELECT_IDX LDZ2 #00 STHkr LB_HEIGHT LDZ STHkr LB_TOP LDZ2 ADD2 LTH2 ,&no_scroll_down JCN
      STHkr LB_TOP LDZ2 INC2 STHkr LB_TOP STZ2
    &no_scroll_down ,&end JMP
    
  &back
    STHk LB_SELECT_IDX LDZ2 #0000 NEQ2 ,&can_go_back JCN
      STHkr LB_LEN LDZ2 #0001 SUB2 STHkr LB_SELECT_IDX STZ2
      ( if number of entries is less than height, don't scroll to bottom )
      STHkr LB_LEN LDZ2 #0001 SUB2 #00 STHkr LB_HEIGHT LDZ LTH2 ,&end JCN
      STHkr LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ SUB2 STHkr LB_TOP STZ2
      ,&end JMP
    &can_go_back
    STHkr LB_SELECT_IDX LDZ2 #0001 SUB2 STHkr LB_SELECT_IDX STZ2
    STHkr LB_SELECT_IDX LDZ2 INC2 STHkr LB_TOP LDZ2 GTH2 ,&no_scroll_up JCN
      STHkr LB_TOP LDZ2 #0001 SUB2 STHkr LB_TOP STZ2
    &no_scroll_up
    
  &end
  STHrk update_sb_pos
  ( onchange )
  STHr ROT ROT JSR2
  
  #01 .refresh/mboxes STZ
  #01 .refresh/list STZ
  
JMP2r

@handle_textbox ( -- )

  .Controller/key DEI DUP #00 EQU ,&no_key JCN
  DUP check_enter_or_esc #01 EQU ,&no_btn JCN
  DUP #08 NEQ ,&no_delete JCN
    POP
    ( handle backspace )
    .textbox/cursor LDZ #00 EQU ,&done JCN
    delete_char
    ,&done JMP
  &no_delete
  ( ascii printable chars only )
  DUP #20 LTH OVR #7e GTH ORA ,&no_btn JCN
  .textbox/len LDZ #fe EQU ,&no_btn JCN
    insert_char
  ,&done JMP
  &no_key
  POP
  .Controller/button DEI DUP #00 EQU ,&no_btn JCN
    DUP #40 AND #00 EQU ,&no_left JCN
      .textbox/cursor LDZ #00 EQU ,&no_btn JCN
      .textbox/cursor LDZ #01 SUB .textbox/cursor STZ
    &no_left
    DUP #80 AND #00 EQU ,&no_right JCN
      .textbox/cursor LDZ .textbox/len LDZ EQU ,&no_btn JCN
      .textbox/cursor LDZk INC SWP STZ
    &no_right
  &no_btn
  POP
  &done
  #01 .refresh/textbox STZ
  
JMP2r

@delete_char ( -- )

  ( if cursor = len, then just decrement both and add null byte )
  .textbox/cursor LDZ .textbox/len LDZ NEQ ,&its_complicated JCN
    .textbox/cursor LDZ #01 SUB .textbox/cursor STZ
    .textbox/len LDZ #01 SUB .textbox/len STZ
    #00 ;textbox_text #00 .textbox/cursor LDZ ADD2 STA
    JMP2r
    
  &its_complicated
  ( otherwise loop through characters from cursor to len,
    and copy them to their location - 1 )
    .textbox/len LDZ INC .textbox/cursor LDZ &loop EQUk ,&end JCN
      #00 OVR ;textbox_text ADD2 LDA STH
      DUP #01 SUB STHr SWP #00 SWP ;textbox_text ADD2 STA
      INC
    ,&loop JMP &end POP2
    ( and then decrement counters and set the null byte )
    .textbox/cursor LDZ #01 SUB .textbox/cursor STZ
    .textbox/len LDZ #01 SUB .textbox/len STZ
    #00 ;textbox_text #00 .textbox/len LDZ ADD2 STA
    
JMP2r

@insert_char ( key -- )

  STH
  ( if cursor = len, then add the charater, increment both counters, and add a null byte )
  .textbox/cursor LDZ .textbox/len LDZ NEQ ,&its_complicated JCN
    STHr
    ;textbox_text #00 .textbox/cursor LDZ ADD2 STA
    .textbox/len LDZk INC SWP STZ
    #00 ;textbox_text  #00 .textbox/len LDZ ADD2 STA
    .textbox/cursor LDZk INC SWP STZ
    JMP2r
    
  &its_complicated
  ( otherwise loop through characters from len to cursor,
    and copy them to their location + 1 )
    .textbox/cursor LDZ #01 SUB .textbox/len LDZ &loop EQUk ,&end JCN
      #00 OVR ;textbox_text ADD2 LDA STH
      DUP INC STHr SWP #00 SWP ;textbox_text ADD2 STA
      #01 SUB
    ,&loop JMP &end POP2
    STHr
    ( and put the character at the cursor locaton, then increment the counts )
    ;textbox_text #00 .textbox/cursor LDZ ADD2 STA
    .textbox/len LDZk INC SWP STZ
    .textbox/cursor LDZk INC SWP STZ
JMP2r

@check_enter_or_esc ( key -- bit )

  DUP #0d NEQ ,&no_enter JCN
  .textbox/mode LDZ ENTRY_SEARCH NEQ ,&no_search JCN
    send_search
    &no_search
  .textbox/mode LDZ ENTRY_REFILE NEQ ,&no_refile JCN
    send_refile
    &no_refile
    ENTRY_OFF reset_textbox
    #01 .refresh/textbox STZ
   #01 ,&done JMP
   
  &no_enter
  DUP #1b NEQ ,&no_esc JCN
    ENTRY_OFF reset_textbox
    #01 .refresh/textbox STZ
    #01
    ,&done JMP
  &no_esc
  
  #00
  &done
  NIP
  
JMP2r

@on_mouse ( -> )

  ;noop_list_click ;mbox_select_handler .mboxes .refresh/mboxes #0000 #00 mouse_event_list
  ;right_click_mail_list ;noop_list_click .list .refresh/list TOP_SECTION MID_SEPARATOR ADD2 #04 mouse_event_list
  .btn_fns .btn_colors SUB mouse_event_buttons

  .resizing LDZ #00 EQU ,&resz_check JCN
    ( resizing )
    .Mouse/x DEI2 .resizing/x LDZ2 SUB2 .resizing/dx STZ2
    .Mouse/y DEI2 .resizing/y LDZ2 SUB2 .resizing/dy STZ2
  
    handle_rsz #01 AND ,&done JCN
  
    ( btn1 release )
    #00 .resizing STZ
  BRK
  
  &resz_check
    .Mouse/x DEI2 .Screen/width DEI2 #0008 SUB2 LTH2 ,&done JCN
    .Mouse/y DEI2 .Screen/height DEI2 #0008 SUB2 LTH2 ,&done JCN
    .Mouse/state DEI #01 EOR ,&done JCN
  
    #01 .resizing STZ
    .Mouse/x DEI2 .resizing/x STZ2
    .Mouse/y DEI2 .resizing/y STZ2
  &done
  
  #01 .refresh/fg STZ
  
BRK

@mouse_event_buttons ( numbtns -- )

  STHk #00 &while EQUk ,&end JCN
    DUP .btn_colors ADD
    DUP LDZ #01 NEQ ,&continue JCN
      #01 .refresh/btns STZ
    &continue
    #03 SWP STZ
      
    INC
  ,&while JMP &end POP2

  .Mouse/x DEI2 #0008 LTH2 ,&done JCN
  .Mouse/x DEI2 #0008 SUB2 [ #00 STHkr #40 SFT2 #0001 SUB2 ] GTH2 ,&done JCN
  
  .Mouse/y DEI2 .Screen/height DEI2 #0030 SUB2 LTH2 ,&done JCN
  .Mouse/y DEI2 .Screen/height DEI2 #0020 SUB2 GTH2 ,&done JCN
  
  #01 [ .Mouse/x DEI2 #0008 SUB2 #04 SFT2 NIP ] .btn_colors ADD STZ
  #01 .refresh/btns STZ
  .Mouse/state DEI #01 AND #00 EQU ,&done JCN
    .Mouse/x DEI2 #0008 SUB2 #04 SFT2 NIP #10 SFT .btn_fns ADD LDZ2 JSR2

  &done
  POPr
  
JMP2r

@handle_rsz ( -- mousestate )

  ( chk_x_rsz )
    .Mouse/x DEI2 .Screen/width DEI2 #0002 SUB2 GTH2 ,&inc_x JCN
    #ffff .resizing/dx LDZ2 SUB2 #0008 GTH2 ,&dec_x JCN
    ,&chk_y_rsz JMP
  &dec_x
    .Screen/width DEI2 #0100 LTH2 ,&chk_y_rsz JCN
    .Screen/width DEI2 #0008 SUB2 .Screen/width DEO2
    ,&chk_y_rsz JMP
  &inc_x
    .Screen/width DEI2 #0008 ADD2 .Screen/width DEO2
  ,&chk_y_rsz JMP
  
  &chk_y_rsz
    .Mouse/y DEI2 .Screen/height DEI2 #0002 SUB2 GTH2 ,&inc_y JCN
    #ffff .resizing/dy LDZ2 SUB2 #0008 GTH2 ,&dec_y JCN
    ,&chk_release JMP
  &dec_y
    .Screen/height DEI2 #0100 LTH2 ,&chk_release JCN
    .Screen/height DEI2 #0008 SUB2 .Screen/height DEO2
    ,&chk_release JMP
  &inc_y
    .Screen/height DEI2 #0008 ADD2 .Screen/height DEO2
    ,&chk_release JMP
  
  &chk_release
    #01 .refresh/list STZ
    #01 .refresh/mboxes STZ
    #01 .refresh/btns STZ
    #01 .refresh/etc STZ
    .Screen/height DEI2 TOP_SECTION BOTTOM_SECTION ADD2 MID_SEPARATOR ADD2 SUB2 #03 SFT2 NIP .list/height STZ
    .Mouse/state DEI
    
JMP2r

@mouse_event_list ( rightclickhanlder* clickhandler* list refresh ypos* multiselect_mask -- )

  ,&multi STR
  ,&y STR2
  ,&r STR
  STH
  
  ( check bounds )
  .Mouse/x DEI2 .Screen/width DEI2 #0008 SUB2 GTH2 ,&almost_done JCN
  .Mouse/y DEI2 ,&y LDR2 LTH2 ,&almost_done JCN
  .Mouse/y DEI2 [ [ ,&y LDR2 ] [ #00 STHkr LB_HEIGHT LDZ #30 SFT2 ] ADD2 #0001 SUB2 ] GTH2 ,&almost_done JCN
  .Mouse/y DEI2 [ [ ,&y LDR2 ] [ STHkr LB_LEN LDZ2 #30 SFT2 ] ADD2 #0001 SUB2 ] GTH2 ,&almost_done JCN
  
  ( check scrollwheel )
  .Mouse/scrolly DEI2 #0000 EQU2 ,&no_scroll JCN
  .Mouse/scrolly DEI2 #0001 EQU2 ,&scroll_down JCN
  
  ( scroll_up )
  STHkr try_scroll_up_mouse
  ,&no_scroll JMP
  
  &almost_done
  ,&done JMP
  
  ( data )
  &multi $1
    &y $2
  &r $1
  &scroll_down
  STHkr try_scroll_down_mouse
  
  &no_scroll
  .Mouse/state DEI #05 AND #00 EQU ,&done JCN
    ,&multi LDR ,&y LDR2 STHkr mouse_select_on_click
  .Mouse/state DEI #01 AND #00 EQU ,&no_left JCN
    ( leftclick )
    STHr ROT ROT JSR2
    POP2
    #01 ,&r LDR STZ
    JMP2r 
  &no_left
  .Mouse/state DEI #04 AND #00 EQU ,&no_right JCN
   ( rightclick )
   STHr POP2 ROT ROT JSR2
    #01 ,&r LDR STZ
    JMP2r
  &no_right
  &done
    #01 ,&r LDR STZ
    POPr
    POP2
    POP2

JMP2r

@mouse_select_on_click ( multi? ypos* list -- )
  STH
  ,&y STR2
  
  .Controller/button DEI #04 AND AND ,&multiselect JCN
    #0001 STHkr LB_SELECT_LEN STZ2
    .Mouse/y DEI2 ,&y LDR2 SUB2 #03 SFT2 STHkr LB_TOP LDZ2 ADD2 STHkr LB_SELECT_IDX STZ2
    POPr
    JMP2r
  &multiselect
    .Mouse/y DEI2 ,&y LDR2 SUB2 #03 SFT2 STHkr LB_TOP LDZ2 ADD2
    DUP2 STHkr LB_SELECT_IDX LDZ2 LTH2 ,&last_to_first JCN
    ( first_to_last )
      STHkr LB_SELECT_IDX LDZ2 SUB2 INC2 STHkr LB_SELECT_LEN STZ2
      POPr JMP2r
    &last_to_first
      DUP2 STHkr LB_SELECT_IDX LDZ2 SWP2 SUB2 INC2 STHkr LB_SELECT_LEN STZ2
      STHr LB_SELECT_IDX STZ2
      
JMP2r
&y $2

@mbox_select_handler ( list -- )

  #0000 ,&idx STR2
  #00 ,&chr STR
  STHk
  
  ( clear the previous selection with null bytes )
  #ff #00 &clear_mbox EQUk ,&ready JCN
    #00 OVR ;selected_mbox ADD2 #00 ROT ROT STA
    INC ,&clear_mbox JMP &ready POP2

  ( get position of the current selection )
  ( bytes ) LDZ2 #0000 &while EQU2k ,&end JCN
    STHkr LB_SELECT_IDX LDZ2 ,&idx LDR2 EQU2 ,&write_str JCN 
    DUP2 STHkr LB_DATA LDZ2 ADD2 LDA #0a EQU ,&inc JCN
    INC2 ,&while JMP
  &inc ,&idx LDR2 INC2 ,&idx STR2 INC2 ,&while JMP
  
  ( data )
  &idx $2
  &chr $1
  
  ( copy the current selection to the buffer )
  &write_str STHkr LB_DATA LDZ2 ADD2
  &loop LDAk #0a EQU ,&end JCN
    LDAk [ ;selected_mbox #00 ,&chr LDR ADD2 ] STA
    ,&chr LDR INC ,&chr STR INC2 ,&loop JMP
  &end
  
  POP2 POP2
  POPr
  send_get_mbox
  
JMP2r

@enter_search_mode ( -- )

  ENTRY_SEARCH  reset_textbox
  ;search_lbl .textbox/msg STZ2
  
JMP2r

@enter_refile_mode ( -- )

  ENTRY_REFILE reset_textbox
  ;refile_lbl .textbox/msg STZ2

JMP2r

@reset_textbox ( mode -- )

  .textbox/mode STZ
  #00 .textbox/len STZ
  #00 .textbox/cursor STZ
  #00 ;textbox_text STA
  #01 .refresh/textbox STZ

JMP2r

@noop_list_click ( list -- )

  POP
  
JMP2r

@right_click_mail_list ( list -- )

   send_reader

JMP2r

@try_scroll_up_mouse ( list -- )

  STHk LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ LTH2 ,&no_scroll_up JCN
  STHkr LB_TOP LDZ2 #0000 EQU2 ,&no_scroll_up JCN
    STHkr LB_TOP LDZ2 #0001 SUB2 STHkr LB_TOP STZ2
    STHkr update_sb_pos
  &no_scroll_up
  POPr
  
JMP2r

@try_scroll_down_mouse ( list -- )

  STHk LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ LTH2 ,&no_scroll_down JCN
  STHkr LB_TOP LDZ2 #00 STHkr LB_HEIGHT LDZ ADD2 STHkr LB_LEN LDZ2 EQU2 ,&no_scroll_down JCN
    STHkr LB_TOP LDZ2k INC2 ROT STZ2
    STHkr update_sb_pos
  &no_scroll_down
  POPr
  
JMP2r

( -== gfx ==- )

@on_screen ( -> )

  .refresh/mboxes LDZ #00 EQU ,&no_mboxes JCN
    #0000 .mboxes/height LDZ clear_listbox
    .mboxes #0000 draw_listbox
    .mboxes #0000 draw_scrollbar
    #00 .refresh/mboxes STZ
  &no_mboxes

  .refresh/list LDZ #00 EQU ,&no_list JCN
    [ TOP_SECTION MID_SEPARATOR ADD2 ] .list/height LDZ clear_listbox
    .list [ TOP_SECTION MID_SEPARATOR ADD2 ] draw_listbox
    .list [ TOP_SECTION MID_SEPARATOR ADD2 ] draw_scrollbar
    #00 .refresh/list STZ
  &no_list
  
  .refresh/btns LDZ #00 EQU ,&no_btns JCN
    .btn_colors/compose LDZ ;compose_button #0008 .Screen/height DEI2 #0030 SUB2 draw_2x2
    .btn_colors/refresh LDZ ;refresh_button #0018 .Screen/height DEI2 #0030 SUB2 draw_2x2
    .btn_colors/read_all LDZ ;all_read_button #0028 .Screen/height DEI2 #0030 SUB2 draw_2x2
    .btn_colors/search LDZ ;search_button #0038 .Screen/height DEI2 #0030 SUB2 draw_2x2
    .btn_colors/refile LDZ ;refile_button #0048 .Screen/height DEI2 #0030 SUB2 draw_2x2
    .btn_colors/trash LDZ ;trash_button #0058 .Screen/height DEI2 #0030 SUB2 draw_2x2
    #00 .refresh/btns STZ
  &no_btns
  
  .refresh/textbox LDZ #00 EQU ,&no_textbox JCN
    clear_textbox
  .textbox/mode LDZ #00 EQU ,&no_textbox JCN
    ;textbox_text #0008 .Screen/height DEI2 #0018 SUB2 #03 draw_str
    draw_bone
    .textbox/msg LDZ2 #0008 .Screen/height DEI2 #0010 SUB2 #02 draw_str
  &no_textbox

  .refresh/etc LDZ #00 EQU ,&no_etc JCN
    draw_search_indicator
    draw_pending_indicator
    draw_resize_handle
    #00 .refresh/etc STZ
  &no_etc
  
  .refresh/fg LDZ #00 EQU ,&no_fg JCN
    clear_fg
    draw_cursor
    #00 .refresh/fg STZ
  &no_fg
  
BRK

@draw_search_indicator ( -- )

  .textbox/searching LDZ #00 EQU ,&nothing JCN
    ;search_indicator #0000 .Screen/height DEI2 #0008 SUB2 #01 draw_str
    JMP2r
  &nothing
    #0000 .Screen/x DEO2
    .Screen/height DEI2 #0008 SUB2 .Screen/y DEO2
    ;blank .Screen/addr DEO2
    #01 .Screen/sprite DEO
  
JMP2r

@draw_pending_indicator ( -- )

  .pending_ops LDZ #00 EQU ,&nothing JCN
    ;pending_indicator #0008 .Screen/height DEI2 #0008 SUB2 #01 draw_str
    JMP2r
  &nothing
    #0008 .Screen/x DEO2
    .Screen/height DEI2 #0008 SUB2 .Screen/y DEO2
    ;blank .Screen/addr DEO2
    #01 .Screen/sprite DEO
  
JMP2r

@draw_bone ( -- )

  #0008 #00 .textbox/cursor LDZ #30 SFT2 ADD2 .Screen/x DEO2
  .Screen/height DEI2 #0018 SUB2 .Screen/y DEO2
  ;bone .Screen/addr DEO2
  #05 .Screen/sprite DEO
  
JMP2r

@clear_textbox ( -- )

  ;blank .Screen/addr DEO2
  .Screen/width DEI2 #0008 &while EQU2k ,&end JCN
    DUP2 .Screen/x DEO2
    .Screen/height DEI2 #0018 SUB2 .Screen/y DEO2
    #01 .Screen/sprite DEO
    .Screen/height DEI2 #0010 SUB2 .Screen/y DEO2
    #01 .Screen/sprite DEO
  #0008 ADD2 ,&while JMP &end POP2 POP2

JMP2r

@clear_fg ( -- )

  ;blank .Screen/addr DEO2
  .Screen/width DEI2 #0000 &whilex EQU2k ,&endx JCN
    DUP2 ,&x STR2
    .Screen/height DEI2 #0000 &whiley EQU2k ,&endy JCN
      DUP2 .Screen/y DEO2
      ,&x LDR2 .Screen/x DEO2
      #41 .Screen/sprite DEO
    #0008 ADD2 ,&whiley JMP &endy POP2 POP2
  #0008 ADD2 ,&whilex JMP &endx POP2 POP2
  
JMP2r
&x $2

@clear_listbox ( top* height -- )

  #00 SWP #30 SFT2
  ,&height STR2
  ,&top STR2
  ;blank .Screen/addr DEO2
  .Screen/width DEI2 #0008 SUB2 #0000 &whilex EQU2k ,&endx JCN
    DUP2 ,&x STR2
    ,&top LDR2 ,&height LDR2 ADD2 ,&top LDR2 &whiley EQU2k ,&endy JCN
      DUP2 .Screen/y DEO2
      ,&x LDR2 .Screen/x DEO2
      #00 .Screen/sprite DEO
    #0008 ADD2 ,&whiley JMP &endy POP2 POP2
  #0008 ADD2 ,&whilex JMP &endx POP2 POP2
  
JMP2r
&x $2
&top $2
&height $2

@draw_resize_handle ( -- )

  .Screen/width DEI2 #0008 SUB2 .Screen/x DEO2
  .Screen/height DEI2 #0008 SUB2 .Screen/y DEO2
  ;resize_handle .Screen/addr DEO2
  #02 .Screen/sprite DEO

JMP2r


@store_char ( char list_e_offset -- char )

  SWP OVR LDZ #00 SWP ;word ADD2 STA
  LDZk INC SWP STZ

JMP2r

@shouldnt_draw_word ( list -- bit )

  DUP LB_OFFSET LDZ2
  ( above top of view )
  STH2k ROT STHk LB_TOP LDZ2 LTH2 ,&clear_rtn JCN 
  
  ( below bottom of view )
  STHr DUP LB_TOP LDZ2 ROT LB_HEIGHT LDZ #00 SWP ADD2 #0001 SUB2 STH2r SWP2 GTH2 ,&no_draw JCN
  #00 JMP2r

  &clear_rtn
  POP2r POPr
  &no_draw
  #01
  
JMP2r

@draw_list_elem ( list -- )

  STHk
  get_entry_color STH 
  [ ;word
    .Screen/x DEI2
    .Screen/y DEI2
    STHr ] draw_str
    STHr finish_line

JMP2r

@get_entry_color ( list -- colorbyte )

  STHk LB_OFFSET LDZ2
  STHkr LB_SELECT_IDX LDZ2
  LTH2 ,&normal JCN
  
  STHkr LB_OFFSET LDZ2
  STHkr LB_SELECT_IDX LDZ2 STHkr LB_SELECT_LEN LDZ2 ADD2 #0001 SUB2
  GTH2 ,&normal JCN
  
  POPr
  ( selected )
    #04 JMP2r
  
  &normal
    POPr
    #03
    
JMP2r

@finish_line ( list -- )

  STH
  ;blank .Screen/addr DEO2
  &while .Screen/x DEI2 .Screen/width DEI2 #0010 SUB2 GTH2 ,&end JCN
    STHkr get_entry_color .Screen/sprite DEO
    .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2
  ,&while JMP &end
  POPr
  
JMP2r

@draw_listbox ( list ypos* -- )

  #0000 .Screen/x DEO2
  ( ypos ) .Screen/y DEO2

  ( .list ) STH
  #0000 STHkr LB_OFFSET STZ2
    STHkr LDZ2 #0000 &while EQU2k ,&end JCN
    DUP2 STHkr LB_DATA LDZ2 ADD2 LDA
    DUP #00 EQU ,&end JCN
    ( if not newline, store the character and increment the offsets )
    DUP #0a EQU ,&inc_line JCN
      STHkr LB_ELEM_OFFSET store_char
    ,&continue JMP ( continue looping )
    
    &inc_line
    POP #0000 STHkr LB_ELEM_OFFSET LDZ ;word ADD2 STA
    STHkr shouldnt_draw_word ,&no_draw JCN
      STHkr draw_list_elem
      #0000 .Screen/x DEO2
      .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2
    &no_draw
    STHkr LB_OFFSET LDZ2 INC2 STHkr LB_OFFSET STZ2
  
    #00 STHkr LB_ELEM_OFFSET STZ

  &continue INC2 ,&while JMP
  &end
  
  STHkr LB_OFFSET LDZ2 STHr LB_LEN STZ2 POP2 POP2

JMP2r

@draw_cursor ( -- )

  .Mouse/x DEI2 .Screen/x DEO2
  .Mouse/y DEI2 .Screen/y DEO2
  ;cursor .Screen/addr DEO2
  #4f .Screen/sprite DEO

JMP2r

@draw_scrollbar ( list ypos* -- )

  ,&y STR2
  STH
  
  .Screen/width DEI2 #0008 SUB2 .Screen/x DEO2
  ,&y LDR2 .Screen/y DEO2

  ( draw the trough no matter what )
  ;blank .Screen/addr DEO2
  STHkr LB_HEIGHT LDZ #00
  &while_trough EQUk ,&end_trough JCN
    #00 .Screen/sprite DEO
    .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2
  INC ,&while_trough JMP &end_trough POP2

  ( stop here if there is no overflow )
  STHkr LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ INC2 LTH2 ,&no_handle JCN
  ,&draw_handle JMP
  
  &no_handle
  POPr
  JMP2r
  &y $2
  ( if there are more entries than will fit in the view area, draw the handle )
  &draw_handle
  ( store the number of entries per tile of the scrollbar )
  STHkr LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ DIV2 STHkr SB_STEP STZ2

  ( set the length of the scrollbar )
  STHkr LB_HEIGHT LDZ STHkr LB_LEN LDZ2 #00 STHkr LB_HEIGHT LDZ SUB2 STHkr SB_STEP LDZ2 DIV2 NIP SUB STHkr SB_LEN STZ

  ;scrollbar .Screen/addr DEO2
  ,&y LDR2 STHkr SB_POS LDZ2 #30 SFT2 ADD2 .Screen/y DEO2
  STHkr SB_LEN LDZ #00 &while_handle EQUk ,&end_handle JCN
    .Screen/y DEI2 .Screen/height DEI2 #0040 SUB2 EQU2 ,&end_handle JCN
    #01 .Screen/sprite DEO
  INC .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 ,&while_handle JMP &end_handle POP2
  POPr
JMP2r

@update_sb_pos ( list -- )
  DUP SB_STEP LDZ2 #0000 NEQ2 ,&safe_to_divide JCN
  POP JMP2r
  
  &safe_to_divide
  DUP DUP
  LB_TOP LDZ2 ROT SB_STEP LDZ2 DIV2 ROT SB_POS STZ2

JMP2r

@draw_str ( addr* x* y* color -- )
	
	STH ( save color )
	.Screen/y DEO2 ( set y )
	.Screen/x DEO2 ( set x )

  ( now the string address is at the top of the stack )
  LDAk #00 EQU ,&done JCN
  &loop
    .Screen/x DEI2 .Screen/width DEI2 #0010 SUB2 GTH2 ,&done JCN
    LDAk DUP
    #7f LTH ,&ascii JCN POP #3f ( replace non_ascii characters with ? )
    &ascii DUP #00 NEQ #20 MUL SUB #00 SWP #30 SFT2 ;font ADD2 .Screen/addr DEO2 
    STHkr .Screen/sprite DEO
    .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2
    INC2
    LDAk ,&loop JCN &done
  POP2
  POPr

JMP2r

@draw_2x2 ( color sprite* x* y* -- )

  .Screen/y DEO2
  .Screen/x DEO2
  #16 .Screen/auto DEO
  .Screen/addr DEO2
  .Screen/sprite DEOk DEO
  #00 .Screen/auto DEO
  
JMP2r

( -== util ==- )

@strlen ( addr* -- len* )

  DUP2
  &loop
    INC2 LDAk ,&loop JCN
  SWP2 SUB2
  
JMP2r

@debug_u8 ( byte -- )

  #00 SWP debug_u16
  
JMP2r

@debug_u16 ( short* -- )

	SWP ,&byte JSR
	&byte ( byte -- ) DUP #04 SFT ,&char JSR
	&char ( char -- ) #0f AND DUP #09 GTH #27 MUL ADD #30 ADD .Console/error DEO

JMP2r

@debug ( str* -- )

	&while
		LDAk .Console/error DEO
		INC2 LDAk ,&while JCN
	POP2

JMP2r

@load_theme ( -- )

  ;theme_file .File0/name DEO2
  #0006 .File0/length DEO2
  ;theme_data .File0/read DEO2
  .File0/success DEI2 #0006 NEQ2 ,&no_theme_file JCN
  ;theme_data/r LDA2 .System/r DEO2
  ;theme_data/g LDA2 .System/g DEO2
  ;theme_data/b LDA2 .System/b DEO2
  &no_theme_file
  
JMP2r

@load_font ( -- )

  ;font_file .File0/name DEO2
  #0300 .File0/length DEO2
  ;font .File0/read DEO2
  
JMP2r

( -== data ==- )

@search_indicator "$ 00
@pending_indicator "* 00
@theme_file ".theme 00
@font_file "font.icn 00

@search_lbl "SEARCHING: 20 "type 20 "query 20 "and 20 "press 20 "{enter}; 20 "{esc} 20 "to 20 "go 20 "back 00
@refile_lbl "REFILING: 20 "type 20 "destination 20 "and 20 "press 20 "{enter}; 20 "{esc} 20 "to 20 "go 20 "back 00

@resize_handle [ e2c2 aa1a 3a02 fe00 ]
@cursor        [ f8e0 e090 8804 0000 ]
@scrollbar     [ 0707 0707 0707 0707 ]
@bone          [ e040 4040 4040 40e0 ]
@blank         [ 0000 0000 0000 0000 ]

@refresh_button [
  0000 0708 1010 1000 0000 e010 3e1c 0800
  0010 387c 0807 0000 0008 0808 10e0 0000
]

@all_read_button [
  0000 0101 0905 003c 0000 8080 90a0 003c 
  3c00 0509 0101 0000 3c00 a090 8080 0000
] 

@search_button [
  0000 0007 0810 2142 0000 00e0 1008 8442
  4221 1008 0700 0000 4284 0810 e000 0000
]

@refile_button [
  0000 003f 202f 2024 0000 fe82 12fa 1202
  2f24 203f 0000 0000 fa02 02fe 0000 0000
]

@trash_button [
  0003 021f 101f 080a 00c0 40f8 08f8 1050
  0a0a 0a08 0f00 0000 5050 5010 f000 0000
]

@compose_button [
  0010 107c 1010 0102 0000 0020 5088 1020
  0408 191e 1d00 0000 4080 00a8 5000 0000
]

@metadata [ 00 "taro 0a
             "v0.2.2 0a
             "GUI 20 "for 20 "mblaze 0a
             "Derek 20 "Stevens 20 "<nilix@nilfm.cc> 0a 00
]

@selected_mbox "INBOX 00 $f9 ( default mailbox is INBOX, total space #06 + #f9 = #ff bytes )
@font $300
@theme_data [ &r $2 &g $2 &b $2 ]
@textbox_text $ff
@word $ff
@mbox_data $1000
@list_data $8000