PreviousUpNext

15.4.1545  src/lib/x-kit/widget/old/text/one-line-virtual-terminal.pkg

## one-line-virtual-terminal.pkg
#
# Compare to:
#     src/lib/x-kit/widget/old/text/virtual-terminal.pkg

# Compiled by:
#     src/lib/x-kit/widget/xkit-widget.sublib




###             "The problem with television is that
###              the people must sit and keep their
###              eyes glued on a screen: the average
###              American family hasn't time for it."
###
###                      -- The New York Times, 1939


# This package gets used in:
#
#     src/lib/x-kit/widget/old/text/string-editor.pkg

stipulate
    include package   threadkit;                                                # threadkit                             is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package vc = rw_vector_of_chars;                                            # rw_vector_of_chars                    is from   src/lib/std/rw-vector-of-chars.pkg
    package wg = widget;                                                        # widget                                is from   src/lib/x-kit/widget/old/basic/widget.pkg
    package xc =  xclient;                                                      # xclient                               is from   src/lib/x-kit/xclient/xclient.pkg
    package g2d=  geometry2d;                                                   # geometry2d                            is from   src/lib/std/2d/geometry2d.pkg
herein

    package   one_line_virtual_terminal
    : (weak)  One_Line_Virtual_Terminal                                         # One_Line_Virtual_Terminal             is from   src/lib/x-kit/widget/old/text/one-line-virtual-terminal.api
    {
        Fn_Table
            =
            { deletec: String -> Void,
              insert:  String -> Void,
              reset:   Void -> Void,

              set_cur_pos: Int -> Void,
              set_cursor:  Bool -> Void,
              set_size:    g2d::Size -> Int
            };

        One_Line_Virtual_Terminal
            =
            ( (Int -> g2d::Size),
              (g2d::Point -> Int), 
              ((xc::Window, g2d::Size) -> Fn_Table)
            );

        Plea_Mail
          #
          = SET_SIZE     g2d::Size
          #
          | INSERT       String
          | DELETE       String
          #
          | SET_CUR_POS  Int
          | SET_CURSOR   Bool
          #
          | RESET
          ;

        fun make_one_line_virtual_terminal
                #
                root
                #
                (foreground, background)
            =
            {   screen =  wg::screen_of  root;

                default_background_color =  xc::white;
                default_foreground_color =  xc::black;

                forec = case foreground   
                            #
                            THE c => c;
                            NULL  => default_foreground_color;
                        esac;

                pen    =  xc::make_pen [xc::p::FOREGROUND (xc::rgb8_from_rgb forec)];
                bltpen =  xc::make_pen [];              #  workaround for blt op bug.  XXX BUGGO FIXME

                font_name = "9x15";
                font = wg::open_font root font_name;

                (xc::font_high font)
                    ->
                    { ascent  => font_ascent,
                      descent => font_descent
                    };

                font_high = font_ascent + font_descent;

                (xc::char_info_of font (char::to_int 'A'))
                    ->
                    xc::CHAR_INFO { left_bearing=>lb, char_width=>fontw, ... };

                col_delta = 1;
                endpad    = 2;

                fun num_chars x
                    =
                    (x - endpad) / fontw;

                fun realize (window, given_size as { wide, high } )
                    =
                    {   plea_slot =  make_mailslot ();
                        reply_slot   =  make_mailslot (); 

                        from =  xc::FROM_WINDOW  window;
                        to   =  xc::drawable_of_window  window;

                        fun text arg
                            =
                            xc::draw_transparent_string  to pen font arg;

                        fun draw_cursor pen p
                            =
                            {   col = p * fontw;
                                #
                                xc::draw_seg  to  pen
                                  ( ( { col, row=>0             },
                                      { col, row=>font_high - 1 }
                                    ) : g2d::Line
                                  );
                            };

                        fun copy (r, p)
                            =
                            xc::pixel_blt_mailop  to bltpen { from, from_box=>r, to_pos=>p };

                        my (clear, cursor_off)
                            =
                            case background   
                                #
                                NULL  => ( xc::clear_box  to,
                                           \\ p = xc::clear_box  to  ({ col=>p*fontw, row=>0, wide=>1, high=>font_high } )
                                         );

                                THE rgb =>
                                    {   clrpen =  xc::make_pen  [xc::p::FOREGROUND (xc::rgb8_from_rgb rgb)];
                                        #
                                        ( xc::fill_box to clrpen,
                                          draw_cursor clrpen
                                        );
                                    };
                            esac;

                        cursor_on = draw_cursor pen;

                        fun main (len, { wide, high } )
                            =
                            loop (0, FALSE)
                            where
                                buf = vc::make_rw_vector (len, ' ');

                                fun clear_buf ()
                                    =
                                    cb (len - 1)
                                    where
                                        fun cb 0 =>   vc::set (buf, 0, ' ');
                                            cb i => { vc::set (buf, i, ' ');   cb (i - 1); };
                                        end;
                                    end;

                                fun del_buf (p, c)                                                      # Delete char at 'p', shift in 'c' (else blank) at end.
                                    =
                                    {
                                        fun shft i
                                            = 
                                            if (i != len)
                                                #
                                                vc::set (buf, i - 1, vc::get (buf, i));
                                                shft (i+1);
                                            fi;

                                        shft p;

                                        size c == 1   ??   vc::set (buf, len - 1, string::get_byte_as_char (c, 0))
                                                      ::   vc::set (buf, len - 1, ' '                            );
                                    };

                                fun ins_buf (p, c)                                                      # Shift to open up slot at 'p', place 'c' in it.
                                    =
                                    {
                                        fun shft i
                                            = 
                                            if (i != p)
                                                #
                                                vc::set (buf, i, vc::get (buf, i - 1));
                                                shft (i - 1);
                                            fi;

                                        shft (len - 1);
                                        vc::set (buf, p, c);
                                    };

                                fun ins_str_buf (p, s)                                                  # Insert 's' at 'p' in buf.
                                    =
                                    {
                                        slen = size s;
                                        endp = p + slen - 1;

                                        fun shft i
                                            = 
                                            if (i == endp)
                                                #
                                                vc::set (buf, i, vc::get (buf, i-slen));
                                                shft (i - 1);
                                            fi;

                                        fun do_update (p, i)
                                            = 
                                            {   vc::set (buf, p, (string::get_byte_as_char (s, i)));
                                                do_update (p+1, i+1);
                                            };

                                        shft (len - 1);

                                        (do_update (p, 0))
                                        except
                                            ord = ();
                                    };

                                fun redraw (p, on_off)
                                    =
                                    {   text ({ col=>0, row=>font_ascent }, vc::to_vector buf);
                                        #
                                        on_off   ?:   cursor_on p;
                                    };

                                fun loop (curp, on_off)
                                    = 
                                    case (take_from_mailslot  plea_slot)
                                        #
                                        SET_SIZE (size as { wide, high } )
                                            =>
                                            {
                                                len' = num_chars wide;

                                                put_in_mailslot  (reply_slot,  len');

                                                main (len', size);
                                            };

                                        INSERT s
                                            => 
                                            if (curp >= len)
                                                #
                                                loop (curp, on_off);
                                            else 
                                                case (size s)
                                                    #
                                                    0 => loop (curp, on_off);

                                                    1 => {   col = curp*fontw;
                                                                   bw = (len - curp - 1)*fontw + endpad;

                                                             ins_buf (curp, string::get_byte_as_char (s, 0));

                                                             base_mailop = copy ({ col, row=>0, wide=>bw, high }, { col=>col+fontw, row=>0 } );

                                                             clear ({ col, row=>0, wide=>fontw, high } );
                                                             text ({ col, row=>font_ascent }, s);

                                                             case (block_until_mailop_fires  base_mailop)
                                                                 #
                                                                 [] => ();
                                                                 _  => redraw (curp+1, on_off);
                                                             esac;


                                                             loop (curp+1, on_off);
                                                         };

                                                    slen =>
                                                         {   count = int::min (slen, len - curp);

                                                             col   = curp*fontw;
                                                             space = count*fontw;
                                                             bw    = (len - curp - count)*fontw + endpad;

                                                             ins_str_buf (curp, substring (s, 0, count));

                                                             base_mailop = copy ({ col, row=>0, wide=>bw, high }, { col=>col+space, row=>0 } );

                                                             clear ({ col, row=>0, wide=>space, high } );
                                                             text ({ col, row=>font_ascent }, substring (s, 0, count));

                                                             case (block_until_mailop_fires  base_mailop)
                                                                 #
                                                                 [] => ();
                                                                 _  => redraw (curp+count, on_off);
                                                             esac;

                                                             loop (curp+count, on_off);
                                                         };
                                                esac;
                                            fi;

                                   SET_CUR_POS curp'
                                       =>
                                       if (curp' >= 0 and curp' <= len)

                                            if on_off 
                                                cursor_off curp;
                                                cursor_on curp';
                                            fi;

                                            loop (curp', on_off);
                                       else
                                            loop (curp, on_off);
                                       fi;

                                   SET_CURSOR on_off'
                                       => 
                                       {
                                           if (on_off' != on_off )
                                               #
                                               if on_off'  cursor_on  curp;
                                               else        cursor_off curp;
                                               fi;
                                           fi;

                                           loop (curp, on_off');
                                       };

                                   RESET
                                       =>
                                       {   clear ({ col=>0, row=>0, wide, high } );
                                           clear_buf ();
                                           loop (0, FALSE);
                                       };

                                   DELETE c
                                       =>
                                       if  (curp > 0)

                                           col    = curp*fontw;
                                           endcol = (len - 1)*fontw;

                                           del_buf (curp, c);

                                           base_mailop = copy ({ col, row=>0, wide=>wide-col, high }, { col=>col-fontw, row=>0 } );

                                           if (curp == len)   clear ({ col=>endcol + 1,  row=>0,  wide=>wide-endcol, high } );
                                           else               clear ({ col=>endcol,      row=>0,  wide=>wide-endcol, high } );
                                           fi;

                                           if (size c == 1)
                                                #
                                                text ({ col=>endcol, row=>font_ascent }, c);
                                           fi;

                                           case (block_until_mailop_fires  base_mailop)
                                               #
                                               [] => ();
                                               _  => redraw (curp - 1, on_off);
                                           esac;

                                           loop (curp - 1, on_off);
                                       else
                                           loop (curp, on_off);
                                       fi;
                                esac;
                            end;


                        xlogger::make_thread  "txtwin"   {. main (num_chars wide, given_size); (); };

                        { set_size    =>  \\ size =  { put_in_mailslot  (plea_slot, SET_SIZE size);   take_from_mailslot  reply_slot; },
                          set_cur_pos =>  \\ v  =      put_in_mailslot  (plea_slot, SET_CUR_POS v),
                          set_cursor  =>  \\ v  =      put_in_mailslot  (plea_slot, SET_CURSOR v),
                          insert      =>  \\ c  =      put_in_mailslot  (plea_slot, INSERT c),
                          reset       =>  \\ () =      put_in_mailslot  (plea_slot, RESET),
                          deletec     =>  \\ c  =      put_in_mailslot  (plea_slot, DELETE c)
                        };
                    };

                fun pttochar ({ col, row } )
                    =
                   (col + col_delta) / fontw;

                fun sizer n
                    =
                    { high=>font_high, wide=>n*fontw + endpad };

                (sizer, pttochar, realize);
            };

    };                                          # one_line_virtual_terminal

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext