3373 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3373 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
 | 
						|
/*******************************************************************************
 | 
						|
*  Copyright 1991-1996 by ORCA Software, Inc.                                  *
 | 
						|
*                                                                              *
 | 
						|
*  All rights reserved.  May not be reproduced or distributed, in printed or   *
 | 
						|
*  electronic form, without permission of ORCA Software, Inc.  May not be      *
 | 
						|
*  distributed as object code, separately or linked with other object modules, *
 | 
						|
*  without permission.                                                         *
 | 
						|
*******************************************************************************/
 | 
						|
 | 
						|
/* {[( */
 | 
						|
 | 
						|
#define XI_INTERNAL
 | 
						|
#include "xi.h"
 | 
						|
#include "xitext.h"
 | 
						|
#include "xilm.h"
 | 
						|
#include "xilmst.h"
 | 
						|
#include "xiutils.h"
 | 
						|
#include "xistx.h"
 | 
						|
 | 
						|
#define is_word_char(ch) (ch != ' ' && ch != '\n')
 | 
						|
#define SB_DELTA 3
 | 
						|
#define GRAN 32
 | 
						|
#define NEW_LEN( a ) (((((a) - 1 ) / GRAN ) + 1 ) * GRAN)
 | 
						|
 | 
						|
/*
 | 
						|
each XI_TEXT can be in an editing state, or a display only state.  at times,
 | 
						|
other modules need to request the state of the wrap.  an instance is when the
 | 
						|
lm or stx modules needs to set state of insertion points.
 | 
						|
 | 
						|
more than one XI_TEXT can be in an editing state.  an example of this is where
 | 
						|
more than one window contain controls using XI_TEXT, each window has a control
 | 
						|
that has focus within that window.
 | 
						|
 | 
						|
when other modules need to interact with an XI_TEXT, such as setting the
 | 
						|
selection, they need to inquire of the XI_TEXT if it is currently in an editing
 | 
						|
state.  there is no provision, and results are undefined, if another module
 | 
						|
calls functions, or uses macros that are only valid for an XI_TEXT that is in
 | 
						|
the editing state.
 | 
						|
 | 
						|
save_text contains a pointer to a copy of an XI_TEXT.  this is used to
 | 
						|
save the state of an XI_TEXT before modifying when editing.  this allows
 | 
						|
us to optimize drawing after any editing action.
 | 
						|
 | 
						|
note for the programmer maintaining this module: save_text must never be
 | 
						|
assumed to contain any allocated data in between calls to this module.  in
 | 
						|
other words, any function that calls save_text_state must call
 | 
						|
free_save_text_state before returning.
 | 
						|
 | 
						|
calls to this module for a particular editing XI_TEXT may be interspersed with
 | 
						|
other calls for another editing XI_TEXT.  don't assume any state in this module
 | 
						|
beyond the scope of one of the calls into the module.
 | 
						|
*/
 | 
						|
 | 
						|
static XI_TEXT *save_text = NULL;
 | 
						|
static void calc_delta_y( XI_TEXT * text );
 | 
						|
static void save_text_state( XI_TEXT * text );
 | 
						|
static void display_if_necessary( XI_TEXT * text, BOOLEAN recalc_delta_y );
 | 
						|
static void xi_text_caret_off( XI_TEXT * text );
 | 
						|
static void xi_text_caret_on( XI_TEXT * text );
 | 
						|
static void calc_delta_x( XI_TEXT * text );
 | 
						|
static void xi_text_hit_test( XI_TEXT * text, XinEvent * ep, int *ip );
 | 
						|
 | 
						|
/*
 | 
						|
sets range, position, and proportion of the scroll bar.  only called if
 | 
						|
there is a scroll bar.
 | 
						|
*/
 | 
						|
static void
 | 
						|
xi_text_sb_set( XI_TEXT * text )
 | 
						|
{
 | 
						|
  if ( xi_itf_in_event_destroy( text->itf ) )
 | 
						|
    return;
 | 
						|
  if ( text->nbr_lines == 0 )
 | 
						|
  {
 | 
						|
    XinScrollBarSet( text->sb_win, XinScrollBarTypeEither, 0, 1000, 0, 0 );
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    double prop,
 | 
						|
    pos;
 | 
						|
 | 
						|
    prop = ( double ) text->max_lines_to_draw / ( double ) text->nbr_lines * 1000;
 | 
						|
    if ( prop > 1000 )
 | 
						|
      prop = 1000;
 | 
						|
    pos = ( double ) text->delta_y / ( double ) text->nbr_lines * 1000;
 | 
						|
    XinScrollBarSet( text->sb_win, XinScrollBarTypeEither, 0, 1000, ( int ) prop, ( int ) pos );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
the process of wrapping text consists of breaking the string into segments.
 | 
						|
this is the function that adds a segment to the line_breaks data structure.
 | 
						|
(the line_breaks data structure contains the segments of wrapped text.
 | 
						|
only called by xi_text_wrap_internal, and only if multi-line.
 | 
						|
*/
 | 
						|
static void
 | 
						|
add_seg( XI_TEXT * text, int seg_starting_pos )
 | 
						|
{
 | 
						|
  XI_TEXT_LINE_BREAK *lb;
 | 
						|
 | 
						|
  ++text->nbr_lines;
 | 
						|
  if ( text->line_breaks )
 | 
						|
    text->line_breaks = ( XI_TEXT_LINE_BREAK * ) xi_tree_realloc( text->line_breaks,
 | 
						|
                            sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines );
 | 
						|
  else
 | 
						|
    text->line_breaks = ( XI_TEXT_LINE_BREAK * ) xi_tree_malloc( sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines,
 | 
						|
                                                                text );
 | 
						|
  lb = &text->line_breaks[text->nbr_lines - 1];
 | 
						|
  lb->line_break = seg_starting_pos;
 | 
						|
  lb->ip1 = lb->ip2 = -1;
 | 
						|
  lb->active_ip = -2;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
creates an xi_text.  initially, the xi_text is not editing text.  to start
 | 
						|
editing text, xi_text_editing_start must be called.
 | 
						|
 | 
						|
win is the window into which the xi_text will be placed.
 | 
						|
 | 
						|
pix_width is the physical pixel width.
 | 
						|
 | 
						|
font is the desired font for the xi_text.
 | 
						|
 | 
						|
parent is a parent pointer for xi_tree memory.  the XI_TEXT is allocated with
 | 
						|
  this as its parent.
 | 
						|
 | 
						|
if multi_line is true, the xi_text is a multi_line edit control.  if false,
 | 
						|
  the xi_text is a single line edit control.
 | 
						|
*/
 | 
						|
 | 
						|
XI_TEXT *
 | 
						|
xi_text_construct( XinWindow win, int pix_width, XinFont * font,
 | 
						|
                  void *parent, BOOLEAN multi_line, int cid,
 | 
						|
                  BOOLEAN scrollbar_always_visible )
 | 
						|
{
 | 
						|
  XI_TEXT *text;
 | 
						|
 | 
						|
  text = xi_tree_malloc( sizeof( XI_TEXT ), parent );
 | 
						|
  text->win = win;
 | 
						|
  text->itf = xi_get_itf( win );
 | 
						|
  text->font = font;
 | 
						|
  text->pix_width = pix_width;
 | 
						|
  text->multi_line = multi_line;
 | 
						|
  text->cid = cid;
 | 
						|
  text->scrollbar_always_visible = scrollbar_always_visible;
 | 
						|
  text->sb_win = XI_NULL_WINDOW;
 | 
						|
  text->delta_y = 0;
 | 
						|
  text->delta_x = 0;
 | 
						|
  text->editing = FALSE;
 | 
						|
  text->visible = TRUE;
 | 
						|
  return text;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function does the actual wrapping of text.  it is only used for a
 | 
						|
multi_line edit control.
 | 
						|
*/
 | 
						|
static void
 | 
						|
xi_text_wrap_internal( XI_TEXT * text )
 | 
						|
{
 | 
						|
  int char_width;
 | 
						|
  int cur_seg,
 | 
						|
  cur_seg_starting_pos,
 | 
						|
  avg_line_len,
 | 
						|
  seg_len;
 | 
						|
  XinFont *font;
 | 
						|
  int internal_pix_width = text->internal_pix_width;
 | 
						|
  char *string = text->string;
 | 
						|
 | 
						|
  if ( ! string )
 | 
						|
    return;
 | 
						|
  font = text->font;
 | 
						|
  if ( text->line_breaks )
 | 
						|
  {
 | 
						|
    xi_tree_free( text->line_breaks );
 | 
						|
    text->line_breaks = NULL;
 | 
						|
  }
 | 
						|
  text->nbr_lines = 0;
 | 
						|
  xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width );
 | 
						|
  text->font_height = text->ascent + text->descent + text->leading;
 | 
						|
  avg_line_len = internal_pix_width / char_width;
 | 
						|
  if ( avg_line_len == 0 )
 | 
						|
    avg_line_len = 1;
 | 
						|
  cur_seg_starting_pos = 0;
 | 
						|
  cur_seg = 0;
 | 
						|
 | 
						|
  /* find all segments in text */
 | 
						|
  while ( string[ cur_seg_starting_pos ] != '\0' )
 | 
						|
  {
 | 
						|
    int this_seg_len,
 | 
						|
    possible_word_break,
 | 
						|
    cur_seg_len,
 | 
						|
    word_break,
 | 
						|
    cnt;
 | 
						|
    BOOLEAN continue_loop;
 | 
						|
 | 
						|
    cur_seg_len = strlen( &string[cur_seg_starting_pos] );
 | 
						|
 | 
						|
    /* if there is a new line in the string, will the line fit in the text
 | 
						|
    * space */
 | 
						|
    while ( TRUE )
 | 
						|
    {
 | 
						|
      continue_loop = FALSE;
 | 
						|
      for ( cnt = 0; cnt < cur_seg_len; ++cnt )
 | 
						|
      {
 | 
						|
        if ( string[cur_seg_starting_pos + cnt] == '\n' )
 | 
						|
        {
 | 
						|
          seg_len = XinFontTextWidthGet( font,
 | 
						|
                                        &string[cur_seg_starting_pos],
 | 
						|
                                        cnt );
 | 
						|
          if ( seg_len <= internal_pix_width )
 | 
						|
          {
 | 
						|
            add_seg( text, cur_seg_starting_pos );
 | 
						|
            cur_seg_starting_pos += cnt + 1;
 | 
						|
            cur_seg_len = strlen( &string[cur_seg_starting_pos] );
 | 
						|
            continue_loop = TRUE;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            continue_loop = FALSE;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if ( !continue_loop )
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    this_seg_len = min( avg_line_len, cur_seg_len );
 | 
						|
    if ( this_seg_len == 0 )
 | 
						|
      this_seg_len = 1;
 | 
						|
 | 
						|
    /* find character that is beyond internal_pix_width */
 | 
						|
    while ( TRUE )
 | 
						|
    {
 | 
						|
      seg_len = XinFontTextWidthGet( font,
 | 
						|
                                    &string[cur_seg_starting_pos],
 | 
						|
                                    this_seg_len );
 | 
						|
      if ( seg_len > internal_pix_width )
 | 
						|
        break;
 | 
						|
      if ( seg_len <= internal_pix_width &&
 | 
						|
          string[cur_seg_starting_pos + this_seg_len] == '\0' )
 | 
						|
      {
 | 
						|
        /* this is the last segment of the string */
 | 
						|
        add_seg( text, cur_seg_starting_pos );
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      ++this_seg_len;
 | 
						|
    }
 | 
						|
 | 
						|
    /* add the first segment */
 | 
						|
    add_seg( text, cur_seg_starting_pos );
 | 
						|
 | 
						|
    /* find character that is just below internal_pix_width */
 | 
						|
    while ( this_seg_len > 1 )
 | 
						|
    {
 | 
						|
      --this_seg_len;
 | 
						|
      seg_len = XinFontTextWidthGet( font,
 | 
						|
                                    &string[cur_seg_starting_pos],
 | 
						|
                                    this_seg_len );
 | 
						|
      if ( seg_len < internal_pix_width )
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    /* find possible word break */
 | 
						|
    possible_word_break = this_seg_len;
 | 
						|
    while ( possible_word_break > 0 )
 | 
						|
    {
 | 
						|
      if ( !is_word_char( string[cur_seg_starting_pos + possible_word_break] ) )
 | 
						|
        break;
 | 
						|
      --possible_word_break;
 | 
						|
    }
 | 
						|
 | 
						|
    /* if there is no possible word break, then break at this_seg_len */
 | 
						|
    if ( possible_word_break == 0 )
 | 
						|
      word_break = this_seg_len;
 | 
						|
    else
 | 
						|
      word_break = possible_word_break;
 | 
						|
 | 
						|
    /* move forward so that word break is on a word */
 | 
						|
    while ( !is_word_char( string[cur_seg_starting_pos + word_break] ) )
 | 
						|
      ++word_break;
 | 
						|
 | 
						|
    ++cur_seg;
 | 
						|
    cur_seg_starting_pos += word_break;
 | 
						|
  }
 | 
						|
 | 
						|
  /* If the text is empty, there will be no segments and nbr_lines will still
 | 
						|
    be zero. This is not a good state for the text object. RGM */
 | 
						|
  if ( text->nbr_lines == 0 )
 | 
						|
    add_seg( text, 0 );
 | 
						|
}
 | 
						|
 | 
						|
/* Returns len, or len truncated to the available space in the buffer */
 | 
						|
static int
 | 
						|
reallocate_text( XI_TEXT * text, int len, BOOLEAN setting_buffer_size )
 | 
						|
{
 | 
						|
  int llen, new_len;
 | 
						|
 | 
						|
  llen = len;
 | 
						|
  if ( ! setting_buffer_size )
 | 
						|
  {
 | 
						|
    llen = text->buffer_size;
 | 
						|
    if ( (!text->var_len_text) && len > text->buffer_size )
 | 
						|
      len = text->buffer_size;
 | 
						|
  }
 | 
						|
  if ( llen < text->min_buffer_size )
 | 
						|
    llen = text->min_buffer_size;
 | 
						|
  if ( text->var_len_text )
 | 
						|
    new_len = NEW_LEN( llen );
 | 
						|
  else
 | 
						|
    new_len = llen;
 | 
						|
  if ( new_len != text->allocated_length )
 | 
						|
  {
 | 
						|
    if ( text->string )
 | 
						|
      text->string = ( char * ) xi_tree_realloc( text->string, new_len );
 | 
						|
    else
 | 
						|
      text->string = ( char * ) xi_tree_malloc( new_len, text );
 | 
						|
  }
 | 
						|
  text->allocated_length = new_len;
 | 
						|
  text->buffer_size = llen;
 | 
						|
  return len;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function sets the text of an xi_text.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_set( XI_TEXT * text, char *string )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
  XinFont *font;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  if ( text->string )
 | 
						|
    if ( strcmp( text->string, string ) == 0 &&
 | 
						|
        text->initialized )
 | 
						|
      return;
 | 
						|
  text->initialized = TRUE;
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  font = text->font;
 | 
						|
  XinWindowFontMap( text->win, font );
 | 
						|
  len = reallocate_text( text, strlen( string ) + 1, FALSE );
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
  memcpy( text->string, string, len );
 | 
						|
  text->string[len - 1] = '\0';
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
  {
 | 
						|
    if ( text->multi_line )
 | 
						|
        calc_delta_y( text );
 | 
						|
    else
 | 
						|
      calc_delta_x( text );
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  }
 | 
						|
  if ( restart )
 | 
						|
  {
 | 
						|
    xi_text_editing_start( text );
 | 
						|
    if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT )
 | 
						|
      xi_text_selection_set_internal( text, 0, SHRT_MAX,
 | 
						|
                0, TRUE, TRUE );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
This function should be called after a cell request that reallocated the buffer.
 | 
						|
*/
 | 
						|
void xi_text_reinitialize( XI_TEXT* text )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  text->initialized = TRUE;
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  len = strlen( text->string );
 | 
						|
  text->allocated_length = len;
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( restart )
 | 
						|
  {
 | 
						|
    xi_text_editing_start( text );
 | 
						|
    if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT )
 | 
						|
      xi_text_selection_set_internal( text, 0, SHRT_MAX,
 | 
						|
                0, TRUE, TRUE );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function wraps the text of an xi_text.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_wrap( XI_TEXT * text )
 | 
						|
{
 | 
						|
  XinFont *font;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  font = text->font;
 | 
						|
  XinWindowFontMap( text->win, font );
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( restart )
 | 
						|
    xi_text_editing_start( text );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function sets the text of an xi_text.  if the pix_width has changed from
 | 
						|
the last time this function was called, then wrapping is performed even if the
 | 
						|
text is the same.  set_font is used by the list.  when setting lots of text,
 | 
						|
the list knows that the font for the xi_text currently being set is the same
 | 
						|
font as the xi_text last set.  this eliminates a call to the windowing system
 | 
						|
to set the font.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_pix_width_and_text_set( XI_TEXT * text, char *string, int pix_width, BOOLEAN set_font )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
  XinFont *font;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  if ( text->string )
 | 
						|
    if ( text->pix_width == pix_width &&
 | 
						|
        strcmp( text->string, string ) == 0 &&
 | 
						|
        text->initialized )
 | 
						|
      return;
 | 
						|
  text->initialized = TRUE;
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  font = text->font;
 | 
						|
  if ( set_font )
 | 
						|
    XinWindowFontMap( text->win, font );
 | 
						|
  len = reallocate_text( text, strlen( string ) + 1, FALSE );
 | 
						|
  text->pix_width = pix_width;
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
  memcpy( text->string, string, len );
 | 
						|
  text->string[ len - 1 ] = '\0';
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( restart )
 | 
						|
  {
 | 
						|
    xi_text_editing_start( text );
 | 
						|
    if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT )
 | 
						|
      xi_text_selection_set_internal( text, 0, SHRT_MAX,
 | 
						|
                0, TRUE, TRUE );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function sets the pix width of an xi_text.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_pix_width_set( XI_TEXT * text, int pix_width )
 | 
						|
{
 | 
						|
  XinFont *font;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  if ( text->string )
 | 
						|
    if ( text->pix_width == pix_width &&
 | 
						|
        text->initialized )
 | 
						|
      return;
 | 
						|
  text->initialized = TRUE;
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  font = text->font;
 | 
						|
  XinWindowFontMap( text->win, font );
 | 
						|
  text->pix_width = pix_width;
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( restart )
 | 
						|
    xi_text_editing_start( text );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_destruct( XI_TEXT * text )
 | 
						|
{
 | 
						|
  if ( text->sb_win )
 | 
						|
    if ( !xi_itf_in_event_destroy( text->itf ) )
 | 
						|
      XinWindowDestroy( text->sb_win );
 | 
						|
  xi_tree_free( text );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
draws the rectangle to the right of text on any line.  after drawing the
 | 
						|
text (in opaque mode), there often is still a small amount of space to the
 | 
						|
right of the text, and to the left of the right edge of the edit control.
 | 
						|
this function fills that space with the background color.
 | 
						|
 | 
						|
for a right justified field, this function draws the rectangle to the left
 | 
						|
of the text and to the right of the left edge of the edit control.
 | 
						|
*/
 | 
						|
static void
 | 
						|
draw_end_rect( XI_TEXT * text, char *str, int len, int left, int right,
 | 
						|
              int baseline, XinDrawTools * save_dt, int delta_x )
 | 
						|
{
 | 
						|
  int x;
 | 
						|
  XinRect r;
 | 
						|
  XinDrawTools dt;
 | 
						|
 | 
						|
  x = XinFontTextWidthGet( text->font, str, len );
 | 
						|
  r.top = baseline - text->leading - text->ascent;
 | 
						|
  r.bottom = baseline + text->descent;
 | 
						|
  if ( text->right_justify )
 | 
						|
  {
 | 
						|
    r.left = left;
 | 
						|
    r.right = right - x + delta_x;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    r.left = left + x - delta_x;
 | 
						|
    r.right = right;
 | 
						|
  }
 | 
						|
  if ( r.left < r.right )
 | 
						|
  {
 | 
						|
    dt = *save_dt;
 | 
						|
    dt.brush.fore_color = text->back_color_in_use;
 | 
						|
    dt.brush.pattern = XinBrushSolid;
 | 
						|
    dt.pen.pattern = XinPenHollow;
 | 
						|
    dt.pen.width = 1;
 | 
						|
    dt.pen.fore_color = XI_COLOR_WHITE;
 | 
						|
    dt.opaque_text = TRUE;
 | 
						|
    XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
    xi_draw_rect( text->win, &r );
 | 
						|
    XinWindowDrawToolsSet( text->win, save_dt );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
free_save_text_state( void )
 | 
						|
{
 | 
						|
  xi_tree_free( save_text );
 | 
						|
  save_text = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
alloc_password_string( int len, void *parent )
 | 
						|
{
 | 
						|
  int cnt;
 | 
						|
  char *str;
 | 
						|
 | 
						|
  str = xi_tree_malloc( len + 1, parent );
 | 
						|
  for ( cnt = 0; cnt < len; ++cnt )
 | 
						|
    str[cnt] = '#';
 | 
						|
  str[len] = '\0';
 | 
						|
  return str;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function draws the XI_TEXT.  if save_text is set, then this function only
 | 
						|
displays differences between save_text and text.
 | 
						|
*/
 | 
						|
static void
 | 
						|
xi_text_draw_internal( XI_TEXT * text, XinColor color, XinColor back_color, BOOLEAN do_carets )
 | 
						|
{
 | 
						|
  XinRect rct;
 | 
						|
  char *s;
 | 
						|
  char *sws;
 | 
						|
  int cnt,
 | 
						|
  nbr_lines,
 | 
						|
  baseline,
 | 
						|
  line_to_draw,
 | 
						|
  top_of_rect;
 | 
						|
  XinWindow win = text->win;
 | 
						|
  XI_TEXT_LINE_BREAK *lb;
 | 
						|
  XinDrawTools save_dt;
 | 
						|
  BOOLEAN turn_caret_on = FALSE;
 | 
						|
 | 
						|
  if ( do_carets && xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_caret_off( text );
 | 
						|
    turn_caret_on = TRUE;
 | 
						|
  }
 | 
						|
  if ( color )
 | 
						|
  {
 | 
						|
    text->fore_color_in_use = color;
 | 
						|
    text->back_color_in_use = back_color;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    text->fore_color_in_use = text->fore_color;
 | 
						|
    text->back_color_in_use = text->back_color;
 | 
						|
  }
 | 
						|
  XinWindowFontMap( text->win, text->font );
 | 
						|
  rct = text->prect;
 | 
						|
  rct.right = rct.left + text->internal_pix_width;
 | 
						|
  xi_rect_intersect( &rct, &rct, &text->clip_rect );
 | 
						|
  xi_set_clip( win, &rct );
 | 
						|
  XinWindowDrawToolsGet( win, &save_dt );
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( text->max_lines_to_draw )
 | 
						|
      nbr_lines = min( xi_text_nbr_lines_get( text ), text->max_lines_to_draw );
 | 
						|
    else
 | 
						|
      nbr_lines = xi_text_nbr_lines_get( text );
 | 
						|
    if ( text->delta_y + nbr_lines > text->nbr_lines )
 | 
						|
      nbr_lines -= ( text->delta_y + nbr_lines - text->nbr_lines );
 | 
						|
  }
 | 
						|
  s = text->string;
 | 
						|
  if ( save_text )
 | 
						|
    sws = save_text->string;
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    for ( cnt = 0, line_to_draw = text->delta_y;
 | 
						|
          cnt < nbr_lines; ++cnt, ++line_to_draw )
 | 
						|
    {
 | 
						|
      int len = -1;
 | 
						|
      XinDrawTools dt;
 | 
						|
      char *str;
 | 
						|
      BOOLEAN dont_draw = FALSE;
 | 
						|
 | 
						|
      lb = &text->line_breaks[line_to_draw];
 | 
						|
      if ( line_to_draw < text->nbr_lines - 1 )
 | 
						|
        len = xi_text_line_break_get( text, line_to_draw + 1 ) -
 | 
						|
                xi_text_line_break_get( text, line_to_draw );
 | 
						|
//#if XIWS == XIWS_WM
 | 
						|
//      baseline = rct.top + 8;
 | 
						|
//#else
 | 
						|
      baseline = rct.top + text->leading + text->ascent;
 | 
						|
// #endif
 | 
						|
      str = &s[xi_text_line_break_get( text, line_to_draw )];
 | 
						|
      if ( len == -1 )
 | 
						|
        len = strlen( str );
 | 
						|
      if ( ( &s[xi_text_line_break_get( text, line_to_draw )] )[len - 1] == '\n' )
 | 
						|
        len--;
 | 
						|
      if ( save_text && line_to_draw < save_text->nbr_lines )
 | 
						|
      {
 | 
						|
        int sw_len = -1;
 | 
						|
        char *sw_str;
 | 
						|
 | 
						|
        if ( line_to_draw < save_text->nbr_lines - 1 )
 | 
						|
          sw_len = xi_text_line_break_get( save_text, line_to_draw + 1 ) - xi_text_line_break_get( save_text, line_to_draw );
 | 
						|
        sw_str = &sws[xi_text_line_break_get( save_text, line_to_draw )];
 | 
						|
        if ( sw_len == -1 )
 | 
						|
          sw_len = strlen( sw_str );
 | 
						|
        if ( ( &sws[xi_text_line_break_get( save_text, line_to_draw )] )[sw_len - 1] == '\n' )
 | 
						|
          sw_len--;
 | 
						|
        if ( ( sw_len == len ) &&
 | 
						|
            ( strncmp( str, sw_str, len ) == 0 ) &&
 | 
						|
            ( text->line_breaks[line_to_draw].ip1 == save_text->line_breaks[line_to_draw].ip1 ) &&
 | 
						|
            ( text->line_breaks[line_to_draw].ip2 == save_text->line_breaks[line_to_draw].ip2 ) )
 | 
						|
          dont_draw = TRUE;
 | 
						|
        /* This piece of code causes problems with scrolling.  Why is it here?
 | 
						|
        * if ( save_text->line_breaks[line_to_draw].ip1 != -1 &&
 | 
						|
        * save_text->line_breaks[line_to_draw].ip1 ==
 | 
						|
        * save_text->line_breaks[line_to_draw].ip2 ) dont_draw = FALSE; */
 | 
						|
      }
 | 
						|
      if ( !dont_draw )
 | 
						|
      {
 | 
						|
        dt = save_dt;
 | 
						|
        dt.text_fore_color = text->fore_color_in_use;
 | 
						|
        dt.text_back_color = text->back_color_in_use;
 | 
						|
        dt.opaque_text = TRUE;
 | 
						|
        XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
        if ( lb->ip1 != lb->ip2 )
 | 
						|
        {
 | 
						|
          if ( lb->ip1 )
 | 
						|
            xi_draw_text( win, text->font, rct.left, baseline,
 | 
						|
                          str, lb->ip1 );
 | 
						|
          dt = save_dt;
 | 
						|
          dt.text_fore_color = text->back_color_in_use;
 | 
						|
          dt.text_back_color = text->fore_color_in_use;
 | 
						|
          dt.opaque_text = TRUE;
 | 
						|
          XinWindowDrawToolsSet( win, &dt );
 | 
						|
          if ( lb->ip2 < len )
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
 | 
						|
            x = XinFontTextWidthGet( text->font, str, lb->ip1 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x, baseline,
 | 
						|
                          &str[lb->ip1], lb->ip2 - lb->ip1 );
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->fore_color_in_use;
 | 
						|
            dt.text_back_color = text->back_color_in_use;
 | 
						|
            dt.opaque_text = TRUE;
 | 
						|
            XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, str, lb->ip2 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x, baseline,
 | 
						|
                          &str[lb->ip2], len - lb->ip2 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, 0 );
 | 
						|
            XinWindowDrawToolsSet( win, &save_dt );
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->back_color_in_use;
 | 
						|
            dt.text_back_color = text->fore_color_in_use;
 | 
						|
            dt.opaque_text = TRUE;
 | 
						|
            XinWindowDrawToolsSet( win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, str, lb->ip1 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x, baseline,
 | 
						|
                          &str[lb->ip1], len - lb->ip1 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, 0 );
 | 
						|
            XinWindowDrawToolsSet( text->win, &save_dt );
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          xi_draw_text( win, text->font, rct.left, baseline,
 | 
						|
                      &s[xi_text_line_break_get( text, line_to_draw )], len );
 | 
						|
          draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                        baseline, &save_dt, 0 );
 | 
						|
        }
 | 
						|
      }
 | 
						|
#if XIWS == XIWS_WM
 | 
						|
      rct.top += text->font_height;
 | 
						|
#else
 | 
						|
      rct.top += xi_text_font_height_get( text );
 | 
						|
#endif
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if ( !text->multi_line )
 | 
						|
  {
 | 
						|
    char *str;
 | 
						|
    char *sw_str;
 | 
						|
    int len,
 | 
						|
    sw_len;
 | 
						|
    BOOLEAN dont_draw;
 | 
						|
 | 
						|
    len = strlen( text->string );
 | 
						|
    if ( text->password )
 | 
						|
      str = alloc_password_string( len, text );
 | 
						|
    else
 | 
						|
      str = text->string;
 | 
						|
//#if XIWS == XI_WMWS
 | 
						|
//    baseline = rct.top + 8;
 | 
						|
//#else
 | 
						|
    baseline = rct.top + text->leading + text->ascent;
 | 
						|
//#endif
 | 
						|
    dont_draw = FALSE;
 | 
						|
    if ( save_text )
 | 
						|
    {
 | 
						|
      sw_len = strlen( save_text->string );
 | 
						|
      if ( save_text->password )
 | 
						|
        sw_str = alloc_password_string( sw_len, save_text );
 | 
						|
      else
 | 
						|
        sw_str = save_text->string;
 | 
						|
      if ( ( sw_len == len ) &&
 | 
						|
          ( strncmp( str, sw_str, len ) == 0 ) &&
 | 
						|
          ( ( ( text->ip1 == save_text->ip1 ) && ( text->ip2 == save_text->ip2 ) ) ||
 | 
						|
      ( ( text->ip1 == text->ip2 ) && ( save_text->ip1 == save_text->ip2 ) ) )
 | 
						|
              )
 | 
						|
        dont_draw = TRUE;
 | 
						|
    }
 | 
						|
    if ( !dont_draw )
 | 
						|
    {
 | 
						|
      int delta_x_pix;
 | 
						|
      XinDrawTools dt;
 | 
						|
      int text_pix_len = XinFontTextWidthGet( text->font, str, -1 );
 | 
						|
 | 
						|
      dt = save_dt;
 | 
						|
      dt.text_fore_color = text->fore_color_in_use;
 | 
						|
      dt.text_back_color = text->back_color_in_use;
 | 
						|
      dt.opaque_text = TRUE;
 | 
						|
      XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
      if ( text->right_justify )
 | 
						|
      {
 | 
						|
        delta_x_pix = XinFontTextWidthGet( text->font,
 | 
						|
                                  &str[len - text->delta_x], text->delta_x );
 | 
						|
        if ( text->ip1 != text->ip2 )
 | 
						|
        {
 | 
						|
          if ( text->ip1 )
 | 
						|
            xi_draw_text( win, text->font,
 | 
						|
                        rct.right - text_pix_len + delta_x_pix, baseline, str,
 | 
						|
                          text->ip1 );
 | 
						|
          dt = save_dt;
 | 
						|
          dt.text_fore_color = text->back_color_in_use;
 | 
						|
          dt.text_back_color = text->fore_color_in_use;
 | 
						|
          dt.opaque_text = TRUE;
 | 
						|
          XinWindowDrawToolsSet( win, &dt );
 | 
						|
          if ( text->ip2 < len )
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
 | 
						|
            x = XinFontTextWidthGet( text->font, &str[text->ip1], strlen( &str[text->ip1] ) );
 | 
						|
            xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline,
 | 
						|
                          &str[text->ip1], text->ip2 - text->ip1 );
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->fore_color_in_use;
 | 
						|
            dt.text_back_color = text->back_color_in_use;
 | 
						|
            XinWindowDrawToolsSet( win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, &str[text->ip2], strlen( &str[text->ip2] ) );
 | 
						|
            xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline,
 | 
						|
                          &str[text->ip2], len - text->ip2 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, delta_x_pix );
 | 
						|
            XinWindowDrawToolsSet( win, &save_dt );
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
            int len_in_pix = XinFontTextWidthGet( text->font, str, -1 );
 | 
						|
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->back_color_in_use;
 | 
						|
            dt.text_back_color = text->fore_color_in_use;
 | 
						|
            dt.opaque_text = TRUE;
 | 
						|
            XinWindowDrawToolsSet( win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, str, text->ip1 );
 | 
						|
            xi_draw_text( win, text->font, rct.right - len_in_pix + x + delta_x_pix, baseline,
 | 
						|
                          &str[text->ip1], len - text->ip1 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, delta_x_pix );
 | 
						|
            XinWindowDrawToolsSet( text->win, &save_dt );
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          int x;
 | 
						|
 | 
						|
          x = XinFontTextWidthGet( text->font, str, -1 );
 | 
						|
          xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline,
 | 
						|
                        str, len );
 | 
						|
          draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                        baseline, &save_dt, delta_x_pix );
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x );
 | 
						|
        if ( text->ip1 != text->ip2 )
 | 
						|
        {
 | 
						|
          if ( text->ip1 )
 | 
						|
            xi_draw_text( win, text->font, rct.left - delta_x_pix, baseline,
 | 
						|
                          str, text->ip1 );
 | 
						|
          dt = save_dt;
 | 
						|
          dt.text_fore_color = text->back_color_in_use;
 | 
						|
          dt.text_back_color = text->fore_color_in_use;
 | 
						|
          dt.opaque_text = TRUE;
 | 
						|
          XinWindowDrawToolsSet( win, &dt );
 | 
						|
          if ( text->ip2 < len )
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
 | 
						|
            x = XinFontTextWidthGet( text->font, str, text->ip1 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline,
 | 
						|
                          &str[text->ip1], text->ip2 - text->ip1 );
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->fore_color_in_use;
 | 
						|
            dt.text_back_color = text->back_color_in_use;
 | 
						|
            dt.opaque_text = TRUE;
 | 
						|
            XinWindowDrawToolsSet( win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, str, text->ip2 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline,
 | 
						|
                          &str[text->ip2], len - text->ip2 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, delta_x_pix );
 | 
						|
            XinWindowDrawToolsSet( win, &save_dt );
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            int x;
 | 
						|
 | 
						|
            dt = save_dt;
 | 
						|
            dt.text_fore_color = text->back_color_in_use;
 | 
						|
            dt.text_back_color = text->fore_color_in_use;
 | 
						|
            dt.opaque_text = TRUE;
 | 
						|
            XinWindowDrawToolsSet( win, &dt );
 | 
						|
            x = XinFontTextWidthGet( text->font, str, text->ip1 );
 | 
						|
            xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline,
 | 
						|
                          &str[text->ip1], len - text->ip1 );
 | 
						|
            draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                          baseline, &save_dt, delta_x_pix );
 | 
						|
            XinWindowDrawToolsSet( text->win, &save_dt );
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          xi_draw_text( win, text->font, rct.left - delta_x_pix, baseline,
 | 
						|
                        str, len );
 | 
						|
          draw_end_rect( text, str, len, rct.left, rct.right,
 | 
						|
                        baseline, &save_dt, delta_x_pix );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if ( text->password )
 | 
						|
    {
 | 
						|
      xi_tree_free( str );
 | 
						|
      if ( save_text )
 | 
						|
        xi_tree_free( sw_str );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    top_of_rect = text->prect.top + nbr_lines * text->font_height;
 | 
						|
    if ( top_of_rect < text->prect.bottom )
 | 
						|
    {
 | 
						|
      XinRect r;
 | 
						|
      XinDrawTools dt;
 | 
						|
 | 
						|
      r.top = top_of_rect;
 | 
						|
      r.left = text->prect.left;
 | 
						|
      r.bottom = text->prect.bottom;
 | 
						|
      r.right = text->prect.left + text->internal_pix_width;
 | 
						|
      dt = save_dt;
 | 
						|
      dt.brush.fore_color = text->back_color_in_use;
 | 
						|
      dt.brush.pattern = XinBrushSolid;
 | 
						|
      dt.pen.pattern = XinPenHollow;
 | 
						|
      dt.pen.width = 1;
 | 
						|
      dt.pen.fore_color = XI_COLOR_WHITE;
 | 
						|
      dt.opaque_text = TRUE;
 | 
						|
      XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
      xi_draw_rect( text->win, &r );
 | 
						|
    }
 | 
						|
  }
 | 
						|
#if 0
 | 
						|
  /* draw line to right of text if there is a scrollbar */
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    XinPoint p;
 | 
						|
    XinDrawTools dt;
 | 
						|
 | 
						|
    dt = save_dt;
 | 
						|
    dt.pen.pattern = XinPenSolid;
 | 
						|
    dt.pen.width = 1;
 | 
						|
    dt.pen.fore_color = text->fore_color_in_use;
 | 
						|
    XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
    p.h = text->prect.left + text->internal_pix_width;
 | 
						|
    p.v = text->prect.top;
 | 
						|
    xi_move_to( text->win, p );
 | 
						|
    p.v = text->prect.bottom;
 | 
						|
    xi_draw_line( text->win, p );
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  /* If there is a scrollbar, fill the space between the text and the sb, and
 | 
						|
  * the sb's space if we aren't editing. */
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    XinRect rect;
 | 
						|
    XinDrawTools dt;
 | 
						|
 | 
						|
    dt = save_dt;
 | 
						|
    dt.pen.pattern = XinPenSolid;
 | 
						|
    dt.pen.width = 1;
 | 
						|
    dt.pen.fore_color = text->back_color_in_use;
 | 
						|
    dt.brush.fore_color = text->back_color_in_use;
 | 
						|
    dt.brush.pattern = XinBrushSolid;
 | 
						|
    XinWindowDrawToolsSet( text->win, &dt );
 | 
						|
    rect = text->prect;
 | 
						|
    rect.left = text->prect.left + text->internal_pix_width;
 | 
						|
    if ( text->sb_win )
 | 
						|
      rect.right = rect.right - text->sb_width;
 | 
						|
    xi_rect_intersect( &rect, &rect, &text->clip_rect );
 | 
						|
    xi_set_clip( win, &rect );
 | 
						|
    xi_draw_rect( text->win, &rect );
 | 
						|
  }
 | 
						|
  XinWindowDrawToolsSet( text->win, &save_dt );
 | 
						|
  if ( turn_caret_on )
 | 
						|
    xi_text_caret_on( text );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_draw( XI_TEXT * text, XinColor color, XinColor back_color, BOOLEAN update )
 | 
						|
{
 | 
						|
  xi_text_draw_internal( text, color, back_color, ( BOOLEAN ) ! update );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
there are two sets of state for insertion points.  the state that this module
 | 
						|
initially modifies when editing is the ip1 and ip2 in the xi_text structure.
 | 
						|
from this, for convenience when drawing the edit control, and for convenience
 | 
						|
when turning on the caret as appropriate, we calculate insertion points for
 | 
						|
every line in the line_breaks array.  this function is used by recalc_line_ips,
 | 
						|
which does calculation of insertion points for every line in the line_breaks
 | 
						|
array.
 | 
						|
 | 
						|
this function is only used if the xi_text is multi_line.
 | 
						|
*/
 | 
						|
static void
 | 
						|
recalc_single_ip( XI_TEXT * text, int ip, BOOLEAN starting, int active_ip )
 | 
						|
{
 | 
						|
  int line_cnt;
 | 
						|
  int total_cnt,
 | 
						|
  old_total_cnt;
 | 
						|
 | 
						|
  total_cnt = 0;
 | 
						|
  for ( line_cnt = 0; line_cnt < text->nbr_lines; ++line_cnt )
 | 
						|
  {
 | 
						|
    int line_len;
 | 
						|
 | 
						|
    if ( line_cnt < text->nbr_lines - 1 )
 | 
						|
      line_len = text->line_breaks[line_cnt + 1].line_break -
 | 
						|
              text->line_breaks[line_cnt].line_break;
 | 
						|
    else
 | 
						|
      line_len = strlen( &text->string[text->line_breaks[line_cnt].line_break] );
 | 
						|
    old_total_cnt = total_cnt;
 | 
						|
    total_cnt += line_len;
 | 
						|
    if ( ip < total_cnt || ( line_cnt == text->nbr_lines - 1 && ip <= total_cnt ) )
 | 
						|
    {
 | 
						|
      int this_line_cnt;
 | 
						|
 | 
						|
      this_line_cnt = ip - old_total_cnt;
 | 
						|
      if ( starting )
 | 
						|
        text->line_breaks[line_cnt].ip1 = this_line_cnt;
 | 
						|
      else
 | 
						|
        text->line_breaks[line_cnt].ip2 = this_line_cnt;
 | 
						|
      if ( ip == active_ip )
 | 
						|
        text->line_breaks[line_cnt].active_ip = this_line_cnt;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
there are two sets of state for insertion points.  the state that this module
 | 
						|
initially modifies when editing is the ip1 and ip2 in the XI_TEXT structure.
 | 
						|
from this, for convenience when drawing the edit control, and for convenience
 | 
						|
when turning on the caret as appropriate, we calculate insertion points for
 | 
						|
every line in the line_breaks array.  this function does the calculation of
 | 
						|
insertion points for the line_breaks array.
 | 
						|
 | 
						|
for each line in the line_breaks array:
 | 
						|
- if ip1 and ip2 both == -1, then the caret is not on this line, and no text
 | 
						|
  on this line is selected.
 | 
						|
- if ip1 and ip2 are both != -1, and they are not equal, then the text on this
 | 
						|
  line from ip1 to ip2 is selected.
 | 
						|
- if ip1 and ip2 are both != -1, and they are equal, then the caret is placed
 | 
						|
  at the indicated position in ip1.
 | 
						|
- it is invalid for either ip1 or ip2 to be -1 where the other is not.
 | 
						|
 | 
						|
this function is used only if the xi_text is multi_line.
 | 
						|
*/
 | 
						|
static void
 | 
						|
recalc_line_ips( XI_TEXT * text )
 | 
						|
{
 | 
						|
  int cnt;
 | 
						|
  XI_TEXT_LINE_BREAK *lb;
 | 
						|
  enum
 | 
						|
  {
 | 
						|
    state_before_sel,
 | 
						|
    state_in_sel,
 | 
						|
    state_after_sel
 | 
						|
  } state;
 | 
						|
  int active_ip;
 | 
						|
 | 
						|
  active_ip = ( text->selection_start_ip == text->ip1 ) ? text->ip2 : text->ip1;
 | 
						|
  for ( cnt = 0, lb = text->line_breaks; cnt < text->nbr_lines; ++cnt, ++lb )
 | 
						|
  {
 | 
						|
    lb->ip1 = lb->ip2 = -1;
 | 
						|
    lb->active_ip = -2;
 | 
						|
  }
 | 
						|
  recalc_single_ip( text, text->ip1, TRUE, active_ip );
 | 
						|
  recalc_single_ip( text, text->ip2, FALSE, active_ip );
 | 
						|
  state = state_before_sel;
 | 
						|
  for ( cnt = 0, lb = text->line_breaks; cnt < text->nbr_lines; ++cnt, ++lb )
 | 
						|
  {
 | 
						|
    if ( lb->ip1 == -1 && lb->ip2 != -1 )
 | 
						|
    {
 | 
						|
      lb->ip1 = 0;
 | 
						|
      state = state_after_sel;
 | 
						|
    }
 | 
						|
    if ( lb->ip1 != -1 && lb->ip2 == -1 )
 | 
						|
    {
 | 
						|
      /* there is no way that lb->ip1 can not be -1, and lb->ip2 is -1 for the
 | 
						|
      * last line, hence the following line will always work. */
 | 
						|
      lb->ip2 = text->line_breaks[cnt + 1].line_break - lb->line_break;
 | 
						|
      state = state_in_sel;
 | 
						|
    }
 | 
						|
    if ( lb->ip1 == -1 && lb->ip2 == -1 && state == state_in_sel )
 | 
						|
    {
 | 
						|
      lb->ip1 = 0;
 | 
						|
      if ( cnt < text->nbr_lines - 1 )
 | 
						|
        lb->ip2 = text->line_breaks[cnt + 1].line_break - lb->line_break;
 | 
						|
      else
 | 
						|
        lb->ip2 = strlen( &text->string[text->line_breaks[cnt].line_break] );
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function sets the selection.   if do_carets is false, then the caret is
 | 
						|
not turned on after setting selection.  this happens when editing is stopped.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_selection_set_internal( XI_TEXT * text, int ip1, int ip2,
 | 
						|
                int selection_start_ip, BOOLEAN do_carets, BOOLEAN map_font )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
 | 
						|
  if ( ! text->string )
 | 
						|
    return;
 | 
						|
  if ( ip1 > ip2 )
 | 
						|
  {
 | 
						|
    int temp;
 | 
						|
 | 
						|
    temp = ip1;
 | 
						|
    ip1 = ip2;
 | 
						|
    ip2 = temp;
 | 
						|
  }
 | 
						|
  text->ip1 = ip1;
 | 
						|
  len = strlen( text->string );
 | 
						|
  if ( ip2 > len )
 | 
						|
    ip2 = len;
 | 
						|
  text->ip2 = ip2;
 | 
						|
  text->selection_start_ip = selection_start_ip;
 | 
						|
  if ( !text->editing && do_carets )
 | 
						|
    return;
 | 
						|
  if ( map_font )
 | 
						|
    XinWindowFontMap( text->win, text->font );
 | 
						|
  if ( do_carets )
 | 
						|
    xi_text_caret_off( text );
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
    recalc_line_ips( text );
 | 
						|
    calc_delta_y( text );
 | 
						|
  }
 | 
						|
  else
 | 
						|
    calc_delta_x( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  xi_text_draw_internal( text, 0L, 0L, FALSE );
 | 
						|
  if ( do_carets )
 | 
						|
    xi_text_caret_on( text );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_selection_set( XI_TEXT * text, int ip1, int ip2 )
 | 
						|
{
 | 
						|
  xi_text_selection_set_internal( text, ip1, ip2, ip2, TRUE, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
xi_text_caret_off( XI_TEXT * text )
 | 
						|
{
 | 
						|
  XinWindowCaretOff( text->win );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
xi_text_caret_on( XI_TEXT * text )
 | 
						|
{
 | 
						|
  int cnt,
 | 
						|
  caret_base;
 | 
						|
  XI_TEXT_LINE_BREAK *lb;
 | 
						|
  int nbr_lines,
 | 
						|
  caret_line;
 | 
						|
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( text->max_lines_to_draw )
 | 
						|
      nbr_lines = min( xi_text_nbr_lines_get( text ), text->max_lines_to_draw );
 | 
						|
    else
 | 
						|
      nbr_lines = xi_text_nbr_lines_get( text );
 | 
						|
    if ( text->delta_y + nbr_lines > text->nbr_lines )
 | 
						|
      nbr_lines -= ( text->delta_y + nbr_lines - text->nbr_lines );
 | 
						|
    caret_base = text->prect.top + text->font_height;
 | 
						|
    for ( cnt = 0, caret_line = text->delta_y;
 | 
						|
          cnt < nbr_lines;
 | 
						|
          ++cnt, ++caret_line )
 | 
						|
    {
 | 
						|
      int ip;
 | 
						|
      BOOLEAN set_caret = FALSE;
 | 
						|
 | 
						|
      lb = &text->line_breaks[caret_line];
 | 
						|
      if ( lb->ip1 == lb->active_ip )
 | 
						|
      {
 | 
						|
        ip = lb->ip1;
 | 
						|
        set_caret = TRUE;
 | 
						|
      }
 | 
						|
      if ( lb->ip2 == lb->active_ip )
 | 
						|
      {
 | 
						|
        ip = lb->ip2;
 | 
						|
        set_caret = TRUE;
 | 
						|
      }
 | 
						|
      if ( set_caret )
 | 
						|
      {
 | 
						|
        char *str;
 | 
						|
        int x;
 | 
						|
        XinRect rect;
 | 
						|
 | 
						|
        str = &text->string[lb->line_break];
 | 
						|
        x = XinFontTextWidthGet( text->font, str, ip );
 | 
						|
        rect = text->prect;
 | 
						|
        rect.right = rect.left + text->internal_pix_width;
 | 
						|
        xi_rect_intersect( &rect, &rect, &text->clip_rect );
 | 
						|
        xi_caret_on( text->win, text->prect.left + x, caret_base,
 | 
						|
                    text->font_height, &rect );
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      caret_base += text->font_height;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    int caret_base = text->prect.top + text->font_height;
 | 
						|
    int ip = ( text->selection_start_ip == text->ip1 ) ? text->ip2 : text->ip1;
 | 
						|
    int x;
 | 
						|
    char *pwc = "#";
 | 
						|
    int pwc_len;
 | 
						|
 | 
						|
    if ( text->password )
 | 
						|
    {
 | 
						|
      pwc_len = XinFontTextWidthGet( text->font, pwc, 1 );
 | 
						|
      x = pwc_len * ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      x = XinFontTextWidthGet( text->font, text->string, ip );
 | 
						|
 | 
						|
    if ( text->right_justify )
 | 
						|
    {
 | 
						|
      int len_in_pix = XinFontTextWidthGet( text->font, text->string, -1 );
 | 
						|
      int len = strlen( text->string );
 | 
						|
      int delta_x_pix = XinFontTextWidthGet( text->font,
 | 
						|
                          &text->string[len - text->delta_x], text->delta_x );
 | 
						|
      int hpos = text->prect.right - len_in_pix + delta_x_pix + x;
 | 
						|
      XinRect r1 = text->prect;
 | 
						|
      XinRect r2 = text->clip_rect;
 | 
						|
      XinRect r3;
 | 
						|
 | 
						|
      /* only turn on caret if caret is in intersection of prect and clipping
 | 
						|
      * rect */
 | 
						|
      if ( xi_rect_intersect( &r3, &r1, &r2 ) )
 | 
						|
      {
 | 
						|
        int caret_height = text->font_height;
 | 
						|
 | 
						|
        if ( hpos >= r3.left && hpos <= r3.right )
 | 
						|
        {
 | 
						|
          if ( caret_base > r3.bottom )
 | 
						|
          {
 | 
						|
            int delta = caret_base - r3.bottom;
 | 
						|
 | 
						|
            caret_base -= delta;
 | 
						|
            caret_height -= delta;
 | 
						|
          }
 | 
						|
          xi_caret_on( text->win, hpos,
 | 
						|
                      caret_base, caret_height, &r3 );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int delta_x_pix;
 | 
						|
      XinRect r1 = text->prect;
 | 
						|
      XinRect r2 = text->clip_rect;
 | 
						|
      XinRect r3;
 | 
						|
      int hpos;
 | 
						|
 | 
						|
      if ( text->password )
 | 
						|
        delta_x_pix = pwc_len * text->delta_x;
 | 
						|
      else
 | 
						|
        delta_x_pix = XinFontTextWidthGet( text->font, text->string, text->delta_x );
 | 
						|
      hpos = text->prect.left + x - delta_x_pix;
 | 
						|
      /* only turn on caret if caret is in intersection of prect and clipping
 | 
						|
      * rect */
 | 
						|
      if ( xi_rect_intersect( &r3, &r1, &r2 ) )
 | 
						|
      {
 | 
						|
        int caret_height = text->font_height;
 | 
						|
 | 
						|
        if ( hpos >= r3.left && hpos <= r3.right )
 | 
						|
        {
 | 
						|
          xi_caret_on( text->win, hpos, caret_base,
 | 
						|
                      caret_height, &r3 );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_editing_start( XI_TEXT * text )
 | 
						|
{
 | 
						|
  if ( text->editing == TRUE )
 | 
						|
    return;
 | 
						|
  text->editing = TRUE;
 | 
						|
  if ( text->scrollbar && !text->scrollbar_always_visible )
 | 
						|
  {
 | 
						|
    XinWindowDef Def;
 | 
						|
    XinRect rct;
 | 
						|
 | 
						|
    MEMCLEAR( Def );
 | 
						|
    Def.control_id = text->cid;
 | 
						|
    Def.type = XinWindowTypeVerticalScrollBar;
 | 
						|
    rct.top = text->prect.top;
 | 
						|
    rct.bottom = text->prect.bottom;
 | 
						|
    rct.right = text->prect.left + text->internal_pix_width + SB_DELTA + text->sb_width;
 | 
						|
    rct.left = text->prect.left + text->internal_pix_width + SB_DELTA;
 | 
						|
    Def.p_rect = &rct;
 | 
						|
    Def.title = "";
 | 
						|
    Def.visible = TRUE;
 | 
						|
    Def.enabled = TRUE;
 | 
						|
    Def.parent = text->win;
 | 
						|
    if ( text->sb_win != XI_NULL_WINDOW )
 | 
						|
      XinWindowDestroy( text->sb_win );
 | 
						|
    text->sb_win = XinWindowCreate( &Def );
 | 
						|
  }
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
    recalc_line_ips( text );
 | 
						|
    calc_delta_y( text );
 | 
						|
  }
 | 
						|
  else
 | 
						|
    calc_delta_x( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  xi_text_draw_internal( text, 0L, 0L, FALSE );
 | 
						|
  xi_text_caret_on( text );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_selection_get( XI_TEXT * text, int *c1, int *c2 )
 | 
						|
{
 | 
						|
  *c1 = text->ip1;
 | 
						|
  *c2 = text->ip2;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_selection_get_internal( XI_TEXT * text, int *c1, int *c2, int *start_ip )
 | 
						|
{
 | 
						|
  *c1 = text->ip1;
 | 
						|
  *c2 = text->ip2;
 | 
						|
  *start_ip = text->selection_start_ip;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
save_text_state( XI_TEXT * text )
 | 
						|
{
 | 
						|
  save_text = xi_tree_malloc( sizeof( XI_TEXT ), NULL );
 | 
						|
  save_text->string = xi_tree_malloc( strlen( text->string ) + 1, save_text );
 | 
						|
  save_text->font = text->font;
 | 
						|
  strcpy( save_text->string, text->string );
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    save_text->line_breaks = xi_tree_malloc( sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines, text );
 | 
						|
    memcpy( save_text->line_breaks, text->line_breaks, sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines );
 | 
						|
  }
 | 
						|
  save_text->nbr_lines = text->nbr_lines;
 | 
						|
  save_text->ip1 = text->ip1;
 | 
						|
  save_text->ip2 = text->ip2;
 | 
						|
  save_text->delta_y = text->delta_y;
 | 
						|
  save_text->delta_x = text->delta_x;
 | 
						|
  save_text->selection_start_ip = text->selection_start_ip;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
display_if_necessary( XI_TEXT * text, BOOLEAN recalc_delta_y )
 | 
						|
{
 | 
						|
/*  This contains a hack for Mac - xvt_dwin_scroll_rect is not called
 | 
						|
    the scrollbar position does not update */
 | 
						|
#if XIWS == XIWS_MAC
 | 
						|
  BOOLEAN scrolled_rect = FALSE;
 | 
						|
#endif
 | 
						|
  xi_text_caret_off( text );
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
    recalc_line_ips( text );
 | 
						|
  }
 | 
						|
  xi_text_draw( text, 0L, 0L, FALSE );
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( recalc_delta_y )
 | 
						|
      calc_delta_y( text );
 | 
						|
  }
 | 
						|
  else
 | 
						|
    calc_delta_x( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( save_text && save_text->delta_y != text->delta_y )
 | 
						|
  {
 | 
						|
    int delta = save_text->delta_y - text->delta_y;
 | 
						|
    XinRect r;
 | 
						|
 | 
						|
    /* need to do this here, because a Paint event will come thru */
 | 
						|
    free_save_text_state(  );
 | 
						|
    xi_set_update_obj( text->parent_obj );
 | 
						|
    r = text->prect;
 | 
						|
    r.bottom = r.top + text->max_lines_to_draw * text->font_height;
 | 
						|
    r.right = r.left + text->internal_pix_width;
 | 
						|
    xi_scroll_rect( text->win, &r, 0,
 | 
						|
                    delta * text->font_height );
 | 
						|
#if XIWS == XIWS_MAC
 | 
						|
    scrolled_rect = TRUE;
 | 
						|
#endif
 | 
						|
 | 
						|
  }
 | 
						|
  if ( save_text && save_text->delta_x != text->delta_x )
 | 
						|
  {
 | 
						|
    if ( text->right_justify )
 | 
						|
    {
 | 
						|
      int old_delta_x_pix = XinFontTextWidthGet( save_text->font,
 | 
						|
        &save_text->string[strlen( save_text->string ) - save_text->delta_x],
 | 
						|
                                                save_text->delta_x );
 | 
						|
      int delta_x_pix = XinFontTextWidthGet( text->font,
 | 
						|
                        &text->string[strlen( text->string ) - text->delta_x],
 | 
						|
                                            text->delta_x );
 | 
						|
      XinRect r;
 | 
						|
 | 
						|
      /* need to do this here, because a Paint event will come thru */
 | 
						|
      free_save_text_state(  );
 | 
						|
      xi_set_update_obj( text->parent_obj );
 | 
						|
      r = text->prect;
 | 
						|
      r.bottom = r.top + text->font_height;
 | 
						|
      r.left = r.right - text->internal_pix_width;
 | 
						|
      xi_scroll_rect( text->win, &r, delta_x_pix - old_delta_x_pix, 0 );
 | 
						|
#if XIWS == XIWS_MAC
 | 
						|
      scrolled_rect = TRUE;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int old_delta_x_pix = XinFontTextWidthGet( save_text->font, save_text->string,
 | 
						|
                                                save_text->delta_x );
 | 
						|
      int delta_x_pix = XinFontTextWidthGet( text->font, text->string,
 | 
						|
                                            text->delta_x );
 | 
						|
      XinRect r;
 | 
						|
 | 
						|
      /* need to do this here, because a Paint event will come thru */
 | 
						|
      free_save_text_state(  );
 | 
						|
      xi_set_update_obj( text->parent_obj );
 | 
						|
      r = text->prect;
 | 
						|
      r.bottom = r.top + text->font_height;
 | 
						|
      r.right = r.left + text->internal_pix_width;
 | 
						|
      xi_scroll_rect( text->win, &r, old_delta_x_pix - delta_x_pix, 0 );
 | 
						|
#if XIWS == XIWS_MAC
 | 
						|
      scrolled_rect = TRUE;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
  }
 | 
						|
#if XIWS == XIWS_MAC
 | 
						|
  if (!scrolled_rect)
 | 
						|
  {
 | 
						|
    XinRect r;
 | 
						|
    r = text->prect;
 | 
						|
    r.bottom = r.top + text->font_height;
 | 
						|
    r.right = r.left + text->internal_pix_width;
 | 
						|
    xi_scroll_rect( text->win, &r, 0, 0 );
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  xi_text_caret_on( text );
 | 
						|
  if ( save_text )
 | 
						|
    free_save_text_state(  );
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
get_line_from_ip( XI_TEXT * text, int ip )
 | 
						|
{
 | 
						|
  int cnt;
 | 
						|
 | 
						|
  for ( cnt = 0; cnt < text->nbr_lines; ++cnt )
 | 
						|
  {
 | 
						|
    if ( text->line_breaks[cnt].line_break > ip )
 | 
						|
      return ( cnt - 1 );
 | 
						|
  }
 | 
						|
  return ( text->nbr_lines - 1 );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
calc_delta_y( XI_TEXT * text )
 | 
						|
{
 | 
						|
  int ip,
 | 
						|
  line;
 | 
						|
 | 
						|
  if ( text->nbr_lines <= text->max_lines_to_draw )
 | 
						|
  {
 | 
						|
    text->delta_y = 0;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if ( text->ip1 == text->selection_start_ip )
 | 
						|
    ip = text->ip2;
 | 
						|
  else
 | 
						|
    ip = text->ip1;
 | 
						|
  line = get_line_from_ip( text, ip );
 | 
						|
  if ( line < text->delta_y )
 | 
						|
  {
 | 
						|
    text->delta_y = line;
 | 
						|
    if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw )
 | 
						|
      text->delta_y = text->nbr_lines - text->max_lines_to_draw;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if ( line > text->delta_y + ( text->max_lines_to_draw - 1 ) )
 | 
						|
  {
 | 
						|
    text->delta_y += line - ( text->delta_y + ( text->max_lines_to_draw - 1 ) );
 | 
						|
    if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw )
 | 
						|
      text->delta_y = text->nbr_lines - text->max_lines_to_draw;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw )
 | 
						|
    text->delta_y = text->nbr_lines - text->max_lines_to_draw;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function calculates text->delta_x such that the insertion point that is
 | 
						|
not the selection start insertion point is visible.
 | 
						|
*/
 | 
						|
static void
 | 
						|
calc_delta_x( XI_TEXT * text )
 | 
						|
{
 | 
						|
  int ip,
 | 
						|
  delta_x_pix,
 | 
						|
  dx,
 | 
						|
  ip_pix,
 | 
						|
  cnt;
 | 
						|
  int len = strlen( text->string );
 | 
						|
 | 
						|
  if ( text->ip1 == text->selection_start_ip )
 | 
						|
    ip = text->ip2;
 | 
						|
  else
 | 
						|
    ip = text->ip1;
 | 
						|
  if ( text->right_justify )
 | 
						|
  {
 | 
						|
    /* for a right justified field, if the insertion point is to the right of
 | 
						|
    * the visible area, then delta_x is easy to calculate.  it is the length
 | 
						|
    * of the string minus the insertion point. */
 | 
						|
    if ( ( len - ip ) < text->delta_x )
 | 
						|
    {
 | 
						|
      text->delta_x = len - ip;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    /* for a left justified field, if the insertion point is to the left of the
 | 
						|
    * visible area, then delta_x is easy to calculate.  it is the insertion
 | 
						|
    * point. */
 | 
						|
    if ( ip < text->delta_x )
 | 
						|
    {
 | 
						|
      text->delta_x = ip;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ( text->right_justify )
 | 
						|
  {
 | 
						|
    /* for a right justified field, if the insertion point is to the left of
 | 
						|
    * the visible area, then the algorythm is as follows: 1. calculate the
 | 
						|
    * length of delta_x in pixels 2. calculate the length of the string from
 | 
						|
    * ip to the end of the string 3. calculate the number of pixels that we
 | 
						|
    * must make visible: (2) - (1) - internal pixel width 4. count the number
 | 
						|
    * of characters from delta_x, going to the left, until the length of the
 | 
						|
    * characters is greater than (3) */
 | 
						|
    delta_x_pix = XinFontTextWidthGet( text->font,
 | 
						|
                          &text->string[len - text->delta_x], text->delta_x );
 | 
						|
    ip_pix = XinFontTextWidthGet( text->font, &text->string[ip], -1 );
 | 
						|
    dx = ip_pix - delta_x_pix - text->internal_pix_width;
 | 
						|
    for ( cnt = text->delta_x; cnt < len; ++cnt )
 | 
						|
      if ( XinFontTextWidthGet( text->font, &text->string[len - cnt], cnt - text->delta_x ) > dx )
 | 
						|
        break;
 | 
						|
    text->delta_x = cnt;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    /* for a left justified field, if the insertion point is to the right of
 | 
						|
    * the visible area, then the algorythm is as follows: 1. calculate the
 | 
						|
    * length of delta_x in pixels 2. calculate the length of the string from
 | 
						|
    * the beginning of the string to the insertion point 3. calculate the
 | 
						|
    * number of pixels that we must make visible: (2) - (1) - internal pixel
 | 
						|
    * width 4. count the number of characters from delta_x, going to the
 | 
						|
    * right, until the length of the characters is greater than (3) */
 | 
						|
    delta_x_pix = XinFontTextWidthGet( text->font, text->string, text->delta_x );
 | 
						|
    ip_pix = XinFontTextWidthGet( text->font, text->string, ip );
 | 
						|
    dx = ip_pix - delta_x_pix - text->internal_pix_width;
 | 
						|
    for ( cnt = text->delta_x; cnt < len; ++cnt )
 | 
						|
      if ( XinFontTextWidthGet( text->font, &text->string[text->delta_x], cnt - text->delta_x ) >= dx )
 | 
						|
        break;
 | 
						|
    text->delta_x = cnt;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this is a utility function that returns the text and line length for a given line.
 | 
						|
 | 
						|
this function is only used if the xi_text is multi_line.
 | 
						|
*/
 | 
						|
static char *
 | 
						|
get_line( XI_TEXT * text, int line, int *line_len )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
  char *s;
 | 
						|
 | 
						|
  s = &text->string[text->line_breaks[line].line_break];
 | 
						|
  if ( line < text->nbr_lines - 1 )
 | 
						|
    len = text->line_breaks[line + 1].line_break -
 | 
						|
            text->line_breaks[line].line_break;
 | 
						|
  else
 | 
						|
    len = strlen( s );
 | 
						|
  if ( line_len )
 | 
						|
    *line_len = len;
 | 
						|
  return s;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
the functions key_left, key_right, key_line_home, key_line_end, key_word_left,
 | 
						|
  key_word_right, key_backspace, key_delete, key_character manipulate the xi_text
 | 
						|
  when editing.  no modifications are necessary for single, multi_line, or
 | 
						|
  right justified edit controls.
 | 
						|
 | 
						|
the functions key_up, key_page_up, key_down, key_page_down are only used for
 | 
						|
  multi-line edit controls.
 | 
						|
*/
 | 
						|
static void
 | 
						|
key_left( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->selection_start_ip = text->ip2;
 | 
						|
      if ( text->ip1 >= 1 )
 | 
						|
        --text->ip1;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->ip1 >= 1 )
 | 
						|
        text->selection_start_ip = text->ip1 = --text->ip2;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if ( text->ip1 == text->selection_start_ip )
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
      text->ip2--;
 | 
						|
    else
 | 
						|
      text->selection_start_ip = text->ip1 = --text->ip2;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      if ( text->ip1 >= 1 )
 | 
						|
        text->ip1--;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int new_ip = text->ip1;
 | 
						|
 | 
						|
      if ( text->ip1 >= 1 )
 | 
						|
        new_ip = text->ip1 - 1;
 | 
						|
      text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_right( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->selection_start_ip = text->ip1;
 | 
						|
      if ( text->ip2 < ( int ) strlen( text->string ) )
 | 
						|
        ++text->ip2;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->ip2 < ( int ) strlen( text->string ) )
 | 
						|
        text->selection_start_ip = text->ip1 = ++text->ip2;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else if ( text->ip2 == text->selection_start_ip )
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
      text->ip1++;
 | 
						|
    else
 | 
						|
      text->selection_start_ip = text->ip2 = ++text->ip1;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      if ( text->ip2 < ( int ) strlen( text->string ) )
 | 
						|
        text->ip2++;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int new_ip = text->ip2;
 | 
						|
 | 
						|
      if ( text->ip2 < ( int ) strlen( text->string ) )
 | 
						|
        new_ip = text->ip2 + 1;
 | 
						|
      text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static BOOLEAN
 | 
						|
get_ip_one_line_above( XI_TEXT * text, int ip, int *new_ip )
 | 
						|
{
 | 
						|
  int line,
 | 
						|
  pix_len;
 | 
						|
  char *s;
 | 
						|
  char *pls;
 | 
						|
 | 
						|
  line = get_line_from_ip( text, ip );
 | 
						|
  if ( line >= 1 )
 | 
						|
  {
 | 
						|
    int cnt,
 | 
						|
    len;
 | 
						|
 | 
						|
    s = get_line( text, line, NULL );
 | 
						|
    pix_len = XinFontTextWidthGet( text->font, s, ip - text->line_breaks[line].line_break );
 | 
						|
    pls = get_line( text, line - 1, &len );
 | 
						|
    for ( cnt = 0; cnt < len; ++cnt )
 | 
						|
    {
 | 
						|
      int lpix_len;
 | 
						|
 | 
						|
      lpix_len = XinFontTextWidthGet( text->font, pls, cnt );
 | 
						|
      if ( lpix_len >= pix_len )
 | 
						|
      {
 | 
						|
        *new_ip = text->line_breaks[line - 1].line_break + cnt;
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    *new_ip = text->line_breaks[line - 1].line_break + cnt - 1;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static BOOLEAN
 | 
						|
key_up( XI_TEXT * text, XinEvent * ep, BOOLEAN redisplay )
 | 
						|
{
 | 
						|
  if ( !text->multi_line )
 | 
						|
    return FALSE;
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_above( text, text->ip1, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip1 = new_ip;
 | 
						|
        text->selection_start_ip = text->ip2;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  if ( text->selection_start_ip == text->ip1 )
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_above( text, text->ip2, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip2 = new_ip;
 | 
						|
        if ( text->ip2 < text->ip1 )
 | 
						|
        {
 | 
						|
          int temp;
 | 
						|
 | 
						|
          temp = text->ip1;
 | 
						|
          text->ip1 = text->ip2;
 | 
						|
          text->ip2 = temp;
 | 
						|
          text->selection_start_ip = text->ip2;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      }
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_above( text, text->ip1, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
        text->ip1 = new_ip;
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    } else if ( text->ip1 != text->ip2 && !ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->selection_start_ip = text->ip2 = text->ip1;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_page_up( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  int cnt;
 | 
						|
 | 
						|
  if ( !text->multi_line )
 | 
						|
    return;
 | 
						|
  for ( cnt = 0; cnt < text->max_lines_to_draw; ++cnt )
 | 
						|
    key_up( text, ep, FALSE );
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static BOOLEAN
 | 
						|
get_ip_one_line_below( XI_TEXT * text, int ip, int *new_ip )
 | 
						|
{
 | 
						|
  int line,
 | 
						|
  pix_len;
 | 
						|
  char *s;
 | 
						|
  char *pls;
 | 
						|
 | 
						|
  line = get_line_from_ip( text, ip );
 | 
						|
  if ( line < text->nbr_lines - 1 )
 | 
						|
  {
 | 
						|
    int cnt,
 | 
						|
    len;
 | 
						|
 | 
						|
    s = get_line( text, line, NULL );
 | 
						|
    pix_len = XinFontTextWidthGet( text->font, s, ip - text->line_breaks[line].line_break );
 | 
						|
    pls = get_line( text, line + 1, &len );
 | 
						|
    for ( cnt = 0; cnt < len; ++cnt )
 | 
						|
    {
 | 
						|
      int lpix_len;
 | 
						|
 | 
						|
      lpix_len = XinFontTextWidthGet( text->font, pls, cnt );
 | 
						|
      if ( lpix_len >= pix_len )
 | 
						|
      {
 | 
						|
        *new_ip = text->line_breaks[line + 1].line_break + cnt;
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    *new_ip = text->line_breaks[line + 1].line_break + cnt - 1;
 | 
						|
    if ( line + 1 == text->nbr_lines - 1 )
 | 
						|
      ++* new_ip;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static BOOLEAN
 | 
						|
key_down( XI_TEXT * text, XinEvent * ep, BOOLEAN redisplay )
 | 
						|
{
 | 
						|
  if ( !text->multi_line )
 | 
						|
    return FALSE;
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_below( text, text->ip1, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip2 = new_ip;
 | 
						|
        text->selection_start_ip = text->ip1;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
  if ( text->selection_start_ip == text->ip2 )
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_below( text, text->ip1, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip1 = new_ip;
 | 
						|
        if ( text->ip2 < text->ip1 )
 | 
						|
        {
 | 
						|
          int temp;
 | 
						|
 | 
						|
          temp = text->ip1;
 | 
						|
          text->ip1 = text->ip2;
 | 
						|
          text->ip2 = temp;
 | 
						|
          text->selection_start_ip = text->ip1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    int new_ip;
 | 
						|
 | 
						|
    if ( get_ip_one_line_below( text, text->ip2, &new_ip ) )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
        text->ip2 = new_ip;
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = new_ip;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    } else if ( text->ip1 != text->ip2 && !ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->selection_start_ip = text->ip1 = text->ip2;
 | 
						|
      if ( redisplay )
 | 
						|
        display_if_necessary( text, TRUE );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_page_down( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  int cnt;
 | 
						|
 | 
						|
  if ( !text->multi_line )
 | 
						|
    return;
 | 
						|
  for ( cnt = 0; cnt < text->max_lines_to_draw; ++cnt )
 | 
						|
    key_down( text, ep, FALSE );
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_line_home( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( text->ip1 == text->ip2 )
 | 
						|
    {
 | 
						|
      int home_ip,
 | 
						|
      line;
 | 
						|
 | 
						|
      line = get_line_from_ip( text, text->ip1 );
 | 
						|
      home_ip = text->line_breaks[line].line_break;
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip1 = home_ip;
 | 
						|
        text->selection_start_ip = text->ip2;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = home_ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->selection_start_ip == text->ip1 )
 | 
						|
      {
 | 
						|
        int home_ip,
 | 
						|
        line;
 | 
						|
 | 
						|
        line = get_line_from_ip( text, text->ip2 );
 | 
						|
        home_ip = text->line_breaks[line].line_break;
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
        {
 | 
						|
          text->ip2 = home_ip;
 | 
						|
          if ( text->ip2 < text->ip1 )
 | 
						|
          {
 | 
						|
            int temp;
 | 
						|
 | 
						|
            temp = text->ip1;
 | 
						|
            text->ip1 = text->ip2;
 | 
						|
            text->ip2 = temp;
 | 
						|
            text->selection_start_ip = text->ip1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = home_ip;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        int home_ip,
 | 
						|
        line;
 | 
						|
 | 
						|
        line = get_line_from_ip( text, text->ip1 );
 | 
						|
        home_ip = text->line_breaks[line].line_break;
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
          text->ip1 = home_ip;
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = home_ip;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( text->ip1 == text->ip2 )
 | 
						|
    {
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip1 = 0;
 | 
						|
        text->selection_start_ip = text->ip2;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = 0;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->selection_start_ip == text->ip1 )
 | 
						|
      {
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
        {
 | 
						|
          text->ip2 = 0;
 | 
						|
          if ( text->ip2 < text->ip1 )
 | 
						|
          {
 | 
						|
            int temp;
 | 
						|
 | 
						|
            temp = text->ip1;
 | 
						|
            text->ip1 = text->ip2;
 | 
						|
            text->ip2 = temp;
 | 
						|
            text->selection_start_ip = text->ip1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = 0;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
          text->ip1 = 0;
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_line_end( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( text->ip1 == text->ip2 )
 | 
						|
    {
 | 
						|
      int end_ip,
 | 
						|
      line,
 | 
						|
      len;
 | 
						|
 | 
						|
      line = get_line_from_ip( text, text->ip1 );
 | 
						|
      get_line( text, line, &len );
 | 
						|
      end_ip = text->line_breaks[line].line_break + len - 1;
 | 
						|
      if ( line == text->nbr_lines - 1 )
 | 
						|
        ++end_ip;
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip2 = end_ip;
 | 
						|
        text->selection_start_ip = text->ip1;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->selection_start_ip == text->ip1 )
 | 
						|
      {
 | 
						|
        int end_ip,
 | 
						|
        line,
 | 
						|
        len;
 | 
						|
 | 
						|
        line = get_line_from_ip( text, text->ip2 );
 | 
						|
        get_line( text, line, &len );
 | 
						|
        end_ip = text->line_breaks[line].line_break + len - 1;
 | 
						|
        if ( line == text->nbr_lines - 1 )
 | 
						|
          ++end_ip;
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
          text->ip2 = end_ip;
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        int end_ip,
 | 
						|
        line,
 | 
						|
        len;
 | 
						|
 | 
						|
        line = get_line_from_ip( text, text->ip2 );
 | 
						|
        get_line( text, line, &len );
 | 
						|
        if ( line == text->nbr_lines - 1 )
 | 
						|
          end_ip = text->line_breaks[line].line_break + len;
 | 
						|
        else
 | 
						|
          end_ip = text->line_breaks[line].line_break + len - 1;
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
        {
 | 
						|
          text->ip1 = end_ip;
 | 
						|
          if ( text->ip2 < text->ip1 )
 | 
						|
          {
 | 
						|
            int temp;
 | 
						|
 | 
						|
            temp = text->ip1;
 | 
						|
            text->ip1 = text->ip2;
 | 
						|
            text->ip2 = temp;
 | 
						|
            text->selection_start_ip = text->ip1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( text->ip1 == text->ip2 )
 | 
						|
    {
 | 
						|
      int end_ip;
 | 
						|
 | 
						|
      end_ip = strlen( text->string );
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip2 = end_ip;
 | 
						|
        text->selection_start_ip = text->ip1;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( text->selection_start_ip == text->ip1 )
 | 
						|
      {
 | 
						|
        int end_ip;
 | 
						|
 | 
						|
        end_ip = strlen( text->string );
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
          text->ip2 = end_ip;
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        int end_ip;
 | 
						|
 | 
						|
        end_ip = strlen( text->string );
 | 
						|
        if ( ep->v.character.shift )
 | 
						|
        {
 | 
						|
          text->ip1 = end_ip;
 | 
						|
          if ( text->ip2 < text->ip1 )
 | 
						|
          {
 | 
						|
            int temp;
 | 
						|
 | 
						|
            temp = text->ip1;
 | 
						|
            text->ip1 = text->ip2;
 | 
						|
            text->ip2 = temp;
 | 
						|
            text->selection_start_ip = text->ip1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else
 | 
						|
          text->selection_start_ip = text->ip1 = text->ip2 = end_ip;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
get_ip_one_word_left( XI_TEXT * text, int ip )
 | 
						|
{
 | 
						|
  int line;
 | 
						|
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    line = get_line_from_ip( text, ip );
 | 
						|
    if ( ip == text->line_breaks[line].line_break )
 | 
						|
    {
 | 
						|
      int len;
 | 
						|
 | 
						|
      if ( line == 0 )
 | 
						|
        return ip;
 | 
						|
      --line;
 | 
						|
      get_line( text, line, &len );
 | 
						|
      return text->line_breaks[line].line_break + len - 1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ( !text->multi_line )
 | 
						|
  {
 | 
						|
    if ( ip == 0 )
 | 
						|
      return ip;
 | 
						|
  }
 | 
						|
  /* move back one character, to get away from the beginning of a word */
 | 
						|
  --ip;
 | 
						|
  /* find the first character that is not white space */
 | 
						|
  while ( TRUE )
 | 
						|
  {
 | 
						|
    if ( text->multi_line )
 | 
						|
    {
 | 
						|
      if ( ip == text->line_breaks[line].line_break )
 | 
						|
        return ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( ip == 0 )
 | 
						|
        return ip;
 | 
						|
    }
 | 
						|
    if ( is_word_char( text->string[ip] ) )
 | 
						|
    {
 | 
						|
      /* find the first character that is white space */
 | 
						|
      while ( TRUE )
 | 
						|
      {
 | 
						|
        if ( text->multi_line )
 | 
						|
        {
 | 
						|
          if ( ip == text->line_breaks[line].line_break )
 | 
						|
            return ip;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          if ( ip == 0 )
 | 
						|
            return ip;
 | 
						|
        }
 | 
						|
        if ( !is_word_char( text->string[ip] ) )
 | 
						|
          return ip;
 | 
						|
        --ip;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    --ip;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_word_left( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    int left_ip;
 | 
						|
 | 
						|
    left_ip = get_ip_one_word_left( text, text->ip1 );
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->ip1 = left_ip;
 | 
						|
      text->selection_start_ip = text->ip2;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      text->selection_start_ip = text->ip1 = text->ip2 = left_ip;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( text->selection_start_ip == text->ip1 )
 | 
						|
    {
 | 
						|
      int left_ip;
 | 
						|
 | 
						|
      left_ip = get_ip_one_word_left( text, text->ip2 );
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip2 = left_ip;
 | 
						|
        if ( text->ip2 < text->ip1 )
 | 
						|
        {
 | 
						|
          int temp;
 | 
						|
 | 
						|
          temp = text->ip1;
 | 
						|
          text->ip1 = text->ip2;
 | 
						|
          text->ip2 = temp;
 | 
						|
          text->selection_start_ip = text->ip2;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = left_ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int left_ip;
 | 
						|
 | 
						|
      left_ip = get_ip_one_word_left( text, text->ip1 );
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
        text->ip1 = left_ip;
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = left_ip;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
get_ip_one_word_right( XI_TEXT * text, int ip )
 | 
						|
{
 | 
						|
  int line,
 | 
						|
  len,
 | 
						|
  string_len;
 | 
						|
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    line = get_line_from_ip( text, ip );
 | 
						|
    get_line( text, line, &len );
 | 
						|
    if ( ip == text->line_breaks[line].line_break + len )
 | 
						|
    {
 | 
						|
      if ( line == text->nbr_lines - 1 )
 | 
						|
        return ip;
 | 
						|
      ++line;
 | 
						|
      return text->line_breaks[line].line_break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  string_len = strlen( text->string );
 | 
						|
  while ( TRUE )
 | 
						|
  {
 | 
						|
    if ( text->multi_line )
 | 
						|
    {
 | 
						|
      if ( ip == text->line_breaks[line].line_break + len )
 | 
						|
        return ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( ip == string_len )
 | 
						|
        return ip;
 | 
						|
    }
 | 
						|
    if ( is_word_char( text->string[ip] ) )
 | 
						|
    {
 | 
						|
      while ( TRUE )
 | 
						|
      {
 | 
						|
        if ( text->multi_line )
 | 
						|
        {
 | 
						|
          if ( ip == text->line_breaks[line].line_break + len )
 | 
						|
            return ip;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          if ( ip == string_len )
 | 
						|
            return ip;
 | 
						|
        }
 | 
						|
        if ( !is_word_char( text->string[ip] ) )
 | 
						|
        {
 | 
						|
          while ( TRUE )
 | 
						|
          {
 | 
						|
            if ( text->multi_line )
 | 
						|
            {
 | 
						|
              if ( ip == text->line_breaks[line].line_break + len )
 | 
						|
                return ip;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
              if ( ip == string_len )
 | 
						|
                return ip;
 | 
						|
            }
 | 
						|
            if ( is_word_char( text->string[ip] ) )
 | 
						|
              return ip;
 | 
						|
            ++ip;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        ++ip;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    ++ip;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_word_right( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    int right_ip;
 | 
						|
 | 
						|
    right_ip = get_ip_one_word_right( text, text->ip1 );
 | 
						|
    if ( ep->v.character.shift )
 | 
						|
    {
 | 
						|
      text->ip2 = right_ip;
 | 
						|
      text->selection_start_ip = text->ip1;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      text->selection_start_ip = text->ip1 = text->ip2 = right_ip;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( text->selection_start_ip == text->ip2 )
 | 
						|
    {
 | 
						|
      int right_ip;
 | 
						|
 | 
						|
      right_ip = get_ip_one_word_right( text, text->ip1 );
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
      {
 | 
						|
        text->ip1 = right_ip;
 | 
						|
        if ( text->ip2 < text->ip1 )
 | 
						|
        {
 | 
						|
          int temp;
 | 
						|
 | 
						|
          temp = text->ip1;
 | 
						|
          text->ip1 = text->ip2;
 | 
						|
          text->ip2 = temp;
 | 
						|
          text->selection_start_ip = text->ip1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = right_ip;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int right_ip;
 | 
						|
 | 
						|
      right_ip = get_ip_one_word_right( text, text->ip2 );
 | 
						|
      if ( ep->v.character.shift )
 | 
						|
        text->ip2 = right_ip;
 | 
						|
      else
 | 
						|
        text->selection_start_ip = text->ip1 = text->ip2 = right_ip;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
delete_selection( XI_TEXT * text, BOOLEAN redisplay )
 | 
						|
{
 | 
						|
  memmove( &text->string[text->ip1],
 | 
						|
          &text->string[text->ip2],
 | 
						|
          strlen( text->string ) - text->ip2 + 1 );
 | 
						|
  text->selection_start_ip = text->ip2 = text->ip1;
 | 
						|
  if ( redisplay )
 | 
						|
    display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_backspace( XI_TEXT * text, BOOLEAN * changed )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    if ( text->ip1 >= 1 )
 | 
						|
    {
 | 
						|
      memmove( &text->string[text->ip1 - 1],
 | 
						|
              &text->string[text->ip1],
 | 
						|
              strlen( text->string ) - text->ip1 + 1 );
 | 
						|
      text->selection_start_ip = text->ip2 = --text->ip1;
 | 
						|
      display_if_necessary( text, TRUE );
 | 
						|
      if ( changed )
 | 
						|
        *changed = TRUE;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( changed )
 | 
						|
        *changed = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    delete_selection( text, TRUE );
 | 
						|
    if ( changed )
 | 
						|
      *changed = TRUE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
key_delete( XI_TEXT * text, BOOLEAN * changed )
 | 
						|
{
 | 
						|
  if ( text->ip1 == text->ip2 )
 | 
						|
  {
 | 
						|
    int len;
 | 
						|
 | 
						|
    len = strlen( text->string );
 | 
						|
    if ( text->ip2 <= len - 1 )
 | 
						|
    {
 | 
						|
      memmove( &text->string[text->ip2],
 | 
						|
              &text->string[text->ip2 + 1],
 | 
						|
              len - text->ip2 + 1 );
 | 
						|
      display_if_necessary( text, TRUE );
 | 
						|
      if ( changed )
 | 
						|
        *changed = TRUE;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if ( changed )
 | 
						|
        *changed = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    delete_selection( text, TRUE );
 | 
						|
    if ( changed )
 | 
						|
      *changed = TRUE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static BOOLEAN
 | 
						|
key_character( XI_TEXT * text, XinEvent * ep, BOOLEAN * changed )
 | 
						|
{
 | 
						|
  int len;
 | 
						|
  int ch;
 | 
						|
 | 
						|
  if ( changed )
 | 
						|
    *changed = FALSE;
 | 
						|
  if ( ep->v.character.ch > 255 )
 | 
						|
    return FALSE;
 | 
						|
  if ( ep->v.character.ch == '\r' || ep->v.character.ch == '\n' )
 | 
						|
  {
 | 
						|
    if ( !text->cr_ok || text->read_only )
 | 
						|
      return FALSE;
 | 
						|
  }
 | 
						|
  else if ( ep->v.character.ch < 128 && !isprint( ep->v.character.ch ) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  ch = ep->v.character.ch;
 | 
						|
  if ( ch == '\r' )
 | 
						|
    ch = '\n';
 | 
						|
  len = strlen( text->string );
 | 
						|
  if ( text->ip1 != text->ip2 )
 | 
						|
  {
 | 
						|
    delete_selection( text, FALSE );
 | 
						|
    if ( changed )
 | 
						|
      *changed = TRUE;
 | 
						|
  }
 | 
						|
  len = strlen( text->string );
 | 
						|
  if ( text->var_len_text || ( ( int ) len < text->buffer_size - 1 ) )
 | 
						|
  {
 | 
						|
    if (text->var_len_text)
 | 
						|
      reallocate_text( text, len + 2, FALSE );
 | 
						|
    memmove( &text->string[text->ip1 + 1],
 | 
						|
            &text->string[text->ip1],
 | 
						|
            len - text->ip1 + 1 );
 | 
						|
    text->string[text->ip1] = ch;
 | 
						|
    text->selection_start_ip = text->ip1 = ++text->ip2;
 | 
						|
    if ( changed )
 | 
						|
      *changed = TRUE;
 | 
						|
    if ( len + 2 > text->buffer_size )
 | 
						|
      text->buffer_size = len + 2;
 | 
						|
  }
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function is changes delta_y when the user operates the scroll bar on a
 | 
						|
multi-line edit control.
 | 
						|
 | 
						|
this function is only used for multi_line edit controls.
 | 
						|
*/
 | 
						|
static void
 | 
						|
move_delta( XI_TEXT * text, int nbr_lines )
 | 
						|
{
 | 
						|
  if ( nbr_lines < 0 )
 | 
						|
  {
 | 
						|
    nbr_lines = -nbr_lines;
 | 
						|
    if ( text->delta_y >= nbr_lines )
 | 
						|
      text->delta_y -= nbr_lines;
 | 
						|
    else
 | 
						|
      text->delta_y = 0;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( text->delta_y + nbr_lines < text->nbr_lines - text->max_lines_to_draw )
 | 
						|
      text->delta_y += nbr_lines;
 | 
						|
    else
 | 
						|
    {
 | 
						|
      text->delta_y = text->nbr_lines - text->max_lines_to_draw;
 | 
						|
      if ( text->delta_y < 0 )
 | 
						|
        text->delta_y = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  display_if_necessary( text, FALSE );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function is changes delta_y when the user operates the scroll bar on a
 | 
						|
multi-line edit control.
 | 
						|
 | 
						|
this function is only used for multi_line edit controls.
 | 
						|
*/
 | 
						|
static void
 | 
						|
set_pos_delta( XI_TEXT * text, int pos, int prop )
 | 
						|
{
 | 
						|
  int new_pos;
 | 
						|
 | 
						|
  new_pos = ( int ) ( ( ( double ) text->nbr_lines - ( double ) text->max_lines_to_draw ) *
 | 
						|
                      ( double ) pos / ( double ) ( 1000 - prop ) );
 | 
						|
  if ( new_pos < 0 )
 | 
						|
    new_pos = 0;
 | 
						|
  text->delta_y = new_pos;
 | 
						|
  display_if_necessary( text, FALSE );
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
xi_text_point_hit_test( XinFont * font, char *str, int hpos, int last_ip, int del_x )
 | 
						|
{
 | 
						|
  int left_point,
 | 
						|
  right_point;
 | 
						|
  int x1,
 | 
						|
  x2,
 | 
						|
  x3;
 | 
						|
 | 
						|
  if ( hpos == 0 )
 | 
						|
  {
 | 
						|
    left_point = 0;
 | 
						|
    x1 = XinFontTextWidthGet( font, str, 1 );
 | 
						|
    right_point = x1 / 2;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    x1 = XinFontTextWidthGet( font, str, hpos - 1 );
 | 
						|
    x2 = XinFontTextWidthGet( font, &str[hpos - 1], 1 );
 | 
						|
    left_point = x1 + x2 / 2 + 1;
 | 
						|
    if ( hpos == last_ip )
 | 
						|
      right_point = x1 + x2;
 | 
						|
    else
 | 
						|
    {
 | 
						|
      x3 = XinFontTextWidthGet( font, &str[hpos], 1 );
 | 
						|
      right_point = x1 + x2 + x3 / 2;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if ( del_x < left_point )
 | 
						|
    return -1;
 | 
						|
  else if ( del_x > right_point )
 | 
						|
    return 1;
 | 
						|
  else
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this function returns an insertion point, given an XinEvent.
 | 
						|
 | 
						|
this function works by doing a binary search.
 | 
						|
*/
 | 
						|
static void
 | 
						|
xi_text_hit_test( XI_TEXT * text, XinEvent * ep, int *ip )
 | 
						|
{
 | 
						|
  int del_y,
 | 
						|
  del_x,
 | 
						|
  line,
 | 
						|
  len,
 | 
						|
  cnt,
 | 
						|
  last_ip;
 | 
						|
  int hpos,
 | 
						|
  d,
 | 
						|
  delta_x_pix,
 | 
						|
  max_str_len;
 | 
						|
  char *str;
 | 
						|
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
    if ( ep->v.mouse.where.v < text->prect.top )
 | 
						|
    {
 | 
						|
      int lines_above;
 | 
						|
 | 
						|
      lines_above = ( text->prect.top - ep->v.mouse.where.v ) / text->font_height + 1;
 | 
						|
      line = text->delta_y - lines_above;
 | 
						|
      if ( line < 0 )
 | 
						|
        line = 0;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      del_y = ep->v.mouse.where.v - text->prect.top;
 | 
						|
      line = del_y / text->font_height + text->delta_y;
 | 
						|
      if ( line >= text->nbr_lines )
 | 
						|
        line = text->nbr_lines - 1;
 | 
						|
    }
 | 
						|
    str = get_line( text, line, &len );
 | 
						|
    delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x );
 | 
						|
    del_x = ep->v.mouse.where.h - text->prect.left + delta_x_pix;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    len = strlen( text->string );
 | 
						|
    if ( text->password )
 | 
						|
      str = alloc_password_string( len, text );
 | 
						|
    else
 | 
						|
      str = text->string;
 | 
						|
    if ( text->right_justify )
 | 
						|
    {
 | 
						|
      /* calculate del_x.  del_x is the distance in pixels from the virtual
 | 
						|
      * beginning of the right justified text to the horizontal position of
 | 
						|
      * the mouse.  the code below works just fine if del_x is negative: ie if
 | 
						|
      * the mouse is to the left of the right justified text. */
 | 
						|
      int str_len_in_pix;
 | 
						|
 | 
						|
      delta_x_pix = XinFontTextWidthGet( text->font,
 | 
						|
                                  &str[len - text->delta_x], text->delta_x );
 | 
						|
      str_len_in_pix = XinFontTextWidthGet( text->font, str, -1 );
 | 
						|
      del_x = ep->v.mouse.where.h - ( text->prect.right - str_len_in_pix +
 | 
						|
                                      delta_x_pix );
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      /* calculate del_x.  del_x is the distance in pixels from the virtual
 | 
						|
      * beginning of the left justified text to the horizontal position of the
 | 
						|
      * mouse.  the code below works just fine if del_x is negative: ie if the
 | 
						|
      * mouse is to the left of the text. */
 | 
						|
      delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x );
 | 
						|
      del_x = ep->v.mouse.where.h - text->prect.left + delta_x_pix;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* binary search - find cnt where the mathmatical line between characters is
 | 
						|
  * closest to pix_len.
 | 
						|
  * 
 | 
						|
  * this binary search uses a deterministic algorythm.  by this, when starting
 | 
						|
  * searching, hpos is always a power of 2.  d is the delta that is added to
 | 
						|
  * or subtracted from hpos after each comparison.  d is initialized as hpos /
 | 
						|
  * 2. therefore, d is *always* a power of 2. */
 | 
						|
 | 
						|
  /* last_ip = len + 1, because there is one more possible insertion point than
 | 
						|
  * characters */
 | 
						|
  last_ip = len + 1;
 | 
						|
  hpos = 1;
 | 
						|
  while ( hpos <= last_ip )
 | 
						|
    hpos = hpos << 1;
 | 
						|
  d = hpos / 2;
 | 
						|
  --hpos;
 | 
						|
  if ( del_x < 0 )
 | 
						|
    del_x = 0;
 | 
						|
  max_str_len = XinFontTextWidthGet( text->font, str, len );
 | 
						|
  if ( del_x > max_str_len )
 | 
						|
    del_x = max_str_len;
 | 
						|
  while ( TRUE )
 | 
						|
  {
 | 
						|
    int result;
 | 
						|
 | 
						|
    if ( hpos > len )
 | 
						|
    {
 | 
						|
      if ( d == 0 )
 | 
						|
      {
 | 
						|
        cnt = len;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      hpos -= d;
 | 
						|
      d /= 2;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    result = xi_text_point_hit_test( text->font, str, hpos, last_ip, del_x );
 | 
						|
    if ( result == 0 )
 | 
						|
    {
 | 
						|
      cnt = hpos;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if ( result < 0 )
 | 
						|
    {
 | 
						|
      hpos -= d;
 | 
						|
      d /= 2;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      hpos += d;
 | 
						|
      d /= 2;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if ( text->multi_line )
 | 
						|
    *ip = text->line_breaks[line].line_break + cnt;
 | 
						|
  else
 | 
						|
    *ip = cnt;
 | 
						|
  if ( text->password )
 | 
						|
    xi_tree_free( str );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
only used if multi_line, and if there is a scroll bar.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_control_event( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  save_text_state( text );
 | 
						|
 | 
						|
  switch ( ep->v.control.ctrl_info.v.scroll.action )
 | 
						|
  {
 | 
						|
    case XinScrollBarActionLineUp:
 | 
						|
      move_delta( text, -1 );
 | 
						|
      break;
 | 
						|
    case XinScrollBarActionLineDown:
 | 
						|
      move_delta( text, 1 );
 | 
						|
      break;
 | 
						|
    case XinScrollBarActionPageUp:
 | 
						|
      move_delta( text, -text->max_lines_to_draw );
 | 
						|
      break;
 | 
						|
    case XinScrollBarActionPageDown:
 | 
						|
      move_delta( text, text->max_lines_to_draw );
 | 
						|
      break;
 | 
						|
    case XinScrollBarActionThumb:
 | 
						|
    case XinScrollBarActionThumbTrack:
 | 
						|
      {
 | 
						|
        int percent = ep->v.control.ctrl_info.v.scroll.position;
 | 
						|
        int prop = XinScrollBarProportionGet( text->sb_win, XinScrollBarTypeEither );
 | 
						|
 | 
						|
        set_pos_delta( text, percent, prop );
 | 
						|
        break;
 | 
						|
      }
 | 
						|
  }
 | 
						|
  if ( save_text )
 | 
						|
    free_save_text_state(  );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
xi_text_character_event, xi_text_mouse_down_event, xi_text_mouse_double_event,
 | 
						|
xi_text_mouse_move_event, and xi_text_mouse_up_event don't care whether the
 | 
						|
xi_text is single or multi_line, or if it is right justified.
 | 
						|
*/
 | 
						|
BOOLEAN
 | 
						|
xi_text_character_event( XI_TEXT * text, XinEvent * ep, BOOLEAN * changed )
 | 
						|
{
 | 
						|
  BOOLEAN retval;
 | 
						|
 | 
						|
  save_text_state( text );
 | 
						|
  switch ( ep->v.character.ch )
 | 
						|
  {
 | 
						|
    case XI_KEY_LEFT:
 | 
						|
      key_left( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_RIGHT:
 | 
						|
      key_right( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_UP:
 | 
						|
      retval = key_up( text, ep, TRUE );
 | 
						|
      break;
 | 
						|
    case XI_KEY_DOWN:
 | 
						|
      retval = key_down( text, ep, TRUE );
 | 
						|
      break;
 | 
						|
    case XI_KEY_PREV:
 | 
						|
      key_page_up( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_NEXT:
 | 
						|
      key_page_down( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_LHOME:
 | 
						|
    case XI_KEY_HOME:
 | 
						|
      key_line_home( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_LEND:
 | 
						|
    case XI_KEY_END:
 | 
						|
      key_line_end( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_WLEFT:
 | 
						|
      key_word_left( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_WRIGHT:
 | 
						|
      key_word_right( text, ep );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case '\b':
 | 
						|
      if ( !text->read_only )
 | 
						|
        key_backspace( text, changed );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    case XI_KEY_DEL:
 | 
						|
      if ( !text->read_only )
 | 
						|
        key_delete( text, changed );
 | 
						|
      retval = TRUE;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      if ( text->read_only )
 | 
						|
      {
 | 
						|
        if ( ep->v.character.ch == '\033' || 
 | 
						|
            ep->v.character.ch == '\r' ||
 | 
						|
            ep->v.character.ch == '\n' )
 | 
						|
        {
 | 
						|
          if ( save_text )
 | 
						|
            free_save_text_state(  );
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
        if ( (ep->v.character.ch != '\r' && ep->v.character.ch != '\n')
 | 
						|
              || !text->itf->v.itf->tab_on_enter )
 | 
						|
        {
 | 
						|
          if ( save_text )
 | 
						|
            free_save_text_state(  );
 | 
						|
          return TRUE;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      retval = key_character( text, ep, changed );
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  if ( save_text )
 | 
						|
    free_save_text_state(  );
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_mouse_down_event( XI_TEXT * text, XinEvent * ep, BOOLEAN gaining_focus )
 | 
						|
{
 | 
						|
  int ip;
 | 
						|
 | 
						|
  if ( text->timer_set )
 | 
						|
  {
 | 
						|
    XinWindowTimerKill( text->win, text->timer_id );
 | 
						|
    text->timer_set = FALSE;
 | 
						|
    text->timer_id = 0;
 | 
						|
    xi_text_selection_set( text, 0, 32000 );
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  if ( gaining_focus && ( text->parent_obj == 0 ||
 | 
						|
                ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT ) ) &&
 | 
						|
      xi_get_pref( XI_PREF_AUTOSEL_ON_MOUSE ) )
 | 
						|
  {
 | 
						|
    xi_text_selection_set( text, 0, INT_MAX );
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  xi_text_hit_test( text, ep, &ip );
 | 
						|
  if ( ep->v.mouse.shift )
 | 
						|
  {
 | 
						|
    if ( text->selection_start_ip == text->ip1 )
 | 
						|
      xi_text_selection_set_internal( text, text->ip1, ip, text->ip1, TRUE, FALSE );
 | 
						|
    else
 | 
						|
      xi_text_selection_set_internal( text, ip, text->ip2, text->ip2, TRUE, FALSE );
 | 
						|
  }
 | 
						|
  else
 | 
						|
    xi_text_selection_set_internal( text, ip, ip, ip, TRUE, FALSE );
 | 
						|
  XinWindowMouseTrap( text->win, TRUE );
 | 
						|
  text->selecting = TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_mouse_double_event( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  int ip,
 | 
						|
  right_ip,
 | 
						|
  left_ip;
 | 
						|
  long time;
 | 
						|
 | 
						|
  xi_text_hit_test( text, ep, &ip );
 | 
						|
  right_ip = get_ip_one_word_right( text, ip );
 | 
						|
  if ( text->string[right_ip - 1] == ' ' )
 | 
						|
    --right_ip;
 | 
						|
  left_ip = get_ip_one_word_left( text, ip );
 | 
						|
  if ( text->string[left_ip] == ' ' )
 | 
						|
    ++left_ip;
 | 
						|
  xi_text_selection_set_internal( text, left_ip, right_ip, left_ip, TRUE, FALSE );
 | 
						|
  XinWindowMouseTrap( text->win, TRUE );
 | 
						|
  text->double_selecting = TRUE;
 | 
						|
  text->double_selecting_start_ip = ip;
 | 
						|
  time = xi_get_pref( XI_PREF_TRIPLE_CLICK_TIME );
 | 
						|
  if ( time )
 | 
						|
  {
 | 
						|
    text->timer_id = XinWindowTimerSet( text->win, time );
 | 
						|
    text->timer_set = TRUE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_mouse_move_event( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  int ip;
 | 
						|
 | 
						|
  if ( text->selecting )
 | 
						|
  {
 | 
						|
    xi_text_hit_test( text, ep, &ip );
 | 
						|
    if ( ip < text->selection_start_ip )
 | 
						|
      xi_text_selection_set_internal( text, ip, text->selection_start_ip,
 | 
						|
                                      text->selection_start_ip, TRUE, FALSE );
 | 
						|
    else
 | 
						|
      xi_text_selection_set_internal( text, text->selection_start_ip, ip,
 | 
						|
                                      text->selection_start_ip, TRUE, FALSE );
 | 
						|
  }
 | 
						|
  if ( text->double_selecting )
 | 
						|
  {
 | 
						|
    xi_text_hit_test( text, ep, &ip );
 | 
						|
    if ( ip < text->double_selecting_start_ip )
 | 
						|
    {
 | 
						|
      int left_ip,
 | 
						|
      right_ip;
 | 
						|
 | 
						|
      left_ip = get_ip_one_word_left( text, ip );
 | 
						|
      if ( text->string[left_ip] == ' ' )
 | 
						|
        ++left_ip;
 | 
						|
      right_ip = get_ip_one_word_right( text, text->double_selecting_start_ip );
 | 
						|
      if ( text->string[right_ip - 1] == ' ' )
 | 
						|
        --right_ip;
 | 
						|
      xi_text_selection_set_internal( text, left_ip, right_ip,
 | 
						|
                                      right_ip, TRUE, FALSE );
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      int left_ip,
 | 
						|
      right_ip;
 | 
						|
 | 
						|
      right_ip = get_ip_one_word_right( text, ip );
 | 
						|
      if ( text->string[right_ip - 1] == ' ' )
 | 
						|
        --right_ip;
 | 
						|
      left_ip = get_ip_one_word_left( text, text->double_selecting_start_ip );
 | 
						|
      if ( text->string[left_ip] == ' ' )
 | 
						|
        ++left_ip;
 | 
						|
      xi_text_selection_set_internal( text, left_ip, right_ip,
 | 
						|
                                      left_ip, TRUE, FALSE );
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_mouse_up_event( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  int ip;
 | 
						|
 | 
						|
  if ( text->selecting )
 | 
						|
  {
 | 
						|
    xi_text_hit_test( text, ep, &ip );
 | 
						|
    if ( ip < text->selection_start_ip )
 | 
						|
      xi_text_selection_set_internal( text, ip, text->selection_start_ip,
 | 
						|
                                      text->selection_start_ip, TRUE, FALSE );
 | 
						|
    else
 | 
						|
      xi_text_selection_set_internal( text, text->selection_start_ip, ip,
 | 
						|
                                      text->selection_start_ip, TRUE, FALSE );
 | 
						|
    XinWindowMouseRelease(  );
 | 
						|
    text->selecting = FALSE;
 | 
						|
  }
 | 
						|
  if ( text->double_selecting )
 | 
						|
  {
 | 
						|
    XinWindowMouseRelease(  );
 | 
						|
    text->double_selecting = FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_timer_event( XI_TEXT * text, XinEvent * ep )
 | 
						|
{
 | 
						|
  if ( ep->v.timer.id == text->timer_id )
 | 
						|
  {
 | 
						|
    XinWindowTimerKill( text->win, ep->v.timer.id );
 | 
						|
    text->timer_id = 0;
 | 
						|
    text->timer_set = FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
all events are passed to this function.
 | 
						|
*/
 | 
						|
BOOLEAN
 | 
						|
xi_text_event( XI_TEXT * text, XinEvent * ep, BOOLEAN gaining_focus, BOOLEAN * changed )
 | 
						|
{
 | 
						|
  BOOLEAN retval = FALSE;
 | 
						|
 | 
						|
  if ( changed )
 | 
						|
    *changed = FALSE;
 | 
						|
  text = text;
 | 
						|
  if ( !text )
 | 
						|
    return retval;
 | 
						|
  switch ( ep->type )
 | 
						|
  {
 | 
						|
    case XinEventControl:
 | 
						|
      xi_text_control_event( text, ep );
 | 
						|
      break;
 | 
						|
    case XinEventCharacter:
 | 
						|
      retval = xi_text_character_event( text, ep, changed );
 | 
						|
      break;
 | 
						|
    case XinEventPaint:
 | 
						|
      xi_text_draw( text, 0L, 0L, TRUE );
 | 
						|
      break;
 | 
						|
    case XinEventMouseDown:
 | 
						|
      xi_text_mouse_down_event( text, ep, gaining_focus );
 | 
						|
      break;
 | 
						|
    case XinEventMouseDouble:
 | 
						|
      xi_text_mouse_double_event( text, ep );
 | 
						|
      break;
 | 
						|
    case XinEventMouseMove:
 | 
						|
      xi_text_mouse_move_event( text, ep );
 | 
						|
      break;
 | 
						|
    case XinEventMouseUp:
 | 
						|
      xi_text_mouse_up_event( text, ep );
 | 
						|
      break;
 | 
						|
    case XinEventTimer:
 | 
						|
      xi_text_timer_event( text, ep );
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
this stops editing for an xi_text.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_editing_stop( XI_TEXT * text )
 | 
						|
{
 | 
						|
  if ( text->editing == FALSE )
 | 
						|
    return;
 | 
						|
  xi_text_caret_off( text );
 | 
						|
  xi_text_selection_set_internal( text, 0, 0, 0, FALSE, TRUE );
 | 
						|
  text->editing = FALSE;
 | 
						|
  if ( text->sb_win && !text->scrollbar_always_visible )
 | 
						|
  {
 | 
						|
    if ( !xi_itf_in_event_destroy( text->itf ) )
 | 
						|
      XinWindowDestroy( text->sb_win );
 | 
						|
    text->sb_win = XI_NULL_WINDOW;
 | 
						|
  }
 | 
						|
  if ( save_text )
 | 
						|
    free_save_text_state(  );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
this function sets the physical rectangle for an xi_text.
 | 
						|
*/
 | 
						|
void
 | 
						|
xi_text_prect_set( XI_TEXT * text, XinRect * rctp )
 | 
						|
{
 | 
						|
  int pix_width;
 | 
						|
  BOOLEAN changed = FALSE;
 | 
						|
 | 
						|
  if ( text->prect.top != rctp->top || text->prect.bottom != rctp->bottom ||
 | 
						|
      text->prect.left != rctp->left || text->prect.right != rctp->right )
 | 
						|
    changed = TRUE;
 | 
						|
 | 
						|
  text->prect = *( rctp );
 | 
						|
  if ( text->font_height == 0 )
 | 
						|
  {
 | 
						|
    XinFont *font;
 | 
						|
    int char_width;
 | 
						|
 | 
						|
    font = text->font;
 | 
						|
    xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width );
 | 
						|
    text->font_height = text->ascent + text->descent + text->leading;
 | 
						|
  }
 | 
						|
  text->max_lines_to_draw = ( rctp->bottom - rctp->top ) / text->font_height;
 | 
						|
  if ( text->max_lines_to_draw < 1 )
 | 
						|
    text->max_lines_to_draw = 1;
 | 
						|
  pix_width = rctp->right - rctp->left;
 | 
						|
  text->pix_width = pix_width;
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA;
 | 
						|
    if ( changed && ( text->scrollbar_always_visible || text->sb_win ) )
 | 
						|
    {
 | 
						|
      XinWindowDef Def;
 | 
						|
      XinRect rct;
 | 
						|
 | 
						|
      MEMCLEAR( Def );
 | 
						|
      Def.control_id = text->cid;
 | 
						|
      Def.type = XinWindowTypeVerticalScrollBar;
 | 
						|
      rct.top = text->prect.top;
 | 
						|
      rct.bottom = text->prect.bottom;
 | 
						|
      rct.right = text->prect.left + text->internal_pix_width + SB_DELTA + text->sb_width;
 | 
						|
      rct.left = text->prect.left + text->internal_pix_width + SB_DELTA;
 | 
						|
      Def.p_rect = &rct;
 | 
						|
      Def.title = "";
 | 
						|
      Def.visible = text->visible;
 | 
						|
      Def.enabled = TRUE;
 | 
						|
      Def.parent = text->win;
 | 
						|
      if ( text->sb_win != XI_NULL_WINDOW )
 | 
						|
        XinWindowDestroy( text->sb_win );
 | 
						|
      text->sb_win = XinWindowCreate( &Def );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
    text->internal_pix_width = text->pix_width;
 | 
						|
}
 | 
						|
 | 
						|
XI_TEXT *
 | 
						|
xi_text_focus_get( XinWindow win )
 | 
						|
{
 | 
						|
  XI_OBJ *itf,
 | 
						|
  *focus_obj;
 | 
						|
 | 
						|
  itf = xi_get_itf( win );
 | 
						|
  focus_obj = xi_get_focus( itf );
 | 
						|
  if ( focus_obj )
 | 
						|
  {
 | 
						|
    switch ( focus_obj->type )
 | 
						|
    {
 | 
						|
      case XIT_CELL:
 | 
						|
        return lm_xi_text_focus_get( focus_obj->parent->v.list->lm );
 | 
						|
      case XIT_FIELD:
 | 
						|
        return stx_xi_text_get( focus_obj->v.field->stx );
 | 
						|
      default:
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_buffer_size_set( XI_TEXT * text, int len )
 | 
						|
{
 | 
						|
  int ip1, ip2, sip;
 | 
						|
  BOOLEAN reset_ips = FALSE;
 | 
						|
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    ip1 = text->ip1;
 | 
						|
    ip2 = text->ip2;
 | 
						|
    sip = text->selection_start_ip;
 | 
						|
    reset_ips = TRUE;
 | 
						|
  }
 | 
						|
  if ( len < text->buffer_size )
 | 
						|
    text->initialized = FALSE;
 | 
						|
  text->buffer_size = len;
 | 
						|
  reallocate_text( text, len, TRUE );
 | 
						|
  xi_text_wrap( text );
 | 
						|
  if ( reset_ips )
 | 
						|
  {
 | 
						|
    ip1 = min( ip1, len - 1 );
 | 
						|
    ip2 = min( ip2, len - 1 );
 | 
						|
    sip = min( sip, len - 1 );
 | 
						|
    xi_text_selection_set_internal( text, ip1, ip2, sip, TRUE, TRUE );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_font_set( XI_TEXT * text, XinFont * font )
 | 
						|
{
 | 
						|
  int char_width;
 | 
						|
  BOOLEAN restart = FALSE;
 | 
						|
 | 
						|
  if ( xi_text_editing_is( text ) )
 | 
						|
  {
 | 
						|
    xi_text_editing_stop( text );
 | 
						|
    restart = TRUE;
 | 
						|
  }
 | 
						|
  text->font = font;
 | 
						|
  xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width );
 | 
						|
  text->font_height = text->ascent + text->descent + text->leading;
 | 
						|
  text->max_lines_to_draw = ( text->prect.bottom - text->prect.top ) / text->font_height;
 | 
						|
  if ( text->max_lines_to_draw < 1 )
 | 
						|
    text->max_lines_to_draw = 1;
 | 
						|
  if ( text->multi_line )
 | 
						|
    xi_text_wrap_internal( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
    xi_text_sb_set( text );
 | 
						|
  if ( restart )
 | 
						|
    xi_text_editing_start( text );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_visible_set( XI_TEXT * text, BOOLEAN visible )
 | 
						|
{
 | 
						|
  text->visible = visible;
 | 
						|
  if ( text->sb_win )
 | 
						|
  {
 | 
						|
    XinWindowShow( text->sb_win, visible );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
XinRect *
 | 
						|
xi_text_rect_get_adjusted( XI_TEXT * text, XinRect * rcta )
 | 
						|
{
 | 
						|
  if ( text->scrollbar )
 | 
						|
  {
 | 
						|
    if ( !text->sb_width )
 | 
						|
      text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth );
 | 
						|
    rcta->right = rcta->right - text->sb_width - SB_DELTA;
 | 
						|
  }
 | 
						|
 | 
						|
  return ( rcta );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_paste_internal( XI_TEXT * text, char *string )
 | 
						|
{
 | 
						|
  int len, len2;
 | 
						|
  int cnt,
 | 
						|
  ip;
 | 
						|
  char *str;
 | 
						|
 | 
						|
  if ( text->read_only )
 | 
						|
      return;
 | 
						|
 | 
						|
  if ( text->ip1 != text->ip2 )
 | 
						|
    delete_selection( text, TRUE );
 | 
						|
 | 
						|
  len = strlen( text->string );
 | 
						|
  len2 = strlen( string );
 | 
						|
 | 
						|
  str = xi_tree_malloc( len + len2 + 1, NULL );
 | 
						|
 | 
						|
/* New string in the middle */
 | 
						|
  if ( text->ip1 > 0 && text->ip1 < len )
 | 
						|
  {
 | 
						|
    gstrncpy( str, text->string, text->ip1 );
 | 
						|
    strcat( str, string );
 | 
						|
    ip = strlen( str );
 | 
						|
    for ( cnt = text->ip1; cnt < len; ++cnt )
 | 
						|
    {
 | 
						|
      str[ip] = text->string[cnt];
 | 
						|
      ++ip;
 | 
						|
    }
 | 
						|
  }
 | 
						|
/* there is nothing in the field, so simply use the string passed */
 | 
						|
  else if ( len <= 0 )
 | 
						|
    strcpy( str, string );
 | 
						|
  else
 | 
						|
/* New string at the end */
 | 
						|
  if ( text->ip1 >= len )
 | 
						|
  {
 | 
						|
    strcpy( str, text->string );
 | 
						|
    strcat( str, string );
 | 
						|
  }
 | 
						|
/* New string at beginning */
 | 
						|
  else
 | 
						|
  {
 | 
						|
    strcpy( str, string );
 | 
						|
    strcat( str, text->string );
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  len = reallocate_text( text, strlen( str ) + 1, FALSE );
 | 
						|
  memcpy( text->string, str, len );
 | 
						|
  xi_tree_free( str );
 | 
						|
 | 
						|
  text->string[ len - 1 ] = '\0';
 | 
						|
 | 
						|
  if ( text->ip2 > len - 1 )
 | 
						|
    text->ip2 = len - 1;
 | 
						|
  if ( !text->editing )
 | 
						|
    return;
 | 
						|
  XinWindowFontMap( text->win, text->font );
 | 
						|
/*
 | 
						|
  xi_text_caret_off( text );
 | 
						|
 | 
						|
  if ( text->multi_line )
 | 
						|
  {
 | 
						|
        xi_text_wrap_internal( text );
 | 
						|
        recalc_line_ips( text );
 | 
						|
        calc_delta_y( text );
 | 
						|
  }
 | 
						|
  else
 | 
						|
        calc_delta_x( text );
 | 
						|
  if ( text->sb_win )
 | 
						|
        xi_text_sb_set( text );
 | 
						|
  xi_text_draw_internal( text, 0L, 0L, FALSE );
 | 
						|
 | 
						|
  xi_text_caret_on( text );
 | 
						|
*/
 | 
						|
  display_if_necessary( text, TRUE );
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xi_text_right_justify_set( XI_TEXT* text, BOOLEAN flag )
 | 
						|
{
 | 
						|
  text->right_justify = flag;
 | 
						|
  if ( text->multi_line )
 | 
						|
    text->right_justify = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* }]) */
 |