home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / amiga / progrmr / exp_src / interfac.c < prev    next >
C/C++ Source or Header  |  1991-05-13  |  24KB  |  1,052 lines

  1. /* interface.c */
  2.  
  3. /* the actual interface to the player routine
  4.  */
  5.  
  6.  
  7. /* $Author: Espie $
  8.  * $Date: 91/05/14 02:29:48 $
  9.  * $Revision: 1.25 $
  10.  * $Log:    interface.c,v $
  11.  * Revision 1.25  91/05/14  02:29:48  Espie
  12.  * The auto resize was no longer working... Latest
  13.  * version hadn't been tested. Put the code in order.
  14.  * Added a temporary fix to the asynchronous resize
  15.  * problem (window jumping all other the place when
  16.  * doing fast resizes).
  17.  * 
  18.  * I should rewrite part of the code to get rid of
  19.  * relative coordinates once and for all (maybe...)
  20.  * 
  21.  * Revision 1.24  91/05/12  19:53:21  Espie
  22.  * pause handled like other gadgets, no longer special case.
  23.  * 
  24.  * Revision 1.23  91/05/12  15:57:15  Espie
  25.  * Minor changes.
  26.  * Did not allocate enough points 2*number of point = coordinates,
  27.  * so it did abort mysteriously, only when optimized.. sigh.
  28.  * 
  29.  * Revision 1.22  91/05/10  00:03:55  Espie
  30.  * 
  31.  * Corrected NewPropInfo bug.
  32.  * 
  33.  * Revision 1.21  91/05/09  17:35:32  Espie
  34.  * pref_xxx added,
  35.  * minor modifications in gadget handling.
  36.  * hook for appwindow: returns the window now,
  37.  * events.c takes care of the signal mask.
  38.  * 
  39.  * Revision 1.20  91/05/08  15:50:50  Espie
  40.  * Volume slider now working.
  41.  * Warning ! Nothing to add another slider right now.
  42.  * 
  43.  * Revision 1.19  91/05/07  12:12:22  Espie
  44.  * *** empty log message ***
  45.  * 
  46.  * Revision 1.18  91/05/07  02:53:53  Espie
  47.  * Added smart ``resize window''.
  48.  * Will now move the window if anything is amiss.
  49.  * Experimented with the GetScreenDrawInfo aspect ratio.
  50.  * 
  51.  * Revision 1.17  91/05/06  23:35:47  Espie
  52.  * Completely cleaned up all codes,
  53.  * added new entries, like temporary_title/restore_title,
  54.  * suppressed obsolete ones. Still needs to get gadgets/borders...
  55.  * tight.
  56.  * 
  57.  * Revision 1.16  91/05/05  04:01:26  Espie
  58.  * Added the void_title() call.
  59.  * Changed minor details.
  60.  * 
  61.  * Revision 1.15  91/05/03  02:49:14  Espie
  62.  * Added sizing gadget. Don't like it, so commented it out
  63.  * (Intuition spends its time trashing its own borders... not neat.
  64.  * Also changed order of gadgets. Load is most important gadget,
  65.  * so it is first. Restart and pause are arranged for graphical
  66.  * symbols (sigh...) |<   and   ''   .
  67.  * 
  68.  * Revision 1.14  91/05/03  00:42:15  Espie
  69.  * Cosmetic changes
  70.  * 
  71.  * Revision 1.13  91/05/02  23:29:50  Espie
  72.  * Cosmetic changes. Starting message when no song is loaded yet.
  73.  * 
  74.  * Revision 1.12  91/05/02  11:20:13  Espie
  75.  * Handle a variable number of gadget much better.
  76.  * Added banner, start_player() conditionnally if there IS a song to play.
  77.  * 
  78.  * Revision 1.11  91/05/02  01:30:28  Espie
  79.  * Many changes in the handle events part, simpler than before.
  80.  * 
  81.  * Revision 1.10  91/05/01  00:49:32  Espie
  82.  * Fonts working, resizing ok.
  83.  * 
  84.  * Revision 1.9  91/04/30  16:51:03  Espie
  85.  * Added a real button for speed.
  86.  * Handle font changes a little better...
  87.  * 
  88.  * Revision 1.8  91/04/30  01:48:11  Espie
  89.  * Some minor problems with tempo changing not when it should, fixed.
  90.  * 
  91.  * Revision 1.7  91/04/30  00:36:17  Espie
  92.  * Stable version III.
  93.  * 
  94.  * Revision 1.6  91/04/30  00:24:56  Espie
  95.  * New reset_tempo() command, for using the current state of the speed
  96.  * setting when swapping songs.
  97.  * 
  98.  * Revision 1.5  91/04/29  23:52:41  Espie
  99.  * Added possibility to load files on the fly.
  100.  * Surprisingly simple, even if limited right now
  101.  * (I need the possibility to spawn my subtasks,
  102.  * that would GREATLY simplify most of the program).
  103.  * 
  104.  * Revision 1.4  91/04/29  15:04:13  Espie
  105.  * Small modifications to take advantage of the new interface/audio_soft/audio_hard.
  106.  * Corrected a misconception concerning toggleselect gadgets:
  107.  * check their state BEFORE waiting for them, and don't assume
  108.  * you can keep a copy of their internal state.
  109.  * Guaranteed way to get out of touch with intuition...
  110.  * 
  111.  * Revision 1.3  91/04/29  13:03:16  Espie
  112.  * Interfaced to new audio_soft.
  113.  * 
  114.  * Revision 1.2  91/04/29  03:52:29  Espie
  115.  * A start for a real interface.
  116.  * Displays the song title and patterns,
  117.  * has boolean gadgets for pause, restart, change speed.
  118.  * Misses some imagery yet...
  119.  * 
  120.  * Revision 1.1  91/04/29  02:23:15  Espie
  121.  * Initial revision
  122.  * 
  123.  *
  124.  */
  125.  
  126.  
  127. #include <exec/types.h>
  128. #include <intuition/intuition.h>
  129. #include <intuition/screens.h>
  130. #include <proto/exec.h>
  131. #include <proto/intuition.h>
  132. #include <proto/graphics.h>
  133. #include <dos/dos.h>
  134. #include <custom/cleanup.h>
  135. #include <custom/graphics.h>
  136. #include <assert.h>
  137. #include "proto.h"
  138. #include "banner.c"
  139.  
  140.  
  141.     /* see <custom/graphics.h> 
  142.     */
  143. #ifdef SIZE_GADGET
  144. struct saveclip *saveclip;
  145. #endif
  146.  
  147. /* this is all the parameters we might want to change
  148.  * depending on the current screen type
  149.  */
  150.  
  151. /* the colors. */
  152. UBYTE TEXT, SHINE, SHADOW, HILIGHT, BACKGROUND;
  153.  
  154. /* the highlighting method for boolean gadgets */
  155. ULONG GAD_HILIGHT;
  156.  
  157. /* the spacing between graphics elements */
  158. int xspace, yspace;
  159.  
  160.  
  161. struct Window *window;
  162. struct Screen *screen;
  163. struct RastPort *rastport;
  164. int sys_interwidth, sys_baseline, scr_interwidth, scr_baseline;
  165.  
  166.  
  167. void setup_environment(void)
  168.     {
  169.         /* get all we can */
  170.         screen = window->WScreen;
  171.         rastport= window->RPort;
  172.         sys_interwidth = rastport->TxHeight + 1;
  173.         sys_baseline = rastport->TxBaseline;
  174.         scr_interwidth = screen->RastPort.TxHeight + 1;
  175.         scr_baseline = screen->RastPort.TxBaseline;
  176.         
  177.         /* colors have changed under 2.0, these are the old Pen Numbers,
  178.          * and should provide reasonable defaults */
  179.         SHINE = 1;
  180.         SHADOW = 2;
  181.         TEXT = 2;
  182.         HILIGHT = 1;
  183.         BACKGROUND = 0;
  184.         GAD_HILIGHT = GADGHIMAGE;
  185.         
  186.         xspace = 4;
  187.         yspace = 4;
  188.         if (running_20())
  189.              {
  190.             struct DrawInfo *di;
  191.             di = GetScreenDrawInfo(window->WScreen);
  192.             if (di->dri_Version >= 1)
  193.                 {
  194.                     if (di->dri_Flags & DRIF_NEWLOOK)
  195.                         {
  196.                             TEXT = di->dri_Pens[textPen];
  197.                             HILIGHT = di->dri_Pens[hilighttextPen];
  198.                             SHADOW = di->dri_Pens[shadowPen];
  199.                             SHINE = di->dri_Pens[shinePen];
  200.                             BACKGROUND = di->dri_Pens[backgroundPen];
  201.                             if (SHADOW == SHINE)
  202.                                 GAD_HILIGHT = GADGHCOMP;
  203.                         }
  204.                     xspace = 108/di->dri_Resolution.X;
  205.                     yspace = 108/di->dri_Resolution.Y;
  206.                 }
  207.             FreeScreenDrawInfo(window->WScreen, di);
  208.          }
  209.         else
  210.                 /* non interlace screen */
  211.             if (screen->Height < 300)
  212.                 yspace = 2;
  213.     }
  214.  
  215.  
  216. #define MAX_VOLUME 16
  217. #define REAL_MAX_VOLUME 257
  218.  
  219. /***
  220.  *
  221.  *        The gadget creation routines.
  222.  *
  223.  *        The basic function are ``object declarations''.
  224.  *        Since these structures don't change very often,
  225.  *        storage is static right now
  226.  *
  227.  ***/
  228.  
  229. /* modify the following constants if you want to add some stuff.
  230.  */
  231.  
  232. #define N_GAD 6
  233. #define N_BORDER 6
  234. #define N_COORD 36
  235. #define N_INTUI 6
  236. #define M_NUMBER 11
  237. #define N_PROP 1
  238. #define N_IMAGE 0
  239.  
  240. /* the actual gadget numbers */
  241.  
  242. #define LOAD_NUMBER 0
  243. #define RESTART_NUMBER 1
  244. #define PAUSE_NUMBER 2
  245. #define SPEED_NUMBER 3
  246. #define MODE_NUMBER 4
  247. #define VOLUME_NUMBER 5
  248.  
  249. LOCAL struct Gadget g_array[N_GAD], *gad;
  250. LOCAL struct Border b_array[N_BORDER], *border;
  251. LOCAL struct IntuiText lab_array[N_INTUI], *label, *status;
  252. LOCAL SHORT XY_array[N_COORD], *XY;
  253. LOCAL struct PropInfo p_array[N_PROP], *prop;
  254. LOCAL struct Image i_array[N_IMAGE + N_PROP], *image;
  255.  
  256. /* the fixed messages */
  257. #define M_PAL 0
  258. #define M_SPEED 5
  259. #define M_RESTART 5
  260. #define M_PAUSE 6
  261. #define M_LOAD 7
  262. #define M_STD 8
  263. #define MAX_SPEED 5
  264. #define MAX_MODE 3
  265.  
  266. LOCAL char *that[M_NUMBER] = {"PAL", "NTSC", "Fast", "Scan", "Slow", "Restart", 
  267.         "Pause", "Load", "Std", "Old", "New"};
  268.  
  269. /* the changing message */
  270.  
  271. /* 30 chars for the song name, + 8 for the numbers --> 40 is plenty enough. */
  272. #define L_STATUS 0
  273. LOCAL char buffer[40];
  274.  
  275. /* to compute the extent of the display elements */
  276. LOCAL int xmax, ymax;
  277.  
  278. /* we have to offset everything by the window border */
  279. #define relx(a) (window->BorderLeft + (a))
  280. #define rely(a) (window->BorderTop + (a))
  281.  
  282.  
  283. /***
  284.  *
  285.  *         the text display functions 
  286.  *
  287.  ****/
  288.  
  289.  
  290. LOCAL void setup_status_line(void)
  291.    {
  292.         label->FrontPen = TEXT;
  293.       label->BackPen = BACKGROUND;
  294.            /* need JAM 2 for fast updates */
  295.       label->DrawMode = JAM2;
  296.       label->LeftEdge = relx(4 * xspace);
  297.       label->TopEdge = rely(yspace);
  298.       label->ITextFont = NULL;
  299.       label->IText = buffer;
  300.       label->NextText = NULL;
  301.        assert(label - lab_array < N_INTUI);
  302.        status = label++;
  303.    }     
  304.  
  305. /* erase_color()/restore_text(): for cleaning up some text.
  306.  */
  307.  
  308. LOCAL int oldcolor;
  309.  
  310. LOCAL void erase_color(struct IntuiText *t)
  311.    {
  312.       oldcolor = t->FrontPen;
  313.       t->FrontPen = 0; 
  314.    }
  315.    
  316. LOCAL void restore_color(struct IntuiText *t)
  317.    {
  318.       t->FrontPen = oldcolor;
  319.    }
  320.  
  321.  
  322. LOCAL void display_status()
  323.     {
  324.         PrintIText(rastport, status, 0, 0);
  325.     }
  326.  
  327.  
  328. /* external hook for audio_soft.c: show whether we have the audio currently,
  329.  * or not.
  330.  */
  331. void have_audio(BOOL yep)
  332.     {
  333.         if (yep)
  334.             status->FrontPen = HILIGHT;
  335.         else
  336.             status->FrontPen = TEXT;
  337.         display_status();
  338.     }
  339.            
  340. /***
  341.  *
  342.  *        The gadget creation functions
  343.  *
  344.  ***/
  345.  
  346.  
  347.  
  348. /* init_gads: setup everything for gadget creation */
  349. LOCAL void init_gads(void)
  350.    {
  351.    int i;
  352.       for (i = 0; i < N_GAD; i++)
  353.          {
  354.             g_array[i].NextGadget = g_array+i+1;
  355.             g_array[i].GadgetID = i;
  356.             g_array[i].Flags =  0;
  357.          }
  358.       g_array[N_GAD-1].NextGadget = NULL;
  359.       gad = g_array;
  360.       XY = XY_array;
  361.       border = b_array;
  362.        label = lab_array;
  363.        prop = p_array;
  364.        image = i_array;
  365.       xmax = 0;
  366.       ymax = 0;
  367.    }
  368.  
  369.  
  370.  
  371. /* border creation functions */
  372.  
  373. LOCAL void point(SHORT x, SHORT y)
  374.    {
  375.       *XY++ = x;
  376.       *XY = y;
  377.       assert(XY - XY_array < N_COORD);
  378.        XY++;
  379.    }
  380.  
  381. LOCAL struct Border *allocate_border(int npoints, int pen)
  382.     {
  383.       border->LeftEdge = 0;
  384.       border->TopEdge = 0;
  385.       border->FrontPen = pen;
  386.       border->XY = XY;
  387.       border->Count = npoints;
  388.       border->DrawMode = JAM1;
  389.       border->NextBorder = NULL;
  390.        assert(border - b_array < N_BORDER);
  391.       return border++;
  392.     }           
  393.  
  394.  
  395. /* setting gadget parameters */    
  396.  
  397.  
  398. LOCAL void set_pos(int x, int y)
  399.    {
  400.       gad->LeftEdge = x;
  401.       gad->TopEdge = y;
  402.    }
  403.    
  404. LOCAL void set_size(int width, int height)
  405.    {
  406.    int xx, yy;
  407.       gad->Width = width;
  408.       gad->Height = height;
  409.       xx = gad->Width + gad->LeftEdge;
  410.       yy = gad->Height + gad->TopEdge;
  411.       if (xx > xmax)
  412.          xmax = xx;
  413.       if (yy > ymax)
  414.          ymax = yy;
  415.    }
  416.  
  417. LOCAL void set_bool(void)
  418.    {
  419.       gad->GadgetType = BOOLGADGET;
  420.       gad->Flags = GAD_HILIGHT;
  421.       gad->Activation = GADGIMMEDIATE | RELVERIFY;
  422.    }
  423.  
  424. LOCAL void set_toggle(void)
  425.    {
  426.       gad->GadgetType = BOOLGADGET;
  427.       gad->Flags = GAD_HILIGHT;
  428.       gad->Activation = GADGIMMEDIATE | TOGGLESELECT;
  429.    }
  430.  
  431. FORWARD LOCAL struct Border *create_box(int pen1, int pen2);
  432.  
  433. LOCAL void reduce_container(void)
  434.     {
  435.         gad->LeftEdge++;
  436.         gad->TopEdge++;
  437.         gad->Width -= 2;
  438.         gad->Height -= 2;
  439.     }
  440.     
  441. LOCAL void set_prop(int maximum, int initial)
  442.     {
  443.         gad->UserData = create_box(SHADOW, SHINE);
  444.         reduce_container();
  445.         gad->GadgetType = PROPGADGET;
  446.         gad->SpecialInfo = prop;
  447.         gad->Flags = GADGHNONE;
  448.         gad->Activation = RELVERIFY|GADGIMMEDIATE;
  449.         gad->GadgetRender = image;
  450.         prop->Flags = AUTOKNOB|FREEVERT|PROPBORDERLESS;
  451.         prop->VertBody = MAXPOT / (maximum+1);
  452.         prop->VertPot = (initial * MAXPOT) / maximum;
  453.         prop->HorizBody = MAXPOT;
  454.     }
  455.  
  456. LOCAL void refresh_prop(struct Gadget *g)
  457.     {
  458.         DrawBorder(rastport, g->UserData, g->LeftEdge-1, g->TopEdge-1);
  459.     }
  460.         
  461. /* the gadget labels */
  462.  
  463. LOCAL void init_label(void)
  464.     {
  465.         label->FrontPen = TEXT;
  466.         label->BackPen = BACKGROUND;
  467.         label->DrawMode = JAM1;
  468.         label->LeftEdge = xspace;
  469.         label->TopEdge = yspace;
  470.         label->ITextFont = window->WScreen->Font;
  471.         label->NextText = NULL;
  472.     }
  473.                 
  474. LOCAL void setup_label(int n)
  475.     {
  476.         init_label();
  477.         label->IText = that[n];
  478.         gad->GadgetText = label;
  479.         assert(label - lab_array < N_INTUI);
  480.         label++;
  481.     }
  482.  
  483. /* each button can have the same size */
  484.  
  485. LOCAL int size_labels(void)
  486.     {
  487.     int l, needed, i;
  488.         needed = 0;
  489.         init_label();
  490.         for (i = 0; i < M_NUMBER; i++)
  491.             {
  492.                 label->IText = that[i];
  493.                 l = IntuiTextLength(label);
  494.                 if (l > needed)
  495.                     needed = l;
  496.             }
  497.         return needed;
  498.     }
  499.  
  500. /* more intricate gadget creation functions */
  501.  
  502. /* this is an ``highlight box'' ala 2.0 */
  503.  
  504. LOCAL struct Border *create_box(int pen1, int pen2)
  505.    {
  506.     struct Border *first, *second;
  507.         first = allocate_border(3, pen1);
  508.           point(0, gad->Height - 1);
  509.           point(gad->Width - 1, gad->Height - 1);
  510.           point(gad->Width - 1, 0);
  511.         second = allocate_border(3, pen2);
  512.           second->NextBorder = first;
  513.         point(0, gad->Height - 1);
  514.         point(0, 0);
  515.         point(gad->Width - 1, 0);
  516.         return second;
  517.    }     
  518.  
  519. LOCAL void set_box(void)
  520.    {
  521.       gad->GadgetRender = create_box(SHADOW, SHINE);
  522.       gad->SelectRender = create_box(SHINE, SHADOW);
  523.    }
  524.  
  525. /* the boxes are shared between gadgets */
  526. LOCAL void same_box(struct Gadget *other)
  527.    {
  528.       gad->GadgetRender = other->GadgetRender;
  529.       gad->SelectRender = other->SelectRender;
  530.    }     
  531.  
  532. #if 0
  533. /* this stuff might be used to add a graphic to some gadgets... later */
  534.  
  535. LOCAL void add_render(struct Border *border)
  536.     {
  537.         border->NextBorder = gad->GadgetRender;
  538.         gad->GadgetRender = border;
  539.     }
  540.     
  541. LOCAL void add_select(struct Border *border)
  542.     {
  543.         border->NextBorder = gad->SelectRender;
  544.         gad->SelectRender = border;
  545.     }
  546. #endif
  547.  
  548. LOCAL void next_gadget(void)
  549.    {
  550.         assert(gad - g_array < N_GAD);
  551.         gad++;
  552.    }
  553.  
  554.    
  555. LOCAL void setup_gadgets(BOOL req_avail)
  556.    {  
  557.    int width, height, x, y;
  558.       /* I want some room for a message 
  559.         * and for a proportional gadget
  560.         */
  561.           x = relx(4 * xspace);
  562.           y = rely(2 * yspace + sys_interwidth);
  563.        
  564.           height = scr_interwidth + 2 * yspace;
  565.            width = size_labels() + 2 * xspace;
  566.               /* these need to get first */
  567.         set_size(width, height);
  568.         set_box();
  569.                /* requester gadget */
  570.         if (req_avail)
  571.             {
  572.                   set_pos(x, y);
  573.                   set_size(width, height);
  574.                   set_bool();
  575.                 setup_label(M_LOAD);
  576.                   next_gadget();
  577.                 x += width + xspace;
  578.                 set_size(width, height);
  579.                 same_box(g_array);
  580.             }
  581.                /* restart gadget */
  582.       set_pos(x, y);
  583.       set_bool();
  584.        setup_label(M_RESTART);
  585.       next_gadget();
  586.        
  587.                /* pause gadget */
  588.       x += width + xspace;
  589.       set_pos(x, y);
  590.       set_size(width, height);
  591.           set_toggle();
  592.        same_box(g_array);
  593.         setup_label(M_PAUSE);
  594.        next_gadget();
  595.         
  596.                /* speed gadget */
  597.           x += width + xspace;
  598.           set_pos(x, y);
  599.           set_size(width, height);
  600.         set_bool();
  601.           same_box(g_array);
  602.         setup_label(M_PAL);
  603.           next_gadget();
  604.             /* ``mode'' gadget */
  605.         x += width + xspace;
  606.         set_pos(x, y);
  607.         set_size(width, height);
  608.         set_bool();
  609.         same_box(g_array);
  610.         setup_label(M_STD);
  611.         next_gadget();
  612.             /* volume gadget */
  613.         x = relx(xspace);
  614.         y = rely(yspace);
  615.         set_pos(x, y);
  616.         set_size(2 * xspace, ymax - y);
  617.         set_prop(MAX_VOLUME, MAX_VOLUME);
  618.         next_gadget();
  619.         xmax+= xspace;
  620.         ymax+= yspace;
  621.    }
  622.  
  623.  
  624.  
  625. /* changing the window size and title...
  626.  * this stuff can also deal with resize gadgets.
  627.  */
  628.  
  629.  
  630. LOCAL int xstart = 80, ystart = 40;
  631. LOCAL int xcurrent, ycurrent;
  632.  
  633. LOCAL char *window_title = "Experiment IV";
  634.  
  635.  
  636. #ifdef SIZE_GADGET
  637. LOCAL void delimit(void)
  638.     {
  639.         WindowLimits(window, 0, 0, xcurrent + window->BorderRight, 
  640.             ycurrent + window->BorderBottom);
  641.     }
  642. #endif
  643.  
  644. /* safeSizeWindow deals of lots of special cases.
  645.  * It tries to enlarge (shrink ?) window by dx, dy,
  646.  * moving it around if it can't do it any other way,
  647.  * respecting the screen size as it goes.
  648.  * You usually pass w->Width and w->Height as current width,
  649.  * current height.
  650.  * However, for frequent resizes, it is better to keep track
  651.  * of the size the window should be, because SizeWindow is actually
  652.  * asynchronous.
  653.  */
  654.  
  655. LOCAL void safeSizeWindow(struct Window *w, int dx, int dy, int cw, int ch)
  656.     {
  657.     int nw, nh, ddx, ddy;
  658.         if (dx > 0)
  659.             {
  660.                 nw = cw + dx;
  661.                 if (nw > w->WScreen->Width)
  662.                     {
  663.                         nw = w->WScreen->Width;
  664.                         dx = nw - w->Width;
  665.                     }
  666.                 ddx = w->WScreen->Width - w->LeftEdge - nw;
  667.                 if (ddx > 0)
  668.                     ddx = 0;
  669.             }
  670.         else
  671.             ddx = 0;
  672.         if (dy > 0)
  673.             {
  674.                 nh = ch + dy;
  675.                 if (nh > w->WScreen->Height)
  676.                     {
  677.                         nh = w->WScreen->Height;
  678.                         dy = nh - w->Height;
  679.                     }
  680.                 ddy = w->WScreen->Height - w->TopEdge - nh;
  681.                 if (ddy > 0)
  682.                     ddy = 0;
  683.             }
  684.         else
  685.             ddy = 0;
  686.         if (ddx || ddy)
  687.             MoveWindow(w, ddx, ddy);
  688.         if (dx || dy)
  689.             SizeWindow(w, dx, dy);
  690.     }
  691.     
  692. LOCAL void add_borders(void)
  693.    {
  694.       safeSizeWindow(window, 
  695.          window->BorderRight + xmax - xstart, 
  696.          window->BorderBottom + ymax - ystart, xstart, ystart);
  697.       xcurrent = xmax;
  698.       ycurrent = ymax;
  699. #ifdef SIZE_GADGET
  700.        delimit();
  701. #endif
  702.    }
  703.  
  704. LOCAL void resize(int xnew, int ynew)
  705.    {
  706.       safeSizeWindow(window, xnew - xcurrent, ynew - ycurrent, 
  707.                    xcurrent + window->BorderRight, 
  708.                 ycurrent + window->BorderBottom);
  709.       xcurrent = xnew;
  710.       ycurrent = ynew;
  711. #ifdef SIZE_GADGET
  712.        delimit();
  713. #endif
  714.    }
  715.           
  716. LOCAL void setup_title(void)
  717.     {
  718.        SetWindowTitles(window, -1, banner);
  719.        ToClean3(SetWindowTitles, window ,0, 0);
  720.     }
  721.     
  722. void temporary_title(char *change)
  723.     {
  724.         SetWindowTitles(window, change, -1);
  725.     }
  726.     
  727. void restore_title(void)
  728.     {
  729.         SetWindowTitles(window, window_title, -1);
  730.     }
  731.     
  732. LOCAL void setup_all()
  733.     {
  734.         init_gads();
  735.         setup_status_line();
  736.         setup_gadgets(init_requester(window));
  737.         add_borders();
  738. #ifdef SIZE_GADGET
  739.         saveclip = cliptoborder(window, NULL);
  740. #endif
  741.         setup_title();
  742.         AddGList(window, g_array, ~0, gad - g_array, NULL);
  743.         ToClean3(RemoveGList, window, g_array, gad - g_array);
  744.         refresh_prop(g_array+VOLUME_NUMBER);
  745.         start_player();
  746.         RefreshGList(g_array, window, NULL, gad - g_array);
  747.     }
  748.  
  749.  
  750. /* externally accessible function */
  751.         
  752. struct Window *init_interface(int xoffset, int yoffset)
  753.    {
  754.    struct NewWindow template;
  755.       template.Type = WBENCHSCREEN;
  756.       template.TopEdge = yoffset; 
  757.       template.LeftEdge = xoffset;
  758.       template.DetailPen = -1;
  759.       template.BlockPen = -1;
  760.       template.IDCMPFlags = CLOSEWINDOW 
  761.                      | REFRESHWINDOW
  762. #ifdef SIZE_GADGET
  763.                       | NEWSIZE
  764. #endif
  765.                      | GADGETDOWN
  766.                       | GADGETUP;
  767.       template.Flags  = WINDOWDEPTH 
  768.                   | WINDOWCLOSE
  769.                   | WINDOWDRAG
  770. #ifdef SIZE_GADGET
  771.                    | WINDOWSIZING
  772. #endif
  773.                    | SIZEBBOTTOM
  774.                   | SIMPLE_REFRESH;
  775.       template.FirstGadget = NULL;
  776.       template.CheckMark = NULL;
  777.       template.Title = window_title;
  778.       template.MinWidth = 0;
  779.       template.MinHeight = 0;
  780.       template.MaxWidth = ~0;
  781.       template.MaxHeight = ~0;
  782.       template.Width = xstart;
  783.       template.Height = ystart;
  784.       window = OpenWindow(&template);
  785.       if (window)
  786.             ToClean(CloseWindow, window);
  787.         else
  788.            mayPanic("Could not open window");
  789.         setup_environment();
  790.            /* setup the window like it should be */
  791.         setup_all();
  792.         
  793.         no_title();
  794.         return window; 
  795.     }
  796.     
  797. /***
  798.  *
  799.  *        Status line management 
  800.  *
  801.  ***/
  802.  
  803. LOCAL void change_title(void)
  804.     { 
  805.      int needed;
  806.         needed = TextLength(rastport, buffer, strlen(buffer)) + 5 * xspace;
  807.         resize(needed > xmax ? needed : xmax, ymax);
  808.         display_status();
  809.     }
  810.             
  811. void new_title(int pos, int len, char *title)
  812.    {
  813.         erase_color(status);
  814.         display_status();
  815.         restore_color(status);
  816.         sprintf(buffer, "%3d:%-3d %s \0", pos, len, title);
  817.         change_title();
  818.    }
  819.          
  820. void update_title(int pos, int len, char *title)
  821.    {
  822.         sprintf(buffer, "%3d:%-3d %s \0", pos, len, title);
  823.         display_status();
  824.    }
  825.  
  826. void no_title(void)
  827.     {
  828.         erase_color(status);
  829.         display_status();
  830.         restore_color(status);
  831.            sprintf(buffer, "No song loaded\0");
  832.         change_title();
  833.     }
  834.  
  835. LOCAL int current_mode = 0;
  836.  
  837.     
  838. LOCAL void reset_mode()
  839.     {
  840.         if (current_mode >= MAX_MODE)
  841.             current_mode = 0;
  842.       erase_color(g_array[MODE_NUMBER].GadgetText);
  843.       RefreshGList(g_array+MODE_NUMBER, window, NULL, 1);
  844.        g_array[MODE_NUMBER].GadgetText->IText = that[M_STD + current_mode];
  845.       restore_color(g_array[MODE_NUMBER].GadgetText);
  846.       RefreshGList(g_array+MODE_NUMBER, window, NULL, 1);
  847.       set_mode(current_mode);
  848.     }
  849.     
  850. LOCAL void toggle_mode()
  851.     {
  852.         current_mode++;
  853.         reset_mode();
  854.     }
  855.                 
  856. void pref_mode(int mode)
  857.     {
  858.         current_mode = mode;
  859.         reset_mode();
  860.     }
  861.     
  862. /* internal (and external) tempo management */
  863.  
  864. LOCAL int current_speed = 0;
  865.  
  866. LOCAL int tempo[] =  {256, 213, 170, 110, 550};
  867. LOCAL int effect[] = {256, 213, 170, 20, 550};
  868.     
  869. /* in some conditions, we need to put back the tempo to its
  870.  * natural value (i.e., after a pause)
  871.  */
  872.  
  873. void reset_tempo(void)
  874.    {
  875.       if (current_speed >= MAX_SPEED)
  876.               current_speed = 0;
  877.         erase_color(g_array[SPEED_NUMBER].GadgetText);
  878.         RefreshGList(g_array+SPEED_NUMBER, window, NULL, 1);
  879.         g_array[SPEED_NUMBER].GadgetText->IText = that[M_PAL + current_speed];
  880.         restore_color(g_array[SPEED_NUMBER].GadgetText);
  881.         RefreshGList(g_array+SPEED_NUMBER, window, NULL, 1);
  882.       set_tempo(tempo[current_speed], effect[current_speed]);
  883.    }
  884.    
  885. void pref_speed(int speed)
  886.     {
  887.         current_speed = speed;
  888.         reset_tempo();
  889.     }
  890.     
  891. LOCAL void toggle_tempo(void)
  892.    {
  893.          current_speed++;
  894.       reset_tempo();
  895.    }
  896.  
  897.  
  898. LOCAL void reset_volume(void)
  899.     {
  900.         set_volume(REAL_MAX_VOLUME * (MAXPOT - prop->VertPot)
  901.             /MAXPOT);
  902.     }
  903.  
  904. void pref_volume(int volume)
  905.     {
  906.         NewModifyProp(g_array+VOLUME_NUMBER, window, NULL, prop->Flags,
  907.             prop->HorizPot, MAXPOT - volume*MAXPOT/100, prop->HorizBody,
  908.             prop->VertBody, VOLUME_NUMBER);
  909.         reset_volume();
  910.     }
  911.  
  912. /* the proper event handling */
  913.  
  914. LOCAL BOOL aborted;
  915.  
  916. LOCAL void add_to_idcmp(ULONG val)
  917.     {
  918.         ModifyIDCMP(window, window->IDCMPFlags | val);
  919.     }
  920.     
  921. LOCAL void remove_from_idcmp(ULONG val)
  922.     {
  923.         ModifyIDCMP(window, window->IDCMPFlags & ~val);
  924.     }
  925.     
  926. /* some gadgets only react to gadget up, other to gadget down,
  927.  * some to both !
  928.  */
  929.  
  930. LOCAL void gadget_up(ULONG id)
  931.     {
  932.         switch(id)
  933.             {
  934.             case RESTART_NUMBER:
  935.                 launch_play(0);
  936.                 break;
  937.             case LOAD_NUMBER:
  938.                 try_change_song();
  939.                 break;
  940.             case VOLUME_NUMBER:
  941.                 remove_from_idcmp(INTUITICKS);
  942.                 break;
  943.             default:
  944.                 break;
  945.             }
  946.     }
  947.  
  948. LOCAL void gadget_down(ULONG id)
  949.     {
  950.         switch(id)
  951.             {
  952.             case SPEED_NUMBER:
  953.                 toggle_tempo();
  954.                 break;
  955.             case PAUSE_NUMBER:
  956.                 if (g_array[PAUSE_NUMBER].Flags & SELECTED)
  957.                     stop_player();
  958.                 else
  959.                     start_player();
  960.                 break;
  961.             case MODE_NUMBER:
  962.                 toggle_mode();
  963.                 break;
  964.                     /* the volume gadget turns on ``busy update'' 
  965.                      * while selected. If I add more prop gadgets,
  966.                      * I will have to keep track of which ones to
  967.                      * update.
  968.                      */
  969.             case VOLUME_NUMBER:
  970.                 add_to_idcmp(INTUITICKS);
  971.                 break;
  972.                     /* right now, the state of the pause gadget is
  973.                      * constantly tested... because ``external events''
  974.                      * (like the availability of a song) might
  975.                      * change the behaviour to follow.
  976.                      */
  977.             default:
  978.                  break;
  979.             }
  980.     }
  981.     
  982.  
  983. LOCAL void process_message(struct IntuiMessage *msg)
  984.    {
  985.    static ULONG class;
  986.    static void *object;
  987.    static struct Gadget *gadget;
  988.         class = msg->Class;
  989.         object = msg->IAddress;
  990.         ReplyMsg((struct Message *)msg);
  991.         switch(class)
  992.            {
  993.              case CLOSEWINDOW:
  994.                 aborted = TRUE;
  995.                 break;
  996.              case GADGETDOWN:
  997.                 gadget = (struct Gadget *)object;
  998.                 gadget_down(gadget->GadgetID);
  999.                 break;
  1000.             case GADGETUP:
  1001.                 gadget = (struct Gadget *)object;
  1002.                 gadget_up(gadget->GadgetID);
  1003.                 break;
  1004.             case INTUITICKS:
  1005.                 reset_volume();
  1006.                 break;
  1007. #ifdef SIZE_GADGET
  1008.             case NEWSIZE:
  1009.                 xcurrent = window->Width - window->BorderRight;
  1010.                 ycurrent = window->Height - window->BorderBottom;
  1011.                 recliptoborder(saveclip);
  1012.                 break;
  1013. #endif
  1014.          case REFRESHWINDOW:
  1015.             BeginRefresh(window);
  1016.              display_status();
  1017.             refresh_prop(g_array+VOLUME_NUMBER);
  1018.             EndRefresh(window, TRUE);
  1019.             break;
  1020.          default:
  1021.             break;
  1022.          }
  1023.    }
  1024.  
  1025. /* access through this one is needed by the filerequester */
  1026.  
  1027. void message_interface(struct IntuiMessage *msg)
  1028.     {
  1029.         process_message(msg);
  1030.     }
  1031.     
  1032. void handle_interface(void)
  1033.    {
  1034.    struct IntuiMessage *msg;
  1035.         while(msg = (struct IntuiMessage *)GetMsg(window->UserPort))
  1036.             process_message(msg);
  1037.    }
  1038.  
  1039. /* concerns events.c exclusively */
  1040.  
  1041. BOOL did_abort(void)
  1042.     {
  1043.         return aborted;
  1044.     }
  1045.     
  1046. void clear_abort(void)
  1047.     {
  1048.         aborted = FALSE;
  1049.     }
  1050.  
  1051.     
  1052.