1997-12-17 10:43:31 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* Copyright 1991-1995 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 "xiutils.h"
|
|
|
|
#include "xilm.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#if XIWS == MTFWS
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/StringDefs.h>
|
|
|
|
#include <X11/Intrinsic.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Error codes 30200-30206 */
|
|
|
|
|
|
|
|
#define TXT_REDRAW_ATR (TXT_ATR_RJUST | TXT_ATR_ENABLED | TXT_ATR_BORDER | TXT_ATR_VISIBLE)
|
|
|
|
#define TXT_ACTIVE_ATR (TXT_ATR_ENABLED | TXT_ATR_VISIBLE)
|
|
|
|
#define BS 8
|
|
|
|
|
|
|
|
#if XVT_OS == XVT_OS_CTOS
|
|
|
|
#define BORDER_WIDTH_X ((npctos_env == CHSERVICE) ? 8 : 1)
|
|
|
|
#define BORDER_WIDTH_Y ((npctos_env == CHSERVICE) ? 0 : 1)
|
|
|
|
#define BORDER_SPACE_X ((npctos_env == CHSERVICE) ? 0 : 1)
|
|
|
|
#define BORDER_SPACE_Y ((npctos_env == CHSERVICE) ? 0 : 1)
|
|
|
|
#define CHR_LEFTBRACKET "["
|
|
|
|
#define CHR_RIGHTBRACKET "]"
|
|
|
|
#else
|
|
|
|
#if XIWS != WMWS
|
|
|
|
#define BORDER_WIDTH_X 1
|
|
|
|
#define BORDER_WIDTH_Y 1
|
|
|
|
#define BORDER_SPACE_X 1
|
|
|
|
#define BORDER_SPACE_Y 1
|
|
|
|
#else
|
|
|
|
#define BORDER_WIDTH_X 8
|
|
|
|
#define BORDER_WIDTH_Y 0
|
|
|
|
#define BORDER_SPACE_X 0
|
|
|
|
#define BORDER_SPACE_Y 0
|
|
|
|
#define CHR_LEFTBRACKET "["
|
|
|
|
#define CHR_RIGHTBRACKET "]"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef NO_PRIMARY_SELECTION
|
|
|
|
#if XIWS == MTFWS
|
|
|
|
/* statics used for implementing cut, copy & paste with the PRIMARY selection */
|
|
|
|
static char *primesel_text = NULL; /* text for primary selection */
|
|
|
|
static int primesel_len; /* length of primary selection */
|
|
|
|
static Widget primesel_widget = NULL; /* widget owning primary selection */
|
|
|
|
|
|
|
|
/* deliver_primesel - this functions delivers the value of the primary
|
|
|
|
selection when another application or something else in this application
|
|
|
|
requests it
|
|
|
|
*/
|
|
|
|
static Boolean
|
|
|
|
deliver_primesel(Widget widget, Atom *selection, Atom *target,
|
|
|
|
Atom *type, XtPointer *value, unsigned long *length, int *format)
|
|
|
|
{
|
|
|
|
static Atom xa_targets = 0;
|
|
|
|
XrmValue source, dest;
|
|
|
|
|
|
|
|
/* printf("deliver_primesel: ENTERED, widget %d, selection %d, target %d\n",
|
|
|
|
widget, *selection, *target); */
|
|
|
|
|
|
|
|
/* get value for Atom "TARGETS" */
|
|
|
|
if (xa_targets == 0)
|
|
|
|
{
|
|
|
|
source.size = strlen("TARGETS") + 1;
|
|
|
|
source.addr = "TARGETS";
|
|
|
|
dest.size = sizeof(Atom);
|
|
|
|
dest.addr = (XtPointer) &xa_targets;
|
|
|
|
(void) XtConvertAndStore(primesel_widget, XtRString, &source, XtRAtom,
|
|
|
|
&dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle request for PRIMARY selection as a string */
|
|
|
|
if (*target == XA_STRING)
|
|
|
|
{
|
|
|
|
*type = XA_STRING;
|
|
|
|
*value = (XtPointer) XtNewString(primesel_text);
|
|
|
|
*length = primesel_len;
|
|
|
|
*format = 8;
|
|
|
|
/* printf("deliver_primesel: RETURNING primary selection '%s'\n",
|
|
|
|
primesel_text); */
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle request for TARGETS */
|
|
|
|
if (*target == xa_targets)
|
|
|
|
{
|
|
|
|
/* printf("deliver_primesel: RETURNING targets \n"); */
|
|
|
|
*type = XA_ATOM;
|
|
|
|
*value = (XtPointer) XtNew(Atom);
|
|
|
|
*(Atom *) *value = XA_STRING;
|
|
|
|
*length = 1;
|
|
|
|
*format = 32;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* anything else return FALSE */
|
|
|
|
/* printf("deliver_primesel: RETURNING FALSE\n"); */
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void clean_primesel()
|
|
|
|
{
|
|
|
|
if (primesel_text)
|
|
|
|
xvt_mem_free(primesel_text);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
lose_primesel - this function is called by the Intrinsics when
|
|
|
|
the primary selection is lost to another application
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
lose_primesel(Widget widget, Atom *selection)
|
|
|
|
{
|
|
|
|
/* printf("lose_primesel: ENTERED, widget %d, selection %d\n", */
|
|
|
|
/* widget, *selection); */
|
|
|
|
primesel_widget = NULL;
|
|
|
|
if (primesel_text)
|
|
|
|
xvt_mem_free(primesel_text);
|
|
|
|
primesel_text = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void xi_widgetDestroyCallBack(Widget w, XtPointer closure, XtPointer data)
|
|
|
|
{
|
|
|
|
/* need to define a local Atom bcos lose_primesel expects it */
|
|
|
|
Atom garbageAtom;
|
|
|
|
lose_primesel(w, &garbageAtom);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set_primary_selection - this function sets or clears the primary selection
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
set_primary_selection(WINDOW win, char *txt, int len)
|
|
|
|
{
|
|
|
|
Widget widget;
|
|
|
|
Time time;
|
|
|
|
|
|
|
|
/* printf("set_primary_selection: ENTERED, win %d, len %d\n", win, len); */
|
|
|
|
|
|
|
|
/* check if clearing selection */
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
/* The following clears the selection if an insertion point is set. */
|
|
|
|
if (primesel_widget != NULL)
|
|
|
|
{
|
|
|
|
/* printf("set_primary_selection: clearing selection\n"); */
|
|
|
|
XtDisownSelection(primesel_widget, XA_PRIMARY,
|
|
|
|
XtLastTimestampProcessed(XtDisplay(primesel_widget)));
|
|
|
|
xvt_mem_free(primesel_text);
|
|
|
|
primesel_text = NULL;
|
|
|
|
primesel_widget = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate space and save text string */
|
|
|
|
primesel_text = xvt_mem_alloc(len + 1);
|
|
|
|
/* xvt_errmsg_sig_if not NULL "out of memory" */
|
|
|
|
strncpy(primesel_text, txt, len);
|
|
|
|
primesel_text[len] = '\0';
|
|
|
|
primesel_len = len;
|
|
|
|
|
|
|
|
/* get widget and selection time */
|
|
|
|
widget = (Widget) xvt_vobj_get_attr(win, ATTR_X_WIDGET);
|
|
|
|
time = XtLastTimestampProcessed(XtDisplay(widget));
|
|
|
|
|
|
|
|
/* try to take ownership of the primary selection */
|
|
|
|
/* printf("set_primary_selection: before XtOwnSelection\n"); */
|
|
|
|
/* printf(" widget %d, text '%s', len %d, time %d\n",
|
|
|
|
widget, primesel_text, primesel_len, time); */
|
|
|
|
if (XtOwnSelection(widget, XA_PRIMARY, time, deliver_primesel,
|
|
|
|
lose_primesel, NULL))
|
|
|
|
{
|
|
|
|
/* printf("set_primary_selection: XtOwnSelection SUCCESSFUL\n"); */
|
|
|
|
|
|
|
|
XtAddCallback(widget, XtNdestroyCallback, xi_widgetDestroyCallBack,
|
|
|
|
(XtPointer)NULL);
|
|
|
|
|
|
|
|
primesel_widget = widget;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* printf("set_primary_selection: XtOwnSelection FAILED\n"); */
|
|
|
|
xvt_mem_free(primesel_text);
|
|
|
|
primesel_text = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(NO_PRIMARY_SELECTION) || XIWS != MTFWS
|
|
|
|
static void
|
|
|
|
set_primary_selection(WINDOW win, char *txt, int len)
|
|
|
|
{
|
|
|
|
NOREF(win);
|
|
|
|
NOREF(txt);
|
|
|
|
NOREF(len);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if XIWS == PMWS
|
|
|
|
#define recalc_hit_test(a)
|
|
|
|
#else
|
|
|
|
|
|
|
|
static void
|
|
|
|
recalc_hit_test(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *s;
|
|
|
|
short *h;
|
|
|
|
|
|
|
|
if (! txt->hit_test)
|
|
|
|
txt->hit_test = (short *)xi_tree_malloc(txt->text_size * sizeof(short), txt);
|
|
|
|
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
for (i = 0, s = txt->text, h = txt->hit_test; i < txt->len;
|
|
|
|
i++, s++, h++)
|
|
|
|
*h = (short)xi_get_text_width(txt->win, s, 1, txt->attrib);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
stx_get_text_width(TXT_DATA *txt, short *hit_test, char *text, int len)
|
|
|
|
{
|
|
|
|
#if XIWS == PMWS
|
|
|
|
NOREF(hit_test);
|
|
|
|
return xi_get_text_width(txt->win, text, len, txt->attrib);
|
|
|
|
#else
|
|
|
|
int c, r;
|
|
|
|
short *s;
|
|
|
|
|
|
|
|
NOREF(txt);
|
|
|
|
NOREF(text);
|
|
|
|
r = 0;
|
|
|
|
for (c = 0, s = hit_test; c < len; ++c, ++s)
|
|
|
|
r += *s;
|
|
|
|
return r;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static DRAW_CTOOLS * near
|
|
|
|
get_txt_ctools(TXT_DATA *txt, DRAW_CTOOLS *ct, FONT_OBJ *font,
|
|
|
|
BOOLEAN do_border, BOOLEAN inverted)
|
|
|
|
{
|
|
|
|
COLOR fore_color, back_color;
|
|
|
|
|
|
|
|
if (inverted)
|
|
|
|
{
|
|
|
|
fore_color = txt->back_color;
|
|
|
|
if (! txt->hilight_color && (txt->well || txt->platform))
|
|
|
|
fore_color = xi_get_pref(XI_PREF_COLOR_CTRL);
|
|
|
|
back_color = txt->fore_color;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
back_color = txt->back_color;
|
|
|
|
if (! txt->hilight_color && (txt->well || txt->platform))
|
|
|
|
back_color = xi_get_pref(XI_PREF_COLOR_CTRL);
|
|
|
|
fore_color = txt->fore_color;
|
|
|
|
}
|
|
|
|
|
|
|
|
xvt_app_get_default_ctools(ct);
|
|
|
|
ct->pen.color = ct->fore_color = fore_color;
|
|
|
|
ct->back_color = ct->brush.color = back_color;
|
|
|
|
ct->pen.width = do_border ? 1 : 0;
|
|
|
|
#if XI_IS_CH
|
|
|
|
CTOS_IS_CH;
|
|
|
|
ct->pen.pat = PAT_HOLLOW;
|
|
|
|
CTOS_END;
|
|
|
|
#endif
|
|
|
|
#if XI_IS_NOT_CH
|
|
|
|
CTOS_IS_PM;
|
|
|
|
ct->pen.pat = do_border ? PAT_SOLID : PAT_HOLLOW;
|
|
|
|
CTOS_END;
|
|
|
|
#endif
|
1997-12-17 10:50:23 +00:00
|
|
|
ct->opaque_text = FALSE; // Minchia!
|
|
|
|
|
1997-12-17 10:43:31 +00:00
|
|
|
*font = *txt->font;
|
|
|
|
ct->mode = M_COPY;
|
|
|
|
return(ct);
|
|
|
|
}
|
|
|
|
|
|
|
|
static RCT * near
|
|
|
|
get_txt_clip_rect(TXT_DATA *txt, RCT *rct)
|
|
|
|
{
|
|
|
|
#if XI_IS_CH
|
|
|
|
BOOLEAN do_border;
|
|
|
|
|
|
|
|
CTOS_IS_CH;
|
|
|
|
do_border = (BOOLEAN)(txt->attrib & XI_ATR_BORDER);
|
|
|
|
CTOS_END;
|
|
|
|
#endif
|
|
|
|
*rct = txt->rct;
|
|
|
|
#if XI_IS_NOT_CH
|
|
|
|
CTOS_IS_PM;
|
|
|
|
xi_inflate_rect(rct, -2);
|
|
|
|
CTOS_END;
|
|
|
|
#endif
|
|
|
|
if (txt->inside_only)
|
|
|
|
{
|
|
|
|
rct->top -= BORDER_SPACE_Y;
|
|
|
|
rct->bottom += BORDER_SPACE_Y;
|
|
|
|
}
|
|
|
|
#if XI_IS_CH
|
|
|
|
CTOS_IS_CH;
|
|
|
|
if (do_border)
|
|
|
|
{
|
|
|
|
rct->right -= 8;
|
|
|
|
rct->left += 8;
|
|
|
|
}
|
|
|
|
CTOS_END;
|
|
|
|
#endif
|
|
|
|
return(rct);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
get_txt_positions(TXT_DATA *txt, int *ip1, int *ip2, int *clipleft,
|
|
|
|
int *clipright)
|
|
|
|
{
|
|
|
|
RCT rct;
|
|
|
|
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
xvt_errmsg_sig_if(!(txt->selstart <= txt->len), NULL_WIN, SEV_FATAL, ERR_ASSERT_4,"30201",
|
|
|
|
30201, "Internal TEXT error");
|
|
|
|
*ip1 = txt->string_xpos + stx_get_text_width(txt, txt->hit_test, txt->text,
|
|
|
|
txt->selstart);
|
|
|
|
*ip2 = *ip1 + stx_get_text_width(txt, txt->hit_test + txt->selstart,
|
|
|
|
txt->text + txt->selstart, txt->selstop - txt->selstart);
|
|
|
|
*clipleft = rct.left;
|
|
|
|
*clipright = rct.right;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_display_caret(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
int clipleft, clipright, caretpos1, caretpos2;
|
|
|
|
int height1, height2, pos1, pos2;
|
|
|
|
|
|
|
|
if (!txt->hasfocus)
|
|
|
|
return;
|
|
|
|
get_txt_positions(txt, &caretpos1, &caretpos2, &clipleft, &clipright);
|
|
|
|
if (caretpos1 == caretpos2 && caretpos1 <= clipright &&
|
|
|
|
caretpos2 >= clipleft)
|
|
|
|
{
|
|
|
|
#if XIWS == MTFWS
|
|
|
|
{
|
|
|
|
/* ugly hack for XVT/XM so that caret will get displayed. */
|
|
|
|
RCT rct;
|
|
|
|
DRAW_CTOOLS new_ctools;
|
|
|
|
FONT_OBJ new_font;
|
|
|
|
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools,
|
|
|
|
&new_font, FALSE, FALSE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
rct.right++;
|
|
|
|
xi_set_clip(txt->win, &rct);
|
|
|
|
if (txt->attrib & TXT_ATR_RJUST)
|
|
|
|
xi_draw_text_attrib(txt->win, txt->string_xpos, txt->pix_baseline, txt->text,
|
|
|
|
txt->len - txt->scroll_pos, txt->attrib);
|
|
|
|
else
|
|
|
|
xi_draw_text_attrib(txt->win, rct.left, txt->pix_baseline,
|
|
|
|
txt->text + txt->scroll_pos, -1, txt->attrib);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
height1 = txt->rct.bottom - txt->rct.top - 2;
|
|
|
|
if ( height1 < 1 )
|
|
|
|
height1 = 1;
|
|
|
|
height2 = txt->ascent + txt->descent;
|
|
|
|
height1 = min(height1, height2);
|
|
|
|
pos1 = txt->pix_baseline + txt->descent;
|
|
|
|
pos2 = txt->rct.bottom - 1;
|
|
|
|
pos1 = min(pos1, pos2);
|
|
|
|
xi_caret_on(txt->win, caretpos1, pos1, height1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
xi_caret_off(txt->win);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
recalc_string_xpos(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
RCT rct;
|
|
|
|
int wid;
|
|
|
|
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
if (txt->scroll_pos > txt->len)
|
|
|
|
txt->scroll_pos = txt->len;
|
|
|
|
xvt_errmsg_sig_if(!(txt->selstart <= txt->len), NULL_WIN, SEV_FATAL, ERR_ASSERT_4,"30202",
|
|
|
|
30202, "Internal TEXT error");
|
|
|
|
if (txt->attrib & TXT_ATR_RJUST)
|
|
|
|
{
|
|
|
|
wid = stx_get_text_width(txt, txt->hit_test,
|
|
|
|
txt->text, txt->len - txt->scroll_pos);
|
|
|
|
txt->string_xpos = rct.right - wid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* left justified */
|
|
|
|
wid = stx_get_text_width(txt, txt->hit_test, txt->text, txt->scroll_pos);
|
|
|
|
txt->string_xpos = rct.left - wid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_hide_caret(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
xi_caret_off(txt->win);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_redraw(TXT_DATA *txt, BOOLEAN inside_only)
|
|
|
|
{
|
|
|
|
DRAW_CTOOLS new_ctools;
|
|
|
|
FONT_OBJ new_font;
|
|
|
|
RCT rct;
|
|
|
|
RCT clip_r;
|
|
|
|
BOOLEAN do_border;
|
|
|
|
int ip1, ip2, clipleft, clipright;
|
|
|
|
long tattrib = txt->attrib;
|
|
|
|
#if XI_IS_CH
|
|
|
|
RCT r;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if XI_IS_CH
|
|
|
|
NOREF(clip_r);
|
|
|
|
#endif
|
|
|
|
txt_hide_caret(txt);
|
|
|
|
do_border = ((tattrib & (TXT_ATR_BORDER | TXT_ATR_VISIBLE)) ==
|
|
|
|
(TXT_ATR_BORDER | TXT_ATR_VISIBLE));
|
|
|
|
get_txt_positions(txt, &ip1, &ip2, &clipleft, &clipright);
|
|
|
|
rct = txt->rct;
|
|
|
|
if (inside_only)
|
|
|
|
xi_inflate_rect(&rct, -1);
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools, &new_font,
|
|
|
|
(BOOLEAN)(do_border && !inside_only), FALSE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
#if XI_IS_CH
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
int len, i;
|
|
|
|
|
|
|
|
CTOS_IS_CH;
|
|
|
|
r = rct;
|
|
|
|
if (do_border)
|
|
|
|
{
|
|
|
|
r.right -= 8;
|
|
|
|
r.left += 8;
|
|
|
|
}
|
|
|
|
len = (r.right - r.left) / 8 + 1;
|
|
|
|
/* optimize here? reallocating with every re-draw? CH only? */
|
|
|
|
/* optimize by not setting DRAW_CTOOLS so often */
|
|
|
|
buf = xi_tree_malloc(len + 1, NULL);
|
|
|
|
for (i = 0; i < len; ++i)
|
|
|
|
buf[i] = ' ';
|
|
|
|
buf[len] = '\0';
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
xi_set_clip(txt->win, &rct);
|
|
|
|
xi_draw_text(txt->win, r.left, txt->pix_baseline, buf, -1);
|
|
|
|
xi_tree_free(buf);
|
|
|
|
CTOS_END;
|
|
|
|
}
|
|
|
|
#endif /* CH */
|
|
|
|
#if XI_IS_NOT_CH
|
|
|
|
CTOS_IS_PM;
|
|
|
|
|
|
|
|
if (inside_only)
|
|
|
|
{
|
|
|
|
clip_r = rct;
|
|
|
|
if (txt->well || txt->platform)
|
|
|
|
xi_inflate_rect(&clip_r, -1);
|
|
|
|
xi_draw_rect(txt->win, &clip_r);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xi_draw_rect(txt->win, &rct);
|
|
|
|
clip_r = rct;
|
|
|
|
}
|
|
|
|
#if (XIWS == PMWS) && (XVT_OS != XVT_OS_CTOS)
|
|
|
|
{
|
|
|
|
CBRUSH hollow_cbrush;
|
|
|
|
RCT rct;
|
|
|
|
DRAW_CTOOLS t;
|
|
|
|
WINDOW win = txt->win;
|
|
|
|
|
|
|
|
/* Bad bug with XVT/PM, needs this before can draw COLOR_LTGRAY */
|
|
|
|
xvt_app_get_default_ctools(&t);
|
|
|
|
xvt_dwin_set_draw_ctools(win, &t);
|
|
|
|
hollow_cbrush.color = COLOR_WHITE;
|
|
|
|
hollow_cbrush.pat = PAT_HOLLOW;
|
|
|
|
xvt_dwin_set_cbrush(win, &hollow_cbrush);
|
|
|
|
rct.top = 0;
|
|
|
|
rct.left = 0;
|
|
|
|
rct.bottom = 0;
|
|
|
|
rct.right = 0;
|
|
|
|
xvt_dwin_draw_rect(win, &rct);
|
|
|
|
xi_set_draw_ctools(win, get_txt_ctools(txt, &new_ctools, &new_font,
|
|
|
|
do_border && !inside_only, FALSE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
}
|
|
|
|
#endif /* PM AND NOT CTOS */
|
|
|
|
if (! inside_only && (txt->well || txt->platform))
|
|
|
|
{
|
|
|
|
RCT r;
|
|
|
|
|
|
|
|
r = rct;
|
|
|
|
xi_inflate_rect(&r, -1);
|
|
|
|
xi_draw_3d_rect(txt->win, &r, txt->well, 1, txt->hilight_color, txt->back_color, txt->shadow_color);
|
|
|
|
}
|
|
|
|
if (tattrib & TXT_ATR_FOCUSBORDER)
|
|
|
|
{
|
|
|
|
if (! inside_only)
|
|
|
|
{
|
|
|
|
CPEN cpen;
|
|
|
|
RCT r;
|
|
|
|
|
|
|
|
cpen = black_cpen;
|
|
|
|
r = rct;
|
|
|
|
xi_set_cpen(txt->win, &cpen);
|
|
|
|
xi_set_draw_mode(txt->win, M_COPY);
|
|
|
|
xi_set_cbrush(txt->win, &hollow_cbrush);
|
|
|
|
xi_set_clip(txt->win, NULL);
|
|
|
|
xi_draw_rect(txt->win, &r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CTOS_END;
|
|
|
|
#endif /* NOT CH */
|
|
|
|
|
|
|
|
if ((tattrib & TXT_ATR_VISIBLE) == 0)
|
|
|
|
return;
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
xi_set_clip(txt->win, &rct);
|
|
|
|
if (tattrib & TXT_ATR_RJUST)
|
|
|
|
xi_draw_text_attrib(txt->win, txt->string_xpos, txt->pix_baseline, txt->text,
|
|
|
|
txt->len - txt->scroll_pos, txt->attrib);
|
|
|
|
else
|
|
|
|
xi_draw_text_attrib(txt->win, rct.left, txt->pix_baseline,
|
|
|
|
txt->text + txt->scroll_pos, -1, txt->attrib);
|
|
|
|
if (txt->selstart != txt->selstop)
|
|
|
|
{
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools, &new_font,
|
|
|
|
(BOOLEAN)(do_border && !inside_only), TRUE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
|
|
|
|
#if XIWS == PMWS
|
|
|
|
{
|
|
|
|
RCT r;
|
|
|
|
r.top = txt->pix_baseline - txt->ascent;
|
|
|
|
r.left = ip1;
|
|
|
|
r.bottom = txt->pix_baseline + txt->descent;
|
|
|
|
r.right = rct.left + xi_xvt_get_text_width(txt->win, txt->text + txt->selstart, txt->selstop - txt->selstart);
|
|
|
|
r.right = ip2;
|
|
|
|
xi_draw_rect(txt->win, &r);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* display inverted selection */
|
|
|
|
xi_draw_text_attrib(txt->win, ip1, txt->pix_baseline, txt->text + txt->selstart,
|
|
|
|
txt->selstop - txt->selstart, txt->attrib);
|
|
|
|
}
|
|
|
|
txt_display_caret(txt);
|
|
|
|
xi_set_clip(txt->win, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
This function performs a binary search to locate the nearest
|
|
|
|
character to the mouse, including characters that are not
|
|
|
|
visible because they are outside the bounding box of the control.
|
|
|
|
*/
|
|
|
|
static int near
|
|
|
|
hit_test(TXT_DATA *txt, int x, int y)
|
|
|
|
{
|
|
|
|
int lstop, start, stop, wid;
|
|
|
|
int curtextpos;
|
|
|
|
|
|
|
|
NOREF(y);
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
if (x <= txt->string_xpos)
|
|
|
|
return 0;
|
|
|
|
if (x >= txt->string_xpos + stx_get_text_width(txt, txt->hit_test,
|
|
|
|
txt->text, txt->len))
|
|
|
|
return(txt->len);
|
|
|
|
lstop = txt->len;
|
|
|
|
start = 0;
|
|
|
|
stop = txt->len / 2;
|
|
|
|
curtextpos = txt->string_xpos;
|
|
|
|
while (stop > start)
|
|
|
|
{
|
|
|
|
wid = stx_get_text_width(txt, txt->hit_test + start,
|
|
|
|
txt->text + start, stop - start);
|
|
|
|
if (x <= curtextpos + wid /* && x >= curtextpos */) {
|
|
|
|
if (stop - start == 1)
|
|
|
|
break;
|
|
|
|
/* subdivide this range */
|
|
|
|
lstop = stop;
|
|
|
|
stop = start + (stop - start) / 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* use other range */
|
|
|
|
start = stop;
|
|
|
|
stop = lstop;
|
|
|
|
curtextpos += wid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Now that the bisection has hit a character, determine which
|
|
|
|
side of the character is closer.
|
|
|
|
*/
|
|
|
|
if (x - curtextpos > curtextpos + wid - x)
|
|
|
|
return(stop);
|
|
|
|
else
|
|
|
|
return(start);
|
|
|
|
}
|
|
|
|
|
|
|
|
TXT_DATA *
|
|
|
|
txt_reset(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
int leading, ascent, descent;
|
|
|
|
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
xi_get_font_metrics(txt->win, &leading, &ascent, &descent);
|
|
|
|
txt->leading = (short)leading;
|
|
|
|
txt->ascent = (short)ascent;
|
|
|
|
txt->descent = (short)descent;
|
|
|
|
txt->select_start = txt->selstart = txt->selstop =
|
|
|
|
txt->scroll_pos = txt->flags = 0;
|
|
|
|
set_primary_selection(txt->win, "", 0);
|
|
|
|
txt->len = strlen(txt->text);
|
|
|
|
txt->hasfocus = FALSE;
|
|
|
|
txt->state = TXT_STATE_NULL;
|
|
|
|
#if XIWS == WMWS
|
|
|
|
txt->pix_baseline = txt->rct.top + BORDER_SPACE_Y + leading +
|
|
|
|
ascent + descent;
|
|
|
|
#else
|
|
|
|
txt->pix_baseline = txt->rct.top + leading + ascent;
|
|
|
|
#endif
|
|
|
|
if (! txt->inside_only)
|
|
|
|
{
|
|
|
|
txt->pix_baseline += BORDER_WIDTH_Y;
|
|
|
|
}
|
|
|
|
if (txt->attrib & XI_ATR_VCENTER)
|
|
|
|
{
|
|
|
|
txt->pix_baseline +=
|
|
|
|
(txt->rct.bottom - txt->rct.top - leading - ascent -
|
|
|
|
descent) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
recalc_hit_test(txt);
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
if (! xi_half_baked(txt->win))
|
|
|
|
txt_redraw(txt, FALSE);
|
|
|
|
return txt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
invert_selection(TXT_DATA *txt, BOOLEAN invert)
|
|
|
|
{
|
|
|
|
int ip1, ip2, clipleft, clipright;
|
|
|
|
DRAW_CTOOLS new_ctools;
|
|
|
|
FONT_OBJ new_font;
|
|
|
|
RCT rct;
|
|
|
|
|
|
|
|
txt_hide_caret(txt);
|
|
|
|
get_txt_positions(txt, &ip1, &ip2, &clipleft, &clipright);
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools, &new_font,
|
|
|
|
FALSE, invert));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
xi_set_clip(txt->win, &rct);
|
|
|
|
/* display inverted selection */
|
|
|
|
|
|
|
|
/* display inverted selection */
|
|
|
|
xi_draw_text_attrib(txt->win, ip1, txt->pix_baseline, txt->text + txt->selstart,
|
|
|
|
txt->selstop - txt->selstart, txt->attrib);
|
|
|
|
xi_set_clip(txt->win, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
deselect(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
if (txt->selstart != txt->selstop)
|
|
|
|
invert_selection(txt, FALSE);
|
|
|
|
txt->selstart = txt->selstop;
|
|
|
|
txt->flags |= TXT_FLAG_SELECTION;
|
|
|
|
set_primary_selection(txt->win, "", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
make_ip_viewable(TXT_DATA *txt, BOOLEAN redraw)
|
|
|
|
{
|
|
|
|
int ip1, ip2, clipleft, clipright, pos;
|
|
|
|
BOOLEAN rjust = (txt->attrib & TXT_ATR_RJUST) != 0;
|
|
|
|
int oldxpos = txt->string_xpos;
|
|
|
|
RCT rct;
|
|
|
|
|
|
|
|
if ((txt->attrib & TXT_ATR_AUTOSCROLL) == 0)
|
|
|
|
return;
|
|
|
|
xi_set_xvt_font(txt->win, txt->font, FALSE);
|
|
|
|
get_txt_positions(txt, &ip1, &ip2, &clipleft, &clipright);
|
|
|
|
pos = (txt->selstart == txt->select_start) ? ip2 : ip1;
|
|
|
|
while (pos < clipleft || pos >= clipright)
|
|
|
|
{
|
|
|
|
if (pos < clipleft && rjust || pos >= clipright && !rjust)
|
|
|
|
{
|
|
|
|
if (txt->scroll_pos >= txt->len)
|
|
|
|
break;
|
|
|
|
/* increase scroll_pos */
|
|
|
|
txt->scroll_pos++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (pos < clipleft && !rjust || pos >= clipright && rjust)
|
|
|
|
{
|
|
|
|
if (txt->scroll_pos <= 0)
|
|
|
|
break;
|
|
|
|
/* decrease scroll_pos */
|
|
|
|
txt->scroll_pos--;
|
|
|
|
}
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
get_txt_positions(txt, &ip1, &ip2, &clipleft, &clipright);
|
|
|
|
pos = (txt->selstart == txt->select_start) ? ip2 : ip1;
|
|
|
|
}
|
|
|
|
if (oldxpos != txt->string_xpos)
|
|
|
|
{
|
|
|
|
txt->flags |= TXT_FLAG_SCROLL;
|
|
|
|
if (redraw)
|
|
|
|
{
|
|
|
|
xvt_dwin_update(txt->win);
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
if (txt->parent_obj)
|
|
|
|
{
|
|
|
|
xi_set_update_obj(txt->parent_obj);
|
|
|
|
if (txt->parent_obj->type == XIT_LIST)
|
|
|
|
lm_text_scrolling(txt->parent_obj);
|
|
|
|
}
|
|
|
|
xi_scroll_rect(txt->win, &rct, txt->string_xpos - oldxpos, 0);
|
|
|
|
/* txt_redraw(txt, TRUE); */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
delete_selection(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
int offset = txt->selstop - txt->selstart;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (offset == 0)
|
|
|
|
return;
|
|
|
|
/*
|
|
|
|
Make redraw more efficient later
|
|
|
|
*/
|
|
|
|
for (i = txt->selstop; txt->text[i] != 0; i++)
|
|
|
|
txt->text[i - offset] = txt->text[i];
|
|
|
|
txt->text[i - offset] = 0;
|
|
|
|
txt->len = strlen(txt->text);
|
|
|
|
recalc_hit_test(txt);
|
|
|
|
txt->select_start = txt->selstop = txt->selstart;
|
|
|
|
set_primary_selection(txt->win, "", 0);
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
make_ip_viewable(txt, FALSE);
|
|
|
|
txt_redraw(txt, TRUE);
|
|
|
|
txt->flags |= (TXT_FLAG_TEXT | TXT_FLAG_SELECTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
delete_char_idx(TXT_DATA *txt, int idx)
|
|
|
|
{
|
|
|
|
int offset = txt->selstop - txt->selstart;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (idx < 0 || idx >= txt->len || offset != 0)
|
|
|
|
return;
|
|
|
|
/*
|
|
|
|
Make redraw more efficient later
|
|
|
|
*/
|
|
|
|
for (i = idx; txt->text[i + 1] != 0; i++)
|
|
|
|
txt->text[i] = txt->text[i + 1];
|
|
|
|
txt->text[i] = 0;
|
|
|
|
txt->len--;
|
|
|
|
recalc_hit_test(txt);
|
|
|
|
if (txt->selstart > idx)
|
|
|
|
txt->select_start = txt->selstop = txt->selstart = txt->selstart - 1;
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
make_ip_viewable(txt, FALSE);
|
|
|
|
txt_redraw(txt, TRUE);
|
|
|
|
txt->flags |= TXT_FLAG_TEXT;
|
|
|
|
set_primary_selection(txt->win, &txt->text[txt->selstart],
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
delete_char_next(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
delete_char_idx(txt, txt->selstart);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
delete_char_prev(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
delete_char_idx(txt, txt->selstart - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOLEAN near
|
|
|
|
char_is_displayable(int c)
|
|
|
|
{
|
|
|
|
return((c >= ' ' && c <= 255) && (c != K_DEL));
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOLEAN near
|
|
|
|
wordbrk(int c)
|
|
|
|
{
|
|
|
|
return(strchr(" .,`~!@#$%^&*()-=+|[]{}\'\";:<>/?", c) != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
txt_set_sel_internal(TXT_DATA *txt, int ip1, int ip2,
|
|
|
|
BOOLEAN autoscroll, BOOLEAN set_primary_sel)
|
|
|
|
{
|
|
|
|
int oldp1, oldp2, dummy;
|
|
|
|
int selstart, selstop, old_selstart, old_selstop;
|
|
|
|
int p1, p2;
|
|
|
|
RCT rct;
|
|
|
|
|
|
|
|
ip2 = clip(ip2, 0, txt->len);
|
|
|
|
ip1 = clip(ip1, 0, txt->len);
|
|
|
|
if (txt->selstart != ip1 && txt->selstop != ip2 && txt->selstart != ip2)
|
|
|
|
{
|
|
|
|
/* both changed at once -- reset the selection start point */
|
|
|
|
txt->select_start = ip1;
|
|
|
|
}
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
xi_set_clip(txt->win, &rct);
|
|
|
|
old_selstart = txt->selstart;
|
|
|
|
old_selstop = txt->selstop;
|
|
|
|
get_txt_positions(txt, &oldp1, &oldp2, &dummy, &dummy);
|
|
|
|
selstart = txt->selstart = ip1;
|
|
|
|
selstop = txt->selstop = ip2;
|
|
|
|
get_txt_positions(txt, &p1, &p2, &dummy, &dummy);
|
|
|
|
if (txt->hasfocus)
|
|
|
|
{
|
|
|
|
DRAW_CTOOLS new_ctools;
|
|
|
|
FONT_OBJ new_font;
|
|
|
|
|
|
|
|
/* only show selection if it has focus */
|
|
|
|
if (p1 >= oldp2 || p2 <= oldp1)
|
|
|
|
{
|
|
|
|
RCT r;
|
|
|
|
txt_hide_caret(txt);
|
|
|
|
|
|
|
|
#if XVTWS == WMWS
|
|
|
|
NOREF(r);
|
|
|
|
#endif
|
|
|
|
r.top = txt->pix_baseline - txt->ascent - txt->leading;
|
|
|
|
r.bottom = txt->pix_baseline + txt->descent;
|
|
|
|
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools,
|
|
|
|
&new_font, FALSE, FALSE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
/* clear old inverted selection */
|
|
|
|
if (txt->attrib & TXT_ATR_RJUST)
|
|
|
|
{
|
|
|
|
#if XIWS == WINWS
|
|
|
|
r.left = oldp1;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + old_selstart, txt->text + old_selstart,
|
|
|
|
old_selstop - old_selstart);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
xi_draw_text_attrib(txt->win, oldp1, txt->pix_baseline,
|
|
|
|
txt->text + old_selstart,
|
|
|
|
old_selstop - old_selstart, txt->attrib);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if XIWS == WINWS
|
|
|
|
r.left = oldp1;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + old_selstart, txt->text + old_selstart,
|
|
|
|
old_selstop - old_selstart);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
xi_draw_text_attrib(txt->win, oldp1, txt->pix_baseline, txt->text + old_selstart,
|
|
|
|
old_selstop - old_selstart, txt->attrib);
|
|
|
|
}
|
|
|
|
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools,
|
|
|
|
&new_font, FALSE, TRUE));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
/* display inverted selection */
|
|
|
|
#if XIWS == WINWS
|
|
|
|
r.left = p1;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + txt->selstart, txt->text + txt->selstart,
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
xi_draw_text_attrib(txt->win, p1, txt->pix_baseline,
|
|
|
|
txt->text + txt->selstart,
|
|
|
|
txt->selstop - txt->selstart, txt->attrib);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (p1 != oldp1)
|
|
|
|
{
|
|
|
|
BOOLEAN invert = p1 < oldp1;
|
|
|
|
#if XIWS == WINWS
|
|
|
|
RCT r;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
order_ints(&p1, &oldp1);
|
|
|
|
order_ints(&selstart, &old_selstart);
|
|
|
|
txt_hide_caret(txt);
|
|
|
|
|
|
|
|
#if XIWS == WINWS
|
|
|
|
r.top = txt->pix_baseline - txt->ascent - txt->leading;
|
|
|
|
r.bottom = txt->pix_baseline + txt->descent;
|
|
|
|
r.left = p1;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + selstart, txt->text + selstart,
|
|
|
|
old_selstart - selstart);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools,
|
|
|
|
&new_font, FALSE, invert));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
/* display inverted selection */
|
|
|
|
xi_draw_text_attrib(txt->win, p1, txt->pix_baseline,
|
|
|
|
txt->text + selstart, old_selstart - selstart,
|
|
|
|
txt->attrib);
|
|
|
|
}
|
|
|
|
if (p2 != oldp2)
|
|
|
|
{
|
|
|
|
BOOLEAN invert = p2 > oldp2;
|
|
|
|
|
|
|
|
order_ints(&p2, &oldp2);
|
|
|
|
order_ints(&selstop, &old_selstop);
|
|
|
|
|
|
|
|
txt_hide_caret(txt);
|
|
|
|
|
|
|
|
xi_set_draw_ctools(txt->win, get_txt_ctools(txt, &new_ctools,
|
|
|
|
&new_font, FALSE, invert));
|
|
|
|
xi_set_xvt_font(txt->win, &new_font, FALSE);
|
|
|
|
|
|
|
|
/* display inverted selection */
|
|
|
|
if (txt->attrib & TXT_ATR_RJUST)
|
|
|
|
{
|
|
|
|
#if XIWS == WINWS
|
|
|
|
RCT r;
|
|
|
|
|
|
|
|
r.top = txt->pix_baseline - txt->ascent - txt->leading;
|
|
|
|
r.bottom = txt->pix_baseline + txt->descent;
|
|
|
|
r.left = p2;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + selstop, txt->text + selstop,
|
|
|
|
old_selstop - selstop);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
xi_draw_text_attrib(txt->win, p2, txt->pix_baseline, txt->text + selstop,
|
|
|
|
old_selstop - selstop, txt->attrib);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if XIWS == WINWS
|
|
|
|
RCT r;
|
|
|
|
|
|
|
|
r.top = txt->pix_baseline - txt->ascent - txt->leading;
|
|
|
|
r.bottom = txt->pix_baseline + txt->descent;
|
|
|
|
r.left = p2;
|
|
|
|
r.right = r.left + stx_get_text_width(txt,
|
|
|
|
txt->hit_test + selstop, txt->text + selstop,
|
|
|
|
old_selstop - selstop);
|
|
|
|
xi_rect_intersect(&r, &r, &rct);
|
|
|
|
xi_set_clip(txt->win, &r);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
xi_draw_text_attrib(txt->win, p2, txt->pix_baseline,
|
|
|
|
txt->text + selstop, old_selstop - selstop,
|
|
|
|
txt->attrib);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (autoscroll)
|
|
|
|
make_ip_viewable(txt, TRUE);
|
|
|
|
txt_display_caret(txt);
|
|
|
|
}
|
|
|
|
xi_set_clip(txt->win, NULL);
|
|
|
|
if (set_primary_sel)
|
|
|
|
set_primary_selection(txt->win, &txt->text[txt->selstart],
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void near
|
|
|
|
insert_char(TXT_DATA *txt, int c)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
xvt_errmsg_sig_if(!(txt->selstart == txt->selstop), NULL_WIN, SEV_FATAL, ERR_ASSERT_4,"30203",
|
|
|
|
30203, "Internal error");
|
|
|
|
if (txt->len >= txt->text_size - 1)
|
|
|
|
{
|
|
|
|
/* beep(); */
|
|
|
|
txt->flags |= TXT_FLAG_OVF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = txt->len; i >= txt->selstart; i--)
|
|
|
|
txt->text[i+1] = txt->text[i];
|
|
|
|
txt->text[txt->selstart] = (char)c;
|
|
|
|
txt->len++;
|
|
|
|
recalc_hit_test(txt);
|
|
|
|
txt->selstart++;
|
|
|
|
txt->selstop++;
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
make_ip_viewable(txt, FALSE);
|
|
|
|
txt_redraw(txt, TRUE);
|
|
|
|
txt->flags |= TXT_FLAG_TEXT;
|
|
|
|
set_primary_selection(txt->win, &txt->text[txt->selstart],
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Process incoming events. Return TRUE if event is consumed.
|
|
|
|
*/
|
|
|
|
BOOLEAN
|
|
|
|
txt_event(TXT_DATA *txt, EVENT *ep, BOOLEAN gaining_focus)
|
|
|
|
{
|
|
|
|
int hit, hit1, hit2;
|
|
|
|
int c, pos, oldpos;
|
|
|
|
static PNT last_pos = {
|
|
|
|
-1, -1 };
|
|
|
|
EVENT_TYPE et;
|
|
|
|
BOOLEAN retval = TRUE;
|
|
|
|
/* This exists to avoid a compiler bug on the Mac/MPW */
|
|
|
|
BOOLEAN check_txt = ( txt != NULL );
|
|
|
|
|
|
|
|
et = ep->type;
|
|
|
|
xvt_errmsg_sig_if(!(check_txt), NULL_WIN, SEV_FATAL, ERR_ASSERT_4,"30206",
|
|
|
|
30206, "Invalid TXT passed to txt_event");
|
|
|
|
if ((txt->attrib & TXT_ACTIVE_ATR) != TXT_ACTIVE_ATR &&
|
|
|
|
et != E_UPDATE)
|
|
|
|
return(FALSE);
|
|
|
|
switch (et)
|
|
|
|
{
|
|
|
|
case E_UPDATE:
|
|
|
|
txt_redraw(txt, FALSE);
|
|
|
|
break;
|
|
|
|
case E_CHAR:
|
|
|
|
if (txt->attrib & TXT_ATR_READONLY)
|
|
|
|
{
|
|
|
|
retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c = ep->v.chr.ch;
|
|
|
|
if (!char_is_displayable(c))
|
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case K_LEFT:
|
|
|
|
case K_RIGHT:
|
|
|
|
case K_LHOME:
|
|
|
|
case K_LEND:
|
|
|
|
case K_WLEFT:
|
|
|
|
case K_WRIGHT:
|
|
|
|
#if (XIWS == WMWS)
|
|
|
|
ep->v.chr.shift = FALSE;
|
|
|
|
#endif
|
|
|
|
if (txt->selstart == txt->selstop)
|
|
|
|
txt->select_start = txt->selstart;
|
|
|
|
if (abs(txt->selstart - txt->select_start) >
|
|
|
|
abs(txt->selstop - txt->select_start))
|
|
|
|
pos = txt->selstart;
|
|
|
|
else
|
|
|
|
pos = txt->selstop;
|
|
|
|
oldpos = pos;
|
|
|
|
switch(c)
|
|
|
|
{
|
|
|
|
case K_LEFT:
|
|
|
|
pos = clip(pos - 1, 0, txt->len);
|
|
|
|
break;
|
|
|
|
case K_RIGHT:
|
|
|
|
pos = clip(pos + 1, 0, txt->len);
|
|
|
|
break;
|
|
|
|
case K_LHOME:
|
|
|
|
pos = 0;
|
|
|
|
break;
|
|
|
|
case K_LEND:
|
|
|
|
pos = txt->len;
|
|
|
|
break;
|
|
|
|
case K_WLEFT:
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (pos > 0)
|
|
|
|
pos--;
|
|
|
|
} while (pos > 0 && !wordbrk(txt->text[pos]));
|
|
|
|
break;
|
|
|
|
case K_WRIGHT:
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (pos < txt->len)
|
|
|
|
pos++;
|
|
|
|
} while (pos < txt->len &&
|
|
|
|
!wordbrk(txt->text[pos]));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ep->v.chr.shift)
|
|
|
|
{
|
|
|
|
/* change current selection */
|
|
|
|
if (pos > txt->select_start)
|
|
|
|
txt_set_sel_internal(txt, txt->select_start,
|
|
|
|
pos, TRUE, TRUE);
|
|
|
|
else
|
|
|
|
txt_set_sel_internal(txt, pos,
|
|
|
|
txt->select_start, TRUE, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* move caret */
|
|
|
|
deselect(txt);
|
|
|
|
txt->select_start = txt->selstop = txt->selstart
|
|
|
|
= pos;
|
|
|
|
make_ip_viewable(txt, TRUE);
|
|
|
|
txt_display_caret(txt);
|
|
|
|
}
|
|
|
|
if (pos != oldpos)
|
|
|
|
txt->flags |= TXT_FLAG_SELECTION;
|
|
|
|
break;
|
|
|
|
case K_CLEAR:
|
|
|
|
case K_DEL:
|
|
|
|
if (txt->selstart != txt->selstop)
|
|
|
|
delete_selection(txt);
|
|
|
|
else
|
|
|
|
delete_char_next(txt);
|
|
|
|
break;
|
|
|
|
case BS:
|
|
|
|
if (txt->selstart != txt->selstop)
|
|
|
|
delete_selection(txt);
|
|
|
|
else
|
|
|
|
delete_char_prev(txt);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
retval = FALSE; /* event not consumed */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* if we get to here then char is displayable */
|
|
|
|
if (txt->selstart != txt->selstop)
|
|
|
|
delete_selection(txt);
|
|
|
|
insert_char(txt, c);
|
|
|
|
if ( txt->auto_tab && txt->len >= txt->text_size - 1 )
|
|
|
|
{
|
|
|
|
EVENT ev;
|
|
|
|
|
|
|
|
MEMCLEAR(ev);
|
|
|
|
ev.type = E_CHAR;
|
|
|
|
ev.v.chr.ch = '\t';
|
|
|
|
xi_event( txt->win, &ev );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case E_MOUSE_DOWN:
|
|
|
|
case E_MOUSE_DBL:
|
|
|
|
if (ep->v.mouse.button != 0)
|
|
|
|
{
|
|
|
|
retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (txt->attrib & TXT_ATR_READONLY)
|
|
|
|
{
|
|
|
|
retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last_pos.h = last_pos.v = -1;
|
|
|
|
hit = hit_test(txt, ep->v.mouse.where.h, ep->v.mouse.where.v);
|
|
|
|
if (ep->v.mouse.shift)
|
|
|
|
{
|
|
|
|
/* alter old selection */
|
|
|
|
if (abs(txt->selstart - hit) > abs(txt->selstop - hit))
|
|
|
|
txt->select_start = txt->selstart;
|
|
|
|
else
|
|
|
|
txt->select_start = txt->selstop;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
txt->select_start = hit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If XI_PREF_AUTOSEL_ON_MOUSE is set to true, don't fall through,
|
|
|
|
so that a mouse down on an AUTOSELECT field selects the entire
|
|
|
|
field. Also, untrap the mouse to the object, so that mouse
|
|
|
|
moves and mouse up events do not go to the object.
|
|
|
|
*/
|
|
|
|
if (gaining_focus && (txt->attrib & TXT_ATR_AUTOSELECT) && xi_get_pref(XI_PREF_AUTOSEL_ON_MOUSE))
|
|
|
|
{
|
|
|
|
XI_OBJ *itf;
|
|
|
|
XI_ITF_DATA *itf_data;
|
|
|
|
|
|
|
|
itf = xi_get_itf(txt->win);
|
|
|
|
itf_data = itf->v.itf;
|
|
|
|
itf_data->trap_obj = NULL;
|
|
|
|
/*
|
|
|
|
Inform the XI module that another module is taking
|
|
|
|
responsibility for trapping the mouse to an object,
|
|
|
|
explicitly.
|
|
|
|
*/
|
|
|
|
itf_data->trap_explicit = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Set the state to select characters or select words.
|
|
|
|
*/
|
|
|
|
txt->state = (et == E_MOUSE_DOWN) ? TXT_STATE_SELC :
|
|
|
|
TXT_STATE_SELW;
|
|
|
|
if (et == E_MOUSE_DOWN && txt->timer_set)
|
|
|
|
{
|
|
|
|
txt_set_sel_internal(txt, 0, 32000, FALSE, TRUE);
|
|
|
|
txt->state = TXT_STATE_NULL;
|
|
|
|
xvt_timer_destroy(txt->timer_id);
|
|
|
|
txt->timer_id = 0;
|
|
|
|
txt->timer_set = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (xi_get_pref(XI_PREF_TRIPLE_CLICK_TIME))
|
|
|
|
{
|
|
|
|
if (et == E_MOUSE_DBL)
|
|
|
|
{
|
|
|
|
txt->timer_id = xvt_timer_create(txt->win,
|
|
|
|
xi_get_pref(XI_PREF_TRIPLE_CLICK_TIME));
|
|
|
|
txt->timer_set = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
et = E_MOUSE_MOVE;
|
|
|
|
/*************
|
|
|
|
fall through to E_MOUSE_MOVE
|
|
|
|
*************/
|
|
|
|
case E_MOUSE_MOVE:
|
|
|
|
#if 0
|
|
|
|
if (last_pos.h == ep->v.mouse.where.h &&
|
|
|
|
last_pos.v == ep->v.mouse.where.v) {
|
|
|
|
RCT rct;
|
|
|
|
/*
|
|
|
|
The mouse did not move from last position.
|
|
|
|
This event should be discarded unless we have dragged
|
|
|
|
off the edge of the edit field.
|
|
|
|
*/
|
|
|
|
get_txt_clip_rect(txt, &rct);
|
|
|
|
if (xvt_rect_has_point(&rct, last_pos))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
last_pos = ep->v.mouse.where;
|
|
|
|
if (txt->state != TXT_STATE_SELW && txt->state != TXT_STATE_SELC)
|
|
|
|
break;
|
|
|
|
hit = hit_test(txt, ep->v.mouse.where.h, ep->v.mouse.where.v);
|
|
|
|
hit1 = hit;
|
|
|
|
hit2 = txt->select_start;
|
|
|
|
order_ints(&hit1, &hit2);
|
|
|
|
if (txt->state == TXT_STATE_SELW)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
select from select_start to here, rounding both ends
|
|
|
|
to an even word boundary
|
|
|
|
*/
|
|
|
|
while (hit1 > 0 && !wordbrk(txt->text[hit1-1]))
|
|
|
|
hit1--;
|
|
|
|
while (hit2 < txt->len && !wordbrk(txt->text[hit2]))
|
|
|
|
hit2++;
|
|
|
|
}
|
|
|
|
txt_set_sel_internal(txt, hit1, hit2, TRUE, FALSE);
|
|
|
|
break;
|
|
|
|
case E_TIMER:
|
|
|
|
if (txt->timer_id == ep->v.timer.id)
|
|
|
|
{
|
|
|
|
xvt_timer_destroy(txt->timer_id);
|
|
|
|
txt->timer_id = 0;
|
|
|
|
txt->timer_set = FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case E_MOUSE_UP:
|
|
|
|
txt->state = TXT_STATE_NULL;
|
|
|
|
set_primary_selection(txt->win, &txt->text[txt->selstart],
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
break;
|
|
|
|
case E_COMMAND:
|
|
|
|
/* todo process clipboard events */
|
|
|
|
retval = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long
|
|
|
|
txt_get_attrib(TXT_DATA *txt)
|
|
|
|
{
|
|
|
|
return(txt->attrib);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_get_sel(TXT_DATA *txt, int *c1, int *c2)
|
|
|
|
{
|
|
|
|
*c1 = txt->selstart;
|
|
|
|
*c2 = txt->selstop;
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT *
|
|
|
|
txt_get_rect(TXT_DATA *txt, RCT *rct)
|
|
|
|
{
|
|
|
|
*rct = txt->rct;
|
|
|
|
return(rct);
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT *
|
|
|
|
txt_set_rect(TXT_DATA *txt, RCT *rct)
|
|
|
|
{
|
|
|
|
txt->rct = *rct;
|
|
|
|
return(rct);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_get_text(TXT_DATA *txt, char *s, int len)
|
|
|
|
{
|
|
|
|
tgstrncpy(s, txt->text, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_set_attrib(TXT_DATA *txt, unsigned long attrib)
|
|
|
|
{
|
|
|
|
BOOLEAN do_redraw;
|
|
|
|
|
|
|
|
do_redraw = (((txt->attrib ^ attrib) & TXT_REDRAW_ATR) != 0);
|
|
|
|
txt->attrib = attrib;
|
|
|
|
if (do_redraw)
|
|
|
|
txt_redraw(txt, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* turns on/off caret if selstart == selstop */
|
|
|
|
void
|
|
|
|
txt_caret(TXT_DATA *txt, BOOLEAN caret_state)
|
|
|
|
{
|
|
|
|
xvt_errmsg_sig_if(!((txt->attrib & TXT_ACTIVE_ATR) == TXT_ACTIVE_ATR || !caret_state), NULL_WIN, SEV_FATAL, ERR_ASSERT_4,"30205",
|
|
|
|
30205, "txt_caret called with disabled field");
|
|
|
|
if (txt->hasfocus && !caret_state || !txt->hasfocus && caret_state)
|
|
|
|
{
|
|
|
|
if (caret_state == TRUE && txt->selstart != txt->selstop)
|
|
|
|
{
|
|
|
|
invert_selection(txt, TRUE);
|
|
|
|
}
|
|
|
|
#if XIWS != WMWS
|
|
|
|
if (caret_state && (txt->attrib & TXT_ATR_FOCUSBORDER))
|
|
|
|
{
|
|
|
|
CPEN cpen;
|
|
|
|
RCT r;
|
|
|
|
|
|
|
|
cpen = black_cpen;
|
|
|
|
r = txt->rct;
|
|
|
|
xi_set_cpen(txt->win, &cpen);
|
|
|
|
xi_set_draw_mode(txt->win, M_COPY);
|
|
|
|
xi_set_cbrush(txt->win, &hollow_cbrush);
|
|
|
|
xi_draw_rect(txt->win, &r);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
txt->hasfocus = caret_state;
|
|
|
|
txt_display_caret(txt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_set_sel(TXT_DATA *txt, int ip1, int ip2)
|
|
|
|
{
|
|
|
|
txt_set_sel_internal(txt, ip1, ip2, FALSE, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
txt_set_text(TXT_DATA *txt, char *s)
|
|
|
|
{
|
|
|
|
txt->select_start = txt->selstart = txt->selstop = txt->scroll_pos = 0;
|
|
|
|
txt->state = TXT_STATE_NULL;
|
|
|
|
if (s)
|
|
|
|
{
|
|
|
|
tgstrncpy(txt->text, s, txt->text_size);
|
|
|
|
txt->len = strlen(txt->text);
|
|
|
|
recalc_hit_test(txt);
|
|
|
|
recalc_string_xpos(txt);
|
|
|
|
txt_redraw(txt, TRUE);
|
|
|
|
set_primary_selection(txt->win, &txt->text[txt->selstart],
|
|
|
|
txt->selstop - txt->selstart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|