/************************************************************
**
** Application: UnitConv
**
** Title:       c.binhex
**
*************************************************************/

/*
*
* Copyright (c) 2015, Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */
/* from standard clib */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* from oslib */
#include "OSLib:colourtrans.h"
#include "OSLib:font.h"
#include "OSLib:os.h"
#include "OSLib:adjuster.h"
#include "OSLib:writablefield.h"
#include "OSLib:wimp.h"
#include "OSLib:window.h"
#include "OSLib:messagetrans.h"
#include "OSLib:radiobutton.h"
#include "OSLib:optionbutton.h"


/* from oslib support */
#include "OSLibSupport:event.h"

/* from CJLib */
#include "CJLib:choices.h"
#include "CJLib:etc.h"
#include "CJLib:kbd.h"
#include "CJLib:tbox.h"
#include "CJLib:message.h"


/* from application */
#include "app.h"
#include "res.h"
#include "msglink.h"
#include "cjoslib.h"
#include "iconbar.h"
#include "main.h"
#include "binhex.h"


/*************************************************************************/
/* Res templates definitions */

        // binhex window
#define BINHEX_TEMPLATE       ((toolbox_id)"BinHex")
#define BINHEX_DUMMY            0x00
#define BINHEX_BIN              0x04
#define BINHEX_OCT              0x05
#define BINHEX_HEX              0x06
#define BINHEX_DEC              0x07
#define BINBEXH_SHIFT_LEFT      0x0e
#define BINHEX_SHIFT_RIGHT      0x0d
#define action_BH_SETTINGS      0x70
#define action_BH_CLEAR         0x71
#define action_BH_INVERT        0x72


#define BINHEX_SETTINGS_TEMPLATE     ((toolbox_id)"Settings")
#define BINHEX_SETTINGS_RADIO_BASE   0x02
#define BINHEX_SETTINGS_SIGNED       0x01
#define BINHEX_SETTINGS_WRAP_BITS    0x08
#define action_BH_SETTINGS_SET       0x78
#define action_BH_SETTINGS_SAVE      0x79
#define action_BH_SETTINGS_CANCEL    0x7A


#define BASE_BINARY       2
#define BASE_OCTAL        8
#define BASE_DECIMAL      10
#define BASE_HEXADECIMAL  16


#define STATE_ON  TRUE

#define BH_SIZE 35
#define TEXT_BUFFER_SIZE 36

/* font for auxiliary text */
#define BOLD_FONT "Corpus.Bold"
#define NORMAL_FONT "Corpus.Medium"
#define FONT_SIZE 16<<4

/* Constants for displaying and redrawing the auxiliary display of the binary digits */
#define TEXT_Y_OFFSET 332
#define TEXT_X_OFFSET 60

/* The shift steps allowed are 1, 4, 8, 16 */
/* Shift masks for wrap around */
#define SHIFT_RIGHT_MASK_1    0x1
#define SHIFT_RIGHT_MASK_4    0xF
#define SHIFT_RIGHT_MASK_8    0xff
#define SHIFT_RIGHT_MASK_16   0xffff

#define SHIFT_LEFT_MASK_1    0x80000000
#define SHIFT_LEFT_MASK_4    0xF0000000
#define SHIFT_LEFT_MASK_8    0xff000000
#define SHIFT_LEFT_MASK_16   0xffff0000


/* globals for manipulating auxaliary text */
static int lineheight;
static int redraw_y_top;
static int redraw_y_bottom;
static double charwidth;

/* display options */
#define FULL_SIZE 0
#define STRIP_LEADING_ZEROS 1
#define SMALLEST_BYTE 2
static int display_option = 1;
static osbool signed_int;

static toolbox_o Binhex_winid;
static wimp_w    Binhex_winhandle;
static toolbox_position Binhex_win_pos;

static toolbox_o Binhex_settings_winid;

static osbool wrap_around = FALSE;



/* Routines to load and save choices files */

#define LEAF "Binhex"
#define FILE_ID "Bin-oct-hex-dec choices"




static CJL_choices_tag  tag_table[] =
{
  "DisplayOpt", TAGINT, &display_option, 0,
  "DecimalSigned", TAGBOOL, &signed_int, 0,
  "WrapBits", TAGBOOL, &wrap_around, 0,

  NULL,0,NULL,0
};




/************************************************************/

void Binhex_LoadChoices (void)
{
  CJL_choices_loadsavedata d;

  d.leafname = LEAF;
  d.file_id = FILE_ID;
  d.app_name = APPNAM;
  d.author_dir = AUTHOR_DIR;
  d.save = FALSE;
  d.use_flex = FALSE;
////  d.data.load.not_found = "PREFnotfound";
  d.data.load.no_read = "PREFnomalloc";
  d.data.load.malloc_fail = "PREFnoread";

  CJL_ChoicesLoad (&d, tag_table);

  return;
}



/************************************************************/

static void SaveChoices (void)
{
  CJL_choices_loadsavedata d;

  /* first get the current values in the choices dialogues */

  /* now do the save */

  d.leafname = LEAF;
  d.file_id = FILE_ID;
  d.app_name = APPNAM;
  d.author_dir = AUTHOR_DIR;
  d.save = TRUE;
  d.use_flex = FALSE;
  d.data.save.write_err = "PREFnosave";

  CJL_ChoicesSave (&d, tag_table);

  return;
}







/************************************************************/

/* Function to set up some of the font related values used
 * in the painting of the binary string in the bottom of the
 * dialogue box for toggling the bit values
 */
static void Binhex_SetupFont (void)
{
  font_f fh;
  int x0, x1, y0, y1;
  int x_res_out, y_res_out;

  font_string_flags flags;
  font_scan_block block;
  int x_out, y_out, length_out;
  char *split_point;


  fh = font_find_font ( BOLD_FONT, FONT_SIZE, FONT_SIZE, 0, 0, &x_res_out, &y_res_out ) ;

  /* now calculate area occupied by the string */
  flags = font_GIVEN_BLOCK | font_GIVEN_FONT | font_RETURN_BBOX ;
  block.split_char = -1;
  block.space.x=0;
  block.space.y=0;
  block.letter.x=0;
  block.letter.y=0;
  block.bbox.x0=0;
  block.bbox.y0=0;
  block.bbox.x1=0;
  block.bbox.y1=0;
  font_scan_string ( fh,
                     "0101010101010101010101010101010101010101",
                     flags,
                     0x7FFFFFFF,
                     0x7FFFFFFF,
                     &block,
                     0,
                     0,
                     &split_point,
                     &x_out,
                     &y_out,
                     &length_out );
  x0 = block.bbox.x1 - block.bbox.x0;
  y0 = block.bbox.y1 - block.bbox.y0;

  font_convertto_os ( x0, y0, &x1, &y1);

  lineheight = y1 + (y1 >> 2);
  charwidth = (double)x1 / 40.0 ;
  charwidth = ceil( charwidth );
  font_lose_font ( fh );

  /* calc limits for redraw area */
  redraw_y_top = TEXT_Y_OFFSET - lineheight;
  redraw_y_bottom = TEXT_Y_OFFSET + lineheight;
  return;
}





/************************************************************/

static char * pad_binary_to_32bit ( char *s1, char *s2, int size)
{
  int i;
  int l;


  if ( size < 33)
  {
    l = 33 - size;
    for ( i = 0; i < l; i++)
    {
      s2[i] = '0';
    }
    s2[l] = '\0';
    strcat ( s2, s1);

    return (s2);
  }
  else
  {
    return (s1);
  }
}




/************************************************************/

static char * strip_leading_zeros ( char * str )
{
  char * ptr;

  ptr = str;
  while ( ptr[0] == '0' )
    ptr++;
  return (ptr);
}




/************************************************************/

/* function to express a str of a four byte integer in the smallest
 * number of bytes by removing leading zeros
 */
static char * smallest_byte ( bits val, char * str, int bytesize )
{
  char * ptr;

  if (val < 0x100)
  {
    ptr = str + bytesize + (bytesize << 1);
  }
  else
  {
    if (val < 0x10000)
    {
      ptr = str + (bytesize << 1);
    }
    else
    {
      if (val < 0x1000000)
      {
        ptr = str + bytesize;
      }
      else
      {
        ptr = str;
      }
    }
  }
  return (ptr);
}




/************************************************************/

static void Binhex_UpdateFieldValues ( bits val, toolbox_c cmp_id )
{
  char *ptr ;
  char result [ BH_SIZE ] ;
  int nibble ;
  char oct_fig [2] ;
  int i;
  bits val2;


  ptr = result;
  if ( cmp_id != BINHEX_BIN )
  {
    os_convert_binary4 ( ( int ) val, result, BH_SIZE ) ;
    if ( display_option == SMALLEST_BYTE )
    {
      ptr = smallest_byte ( val, result, 8 );
    }
    else
    {
      if ( display_option == STRIP_LEADING_ZEROS )
      {
        if ( val == 0 )
        {
          ptr[0] = '0';
          ptr[1] = '\0';
        }
        else
        {
          ptr = strip_leading_zeros (result);
        }
      }

    }
    writablefield_set_value (0, Binhex_winid, BINHEX_BIN , ptr );
  }

  if ( cmp_id != BINHEX_HEX )
  {
    os_convert_hex8 ( ( int ) val, result, BH_SIZE ) ;
    if ( display_option == SMALLEST_BYTE )
    {
      ptr = smallest_byte ( val, result, 2 );
    }
    else
    {
      if ( display_option == STRIP_LEADING_ZEROS )
      {
        if ( val == 0 )
        {
          ptr[0] = '0';
          ptr[1] = '\0';
        }
        else
        {
          ptr = strip_leading_zeros (result);
        }
      }

    }
    writablefield_set_value ( 0, Binhex_winid, BINHEX_HEX , ptr );
  }

  if ( cmp_id != BINHEX_DEC )
  {
    if (signed_int)
    {
      os_convert_integer4 ( ( int ) val, result, BH_SIZE ) ;
    }
    else
    {
      os_convert_cardinal4 ( ( int ) val, result, BH_SIZE ) ;
    }
    writablefield_set_value ( 0, Binhex_winid, BINHEX_DEC , result );
  }

  if ( cmp_id != BINHEX_OCT )
  {
    /* we need to do this the hard way */
    /* construct the octal string */
    if ( val == 0 )
    {
      if ( display_option == STRIP_LEADING_ZEROS )
      {
        strcpy ( result, "0" ) ;
      }
      else
      {
        if ( display_option == SMALLEST_BYTE )
        {
          strcpy ( result, "000" ) ;
        }
        else
        {
          strcpy ( result, "00000000000" ) ;
        }
      }
      ptr = result ;
    }
    else
    {
      /* put the chars into the result string
         one at a time, last (lowest fig) first */
      /* put the terminating 0x00 at end first */
      /* longest octal string has 11 chars */
      for ( i=0; i<11; i++)
        result[i] = '0';
      ptr = result + 11 ;
      ptr [0] = '\0' ;
      val2 = val;
      while ( val2 != 0 )
      {
        nibble = ( val2 & 7 ) ;
        sprintf ( oct_fig, "%d", nibble ) ;
        ptr--;
        ptr [0] = oct_fig [0] ;
        val2 >>= 3 ;
      }
      /* ptr now points to the first non-zero digit - as required when
       * leading zeros are being stripped */
      if ( display_option != STRIP_LEADING_ZEROS )
      {
        ptr = result;
        if ( display_option == SMALLEST_BYTE )
        {
          if (val < 0x100)
          {
            ptr += 8;
          }
          else
          {
            if (val < 0x10000)
            {
              ptr += 5;
            }
            else
            {
              if (val < 0x1000000)
              {
                ptr += 3;
              }
            }
          }
        }
      }

    }
    writablefield_set_value ( 0, Binhex_winid, BINHEX_OCT , ptr );

  }

  return;
}





/************************************************************/

static void Binhex_ClearAllFields (void)

{
  /* zero bytes written - null all the strings */
  cjlib_clear_writable ( Binhex_winid, BINHEX_BIN ) ;
  cjlib_clear_writable ( Binhex_winid, BINHEX_OCT ) ;
  cjlib_clear_writable ( Binhex_winid, BINHEX_HEX ) ;
  cjlib_clear_writable ( Binhex_winid, BINHEX_DEC ) ;

  return;
}



/************************************************************/

static void Binhex_WritableFieldValueChanged ( char *text, toolbox_c cmp_id)
{
  osbool convert ;
  os_read_unsigned_flags base ;
  int length ;
  int value ;
  bits val ;
  char *end ;
  char result [ BH_SIZE ] ;
  osbool negative_decimal ;
  osbool expr_is_str ;


  /* check if there is any text */
  if ( strlen (text) == 0 )
  {
    Binhex_ClearAllFields ();
    wimp_force_redraw ( Binhex_winhandle,
                        TEXT_X_OFFSET,
                        -redraw_y_bottom, 860, -redraw_y_top );
  }
  else
  {
    /* Do calculations and write new values */
    negative_decimal = FALSE ;
    convert = TRUE ;
    switch ( cmp_id )
    {
      case BINHEX_BIN :
        base = 2 ;
        break ;

      case BINHEX_OCT :
        base = 8 ;
        length = strlen ( text ) ;
        /* max length should be limited to 11 chars by wimp */
        if (length >= 11 )
        {
          value = strcmp ( text, "37777777777" ) ;
          if ( value > 0 )
          {
            /* decimal value overflows 32 bit signed number */
            /* clear the other number fields */
            cjlib_clear_writable ( Binhex_winid, BINHEX_BIN ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_DEC ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_HEX ) ;
            Msg_Warn ( OCTTOOBIG );
            /* do not do any more conversion on this string */
            convert = FALSE ;
            return ;
          }
        }
        break ;

      case BINHEX_DEC :
        base = 10 ;
        length = strlen ( text ) ;
        if (text[0] == '-')
        {
          /* negative value */
          if ( length > 1 )
          {
            negative_decimal = TRUE ;
          }
          else
          {
            cjlib_clear_writable ( Binhex_winid, BINHEX_BIN ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_OCT ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_HEX ) ;
            convert = FALSE ;
            return ;
          }
        }
        else
        {
          if (length >= 10 )
          {
            value = strcmp ( text, "4294967295" ) ;
            if ( ( value > 0 ) || ( length > 10 ) )
            {
              /* decimal value overflows 32 bit signed number */
              /* clear the other number fields */
              cjlib_clear_writable ( Binhex_winid, BINHEX_BIN ) ;
              cjlib_clear_writable ( Binhex_winid, BINHEX_OCT ) ;
              cjlib_clear_writable ( Binhex_winid, BINHEX_HEX ) ;
              Msg_Warn ( DECTOOBIG );
              /* do not do any more conversion on this string */
              convert = FALSE ;
              return ;
            }
          }
        }
        break ;

      case BINHEX_HEX :
        base = 16 ;
        break ;

      default:
        base = 10;
        convert = FALSE ;
        break;
    }
    if ( convert )
    {
      if ( negative_decimal )
      {
        /* evaluate the expression */
        expr_is_str = os_evaluate_expression ( text, result, BH_SIZE, &value );
        if ( expr_is_str )
        {
          /* error condition - value is not an integer */
          ////////////Error msg needed
          return ;
        }
        else
        {
          /* check value is in range of a signed 32 bit negative no */
          if ( ( value >= -2147483648 ) && ( value < 1 ) )
          {
            val = value ;
          }
          else
          {
            cjlib_clear_writable ( Binhex_winid, BINHEX_BIN ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_OCT ) ;
            cjlib_clear_writable ( Binhex_winid, BINHEX_HEX ) ;
            Msg_Warn ( DECTOOSMALL );
            /* do not do any more conversion on this string */
            convert = FALSE ;
            return ;
          }

        }
      }
      else
      {
        /* just convert the value */
        val = os_read_unsigned ( base , text, 0, &end ) ;
      }

      Binhex_UpdateFieldValues ( val, cmp_id );

      wimp_force_redraw ( Binhex_winhandle,
                          TEXT_X_OFFSET,
                          -redraw_y_bottom, 860, -redraw_y_top );

    }
  }

  return ;

}




/*************************************************************************/

static void Binhex_InvertBinaryValue (void)

{
  char text[TEXT_BUFFER_SIZE];
  char text2[TEXT_BUFFER_SIZE];
  char * textptr;
  int used;
  bits val ;
  char *end ;


  /* get binary text string to be inverted */
  used = writablefield_get_value ( 0, Binhex_winid,
                                   BINHEX_BIN , text, TEXT_BUFFER_SIZE );
  textptr = pad_binary_to_32bit ( text, text2, used);

  val = os_read_unsigned ( BASE_BINARY , textptr, 0, &end ) ;
  /* Now invert the values */
  val = val ^ 0xffffffff;

  /* Put the new value back in to the number fields */
  Binhex_UpdateFieldValues ( val, BINHEX_DUMMY );
  wimp_force_redraw ( Binhex_winhandle,
                      TEXT_X_OFFSET,
                      -redraw_y_bottom, 860, -redraw_y_top );

  return;
}




/*************************************************************************/

static void Binhex_ShiftBinaryValue (osbool shift_right, int step)

{
  char text[TEXT_BUFFER_SIZE];
  char text2[TEXT_BUFFER_SIZE];
  char * textptr;
  int used;
  bits val ;
  char *end ;
  bits wrap_bits;

  /* Check for sensible values */
  if (step == 0) return;
  if (step < 0)
  {
    step = -step;
    shift_right = !shift_right;
  }
  step = step % 32;

  /* get binary text string to be shifted */
  used = writablefield_get_value ( 0, Binhex_winid,
                                   BINHEX_BIN , text, TEXT_BUFFER_SIZE );
  textptr = pad_binary_to_32bit ( text, text2, used);

  /* convert to integer */
  val = os_read_unsigned ( BASE_BINARY , textptr, 0, &end ) ;

  if (shift_right)
  {
    if (wrap_around)
    {
      switch (step)
      {
        case 1:
          wrap_bits = val & SHIFT_RIGHT_MASK_1;
          wrap_bits = wrap_bits << (32 - step);
          break;

        case 4:
          wrap_bits = val & SHIFT_RIGHT_MASK_4;
          wrap_bits = wrap_bits << (32 - step);
          break;

        case 8:
          wrap_bits = val & SHIFT_RIGHT_MASK_8;
          wrap_bits = wrap_bits << (32 - step);
          break;

        case 16:
          wrap_bits = val & SHIFT_RIGHT_MASK_16;
          wrap_bits = wrap_bits << (32 - step);
          break;

      }
    }
    val = val >> step;
    if (wrap_around) val = val | wrap_bits;
  }
  else
  {
    if (wrap_around)
    {
      switch (step)
      {
        case 1:
          wrap_bits = val & SHIFT_LEFT_MASK_1;
          wrap_bits = wrap_bits >> (32 - step);
          break;

        case 4:
          wrap_bits = val & SHIFT_LEFT_MASK_4;
          wrap_bits = wrap_bits >> (32 - step);
          break;

        case 8:
          wrap_bits = val & SHIFT_LEFT_MASK_8;
          wrap_bits = wrap_bits >> (32 - step);
          break;

        case 16:
          wrap_bits = val & SHIFT_LEFT_MASK_16;
          wrap_bits = wrap_bits >> (32 - step);
          break;

      }
    }
    val = val << step;
    if (wrap_around) val = val | wrap_bits;
  }

  Binhex_UpdateFieldValues ( val, BINHEX_DUMMY );
  wimp_force_redraw ( Binhex_winhandle,
                      TEXT_X_OFFSET,
                      -redraw_y_bottom, 860, -redraw_y_top );

  return;
}




/*************************************************************************/

static void Binhex_RedrawWindow ( wimp_draw *block, char *text )
{
  int x, y;
  int x1;
  font_string_flags flags = font_OS_UNITS;
  int win_x_origin;
  int win_y_origin;
  font_f fh;
  // variables to take return values
  int x_res_out, y_res_out;
  os_colour bg_hint_out;
  os_colour fill_out;
  int offset_out;

  if (*text == 0) return;

  /* set up font */
  fh = font_find_font ( BOLD_FONT,
                        FONT_SIZE, FONT_SIZE, 0, 0, &x_res_out, &y_res_out ) ;
  win_x_origin = block->box.x0 - block->xscroll;
  win_y_origin = block->box.y1 - block->yscroll;
  wimp_set_colour ( wimp_COLOUR_BLACK );
  colourtrans_set_font_colours ( fh, 0xFFFFFF00, 0, 6,
                                 &bg_hint_out, &fill_out, &offset_out );
  x = win_x_origin + TEXT_X_OFFSET;
  y = win_y_origin - TEXT_Y_OFFSET - lineheight;

  font_paint ( fh, text, flags, x, y, 0,0,0 );
  y -= lineheight;
  font_lose_font ( fh );
  fh = font_find_font ( NORMAL_FONT,
                        FONT_SIZE, FONT_SIZE, 0, 0, &x_res_out, &y_res_out ) ;
  font_paint ( fh, "                        ", flags, x, y, 0,0,0 );
  y -= lineheight;
  x1 = x - (charwidth / 2);
  font_paint ( fh, "   28  24  20  16  12", flags, x1, y, 0,0,0 );
  x1 = x + (charwidth * 23);
  font_paint ( fh, "8   4   0", flags, x1, y, 0,0,0 );

  font_lose_font ( fh );
  return;
}



/*************************************************************************/

static osbool Binhex_RedrawRequest ( wimp_event_no event,
                                     wimp_block * blk,
                                     toolbox_block * id_block,
                                     void * handle )
{
  osbool   more;
  wimp_draw *b;
  char text[TEXT_BUFFER_SIZE];
  char text2[TEXT_BUFFER_SIZE];
  char * textptr;
  int used;

  /* get text string to be printed */
  used = writablefield_get_value ( 0,
                                   Binhex_winid,
                                   BINHEX_BIN , text, TEXT_BUFFER_SIZE );
  textptr = pad_binary_to_32bit ( text, text2, used);

  b = (wimp_draw *) blk;
  more = wimp_redraw_window ( b );
  while (more)
  {
    Binhex_RedrawWindow ( b, textptr );
    more = wimp_get_rectangle ( b );
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}




/************************************************************/

static osbool Binhex_KeyPress ( wimp_event_no event,
                                wimp_block * blk,
                                toolbox_block * id_block,
                                void * handle )

{
  wimp_key *wkey;

  wkey = (wimp_key*)blk;
  if (wkey->c == wimp_KEY_F1)
    IconbarShowHelp();
  else
  if (( wkey->c < 32 ) || ( wkey->c > 126 ))
    wimp_process_key (wkey->c);

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}





/************************************************************/

static osbool Binhex_MouseClick ( wimp_event_no event,
                                  wimp_block * blk,
                                  toolbox_block * id_block,
                                  void * handle )
{
  wimp_pointer *b;
  wimp_window_info info;
  int win_x_orig, win_y_orig;
  int str_top, str_bot;
  int str_left;
  char text[TEXT_BUFFER_SIZE];
  char text2[TEXT_BUFFER_SIZE];
  char * textptr;
  bits val ;
  char *end ;
  int used;

  double offset;
  int offset1;


  b = (wimp_pointer *)blk;
  /* get window details */
  info.w = Binhex_winhandle;
  wimp_get_window_info_header_only ( &info );
  win_x_orig = info.visible.x0 - info.xscroll;
  win_y_orig = info.visible.y1 - info.yscroll;
  /* calculate boundaries of binary string */
  str_top = win_y_orig - TEXT_Y_OFFSET;
  str_bot = str_top - lineheight;
  str_left = win_x_orig + TEXT_X_OFFSET;

  /* was the mouse click on the binary text? */
  if (( b->pos.y < str_top ) && ( b->pos.y > str_bot )
                                   && (b->pos.x > (str_left)))
  {
    offset = (((double)b->pos.x - (double)str_left) / charwidth);
    offset1 = (int)floor(offset);
    if ((offset1 >= 0) && (offset1 < 32))
    {
      /* now get the binary string */
      used = writablefield_get_value ( 0, Binhex_winid,
                                       BINHEX_BIN , text, TEXT_BUFFER_SIZE );
      textptr = pad_binary_to_32bit ( text, text2, used);

      /* now toggle the bit */
      if ( textptr[offset1] == '0' ) textptr[offset1] = '1';
      else textptr[offset1] = '0';
      /* convert the value */
      val = os_read_unsigned ( 2, textptr, 0, &end ) ;
      /* now rewrite the binary string in the main writable */
      /* we need to take account of leading zero stripping, etc */
      if ( display_option == SMALLEST_BYTE )
      {
        textptr = smallest_byte ( val, textptr, 8 );
      }
      else
      {
        if ( display_option == STRIP_LEADING_ZEROS )
        {
          if ( val == 0 )
          {
            textptr[0] = '0';
            textptr[1] = '\0';
          }
          else
          {
            textptr = strip_leading_zeros (textptr);
          }
        }
      }
      writablefield_set_value (0, Binhex_winid, BINHEX_BIN , textptr );
      /* now calculate and update the values  for the other fields*/
      Binhex_UpdateFieldValues ( val, BINHEX_BIN );

      wimp_force_redraw ( Binhex_winhandle,
                          TEXT_X_OFFSET,
                          -redraw_y_bottom, 860, -redraw_y_top );
    }
  }

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}





/************************************************************/

static void GetSettings (void)
{
  osbool state ;
  toolbox_c on_button ;

  /* Find which radio icon is selected */
  state = radiobutton_get_state ( 0, Binhex_settings_winid,
                                  BINHEX_SETTINGS_RADIO_BASE , &on_button ) ;
  display_option = (int)on_button - BINHEX_SETTINGS_RADIO_BASE;

  signed_int = (osbool) optionbutton_get_state (0,
                                                Binhex_settings_winid,
                                                BINHEX_SETTINGS_SIGNED );
  wrap_around = (osbool) optionbutton_get_state ( 0,
                                                  Binhex_settings_winid,
                                                  BINHEX_SETTINGS_WRAP_BITS );
  return;
}




/************************************************************/

static void Binhex_SetupSettings (void)
{
  /* make sure correct radiobutton is selected */
  radiobutton_set_state ( 0,
                          Binhex_settings_winid,
                          BINHEX_SETTINGS_RADIO_BASE + display_option,
                          STATE_ON ) ;
  optionbutton_set_state (0, Binhex_settings_winid, BINHEX_SETTINGS_SIGNED,
                          signed_int ) ;
  optionbutton_set_state (0, Binhex_settings_winid, BINHEX_SETTINGS_WRAP_BITS,
                          wrap_around ) ;

  return;
}




/************************************************************/

static osbool Binhex_SettingsHandler ( bits event_code,
                                       toolbox_action *action,
                                       toolbox_block *id_block,
                                       void *handle )
{

  switch (event_code)
  {
    case action_BH_SETTINGS_SET:
      GetSettings ();
      break;

    case action_BH_SETTINGS_SAVE:
      GetSettings ();
      SaveChoices ();
      break;

    case action_BH_SETTINGS_CANCEL:
      if ((action->flags & 1) == 1)
      {
        /* Adjust used */
        /* reset settings to entry conditions */
        Binhex_SetupSettings ();
      }
      else
      {
        /* Just close window */
        toolbox_hide_object ( 0, Binhex_settings_winid );
      }
      break;

    case action_WINDOW_DIALOGUE_COMPLETED:

      event_deregister_toolbox_handler ( Binhex_settings_winid,
                                         action_ANY,
                                         Binhex_SettingsHandler,
                                         NULL);
      toolbox_delete_object ( 0, Binhex_settings_winid );
      Binhex_settings_winid = toolbox_NULL_OBJECT;
      break;
  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}



/************************************************************/

static void Binhex_SettingsOpen (void)
{

  if (Binhex_settings_winid == toolbox_NULL_OBJECT)
  {
    Binhex_settings_winid = toolbox_create_object ( 0, BINHEX_SETTINGS_TEMPLATE);
    event_register_toolbox_handler ( Binhex_settings_winid,
                                     action_ANY,
                                     Binhex_SettingsHandler,
                                     NULL);

    Binhex_SetupSettings ();

    toolbox_show_object ( 0,
                          Binhex_settings_winid,
                          toolbox_POSITION_CENTRED,
                          0,
                          toolbox_NULL_OBJECT,
                          toolbox_NULL_COMPONENT ) ;
  }
  else
  {
    toolbox_show_object ( 0,
                          Binhex_settings_winid,
                          toolbox_POSITION_DEFAULT,
                          NULL,
                          toolbox_NULL_OBJECT,
                          toolbox_NULL_COMPONENT ) ;
  }
  return;
}








/************************************************************/

static osbool Binhex_Handler ( bits event_code,
                               toolbox_action *action,
                               toolbox_block *id_block,
                               void *handle )
{
  char *text;
  adjuster_action_clicked_block * blk;
  osbool shift_right;
  int step = 1;
  osbool shift, ctrl;

  switch (event_code)
  {
    case action_BH_CLEAR:
      Binhex_ClearAllFields ();
      wimp_force_redraw ( Binhex_winhandle, TEXT_X_OFFSET, -redraw_y_bottom, 860, -redraw_y_top );
      break;

    case action_BH_INVERT:
      Binhex_InvertBinaryValue ();
      break;

    case action_ADJUSTER_CLICKED:
      blk = (adjuster_action_clicked_block *)action;
      /* Is it shift right or left? */
      shift_right = blk->up;
      /* Are we shifting several bits? */
      shift = CJL_ShiftPressed ();
      ctrl = CJL_ControlPressed ();
      if (shift && ctrl) step = 16;
      else if (ctrl) step = 8;
      else if (shift) step = 4;
      /* Now do the shifting */
      Binhex_ShiftBinaryValue (shift_right, step);
      break;

    case action_WRITABLE_FIELD_VALUE_CHANGED:
      text = (char *)&action->data.reserved;
      Binhex_WritableFieldValueChanged ( text, id_block->this_cmp);
      break;

    case action_BH_SETTINGS:
      Binhex_SettingsOpen ();
      break;

    case action_WINDOW_DIALOGUE_COMPLETED:
      /* get current position of Binhex window */
      CJL_GetTopLeftWinPos ( Binhex_winhandle, &Binhex_win_pos );

      event_deregister_toolbox_handler ( Binhex_winid,
                                         action_ANY,
                                         Binhex_Handler,
                                         NULL);
      event_deregister_wimp_handler ( Binhex_winid,
                                      wimp_REDRAW_WINDOW_REQUEST,
                                      Binhex_RedrawRequest,
                                      NULL );
      event_deregister_wimp_handler ( Binhex_winid,
                                      wimp_MOUSE_CLICK,
                                      Binhex_MouseClick,
                                      NULL );
      event_deregister_wimp_handler ( Binhex_winid,
                                      wimp_KEY_PRESSED,
                                      Binhex_KeyPress,
                                      NULL );
      toolbox_delete_object ( 0, Binhex_winid );
      Binhex_winid = toolbox_NULL_OBJECT;
      if (Binhex_settings_winid)
        toolbox_hide_object (0, Binhex_settings_winid);
      break;
  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}





/************************************************************/

void Binhex_Open (void)
{

  if (Binhex_winid == toolbox_NULL_OBJECT)
  {
    Binhex_winid = toolbox_create_object ( 0, BINHEX_TEMPLATE);
    Binhex_winhandle = window_get_wimp_handle (0, Binhex_winid);
    event_register_toolbox_handler ( Binhex_winid,
                                  action_ANY,
                                  Binhex_Handler,
                                  NULL);
    event_register_wimp_handler ( Binhex_winid,
                                  wimp_REDRAW_WINDOW_REQUEST,
                                  Binhex_RedrawRequest,
                                  NULL );
    event_register_wimp_handler ( Binhex_winid,
                                  wimp_MOUSE_CLICK,
                                  Binhex_MouseClick,
                                  NULL );
    event_register_wimp_handler ( Binhex_winid,
                                  wimp_KEY_PRESSED,
                                  Binhex_KeyPress,
                                  NULL );
    Binhex_SetupFont ();

    if (Binhex_win_pos.top_left.x == 0)
    {
      toolbox_show_object ( 0,
                            Binhex_winid,
                            toolbox_POSITION_CENTRED,
                            0,
                            toolbox_NULL_OBJECT,
                            toolbox_NULL_COMPONENT ) ;
    }
    else
    {
      toolbox_show_object ( 0,
                            Binhex_winid,
                            toolbox_POSITION_TOP_LEFT,
                            &Binhex_win_pos,
                            toolbox_NULL_OBJECT,
                            toolbox_NULL_COMPONENT ) ;
    }
  }
  else
  {
      toolbox_show_object ( 0,
                            Binhex_winid,
                            toolbox_POSITION_DEFAULT,
                            NULL,
                            toolbox_NULL_OBJECT,
                            toolbox_NULL_COMPONENT ) ;
  }
  return;
}







/************************************************************/





/*************  End of c.binhex  ***********************/





