PreviousUpNext

15.4.1360  src/lib/x-kit/tut/arithmetic-game/diver-pane.pkg

## diver-pane.pkg
#
# Application pane which displays a stick-figure
# animation of a diver step-by-step climbing a
# pole and finally diving in response to
# successive correct user answers to arithmetic
# problems.

# Compiled by:
#     src/lib/x-kit/tut/arithmetic-game/arithmetic-game-app.lib

stipulate
    include package   threadkit;                # threadkit     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package g2d=  geometry2d;                   # geometry2d    is from   src/lib/std/2d/geometry2d.pkg
    #
    package xc =  xclient;                      # xclient       is from   src/lib/x-kit/xclient/xclient.pkg
    #
    package wg =  widget;
    #
    package di =  diver_images;                 # diver_images  is from   src/lib/x-kit/tut/arithmetic-game/diver-images.pkg
    package si =  splash_images;                # splash_images is from   src/lib/x-kit/tut/arithmetic-game/splash-images.pkg
herein

    package  diver_pane
    :        Diver_Pane                         # Diver_Pane    is from   src/lib/x-kit/tut/arithmetic-game/diver-pane.api
    {
        Plea_Mail = START | UP | WAVE | DIVE;

        Diver_Pane
            =
            DIVER_PANE
              { widget:     wg::Widget,
                plea_slot:  Mailslot( Plea_Mail )
              };

        Position = GONE | TOP | STEP Int;

        top_margin    = 48;
        bottom_margin = 48;

        person_high   = 32;
        pole_wide     =  4;

        platform_width = 12;
        platform_depth =  2;

        climb_increment = 9;

        land_data =  ( 16,

                       [ [  "0x8888", "0x2222", "0x1111", "0x4444",
                            "0x8888", "0x2222", "0x1111", "0x4444",
                            "0x8888", "0x2222", "0x1111", "0x4444",
                            "0x8888", "0x2222", "0x1111", "0x4444"
                       ] ]
                     );


        water_data = ( 16,

                       [ [  "0x5555", "0xaaaa", "0x5555", "0xaaaa",
                            "0x5555", "0xaaaa", "0x5555", "0xaaaa",
                            "0x5555", "0xaaaa", "0x5555", "0xaaaa",
                            "0x5555", "0xaaaa", "0x5555", "0xaaaa"
                       ] ]
                      );


        fun make_diver_pane  root_window  steps
            =
            {   screen    =  wg::screen_of  root_window;

                plea_slot =  make_mailslot ();
                plea'     =  take_from_mailslot' plea_slot;

                realize_oneshot
                    =
                    make_oneshot_maildrop ();

                natural_height = top_margin + bottom_margin + platform_depth + (steps * person_high);

                size_preferences
                    =
                    { col_preference =>  wg::INT_PREFERENCE { start_at=>0, step_by=>1, min_steps=>80,             best_steps=>180,            max_steps=>NULL },
                      row_preference =>  wg::INT_PREFERENCE { start_at=>0, step_by=>1, min_steps=>natural_height, best_steps=>natural_height, max_steps=>NULL }
                    };

                widget
                    =
                    wg::make_widget
                      { root_window,
                        size_preference_thunk_of =>  \\ () = size_preferences,
                        realize_widget           =>  \\ arg = threadkit::put_in_oneshot (realize_oneshot, arg),

                        # I added the following line, cribbed randomly
                        # from the other examples, to get this to
                        # compile.  Apparently the 'args' element was
                        # added after this example was written and it
                        # was never updated (I checked the raw SML/NJ 110.58 source.)
                        #     -- 2009-11-30 CrT
                        #
                        args         => \\ () = { background => NULL }
                      };

                diver_image_array  = rw_vector::from_list (map (di::make_diver_image screen) di::images);

                dive_image   = rw_vector::get (diver_image_array, di::dive_index);
                top_image    = rw_vector::get (diver_image_array, di::top_index);
                top2_image   = rw_vector::get (diver_image_array, di::top_index+1);
                top3_image   = rw_vector::get (diver_image_array, di::top_index+2);
                top4_image   = rw_vector::get (diver_image_array, di::top_index+3);

                wave_list = [top_image, top2_image, top3_image, top4_image, top3_image, top2_image];

                climb1 = rw_vector::get (diver_image_array, di::climb_index);
                climb2 = rw_vector::get (diver_image_array, di::climb_index+1);
                climb3 = rw_vector::get (diver_image_array, di::climb_index+2);
                climb4 = rw_vector::get (diver_image_array, di::climb_index+3);

                my  { high => climb_height, ... }
                    =
                    xc::size_of_ro_pixmap  climb1.data;

                climb_bound =  top_margin + climb_increment + climb_height - 1;
                stand_image =  rw_vector::get (diver_image_array, di::stand_index);

                land_ro_pixmap  =  xc::make_readonly_pixmap_from_ascii  screen   land_data;
                water_ro_pixmap =  xc::make_readonly_pixmap_from_ascii  screen  water_data;

                tower_pen
                    = 
                    xc::make_pen  [ xc::p::FOREGROUND xc::rgb8_black,
                                    xc::p::BACKGROUND xc::rgb8_white
                                  ];

                image_pen = tower_pen;

                water_pen    =  xc::clone_pen (tower_pen, [xc::p::FILL_STYLE_STIPPLED,  xc::p::STIPPLE water_ro_pixmap]);
                land_pen     =  xc::clone_pen (tower_pen, [xc::p::FILL_STYLE_STIPPLED,  xc::p::STIPPLE  land_ro_pixmap]);

                splash_list  =  si::make_splashes  (root_window, water_ro_pixmap);

                fun pause ()
                    =
                    sleep_for  0.04;

                fun realize { window, window_size, kidplug } position
                    =
                    init (window_size, position)
                    where
                        (xc::ignore_mouse_and_keyboard  kidplug)
                            ->
                            xc::KIDPLUG { from_other', ... };

                        drawwin =  xc::drawable_of_window  window;

                        auto_drawwin
                            =
                            xc::make_unbuffered_drawable
                                drawwin;

                        fun init ({ wide, high }, position)
                            =
                            {   midx = wide / 2;
                                #
                                land = {    shape => xc::CONVEX_SHAPE,

                                            verts => [ { col=>midx,               row=>high-bottom_margin },
                                                       { col=>wide - 1,           row=>high-bottom_margin },
                                                       { col=>wide - 1,           row=>high - 1 },
                                                       { col=>midx-bottom_margin, row=>high - 1 }
                                                     ]
                                         };

                                water = {   shape => xc::CONVEX_SHAPE,

                                            verts => [ { col=>midx,               row=>high-bottom_margin },
                                                       { col=>0,                  row=>high-bottom_margin },
                                                       { col=>0,                  row=>high - 1 },
                                                       { col=>midx-bottom_margin, row=>high - 1 }
                                                     ]
                                        };

                                pole_height = high-(bottom_margin+top_margin);

                                platform
                                    = 
                                    { col  => midx-((platform_width - pole_wide) / 2),
                                      row  => top_margin,
                                      high => platform_depth,
                                      wide => platform_width
                                    };

                                pole =   { col  => midx,
                                           row  => top_margin,
                                           wide => pole_wide,
                                           high => pole_height
                                         };

                                top =   { col => midx,
                                          row => top_margin - 1
                                        };

                                fun draw_tower ()
                                    = 
                                    {   xc::fill_box  drawwin  tower_pen  pole;
                                        xc::fill_box  drawwin  tower_pen  platform;
                                    };

                                fun draw_landscape ()
                                    =
                                    {   xc::fill_polygon  drawwin  water_pen  water;
                                        xc::fill_polygon  drawwin  land_pen   land;
                                    };

                                stepx = midx+pole_wide;
                                stepy = high-(bottom_margin+1);
                                step  = pole_height / steps;

                                fun step_pt i
                                    =
                                    { col =>  stepx,
                                      row =>  stepy-(step*i)
                                    };

                                dive_point
                                    =
                                    { col =>  stepy+1,
                                      row =>  midx - 32
                                    };

                                splash_pt
                                    =
                                    g2d::point::subtract (dive_point, { col=>0, row=>1 } );


                                fun put_top ()
                                    = 
                                    di::set_diver_image
                                        (auto_drawwin, image_pen)
                                        (top_image, top);


                                fun clear_top ()
                                    =
                                    di::clear_diver_image
                                        auto_drawwin
                                        (top_image, top);


                                fun put_step 0 =>  di::set_diver_image  (auto_drawwin, image_pen)  (stand_image,  step_pt 0);
                                    put_step i =>  di::set_diver_image  (auto_drawwin, image_pen)  (climb1,       step_pt i);
                                end; 


                                fun clear_step 0 =>  di::clear_diver_image  auto_drawwin  (stand_image,  step_pt 0);
                                    clear_step i =>  di::clear_diver_image  auto_drawwin  (climb1,       step_pt i);
                                end;


                                fun do_image (image, pt)
                                    =
                                    {   di::set_diver_image (auto_drawwin, image_pen) (image, pt);

                                        pause();

                                        di::clear_diver_image drawwin (image, pt);
                                    };

                                fun wave ()
                                    =
                                    repeat 4
                                    where
                                        fun cycle _ = apply (\\ i = do_image (i, top))
                                                            wave_list;

                                        fun repeat 0 =>  ();
                                            repeat i =>  {  cycle();  repeat (i - 1);  };
                                        end;
                                    end;

                                fun splash ()
                                    =
                                    apply (\\ i = do_image (i, splash_pt))
                                          splash_list;

                                fun make_dive i
                                    =
                                    {  dive_point ->  { col=>dive_x, row=>dive_y };

                                       init_x = midx - 2;
                                       init_y = (stepy-(step*i)) + 16;

                                       del_x = init_x - dive_x;
                                       del_y = init_y - dive_y;

                                       incr = 6;

                                       fun x_of_y  y
                                           =
                                           (y*del_x  + init_x*del_y
                                                     - init_y*del_x
                                           )
                                           /
                                           del_y;


                                       fun dive (pt as { col=>x, row=>y } )
                                           =
                                           if (y < dive_y)

                                               di::set_diver_image  (auto_drawwin, image_pen)  (dive_image, pt);

                                               pause ();

                                               di::clear_diver_image  auto_drawwin  (dive_image, pt);

                                               dive ({ col => x_of_y (y+incr),
                                                       row => y+incr
                                                     }
                                                    );
                                           fi;

                                       dive ({ col=>init_x, row=>init_y } );
                                    };


                                fun climb i
                                    =
                                    loop pt0
                                    where
                                        pt0 = step_pt i;
                                        #
                                        (step_pt (i+1)) ->  { row=>y1, ... };

                                        ybound = max (y1, climb_bound);


                                        fun loop (pt as { col=>x, row=>y  } )
                                            =
                                            if (y > ybound)

                                                pt' = { col=>x, row=>y-climb_increment };

                                                do_image (climb1, pt);
                                                do_image (climb2, pt);
                                                do_image (climb3, pt');
                                                do_image (climb4, pt');

                                                loop pt';

                                            fi;
                                    end;


                                fun redraw (_, position)
                                    =
                                    {   xc::clear_drawable  drawwin;

                                        draw_tower ();

                                        draw_landscape ();

                                        case position
                                            #
                                            GONE   =>  ();
                                            TOP    =>  put_top ();
                                            STEP i =>  put_step i;
                                        esac;
                                    };


                                fun do_mom (xc::ETC_REDRAW rlist, position)
                                        =>
                                        redraw (rlist, position);

                                    do_mom (xc::ETC_RESIZE ({ wide, high, ... } ), position)
                                        =>
                                        init ({ wide, high }, position);

                                    do_mom _
                                        =>
                                        ();
                                end;


                                fun do_gone ()
                                    =
                                    {   fun do_plea START =>  climbing 0;
                                            do_plea _     =>  do_gone ();
                                        end;


                                        do_one_mailop [

                                            from_other'
                                                ==>
                                                (\\ envelope = do_gone (do_mom (xc::get_contents_of_envelope  envelope,  GONE))),

                                            plea'
                                                ==>
                                                do_plea
                                        ];
                                    }

                                also
                                fun do_top ()
                                    =
                                    {   wave    ();
                                        put_top ();
                                        loop    ();
                                    }
                                    where
                                        fun loop ()
                                            =
                                            do_one_mailop [

                                                from_other'
                                                    ==>
                                                   (\\ mailop = loop (do_mom (xc::get_contents_of_envelope  mailop,  TOP))),

                                                plea'
                                                    ==>
                                                    (\\ req = loop (do_plea req))
                                            ]
                                            where
                                                fun do_plea START
                                                        =>
                                                        {   clear_top ();
                                                            climbing  0;
                                                        };

                                                    do_plea _
                                                        =>
                                                        ();
                                                end;
                                            end;
                                    end


                                also
                                fun climbing i
                                    =
                                    {   put_step i;
                                        loop ();
                                    }
                                    where
                                        fun loop ()
                                            = 
                                            do_one_mailop [
                                                from_other'        ==>  (\\ mailop =  loop (do_mom (xc::get_contents_of_envelope  mailop,  STEP i))),
                                                plea'  ==>  loop o do_plea
                                            ]
                                            where
                                                fun to_top ()
                                                    =
                                                    {   clear_step i;
                                                        climb i;
                                                        do_top();
                                                    };

                                                fun do_climb s
                                                    =
                                                    {   clear_step i;
                                                        climb i;
                                                        climbing s;
                                                    };

                                                fun do_plea START =>  if (i != 0)   clear_step i;   climbing 0;  fi;
                                                    do_plea WAVE  =>  to_top ();
                                                    do_plea DIVE  => { clear_step i;     do_dive i; };
                                                    do_plea UP    =>  if (i+1 < steps)  do_climb (i+1);
                                                                         else              to_top ();
                                                                         fi;
                                                end;
                                            end;
                                    end

                                also
                                fun do_dive i
                                    =
                                    {   make_dive i;
                                        splash  ();
                                        do_gone ();
                                    };


                                case position
                                    #
                                    GONE   => do_gone ();
                                    TOP    => do_top  ();
                                    STEP i => climbing i;
                                esac;
                          };                            # fun init


                  end;                          # fun realize

                fun diver_pane position
                    =
                    {   fun do_plea (START,   _) =>  STEP 0;
                            do_plea (DIVE,    _) =>  GONE;
                            do_plea (WAVE,    _) =>  TOP;
                            do_plea (UP, STEP i) =>  i+1 < steps   ??  STEP (i+1)   ::   TOP;
                            do_plea (UP, p     ) =>  p;
                        end; 


                        do_one_mailop [

                            plea'
                                ==>
                                (\\ msg = diver_pane (do_plea (msg, position))),

                            get_from_oneshot'  realize_oneshot
                                ==>
                                (\\ arg = realize arg position)
                        ];
                    };

                  make_thread "diver_pane" {.
                      #
                      diver_pane (STEP 0);
                  };

                  DIVER_PANE { widget, plea_slot };

            };                                                  # fun make_diver_pane

        fun as_widget (DIVER_PANE { widget, ... } )
            =
            widget;

        fun start (DIVER_PANE { plea_slot, ... } ) =  put_in_mailslot (plea_slot, START);
        fun up    (DIVER_PANE { plea_slot, ... } ) =  put_in_mailslot (plea_slot, UP   );
        fun dive  (DIVER_PANE { plea_slot, ... } ) =  put_in_mailslot (plea_slot, DIVE );
        fun wave  (DIVER_PANE { plea_slot, ... } ) =  put_in_mailslot (plea_slot, WAVE );

    };

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext