PreviousUpNext

15.4.1427  src/lib/x-kit/widget/text/scrollable-string-editor.pkg

## scrollable-string-editor.pkg
#
# String edit widget with arrow buttons for scrolling.

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






###                  "You are what you read."
###
###                           -- Bert Schoenfeld


stipulate
    include threadkit;                                                  # threadkit                     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package xc =  xclient;                                              # xclient                       is from   src/lib/x-kit/xclient/xclient.pkg
    #
    package fil =  file__premicrothread;                                # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
    package mr =  xevent_mail_router;                                   # xevent_mail_router            is from   src/lib/x-kit/widget/basic/xevent-mail-router.pkg
    package pb =  pushbuttons;                                          # pushbuttons                   is from   src/lib/x-kit/widget/leaf/pushbuttons.pkg
    package se =  string_editor;                                        # string_editor                 is from   src/lib/x-kit/widget/text/string-editor.pkg
    package wg =  widget;                                               # widget                        is from   src/lib/x-kit/widget/basic/widget.pkg
    package xg =  xgeometry;                                            # xgeometry                     is from   src/lib/std/2d/xgeometry.pkg
herein

    package   scrollable_string_editor
    : (weak)  Scrollable_String_Editor                                  # Scrollable_String_Editor      is from   src/lib/x-kit/widget/text/scrollable-string-editor.api
    {
        Scrollable_String_Editor
            = 
            SCROLLABLE_STRING_EDITOR
              ( wg::Widget,
                (Void -> String),
                (String -> Void)
              );

        fun make_scrollable_string_editor  root_window  (arg as { foreground, background, initial_string, min_length } )
            =
            {   screen =  wg::screen_of  root_window;

                stredit =  se::make_string_editor  root_window  arg;
                cwidget =  se::as_widget  stredit;

                cbnds     =  wg::size_preference_thunk_of  cwidget;
                c_realize =  wg::realize_fn                cwidget;

                my { row_preference, ... } = cbnds ();
                naty = wg::preferred_length  row_preference;
                shift =  se::shift_window stredit;

                lefta = pb::make_arrow_pushbutton root_window { direction=>pb::ARROW_LEFT, size=>naty, foreground, background };
                leftw = pb::as_widget lefta;

                lbnds     =  wg::size_preference_thunk_of  leftw;
                l_realize =  wg::realize_fn                leftw;

                leftevt = pb::button_transition'_of lefta;

                righta = pb::make_arrow_pushbutton root_window { direction=>pb::ARROW_RIGHT, size=>naty, foreground, background };
                rightw = pb::as_widget righta;

                rbnds     =  wg::size_preference_thunk_of  rightw;
                r_realize =  wg::realize_fn                rightw;

                rightevt = pb::button_transition'_of righta;

                fun sizer ()
                    =
                    {   (cbnds ()) ->  { col_preference, row_preference };

                        wg::make_tight_size_preference
                          ( (wg::preferred_length  col_preference) + 4,
                            (wg::preferred_length  row_preference)
                          );
                    };

                fun wont_fit (xg::SIZE { wide, ... } )
                    =
                    {    (cbnds ()) ->  { col_preference, ... };

                         wg::preferred_length col_preference   >  wide;
                    };

                fun layout (size as xg::SIZE { wide, high } )
                    =
                    {   my { col_preference,       ... } = cbnds ();
                        my { col_preference=>ldim, ... } = lbnds ();
                        my { col_preference=>rdim, ... } = rbnds ();

                        lx = wg::preferred_length  ldim;
                        rx = wg::preferred_length  rdim;

                        if (wg::preferred_length  col_preference  <=  wide)
                            #
                            (
                              FALSE,
                              xg::BOX { col=>0,       row=>0, wide=>lx, high },
                              xg::BOX { col=>0,       row=>0, wide,     high },
                              xg::BOX { col=>wide-rx, row=>0, wide=>rx, high }
                            );
                        else
                            ( TRUE,
                              xg::BOX { col=>0,       row=>0, wide=>lx,                       high },
                              xg::BOX { col=>lx,      row=>0, wide=>int::max (1, wide-lx-rx), high },
                              xg::BOX { col=>wide-rx, row=>0, wide=>rx,                       high }
                            );
                        fi;
                    };

                fun listener mailop action
                    =
                    {   timeout' =  timeout_in' 0.05;
                        #
                        fun down_loop ()
                            =
                            {   block_until_mailop_fires  timeout';
                                #
                                case (block_until_mailop_fires  mailop)
                                    #
                                    pb::BUTTON_DOWN _
                                        =>
                                        {   action ();
                                            down_loop ();
                                        };

                                    _ => ();
                                esac;
                            };

                        fun loop ()
                            =
                            loop { block_until_mailop_fires mailop;
                                   action    ();
                                   down_loop ();
                                 };

                        loop ();
                    };

                pr =   fn _ = ();


                fun realize_scrollable_string_editor { kidplug, window, window_size }
                    =
                    {   my lo as (active, lrect, crect, rrect)
                            =
                            layout window_size;

                        lwin =  wg::make_child_window (window, lrect, wg::args_of leftw);       
                        cwin =  wg::make_child_window (window, crect, wg::args_of cwidget);
                        rwin =  wg::make_child_window (window, rrect, wg::args_of rightw);

                        my { kidplug => lkidplug, momplug => lmomplug as xc::MOMPLUG { from_kid'=>lco, ... } } =  xc::make_widget_cable ();
                        my { kidplug => ckidplug, momplug => cmomplug as xc::MOMPLUG { from_kid'=>cco, ... } } =  xc::make_widget_cable ();
                        my { kidplug => rkidplug, momplug => rmomplug as xc::MOMPLUG { from_kid'=>rco, ... } } =  xc::make_widget_cable ();

                        (xc::make_widget_cable ())
                            ->
                            { kidplug =>  my_kidplug,
                              momplug =>  my_momplug
                            };

                        my_kidplug
                            ->
                            xc::KIDPLUG { from_other'    => myci,
                                          from_mouse'    => mym,
                                          from_keyboard' => myk,
                                          ...
                                        };

                        router = mr::make_xevent_mail_router (kidplug, my_momplug, []);

                        childco =  wg::wrap_queue  cco;

                        fun do_layout ((a, lr, cr, rr), (a', lr', cr', rr'))
                            =
                            {   if (a' != a)
                                    #                           
                                    if a'
                                        xc::show_window  lwin;
                                        xc::show_window  rwin;
                                    else
                                        xc::hide_window  lwin;
                                        xc::hide_window  rwin;
                                    fi;
                                fi;

                                if (lr' != lr)                           xc::move_and_resize_window lwin lr';  fi;
                                if (cr' != cr)  pr "resize stredit\n";   xc::move_and_resize_window cwin cr';  fi;
                                if (rr' != rr)                           xc::move_and_resize_window rwin rr';  fi;
                            };

                        fun main window_size lo
                            =
                            loop lo
                            where
                                fun loop lo
                                    =
                                    loop (
                                        do_one_mailop [
                                            myci    ==>  .{  do_mom       (xc::envelope_contents #mailop, lo);  },
                                            myk     ==>  .{  do_keyboard  (xc::envelope_contents #mailop, lo);  },
                                            mym     ==>  .{  do_mouse     (xc::envelope_contents #mailop, lo);  },

                                            childco ==>  .{  handle_c (#mailop, lo);  },

                                            lco     ==>  (fn _ = lo),
                                            rco     ==>  (fn _ = lo)
                                        ]
                                    )
                                where

                                    fun do_mom (xc::ETC_RESIZE (xg::BOX { col, row, wide, high } ), lo)
                                            =>
                                            {   window_size' = xg::SIZE { wide, high };
                                                lo'   = layout window_size';

                                                do_layout (lo, lo');
                                                main window_size' lo';
                                            };

                                        do_mom (_, lo)
                                            =>
                                            lo;
                                    end;


                                    fun handle_c (xc::REQ_RESIZE, lo as (a, _, _, _))
                                            =>
                                            {   pr "resize plea\n";

                                                a' = wont_fit  window_size;

                                                if (a == a' ) 
                                                    #
                                                    lo;
                                                else
                                                    lo' = layout window_size;
                                                    pr "newlayout\n";

                                                    do_layout (lo, lo');
                                                    lo';
                                                fi;
                                            };

                                        handle_c (xc::REQ_DESTRUCTION, lo)
                                            =>
                                            lo;
                                    end;


                                    fun do_keyboard ((xc::KEY_PRESS _), lo)
                                            => 
                                            { (fil::print " [field-edit received KEY_PRESS]\n"); lo; };

                                        do_keyboard ((_), lo)
                                            =>
                                            lo;
                                    end;


                                    fun do_mouse ((xc::MOUSE_ENTER _), lo)
                                            =>
                                            {   a =  xc::grab_keyboard  cwin;
                                                #
                                                #  (fil::print (" [field-edit received xc::MOUSE_ENTER: "$(int::to_string (a))$"]\n")) 

                                                lo;
                                            };

                                        do_mouse ((_), lo)
                                            =>
                                            lo;
                                    end;
                                end;
                            end;


                        mr::add_child router (lwin, lmomplug);
                        mr::add_child router (cwin, cmomplug);
                        mr::add_child router (rwin, rmomplug);

                        make_thread  "scrollable_string_editor left"   .{   listener leftevt   .{ shift -1; };   };
                        make_thread  "scrollable_string_editor right"  .{   listener rightevt  .{ shift  1; };   };

                        make_thread  "scrollable_string_editor"  .{
                            #
                            main window_size (active, lrect, crect, rrect);
                            ();
                        };

                        l_realize { kidplug=>lkidplug, window=>lwin, window_size=>xg::box::size lrect };
                        c_realize { kidplug=>ckidplug, window=>cwin, window_size=>xg::box::size crect };
                        r_realize { kidplug=>rkidplug, window=>rwin, window_size=>xg::box::size rrect };

                        if active
                            #
                            xc::show_window  lwin;
                            xc::show_window  rwin;
                        fi;

                        xc::show_window  cwin;
                };

                SCROLLABLE_STRING_EDITOR
                  (
                    wg::make_widget
                      {
                        root_window, 
                        args=> fn () = { background => NULL }, 
                        size_preference_thunk_of => sizer, 
                        realize   => realize_scrollable_string_editor
                      },

                    fn () =  se::get_string  stredit,

                    se::set_string  stredit
                  );
            };

        fun as_widget  (SCROLLABLE_STRING_EDITOR (w, _, _)) = w;
        fun get_string (SCROLLABLE_STRING_EDITOR (w, g, _)) = g ();
        fun set_string (SCROLLABLE_STRING_EDITOR (_, _, s)) = s;

    };          #  scrollable_string_editor 

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext