36d6a7f5e7
Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione 22.1 patch 246 git-svn-id: svn://10.65.10.50/trunk@12818 c028cbd2-c16b-5b4b-a496-9718f37d4682
3391 lines
90 KiB
C
Executable File
3391 lines
90 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"
|
|
#include <limits.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 = NULL;
|
|
int cnt,
|
|
nbr_lines = 0,
|
|
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 = NULL;
|
|
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 = 0;
|
|
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 = 0;
|
|
|
|
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
|
|
ep->v.character.ch = XI_KEY_BTAB; // AGA was here
|
|
}
|
|
}
|
|
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;
|
|
else
|
|
ep->v.character.ch = XI_KEY_BTAB; // AGA was here
|
|
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
|
|
ep->v.character.ch = '\t'; // AGA was here
|
|
}
|
|
}
|
|
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;
|
|
else
|
|
ep->v.character.ch = '\t'; // AGA was here
|
|
|
|
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 = 0;
|
|
|
|
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 = 0,
|
|
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 = 0,
|
|
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;
|
|
}
|
|
default:
|
|
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;
|
|
case XI_KEY_F3:
|
|
case XI_KEY_F4:
|
|
retval = key_character( text, ep, changed ); // Added by AGA
|
|
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;
|
|
default:
|
|
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 = 0, ip2 = 0, sip = 0;
|
|
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;
|
|
}
|
|
|
|
/* }]) */
|