#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "text.h"
#include "textP.h"
#include "calltips.h"
#include "../util/misc.h"
#include "../util/nedit_malloc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <X11/Shell.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
static char *expandAllTabs(
char *text,
int tab_width );
void KillCalltip(WindowInfo *window,
int calltipID) {
textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
TextDKillCalltip( textD, calltipID );
}
void TextDKillCalltip(textDisp *textD,
int calltipID) {
if( textD->calltip.
ID ==
0 )
return;
if( calltipID ==
0 || calltipID == textD->calltip.
ID ) {
XtPopdown( textD->calltipShell );
textD->calltip.
ID =
0;
}
}
int GetCalltipID(WindowInfo *window,
int calltipID) {
textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
if( calltipID ==
0 )
return textD->calltip.
ID;
else {
if( calltipID == textD->calltip.
ID)
return calltipID;
else
return 0;
}
}
#define CALLTIP_EDGE_GUARD 5
static Boolean offscreenV(XWindowAttributes *screenAttr,
int top,
int height) {
return (top <
CALLTIP_EDGE_GUARD ||
top + height >= screenAttr->height -
CALLTIP_EDGE_GUARD);
}
void TextDRedrawCalltip(textDisp *textD,
int calltipID) {
int lineHeight = textD->ascent + textD->descent;
Position txtX, txtY, borderWidth, abs_x, abs_y, tipWidth, tipHeight;
XWindowAttributes screenAttr;
int rel_x, rel_y, flip_delta;
if( textD->calltip.
ID ==
0 )
return;
if( calltipID !=
0 && calltipID != textD->calltip.
ID )
return;
XtVaGetValues(textD->w, XmNx, &txtX, XmNy, &txtY,
NULL);
if( textD->calltip.anchored ) {
if (!TextDPositionToXY(textD, textD->calltip.pos, &rel_x, &rel_y)) {
if (textD->calltip.alignMode ==
TIP_STRICT)
TextDKillCalltip(textD, textD->calltip.
ID);
return;
}
}
else {
if (textD->calltip.pos <
0) {
textD->calltip.pos = textD->width/
2;
textD->calltip.hAlign =
TIP_CENTER;
rel_y = textD->height/
3;
}
else if (!TextDPositionToXY(textD, textD->cursor->cursorPos, &rel_x, &rel_y)){
if (textD->calltip.alignMode ==
TIP_STRICT)
TextDKillCalltip(textD, textD->calltip.
ID);
return;
}
rel_x = textD->calltip.pos;
}
XtVaGetValues(textD->calltipShell, XmNwidth, &tipWidth, XmNheight,
&tipHeight, XmNborderWidth, &borderWidth,
NULL);
rel_x += borderWidth;
rel_y += lineHeight/
2 + borderWidth;
if (textD->calltip.hAlign ==
TIP_CENTER)
rel_x -= tipWidth/
2;
else if (textD->calltip.hAlign ==
TIP_RIGHT)
rel_x -= tipWidth;
if (textD->calltip.vAlign ==
TIP_ABOVE) {
flip_delta = tipHeight + lineHeight +
2*borderWidth;
rel_y -= flip_delta;
}
else
flip_delta = -(tipHeight + lineHeight +
2*borderWidth);
XtTranslateCoords(textD->w, rel_x, rel_y, &abs_x, &abs_y);
if (textD->calltip.alignMode ==
TIP_SLOPPY) {
XGetWindowAttributes(XtDisplay(textD->w),
RootWindowOfScreen(XtScreen(textD->w)), &screenAttr);
if (abs_x + tipWidth >= screenAttr.width -
CALLTIP_EDGE_GUARD)
abs_x = screenAttr.width - tipWidth -
CALLTIP_EDGE_GUARD;
if (abs_x <
CALLTIP_EDGE_GUARD)
abs_x =
CALLTIP_EDGE_GUARD;
if (screenAttr.height > tipHeight &&
offscreenV(&screenAttr, abs_y, tipHeight)) {
if (!offscreenV(&screenAttr, abs_y + flip_delta, tipHeight))
abs_y += flip_delta;
else if (abs_y + tipHeight <
0)
abs_y =
CALLTIP_EDGE_GUARD;
else if (abs_y >= screenAttr.height)
abs_y = screenAttr.height - tipHeight -
CALLTIP_EDGE_GUARD;
}
}
XtVaSetValues( textD->calltipShell, XmNx, abs_x, XmNy, abs_y,
NULL );
}
static char *expandAllTabs(
char *text,
int tab_width ) {
int i, nTabs=
0;
size_t len;
char *c, *cCpy, *textCpy;
for( c = text; *c; ++c )
if( *c ==
'\t' )
++nTabs;
if( nTabs ==
0 )
return text;
len = strlen( text ) + ( tab_width -
1 )*nTabs;
textCpy = (
char*)malloc( len +
1 );
if( !textCpy ) {
fprintf(stderr,
"xnedit: Out of heap memory in expandAllTabs!\n");
return NULL;
}
for( c = text, cCpy = textCpy; *c; ++c, ++cCpy) {
if( *c ==
'\t' ) {
for( i =
0; i < tab_width; ++i, ++cCpy )
*cCpy =
' ';
--cCpy;
}
else
*cCpy = *c;
}
*cCpy =
'\0';
return textCpy;
}
int ShowCalltip(WindowInfo *window,
char *text, Boolean anchored,
int pos,
int hAlign,
int vAlign,
int alignMode) {
static int StaticCalltipID =
1;
textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
int rel_x, rel_y;
Position txtX, txtY;
char *textCpy;
XmString str;
TextDKillCalltip( textD,
0 );
if (text ==
NULL)
return 0;
textCpy = expandAllTabs( text, BufGetTabDistance(textD->buffer) );
if( textCpy ==
NULL )
return 0;
str = XmStringCreateLtoR(textCpy, XmFONTLIST_DEFAULT_TAG);
if( textCpy != text )
NEditFree( textCpy );
XtVaGetValues(textD->w,
XmNx, &txtX,
XmNy, &txtY,
NULL);
if (textD->calltipW ==
NULL) {
Arg args[
10];
int argcnt =
0;
XtSetArg(args[argcnt], XmNsaveUnder, True); argcnt++;
XtSetArg(args[argcnt], XmNallowShellResize, True); argcnt++;
textD->calltipShell = CreatePopupShellWithBestVis(
"calltipshell",
overrideShellWidgetClass, textD->w, args, argcnt);
textD->calltipW = XtVaCreateManagedWidget(
"calltip", xmLabelWidgetClass, textD->calltipShell,
XmNborderWidth,
1,
XmNhighlightThickness,
0,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNforeground, textD->calltipFGPixel,
XmNbackground, textD->calltipBGPixel,
NULL );
}
XtVaSetValues( textD->calltipW, XmNlabelString, str,
NULL );
XmStringFree( str );
if (anchored) {
if (pos < textD->firstChar || pos > textD->lastChar ) {
XBell(TheDisplay,
0);
return 0;
}
textD->calltip.pos = pos;
}
else {
if (!TextDPositionToXY(textD, textD->cursor->cursorPos, &rel_x, &rel_y)) {
if (alignMode ==
TIP_STRICT) {
XBell(TheDisplay,
0);
return 0;
}
textD->calltip.pos = -
1;
}
else
textD->calltip.pos = rel_x;
}
textD->calltip.
ID = StaticCalltipID;
textD->calltip.anchored = anchored;
textD->calltip.hAlign = hAlign;
textD->calltip.vAlign = vAlign;
textD->calltip.alignMode = alignMode;
if(++StaticCalltipID <=
0)
StaticCalltipID =
1;
XtRealizeWidget( textD->calltipShell );
TextDRedrawCalltip(textD,
0);
XtPopup( textD->calltipShell, XtGrabNone );
return textD->calltip.
ID;
}