1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "text.h"
34 #include "textP.h"
35 #include "calltips.h"
36 #include "../util/misc.h"
37 #include "../util/nedit_malloc.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <limits.h>
43
44 #include <Xm/Xm.h>
45 #include <Xm/Label.h>
46 #include <X11/Shell.h>
47
48 #ifdef HAVE_DEBUG_H
49 #include "../debug.h"
50 #endif
51
52 static char *expandAllTabs(
char *text,
int tab_width );
53
54
55
56
57 void KillCalltip(WindowInfo *window,
int calltipID) {
58 textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
59 TextDKillCalltip( textD, calltipID );
60 }
61
62 void TextDKillCalltip(textDisp *textD,
int calltipID) {
63 if( textD->calltip.
ID ==
0 )
64 return;
65 if( calltipID ==
0 || calltipID == textD->calltip.
ID ) {
66 XtPopdown( textD->calltipShell );
67 textD->calltip.
ID =
0;
68 }
69 }
70
71
72
73
74
75
76
77 int GetCalltipID(WindowInfo *window,
int calltipID) {
78 textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
79 if( calltipID ==
0 )
80 return textD->calltip.
ID;
81 else {
82 if( calltipID == textD->calltip.
ID)
83 return calltipID;
84 else
85 return 0;
86 }
87 }
88
89 #define CALLTIP_EDGE_GUARD 5
90 static Boolean offscreenV(XWindowAttributes *screenAttr,
int top,
int height) {
91 return (top <
CALLTIP_EDGE_GUARD ||
92 top + height >= screenAttr->height -
CALLTIP_EDGE_GUARD);
93 }
94
95
96
97
98 void TextDRedrawCalltip(textDisp *textD,
int calltipID) {
99 int lineHeight = textD->ascent + textD->descent;
100 Position txtX, txtY, borderWidth, abs_x, abs_y, tipWidth, tipHeight;
101 XWindowAttributes screenAttr;
102 int rel_x, rel_y, flip_delta;
103
104 if( textD->calltip.
ID ==
0 )
105 return;
106 if( calltipID !=
0 && calltipID != textD->calltip.
ID )
107 return;
108
109
110 XtVaGetValues(textD->w, XmNx, &txtX, XmNy, &txtY,
NULL);
111
112 if( textD->calltip.anchored ) {
113
114 if (!TextDPositionToXY(textD, textD->calltip.pos, &rel_x, &rel_y)) {
115 if (textD->calltip.alignMode ==
TIP_STRICT)
116 TextDKillCalltip(textD, textD->calltip.
ID);
117 return;
118 }
119 }
else {
120 if (textD->calltip.pos <
0) {
121
122
123 textD->calltip.pos = textD->width/
2;
124 textD->calltip.hAlign =
TIP_CENTER;
125 rel_y = textD->height/
3;
126 }
else if (!TextDPositionToXY(textD, textD->cursor->cursorPos, &rel_x, &rel_y)){
127
128 if (textD->calltip.alignMode ==
TIP_STRICT)
129 TextDKillCalltip(textD, textD->calltip.
ID);
130 return;
131 }
132 rel_x = textD->calltip.pos;
133 }
134
135 XtVaGetValues(textD->calltipShell, XmNwidth, &tipWidth, XmNheight,
136 &tipHeight, XmNborderWidth, &borderWidth,
NULL);
137 rel_x += borderWidth;
138 rel_y += lineHeight/
2 + borderWidth;
139
140
141 if (textD->calltip.hAlign ==
TIP_CENTER)
142 rel_x -= tipWidth/
2;
143 else if (textD->calltip.hAlign ==
TIP_RIGHT)
144 rel_x -= tipWidth;
145
146
147 if (textD->calltip.vAlign ==
TIP_ABOVE) {
148 flip_delta = tipHeight + lineHeight +
2*borderWidth;
149 rel_y -= flip_delta;
150 }
else
151 flip_delta = -(tipHeight + lineHeight +
2*borderWidth);
152
153 XtTranslateCoords(textD->w, rel_x, rel_y, &abs_x, &abs_y);
154
155
156 if (textD->calltip.alignMode ==
TIP_SLOPPY) {
157 XGetWindowAttributes(XtDisplay(textD->w),
158 RootWindowOfScreen(XtScreen(textD->w)), &screenAttr);
159
160
161 if (abs_x + tipWidth >= screenAttr.width -
CALLTIP_EDGE_GUARD)
162 abs_x = screenAttr.width - tipWidth -
CALLTIP_EDGE_GUARD;
163 if (abs_x <
CALLTIP_EDGE_GUARD)
164 abs_x =
CALLTIP_EDGE_GUARD;
165
166
167 if (screenAttr.height > tipHeight &&
168 offscreenV(&screenAttr, abs_y, tipHeight)) {
169
170 if (!offscreenV(&screenAttr, abs_y + flip_delta, tipHeight))
171 abs_y += flip_delta;
172
173 else if (abs_y + tipHeight <
0)
174 abs_y =
CALLTIP_EDGE_GUARD;
175 else if (abs_y >= screenAttr.height)
176 abs_y = screenAttr.height - tipHeight -
CALLTIP_EDGE_GUARD;
177
178 }
179 }
180
181 XtVaSetValues( textD->calltipShell, XmNx, abs_x, XmNy, abs_y,
NULL );
182 }
183
184
185
186
187
188
189
190
191 static char *expandAllTabs(
char *text,
int tab_width ) {
192 int i, nTabs=
0;
193 size_t len;
194 char *c, *cCpy, *textCpy;
195
196
197 for( c = text; *c; ++c )
198 if( *c ==
'\t' )
199 ++nTabs;
200 if( nTabs ==
0 )
201 return text;
202
203
204 len = strlen( text ) + ( tab_width -
1 )*nTabs;
205 textCpy = (
char*)malloc( len +
1 );
206 if( !textCpy ) {
207 fprintf(stderr,
208 "xnedit: Out of heap memory in expandAllTabs!\n");
209 return NULL;
210 }
211
212
213 for( c = text, cCpy = textCpy; *c; ++c, ++cCpy) {
214 if( *c ==
'\t' ) {
215 for( i =
0; i < tab_width; ++i, ++cCpy )
216 *cCpy =
' ';
217 --cCpy;
218 }
else
219 *cCpy = *c;
220 }
221 *cCpy =
'\0';
222 return textCpy;
223 }
224
225
226
227
228
229
230 int ShowCalltip(WindowInfo *window,
char *text, Boolean anchored,
231 int pos,
int hAlign,
int vAlign,
int alignMode) {
232 static int StaticCalltipID =
1;
233 textDisp *textD = ((TextWidget)window->lastFocus)->text.textD;
234 int rel_x, rel_y;
235 Position txtX, txtY;
236 char *textCpy;
237 XmString str;
238
239
240 TextDKillCalltip( textD,
0 );
241
242
243 if (text ==
NULL)
return 0;
244
245
246 textCpy = expandAllTabs( text, BufGetTabDistance(textD->buffer) );
247 if( textCpy ==
NULL )
248 return 0;
249 str = XmStringCreateLtoR(textCpy, XmFONTLIST_DEFAULT_TAG);
250 if( textCpy != text )
251 NEditFree( textCpy );
252
253
254 XtVaGetValues(textD->w,
255 XmNx, &txtX,
256 XmNy, &txtY,
257 NULL);
258
259
260 if (textD->calltipW ==
NULL) {
261 Arg args[
10];
262 int argcnt =
0;
263 XtSetArg(args[argcnt], XmNsaveUnder, True); argcnt++;
264 XtSetArg(args[argcnt], XmNallowShellResize, True); argcnt++;
265
266 textD->calltipShell = CreatePopupShellWithBestVis(
"calltipshell",
267 overrideShellWidgetClass, textD->w, args, argcnt);
268
269
270
271 textD->calltipW = XtVaCreateManagedWidget(
272 "calltip", xmLabelWidgetClass, textD->calltipShell,
273 XmNborderWidth,
1,
274 XmNhighlightThickness,
0,
275 XmNalignment, XmALIGNMENT_BEGINNING,
276 XmNforeground, textD->calltipFGPixel,
277 XmNbackground, textD->calltipBGPixel,
278 NULL );
279 }
280
281
282 XtVaSetValues( textD->calltipW, XmNlabelString, str,
NULL );
283 XmStringFree( str );
284
285
286 if (anchored) {
287
288
289 if (pos < textD->firstChar || pos > textD->lastChar ) {
290 XBell(TheDisplay,
0);
291 return 0;
292 }
293 textD->calltip.pos = pos;
294 }
else {
295
296
297 if (!TextDPositionToXY(textD, textD->cursor->cursorPos, &rel_x, &rel_y)) {
298 if (alignMode ==
TIP_STRICT) {
299 XBell(TheDisplay,
0);
300 return 0;
301 }
302 textD->calltip.pos = -
1;
303 }
else
304
305 textD->calltip.pos = rel_x;
306 }
307
308
309 textD->calltip.
ID = StaticCalltipID;
310 textD->calltip.anchored = anchored;
311 textD->calltip.hAlign = hAlign;
312 textD->calltip.vAlign = vAlign;
313 textD->calltip.alignMode = alignMode;
314
315
316
317 if(++StaticCalltipID <=
0)
318 StaticCalltipID =
1;
319
320
321 XtRealizeWidget( textD->calltipShell );
322
323 TextDRedrawCalltip(textD,
0);
324 XtPopup( textD->calltipShell, XtGrabNone );
325 return textD->calltip.
ID;
326 }
327