First checkin, AXE release 0.2
[AXE.git] / src / edit.cpp
1
2 /**************************************************************************
3 **  (c) Copyright 1998, Andromeda Technology & Automation
4 ***************************************************************************
5 ** MODULE INFORMATION *
6 ***********************
7 **      FILE NAME      : edit.cpp
8 **      SYSTEM NAME    : AXE - Andromeda X-windows Encapsulation
9 **      VERSION NUMBER : $Revision: 1.1 $
10 **
11 **  DESCRIPTION      :  Implementation of text editor classes
12 **
13 **  EXPORTED OBJECTS : 
14 **  LOCAL    OBJECTS : 
15 **  MODULES  USED    :
16 ***************************************************************************
17 **  ADMINISTRATIVE INFORMATION *
18 ********************************
19 **      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
20 **      CREATION DATE   : Mar 13, 1998
21 **      LAST UPDATE     : Jun 18, 1998
22 **      MODIFICATIONS   : 
23 **************************************************************************/
24
25 /*****************************
26    $Log: edit.cpp,v $
27    Revision 1.1  2002-07-25 08:01:26  arjen
28    First checkin, AXE release 0.2
29
30 *****************************/
31
32 static const char *RCSID = "$Id: edit.cpp,v 1.1 2002-07-25 08:01:26 arjen Exp $";
33
34 #include "edit.h"
35 #include <X11/keysym.h>
36
37 #include <stdio.h>
38
39 /*=========================================================================
40 **  NAME           : EV_KeyPress
41 **  SYNOPSIS       :
42 **  PARAMETERS     :
43 **  RETURN VALUE   :
44 **
45 **  DESCRIPTION    : 
46 **
47 **  VARS USED      :
48 **  VARS CHANGED   :
49 **  FUNCTIONS USED :
50 **  SEE ALSO       :
51 **  LAST MODIFIED  : May 21, 1998
52 **=========================================================================
53 */
54
55 int edit::EV_KeyPress(XKeyEvent ev)
56 {
57    KeySym   key;
58    int      x_cursor;
59    unsigned w, h;
60
61    Size(w, h);   //  The size of the window
62
63    toggle_cursor();
64    key = XLookupKeysym(&ev, ev.state & 1);
65
66    //  If text is selected, remove it first.
67
68    DeleteSelection();
69
70    switch (key)
71    {
72    case XK_Left:
73       if (cursor_position > 0)
74       {
75          cursor_position--;
76       }
77       break;
78
79    case XK_Right:
80       if (cursor_position < ~text)
81       {
82          cursor_position++;
83       }
84       break;
85
86    case XK_BackSpace:
87       if (cursor_position > 0)
88       {
89          cursor_position--;
90          text(cursor_position, 1) = "";
91       }
92       break;
93
94    case XK_Delete:
95       text(cursor_position, 1) = "";
96       break;
97
98    case XK_Return:
99    case XK_KP_Enter:
100       enter();
101       break;
102
103    default:
104       if (key >= 0x20 && key <= 0x7e)
105       {
106          text(cursor_position, 0) = String((char)key);
107          cursor_position++;
108       }
109       break;
110
111    }
112    if (cursor_position != 0)
113       x_cursor = fixed.TextWidth(text,cursor_position) + text_position;
114    else
115       x_cursor = text_position;
116
117    if (x_cursor < 0)
118    {
119       text_position += w/4;
120    }
121    else if ((unsigned)x_cursor > w)
122    {
123       text_position -= w / 4;
124    }
125    redraw();   //  Recreates the cursor.
126
127    return 1;
128 }
129
130 /*=========================================================================
131 **  NAME           : EV_ButtonPress - Handle press of mouse button
132 **  SYNOPSIS       :
133 **  PARAMETERS     :
134 **  RETURN VALUE   :
135 **
136 **  DESCRIPTION    : Buttonpress of the left mouse button puts the text
137 **                   cursor at the mouse's position and sets the focus to
138 **                   the edit window.
139 **                   The X server will send a FocusIn event as a result of
140 **                   the SetFocus
141 **
142 **  VARS USED      :
143 **  VARS CHANGED   :
144 **  FUNCTIONS USED :
145 **  SEE ALSO       :
146 **  LAST MODIFIED  : May 22, 1998
147 **=========================================================================
148 */
149
150
151 int edit::EV_ButtonPress(XButtonEvent ev)
152 {
153    if (selected_until != -1)
154    {
155       selected_until = -1;
156       redraw();
157    }
158
159    if (ev.button == 1)
160    { 
161       //  Left mouse button
162
163       if (focus_state != No_Focus)
164       {
165          //  The cursor is visible; hide it from its old position
166
167          toggle_cursor();
168       }
169       cursor_position = map_to_textposition(ev.x);
170       if (cursor_position > ~text)
171          cursor_position = ~text;
172
173       SetFocus();
174
175       if (focus_state != No_Focus)
176       {
177          //  If we already have the focus, show the cursor on its new
178          //  position, else the FocusIn event will take care of this.
179
180          toggle_cursor();
181       }
182    }
183    else if (ev.button == 2)
184    {
185       // Middle mouse button, paste the cut buffer
186
187       int   nbytes;
188       char  *paste_text;
189
190       paste_text = XFetchBytes(stddpy, &nbytes);
191       if (paste_text)
192       {
193          printf(" Pasting %s\n", paste_text);
194          text(cursor_position, 0) = paste_text;
195          redraw();
196       }
197    }
198    return 1;
199 }
200
201 /*=========================================================================
202 **  NAME           : EV_FocusIn - Handle FocusIn event
203 **  SYNOPSIS       :
204 **  PARAMETERS     :
205 **  RETURN VALUE   :
206 **
207 **  DESCRIPTION    : Four event handling functions work together to track
208 **                   the keyboard focus. The events involved are FocusIn,
209 **                   FocusOut, EnterNotify and LeaveNotify
210 **
211 **  VARS USED      :
212 **  VARS CHANGED   :
213 **  FUNCTIONS USED :
214 **  SEE ALSO       :
215 **  LAST MODIFIED  : May 21, 1998
216 **=========================================================================
217 */
218
219 int edit::EV_FocusIn(XFocusChangeEvent ev)
220 {
221    if (focus_state == No_Focus)
222       toggle_cursor();
223    focus_state = Explicit_Focus;
224    return 1;
225 }
226
227 int edit::EV_FocusOut(XFocusChangeEvent ev)
228 {
229    focus_state = No_Focus;
230    toggle_cursor();
231    return 1;
232 }
233 int edit::EV_EnterNotify(XCrossingEvent ev)
234 {
235    if (ev.focus && focus_state == No_Focus)
236    {
237       focus_state = Implicit_Focus;
238       toggle_cursor();
239    }
240    return 1;
241 }
242
243 int edit::EV_LeaveNotify(XCrossingEvent ev)
244 {
245    if (ev.focus && focus_state == Implicit_Focus)
246    {
247       focus_state = No_Focus;
248       toggle_cursor();
249    }
250    return 1;
251 }
252
253
254 /*=========================================================================
255 **  NAME           : EV_MotionNotify - handle motion event.
256 **  SYNOPSIS       :
257 **  PARAMETERS     :
258 **  RETURN VALUE   :
259 **
260 **  DESCRIPTION    : 
261 **
262 **  VARS USED      :
263 **  VARS CHANGED   :
264 **  FUNCTIONS USED :
265 **  SEE ALSO       :
266 **  LAST MODIFIED  : May 22, 1998
267 **=========================================================================
268 */
269
270 int edit::EV_MotionNotify(XMotionEvent ev)
271 {
272    selected_until = map_to_textposition(ev.x);
273
274    redraw();
275
276    return 1;
277 }
278
279 int edit::EV_ButtonRelease(XButtonEvent ev)
280 {
281    String selected_text;
282    int    selection_length;
283
284    if (ev.button == 1 && selected_until != -1)
285    {
286       selected_until = map_to_textposition(ev.x);
287
288       if (selected_until >= cursor_position)
289       {
290          selection_length = selected_until - cursor_position;
291          selected_text = text(cursor_position, selection_length);
292       }
293       else
294       {
295          selection_length = cursor_position - selected_until;
296          selected_text = text(selected_until, selection_length);
297       }
298       if (selected_text)
299       {
300          printf("%d chars selected: %s\n", selection_length,(char *)selected_text);
301
302          XStoreBytes(stddpy, selected_text, selection_length);
303       }
304       else
305       {
306          printf("Nothing selected\n");
307       }
308    }
309
310    return 1;
311 }
312
313 int edit::map_to_textposition(int x)
314 {
315
316    return (x - text_position) / 6;
317 }
318
319 int edit::map_to_pixelposition(int tp)
320 {
321       return fixed.TextWidth(text, tp) + text_position;
322 }
323
324 /*=========================================================================
325 **  NAME           : toggle_cursor
326 **  SYNOPSIS       :
327 **  PARAMETERS     :
328 **  RETURN VALUE   :
329 **
330 **  DESCRIPTION    : 
331 **
332 **  VARS USED      :
333 **  VARS CHANGED   :
334 **  FUNCTIONS USED :
335 **  SEE ALSO       :
336 **  LAST MODIFIED  : Mar 17, 1998
337 **=========================================================================
338 */
339
340 void edit::toggle_cursor(void)
341 {
342    int  x_cursor;
343
344    if (cursor_position != 0)
345       x_cursor = fixed.TextWidth(text,cursor_position) + text_position;
346    else
347       x_cursor = 0;
348
349    DrawLine(edit_cursor_gc, x_cursor, 1, x_cursor, 13);
350 }
351
352 /*=========================================================================
353 **  NAME           : redraw - Draw the edit object (again)
354 **  SYNOPSIS       :
355 **  PARAMETERS     :
356 **  RETURN VALUE   :
357 **
358 **  DESCRIPTION    : Clear the window and redraw the edited text.
359 **                   If part of the text is selected, draw this part
360 **                   in a different color.
361 **                   Draw a text cursor if we have the focus.
362 **
363 **  VARS USED      :
364 **  VARS CHANGED   :
365 **  FUNCTIONS USED :
366 **  SEE ALSO       :
367 **  LAST MODIFIED  : May 22, 1998
368 **=========================================================================
369 */
370
371 void edit::redraw(void)
372 {
373    int    selection_length;
374    String selected_text;
375    int    x_start, x_end;
376
377    /*  Redraw the entire text */
378
379    Clear();
380    DrawString(text_normal_gc, text_position, 12, text);
381
382    /*  If part of the text is selected, highlight this part */
383
384    if (selected_until != -1)
385    {
386       if (selected_until >= cursor_position)
387       {
388          selection_length = selected_until - cursor_position;
389          x_start = map_to_pixelposition(cursor_position);
390          x_end   = map_to_pixelposition(selected_until);
391          selected_text = text(cursor_position, selection_length);
392       }
393       else
394       {
395          selection_length = cursor_position - selected_until;
396          x_start = map_to_pixelposition(selected_until);
397          x_end   = map_to_pixelposition(cursor_position);
398          selected_text = text(selected_until, selection_length);
399       }
400
401       XFillRectangle(stddpy, ID(), inside_3D_gc, x_start, 1, x_end-x_start, 14);
402       DrawString(text_normal_gc, x_start, 12, selected_text);
403    }
404
405    /*  If we have the focus, draw the text cursor */
406
407    if (focus_state != No_Focus)
408    {
409       toggle_cursor();
410    }
411 }
412
413 void edit::enter(void)
414 {
415    ParentMessage(EDIT_ENTERED);
416 }
417
418 void edit::focuslost(void)
419 {
420    ParentMessage(EDIT_FOCUSLOST);
421 }
422
423
424 /*=========================================================================
425 **  NAME           : DeleteSelection - Delete any selected text
426 **  SYNOPSIS       :
427 **  PARAMETERS     :
428 **  RETURN VALUE   : The number of characters deleted.
429 **
430 **  DESCRIPTION    : 
431 **                   Make sure the cursor stays within the text. If the
432 **                   selection is 'right-to-left', i.e. from selected_until
433 **                   to cursor_position, the cursor is moved to the beginning
434 **                   of the selected text.
435 **
436 **  VARS USED      :
437 **  VARS CHANGED   :
438 **  FUNCTIONS USED :
439 **  SEE ALSO       :
440 **  LAST MODIFIED  : Jun 18, 1998
441 **=========================================================================
442 */
443
444 int edit::DeleteSelection(void)
445 {
446    int  selection_length;
447
448    selection_length = 0;
449
450    if (selected_until != -1)
451    {
452
453       if (selected_until >= cursor_position)
454       {
455          selection_length = selected_until - cursor_position;
456          text(cursor_position, selection_length) = "";
457       }
458       else
459       {
460          selection_length = cursor_position - selected_until;
461          text(selected_until, selection_length) = "";
462          cursor_position = selected_until;
463       }
464    }
465    selected_until = -1;  // Nothing selected
466
467    return selection_length;
468 }
469
470 /*=========================================================================
471 **  NAME           : ClearSelection
472 **  SYNOPSIS       :
473 **  PARAMETERS     :
474 **  RETURN VALUE   :
475 **
476 **  DESCRIPTION    : 
477 **
478 **  VARS USED      :
479 **  VARS CHANGED   :
480 **  FUNCTIONS USED :
481 **  SEE ALSO       :
482 **  LAST MODIFIED  : Jun 18, 1998
483 **=========================================================================
484 */
485
486 int edit::ClearSelection(void)
487 {
488    if (selected_until != -1)
489    {
490       selected_until = -1;
491       redraw();
492    }
493
494    return 0;
495 }
496
497 /*=========================================================================
498 **  NAME           : SelectAll
499 **  SYNOPSIS       :
500 **  PARAMETERS     :
501 **  RETURN VALUE   :
502 **
503 **  DESCRIPTION    : 
504 **
505 **  VARS USED      :
506 **  VARS CHANGED   :
507 **  FUNCTIONS USED :
508 **  SEE ALSO       :
509 **  LAST MODIFIED  : Jun 18, 1998
510 **=========================================================================
511 */
512
513 void edit::SelectAll(void)
514 {
515    cursor_position = 0;
516    selected_until = ~text - 1;
517    redraw();
518
519 }