#pragma mode( separator(.,;) integer(h32) )

// Version 1.0 - December 31, 2019
// Jacob Wall - jacob@sgss.ca

// subroutines
ChooseDemo1();
ChooseDemo2();
SetThemeColors();
CHOOSE_R();
DrawChooseItems();
DrawChooseScroll();
ResetTExit();
FlushKeysMouse();
ClearMouse();
FlashBtn();
FlashMenu();
DelFromList();

// color constants, set depending on theme settings
main_color,main_bg,light_accent,dark_accent,highlight_color,invhi_color,field_border,key_label;
field_bg,field_accent,title_color;
// auto-exit, TExit is time in minutes to exit
TExit_count:=0,TExit:=5;
// input globals
MK_in,MK_mx,MK_my;

EXPORT ChooseDemos()
BEGIN
  LOCAL ch_sel;
  CHOOSE(ch_sel,"CHOOSE_R Demos",{"ChooseDemo1","ChooseDemo2"});
  CASE
    IF ch_sel==1 THEN
      ChooseDemo1();
    END;
    IF ch_sel==2 THEN
      ChooseDemo2();
    END;
  END;
END;

// simple choose list
ChooseDemo1()
BEGIN
  LOCAL opt:=1,choose_list:={"Item_1","Item_2","Item_3"};
  SetThemeColors();
  opt:=CHOOSE_R("ChooseDemo1",choose_list,opt,0);
  IF opt THEN
    MSGBOX("You selected "+choose_list(opt));
  ELSE
    MSGBOX("Choose was cancelled");
  END;
END;

// choose list with option to delete from the list
ChooseDemo2()
BEGIN
  LOCAL opt:=1,exit_choose:=0,choose_list:={"Item_1","Item_2","Item_3","Item_4","Item_5","Item_6","Item_7","Item_8","Item_9","Item_10","Item_11","Item_12"};
  SetThemeColors();
  REPEAT
    IF SIZE(choose_list) THEN
      opt:=CHOOSE_R("ChooseDemo1",choose_list,MIN(opt,SIZE(choose_list)),1);
      CASE
        IF opt<0 THEN // delete
          opt:=ABS(opt);
          choose_list:=DelFromList(choose_list,opt);
          // other optional code to maintain external lists
        END;
        IF opt>0 THEN // selection
          MSGBOX("You selected "+choose_list(opt));
          exit_choose:=1;
        END;
        DEFAULT // cancel
        MSGBOX("Choose was cancelled");
        exit_choose:=1;
      END;
    ELSE
      MSGBOX("No items in list");
      exit_choose:=1;
    END;
  UNTIL exit_choose;
END;

// set theme colors
SetThemeColors()
BEGIN
  LOCAL dark_light:=B→R(Theme(1)),clr:=B→R(Theme(2)),clrs;
  LOCAL gen_clrs:={{#000000h,#FFFFFFh,#F7F7F7h,#FFFFFFh,#8C8C8Ch,#CCCCCCh},{#FFFFFFh,#000000h,#191919h,#000000h,#949494h,#666666h}};
  LOCAL light_clrs:={{#FB0000h,#FC4040h,#FD7F7Fh,#FB0000h,#FFFFFFh},{#FF9504h,#FFB043h,#FFCA81h,#FF9504h,#000000h},{#D4D400h,#FCFC02h,#FDFD80h,#D4D400h,#000000h},{#14AA00h,#4FBF40h,#89D47Fh,#14AA00h,#FFFFFFh},{#0069D1h,#408FDDh,#7FB4E8h,#0069D1h,#FFFFFFh},{#8000FFh,#C060FFh,#A77FCFh,#8000FFh,#FFFFFFh}};
  LOCAL dark_clrs:={{#800000h,#FC4040h,#FB0000h,#FD7F7Fh,#FFFFFFh},{#803800h,#FFB043h,#FF9504h,#FFCA81h,#FFFFFFh},{#808000h,#FCFC02h,#D4D400h,#FDFD80h,#FFFFFFh},{#148000h,#4FBF40h,#14AA00h,#89D47Fh,#FFFFFFh},{#004080h,#408FDDh,#0069D1h,#7FB4E8h,#FFFFFFh},{#400080h,#C060FFh,#8000FFh,#A77FCFh,#FFFFFFh}};
  main_color:=gen_clrs(dark_light,1);
  main_bg:=gen_clrs(dark_light,2);
  light_accent:=gen_clrs(dark_light,3);
  field_bg:=gen_clrs(dark_light,4);
  field_accent:=gen_clrs(dark_light,5);
  key_label:=gen_clrs(dark_light,6);
  clrs:=IFTE(dark_light==1,light_clrs,dark_clrs);
  dark_accent:=clrs(clr,1);
  field_border:=clrs(clr,2);
  highlight_color:=clrs(clr,3);
  invhi_color:=clrs(clr,4);
  title_color:=clrs(clr,5);
END;

// replacement for CHOOSE command
// title is a string
// items is a list of strings (index is automatically added to each string starting with 1)
// cur_sel is the selected item on initialization
// del_opt specifies if a Delete option is on the menu
// returns 0 if cancelled
// returns index of selection in list if selection was made
// returns negative index of selection if 'Delete' option is enabled and was used
CHOOSE_R(title,items,cur_sel,del_opt)
BEGIN
  LOCAL top_IDX:=MAX(1,cur_sel-6),num_items:=SIZE(items),prev_sel;
  LOCAL exit_ch:=0,ret_code:=0,i,j,item_width,x_right,draw_items:={1};
  LOCAL mt,dx,dy,init_x:=0,init_y:=0,choose_menu:={"","","","","Cancel","OK"};
  IF del_opt THEN
    choose_menu(1):="Delete";
  END;
  item_width:=IFTE(num_items>7,280,290);
  x_right:=IFTE(num_items>7,299,309);
  RECT_P(G0,0,0,319,239,light_accent);
  RECT_P(G0,10,7,310,212,main_color,main_bg);
  RECT_P(G0,11,8,309,27,dark_accent);
  TEXTOUT_P(UPPER(title),G0,15,10,3,title_color,290);
  LINE_P(G0,10,28,310,28,main_color);
  IF num_items>7 THEN
    LINE_P(G0,300,29,300,211,main_color);
  END;
  DrawChooseScroll(num_items,top_IDX,cur_sel);
  TExit_count:=0;
  REPEAT
    DrawChooseItems(num_items,top_IDX,cur_sel,items,draw_items,item_width,x_right);
    DRAWMENU(choose_menu);
    IF TExit_count==TExit THEN
      MK_in:=400;
    ELSE
      REPEAT
        IFERR MK_in:=WAIT(-1); THEN
          MK_in:=4;
          FlushKeysMouse();
        END;
      UNTIL TYPE(MK_in)==0 OR SIZE(MK_in)>1;
    END;
    IF TYPE(MK_in)==0 THEN // keyboard
      IF MK_in==-1 THEN // timeout after 60 seconds
        TExit_count:=TExit_count+1;
        IF TExit_count>=TExit THEN
          exit_ch:=1;
        END;
      ELSE
        ResetTExit();
        CASE
          IF MK_in==2 THEN // UP CURSOR
            prev_sel:=cur_sel;
            cur_sel:=IFTE(cur_sel==1,num_items,cur_sel-1);
            draw_items:={2,{prev_sel,cur_sel}};
            IF cur_sel<top_IDX THEN
              top_IDX:=top_IDX-1;
              draw_items:={1};
            END;
            IF cur_sel>top_IDX+6 THEN
              top_IDX:=cur_sel-6;
              draw_items:={1};
            END;
          END;
          IF POS({4,46,400},MK_in) THEN // ESC or ON or TExit timeout
            exit_ch:=1;
          END;
          IF MK_in==12 THEN // DOWN CURSOR
            prev_sel:=cur_sel;
            cur_sel:=IFTE(cur_sel==num_items,1,cur_sel+1);
            draw_items:={2,{prev_sel,cur_sel}};
            IF cur_sel>top_IDX+6 THEN
              top_IDX:=top_IDX+1;
              draw_items:={1};
            END;
            IF cur_sel<top_IDX THEN
              top_IDX:=cur_sel;
              draw_items:={1};
            END;
          END;
          IF MK_in==30 THEN // ENTER
            ret_code:=cur_sel;
          END;
          IF MK_in==42 THEN // 1
            IF num_items>=1 THEN
              ret_code:=1;
            END;
          END;
          IF MK_in==43 THEN // 2
            IF num_items>=2 THEN
              ret_code:=2;
            END;
          END;
          IF MK_in==44 THEN // 3
            IF num_items>=3 THEN
              ret_code:=3;
            END;
          END;
          IF MK_in==37 THEN // 4
            IF num_items>=4 THEN
              ret_code:=4;
            END;
          END;
          IF MK_in==38 THEN // 5
            IF num_items>=5 THEN
              ret_code:=5;
            END;
          END;
          IF MK_in==39 THEN // 6
            IF num_items>=6 THEN
              ret_code:=6;
            END;
          END;
          IF MK_in==32 THEN // 7
            IF num_items>=7 THEN
              ret_code:=7;
            END;
          END;
          IF MK_in==33 THEN // 8
            IF num_items>=8 THEN
              ret_code:=8;
            END;
          END;
          IF MK_in==34 THEN // 9
            IF num_items>=9 THEN
              ret_code:=9;
            END;
          END;
          DEFAULT
          draw_items:={0};
        END;
      END;
    ELSE // touch
      TExit_count:=0;
      mt:=MK_in(1);
      MK_mx:=MK_in(2);
      MK_my:=MK_in(3);
      CASE
        IF mt==0 THEN // new down
          init_x:=MK_mx;
          init_y:=MK_my;
          draw_items:={0};
        END;
        IF mt==1 THEN // move or pan
          IF 28<MK_my<210 THEN // within area of rows
            dy:=MK_my-init_y;
            CASE
              IF dy>2 THEN
                IF top_IDX>1 THEN
                  top_IDX:=top_IDX-1;
                  IF cur_sel>top_IDX+6 THEN
                    cur_sel:=cur_sel-1;
                  END;
                  draw_items:={1};
                END;
              END;
              IF dy<-2 THEN
                IF top_IDX<(num_items-6) THEN
                  top_IDX:=top_IDX+1;
                  IF cur_sel<top_IDX THEN
                    cur_sel:=top_IDX;
                  END;
                  draw_items:={1};
                END;
              END;
              DEFAULT
              draw_items:={0};
            END;
            init_x:=MK_mx;
            init_y:=MK_my;
          ELSE
            draw_items:={0};
          END;
        END;
        IF mt==3 THEN // click
          CASE
            IF 310>MK_mx>10 AND 220>MK_my>28 THEN // within area of list
              CASE
                IF 55>MK_my>28 THEN // first row
                  IF num_items>=top_IDX THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 81>MK_my>54 THEN // second row
                  IF num_items>=top_IDX+1 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+1;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 106>MK_my>80 THEN // third row
                  IF num_items>=top_IDX+2 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+2;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 130>MK_my>105 THEN // fourth row
                  IF num_items>=top_IDX+3 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+3;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 156>MK_my>129 THEN // fifth row
                  IF num_items>=top_IDX+4 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+4;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 182>MK_my>155 THEN // sixth row
                  IF num_items>=top_IDX+5 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+5;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
                IF 208>MK_my>181 THEN // seventh row
                  IF num_items>=top_IDX+6 THEN
                    prev_sel:=cur_sel;
                    cur_sel:=top_IDX+6;
                    IF prev_sel==cur_sel THEN
                      ret_code:=cur_sel;
                    ELSE
                      draw_items:={2,{prev_sel,cur_sel}};
                    END;
                  END;
                END;
              END;
            END;
            IF MK_my>219 THEN // menu
              FlashMenu();
              CASE
                IF MK_mx<52 THEN // Delete
                  IF del_opt THEN
                    ret_code:=cur_sel*-1;
                  END;
                END;
                IF 265>MK_mx>212 THEN // Cancel
                  exit_ch:=1;
                END;
                IF MK_mx>264 THEN // OK
                  ret_code:=cur_sel;
                END;
              END;
            END;
            DEFAULT
            draw_items:={0};
          END;
        END;
        DEFAULT
        draw_items:={0};
      END;
    END;
    IF ret_code THEN
      exit_ch:=1;
    END;
  UNTIL exit_ch;
  FlushKeysMouse();
  RETURN ret_code;
END;

DrawChooseItems(num_items,top_IDX,cur_sel,items,draw_items,item_width,x_right)
BEGIN
  LOCAL j;
  CASE
    IF draw_items(1)==1 THEN // everything
      RECT_P(G0,11,29,x_right,211,main_bg);
      RECT_P(G0,11,3+(cur_sel-top_IDX+1)*26,x_right,29+(cur_sel-top_IDX+1)*26,highlight_color);
      FOR j FROM top_IDX TO MIN(num_items,top_IDX+6) DO
        TEXTOUT_P(STRING(j,2,0)+". "+items(j),G0,15,(j-top_IDX+1)*26+7,4,main_color,item_width);
      END;
      DrawChooseScroll(num_items,top_IDX,cur_sel);
    END;
    IF draw_items(1)==2 THEN // only updated items
      RECT_P(G0,11,3+(draw_items(2,1)-top_IDX+1)*26,x_right,29+(draw_items(2,1)-top_IDX+1)*26,main_bg);
      RECT_P(G0,11,3+(draw_items(2,2)-top_IDX+1)*26,x_right,29+(draw_items(2,2)-top_IDX+1)*26,highlight_color);
      TEXTOUT_P(STRING(draw_items(2,1),2,0)+". "+items(draw_items(2,1)),G0,15,(draw_items(2,1)-top_IDX+1)*26+7,4,main_color,item_width);
      TEXTOUT_P(STRING(draw_items(2,2),2,0)+". "+items(draw_items(2,2)),G0,15,(draw_items(2,2)-top_IDX+1)*26+7,4,main_color,item_width);
    END;
  END;
END;

DrawChooseScroll(num_items,top_IDX,cur_sel)
BEGIN
  LOCAL scrH,topY;
  IF num_items>7 THEN
    scrH:=IP((7/num_items)*180);
    topY:=IP(30+((180-scrH)*(top_IDX-1)/(num_items-7)));
    RECT_P(G0,301,29,309,211,main_bg);
    RECT_P(G0,303,topY,307,topY+scrH,field_accent);
  END;
END;

ResetTExit()
BEGIN
  IF TYPE(MK_in)==0 THEN
    IF MK_in<>400 THEN
      TExit_count:=0;
    END;
  END;
END;

// get all keys and mouse events out of the system
FlushKeysMouse()
BEGIN
  LOCAL j,ksum;
  REPEAT
    ksum:=0;
    FOR j FROM 0 TO 50 DO
      ksum:=ksum+ISKEYDOWN(j);
    END;
  UNTIL ksum==0;
  ClearMouse();
END;

ClearMouse()
BEGIN
  LOCAL m;
  REPEAT
    m:=MOUSE();
  UNTIL SIZE(m(1))==0;
END;

FlashBtn(indx)
BEGIN
  LOCAL x1:={0,52,105,158,211,264},x2:={52,105,158,211,264,319};
  INVERT_P(G0,x1(indx),219,x2(indx),239);
  WAIT(0.1);
END;

FlashMenu()
BEGIN
  CASE
    IF MK_mx<52 THEN
      FlashBtn(1);
    END;
    IF 105>MK_mx>52 THEN
      FlashBtn(2);
    END;
    IF 158>MK_mx>105 THEN
      FlashBtn(3);
    END;
    IF 211>MK_mx>158 THEN
      FlashBtn(4);
    END;
    IF 264>MK_mx>211 THEN
      FlashBtn(5);
    END;
    IF MK_mx>264 THEN
      FlashBtn(6);
    END;
  END;
END;

// delete element at position from list
DelFromList(Lst,Pos_)
BEGIN
  LOCAL Tmp;
  IF Pos_==1 THEN
    IF SIZE(Lst)==1 THEN
      Tmp:={};
    ELSE
      Tmp:=SUB(Lst,2,SIZE(Lst));
    END;
  ELSE
    IF Pos_==SIZE(Lst) THEN
      Tmp:=SUB(Lst,1,SIZE(Lst)-1);
    ELSE
      Tmp:=CONCAT(Sub(Lst,1,Pos_-1),Sub(Lst,Pos_+1,(SIZE(Lst))));
    END;
  END;
  RETURN Tmp;
END;