/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Slider.h
    Author:  Copyright  1994 Peter Gaunt
    Version: 1.00 (12 Mar 1994)
    Purpose: Provide a clean way of using 'slider' icons.  These routines 
      	     are more general-purpose, friendly and efficient that those
      	     found in the Icon library.  (The Icon slider functions are left
      	     in for backwards compatibility at the moment - you should
      	     use these functions in preference).
*/

#ifndef __dl_slider_h
#define __dl_slider_h

#ifdef __cplusplus
extern "C" {
#endif


#ifndef __dl_core_h
#include "Core.h"
#endif

#ifndef __dl_WimpSWIs_h
#include "WimpSWIs.h"
#endif

#ifndef __dl_Sprite_h
#include "Sprite.h"
#endif

#define SLIDER_MAX 100000

/*
To work, sliders need a base icon. This should be a non-text, non-sprite icon
with an unfilled background. The window should have its auto-redraw flag clear.
They need a minimal amount of co-operation from the rest of the program in
order to be redrawn after redraw events (this basically just involves calling
Slider_Redraw inside a redraw loop). The boundary for the slider icon should
not overlap any part of the window which also needs help to be redrawn.

Although sliders maintain their current value internally on a scale of
0 - SLIDER_MAX, the values returned when Slider functions are called are always
in "user units" which are set within whatever limits suit your program best
(within reason of course).

Slider functions need screen_delta info to be kept up to date
Make sure the mode change event is enabled and Handler_ModeChange is called

*/




typedef struct
{
  window_handle window;
  icon_handle   icon;

  int value;

  struct
  { int         min;
    int         max;
  } limits;

  struct
  { int foreground;
    int background;
  } colour;

  struct
  { int x;
    int y;
  } border;

  struct
  { sprite_areainfo *spritearea;
    sprite_header   *sprite;
  } knob;

  struct
  { int  vertical  :1;
    int  rgb       :1;
    int  dragging  :1;
    int  clickstop :1;
    int  reserved  :28;
  } flags;

  int ( *update )( void *, void * );
  int reference;
} slider_info;
/*
    The slider functions use this structure extensively.
    
    The elements are as follows :

    window: handle of window containing the slider
    icon  : handle of base icon within the window. Should have unfilled 
            background.
            If you want to be able to drag the slider you should normally 
            set the icon's button type to click (type 3). You then call 
            Slider_Drag when the icon is clicked.

    value: slider functions use values between 0 & SLIDER_MAX which are
           converted to user units between limits.min and limits.max when
           returned to calling functions. Set this status.value to
           SLIDER_MAX +1 when initialising the slider.

    limits.min
    limits.max: Values returned when the slider is at its minimum or maximum
                extent. Other slider positions return intermediate values.
                The slider is clamped to these values.

    colour.foreground
    colour.background: Foreground and background colours of the slider.
                       Set colours to -1 if not wanting a visible slider.
                       See also flags.rgb below
    border.x
    border.y: size of blank border which will be left between the slider and
              the base icon boundary. OS units.
              Note that if the base icon has a border then setting the slider
              borders to 0 causes the icon's border to flicker when the 
              slider is updated. Setting a slider border avoids this. The 
              slider border needed to prevent flicker depends on the type of
              border which the icon has. A value of 4 suffices for most of 
              the standard icon borders. A value of 12 produces sliders 
              similar to those in the RISC OS 3 Style Guide if the icon has 
              an r2 type border. Setting borders greater than half the size 
              of the icon produces odd effects...

    knob: Not used at present but may be used in future versions to specify
          a sprite to be used as a knob. For now set knob.spritearea to NULL
          to indicate no knob.

    flags.vertical: If set then slider is vertical. If clear then it is
                    horizontal.
    flags.rgb:      If clear then colour.foreground & colour.background refer
                    to Wimp colours 0-15. If set then they refer to an RGB
                    palette suitable for passing to ColourTrans (0xBBGGRR00).
    flags.dragging: This is set by Slider_Drag while it is dragging a slider.
                    Set this to zero when initialising slider.
    flags.clickstop:If clear then slider is dragged as smoothly as possible.
                    If set then slider jumps between exact user values as it
                    is dragged, i.e. slider will only be redrawn when user 
                    value changes.
    flags.reserved: For future expansion. Set this to zero.

    update: If this is not set to NULL then it is a pointer to a function
            which will be called if the slider value (in user units not
            internal units) changes during a call to Slider_SetValue
            or Slider_Drag.

            Providing an update function is useful since it allows you
            to centralise other operations, such as updating a text icon
            showing the slider's value, regardless of whether the slider
            moves because of a drag or a call to Slider_SetValue. It is
            also useful for continually monitoring the current value during
            a drag operation which otherwise you wouldn't know until the
            drag finished.

            The function should take two arguments. The first is a
            pointer to a slider_info structure. When the function is
            called this argument is a pointer to the slider currently
            being dealt with.

            The second argument is a pointer to any data you wish.
            You pass a pointer (which can be NULL) to the data to
            Slider_SetValue or Slider_Drag when you call them and it
            gets passed on to the update function when/if it is called.
            This argument can be useful, for example, for passing
            information to your update function to indicate just what
            operation is currently being performed (e.g. to let it
            distinguish between a call to Slider_SetValue and a call to
            Slider_Drag).

            The function should return non-NULL if it wants the drag
            function to stop dragging. This allows you to, for example,
            stop the slider going above or below a maximum or minimum
            value, independently of limits.min and limits.max.

    reference: You may use this for any purpose you like. If you set up more
               than one slider, it is useful to give each a separate 
               reference so that your update function (if any) can 
               distinguish between them without having to check the window &
               icon handles.
*/





extern os_error *Slider_Redraw(slider_info *slider, wimp_rect *clipwindow);
/*    
  Inputs:   slider - the slider info for this slider.
      	    clipwindow - the area of the window being redrawn (in screen
      	    coordinates).
  Returns:  An error pointer, or NULL if no errors occured.
  Purpose:  Redraws a slider icon - call this function from within your 
      	    redraw loops.
            If clipwindow != NULL then does nothing if slider is outside 
            clip window.
  Errors:   Unable to use the colour indicated in 'slider'.
  SeeAlso:  Slider_ReadValue; Slider_SetValue; Slider_Drag
*/





extern int Slider_ReadValue( slider_info *slider );
/*
  int Slider_ReadValue(slider_info *slider);
    
  Inputs:   slider - the slider info for this slider.
  Returns:  The current slider value, in user units.
  Purpose:  Returns current slider setting in user units.
            (i.e. between slider->limits.min and slider->limits.max)
  SeeAlso:  Slider_SetValue; Slider_Drag; Slider_Redraw
*/





extern os_error *Slider_SetValue(slider_info *slider,
                                 int value,
                                 int *valueset,
                                 void *ref );
/*
  os_error *Slider_SetValue(slider_info *slider,
                            int value,
                            int *valueset,
                            void *ref );
    
  Inputs:   slider - the slider info for this slider.
      	    value  - the value (in user units) that the slider should be
      	      	     set to.
      	    ref    - a reference to pass to the update callback funtion.
  Outputs:  valueset - if not NULL, this is updated to hold the value
                       actually the slider is actually set to (this can be
                       different to 'value', e.g. if value is outside the
                       slider limits).
  Returns:  Standard error block or NULL if no error occurs.
  Purpose:  Sets slider to value in value (user units).
      	    If the slider is being dragged (i.e. if slider->status.dragging 
      	    is set) then the function does nothing.

            The value is clamped to numbers between slider->limits.min and
            slider->limits.max.

            The slider->update function (if any) will be called if the value
            has changed.

            Can also be used to alter other settings (e.g. colour) by 
            directly changing the slider structure before calling.
  Errors:   An error is returned if there is a problem accessing or
      	    redrawing the icon.
  SeeAlso:  Slider_ReadValue; Slider_Drag; Slider_Redraw
*/





extern os_error *Slider_Drag(slider_info *slider,
                             int *closed,
                             int *value,
                             void *ref);
/*
  os_error *Slider_Drag(slider_info *slider,
                        BOOL *closed,
                        int *value,
                        void *ref )
    
  Inputs:   slider - the slider info for this slider.
      	    ref    - a reference to pass to the update callback funtion.
  Outputs:  closed - if not NULL, and the window is closed during the drag,
      	      	     then closed is set to TRUE.
      	    value  - if not NULL, then it is set to the slider value (in
      	      	     user units) on exit.
  Returns:  Standard error block, or none if no errors encountered.
  Purpose:  Drag a slider. Call when slider's base icon is clicked on.
      	    Polls the Wimp, grabbing NULL events but passing the rest on to 
      	    Event_Process.
      	    Exits when dragging stops or the slider->update function (if any)
      	    returns a non-NULL value.
      	    Also exits if window is closed while dragging (see Outputs).
  Errors:   An error is returned if there is a problem accessing or
      	    redrawing the icon.
  SeeAlso:  Slider_SetValue; Slider_ReadValue; Slider_Redraw
*/


#ifdef __cplusplus
}
#endif


#endif
