home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / ltk / ltktextin.cc < prev    next >
C/C++ Source or Header  |  1998-11-27  |  12KB  |  488 lines

  1. //========================================================================
  2. //
  3. // LTKTextIn.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. #pragma implementation
  11. #endif
  12.  
  13. #include <stdlib.h>
  14. #include <stdarg.h>
  15. #include <stddef.h>
  16. #include <X11/Xlib.h>
  17. #include <X11/Xutil.h>
  18. #include <X11/keysym.h>
  19. #include "gtypes.h"
  20. #include "GString.h"
  21. #include "LTKWindow.h"
  22. #include "LTKTextIn.h"
  23. #include "LTKBorder.h"
  24.  
  25. #define horizBorder 2
  26. #define vertBorder  2
  27.  
  28. LTKTextIn::LTKTextIn(char *name1, int widgetNum1, int minWidth1,
  29.              char *fontName1, LTKStringValCbk doneCbk1,
  30.              char *tabTarget1):
  31.     LTKWidget(name1, widgetNum1) {
  32.   minWidth = minWidth1;
  33.   text = new GString();
  34.   active = gFalse;
  35.   firstChar = 0;
  36.   cursor = 0;
  37.   selectionEnd = 0;
  38.   dragging = gFalse;
  39.   doneCbk = doneCbk1;
  40.   tabTarget = tabTarget1;
  41.   fontName = fontName1;
  42.   fontStruct = NULL;
  43.   textGC = None;
  44. }
  45.  
  46. LTKTextIn::~LTKTextIn() {
  47.   delete text;
  48.   if (fontName && fontStruct) {
  49.     XFreeFont(getDisplay(), fontStruct);
  50.     XFreeGC(getDisplay(), textGC);
  51.   }
  52. }
  53.  
  54. long LTKTextIn::getEventMask() {
  55.   return LTKWidget::getEventMask() |
  56.          ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
  57.          PointerMotionHintMask | KeyPressMask;
  58. }
  59.  
  60. void LTKTextIn::setText(char *s) {
  61.   delete text;
  62.   text = new GString(s);
  63.   firstChar = 0;
  64.   if (getXWindow() != None && active)
  65.     xorCursor();
  66.   cursor = selectionEnd = 0;
  67.   if (getXWindow() != None) {
  68.     redrawTail(0);
  69.     if (active)
  70.       xorCursor();
  71.   }
  72. }
  73.  
  74. void LTKTextIn::layout1() {
  75.   XGCValues gcValues;
  76.  
  77.   if (textGC == None) {
  78.     if (fontName &&
  79.     (fontStruct = XLoadQueryFont(getDisplay(), fontName))) {
  80.       XGetGCValues(getDisplay(), getFgGC(),
  81.            GCForeground | GCBackground | GCGraphicsExposures,
  82.            &gcValues);
  83.       gcValues.font = fontStruct->fid;
  84.       textGC = XCreateGC(getDisplay(), parent->getXWindow(),
  85.              GCForeground | GCBackground | GCGraphicsExposures |
  86.              GCFont, &gcValues);
  87.     } else {
  88.       fontName = NULL;
  89.       fontStruct = parent->getXFontStruct();
  90.       textGC = getFgGC();
  91.     }
  92.   }
  93.   textHeight = fontStruct->ascent + fontStruct->descent;
  94.   textBase = fontStruct->ascent;
  95.   width = minWidth * fontStruct->max_bounds.width + 2 * horizBorder + 1;
  96.   height = textHeight + 2 * vertBorder;
  97. }
  98.  
  99. void LTKTextIn::layout3() {
  100.   XRectangle rect;
  101.  
  102.   LTKWidget::layout3();
  103.   rect.x = horizBorder - 1;   // need one pixel in left border for cursor
  104.   rect.y = 0;
  105.   rect.width = width - 2 * horizBorder + 1;
  106.   rect.height = height;
  107.   XSetClipRectangles(getDisplay(), textGC, 0, 0, &rect, 1, Unsorted);
  108. }
  109.  
  110. void LTKTextIn::redraw() {
  111.   XFillRectangle(getDisplay(), xwin, getBgGC(), 0, 0, width, height);
  112.   redrawTail(firstChar);
  113.   if (active)
  114.     xorCursor();
  115. }
  116.  
  117. void LTKTextIn::buttonPress(int mx, int my, int button, GBool dblClick) {
  118.   // move cursor
  119.   if (button == 1) {
  120.     xorCursor();
  121.     cursor = xToCursor(mx);
  122.     if (cursor < firstChar)
  123.       cursor = firstChar;
  124.     selectionEnd = cursor;
  125.     xorCursor();
  126.     dragging = gTrue;
  127.     dragAnchor = cursor;
  128.  
  129.   // paste
  130.   } else if (button == 2) {
  131.     parent->requestPaste(this);
  132.   }
  133. }
  134.  
  135. void LTKTextIn::buttonRelease(int mx, int my, int button, GBool click) {
  136.   dragging = gFalse;
  137.   if (cursor != selectionEnd)
  138.     parent->setSelection(this, new GString(text->getCString() + cursor,
  139.                        selectionEnd - cursor));
  140. }
  141.  
  142. void LTKTextIn::mouseMove(int mx, int my, int btn) {
  143.   int newCursor, newSelectionEnd;
  144.   int i;
  145.  
  146.   if (dragging) {
  147.     i = xToCursor(mx);
  148.     if (i >= dragAnchor) {
  149.       newCursor = dragAnchor;
  150.       newSelectionEnd = i;
  151.     } else {
  152.       newCursor = i;
  153.       newSelectionEnd = dragAnchor;
  154.     }
  155.     if (newCursor != cursor || newSelectionEnd != selectionEnd)
  156.       moveCursor(newCursor, newSelectionEnd, i);
  157.   }
  158. }
  159.  
  160. void LTKTextIn::activate(GBool on) {
  161.   if (active != on) {
  162.     if (on) {
  163.       xorCursor();
  164.       parent->setKeyWidget(this);
  165.       active = gTrue;
  166.     } else {
  167.       xorCursor();
  168.       selectionEnd = cursor;
  169.       parent->setKeyWidget(NULL);
  170.       active = gFalse;
  171.       if (doneCbk)
  172.     (*doneCbk)(this, widgetNum, text);
  173.     }
  174.   }
  175. }
  176.  
  177. void LTKTextIn::keyPress(KeySym key, Guint modifiers, char *s, int n) {
  178.   int newCursor, newSelectionEnd;
  179.   int redrawPos;
  180.   GBool killSelection;
  181.   LTKWidget *widget;
  182.  
  183.   newCursor = cursor;
  184.   killSelection = gTrue;
  185.   redrawPos = -1;
  186.   if (key == XK_Left) {        // left arrow
  187.     if (cursor > 0)
  188.       --newCursor;
  189.   } else if (key == XK_Right) {    // right arrow
  190.     if (cursor < text->getLength())
  191.       ++newCursor;
  192.   } else if (n >= 1) {
  193.     switch (s[0]) {
  194.     case '\001':        // ^A
  195.       newCursor = 0;
  196.       break;
  197.     case '\002':        // ^B
  198.       if (cursor > 0)
  199.     --newCursor;
  200.       break;
  201.     case '\005':        // ^E
  202.       newCursor = text->getLength();
  203.       break;
  204.     case '\006':        // ^F
  205.       if (cursor < text->getLength())
  206.     ++newCursor;
  207.       break;
  208.     case '\014':        // ^L
  209.       redrawPos = firstChar;
  210.       killSelection = gFalse;
  211.       break;
  212.     case '\b':            // bs
  213.     case '\177':        // del
  214.       if (selectionEnd > cursor) {
  215.     text->del(cursor, selectionEnd - cursor);
  216.     redrawPos = cursor;
  217.       } else if (cursor > 0) {
  218.     text->del(cursor - 1);
  219.     --newCursor;
  220.     redrawPos = newCursor;
  221.       }
  222.       break;
  223.     case '\004':        // ^D
  224.       if (selectionEnd > cursor) {
  225.     text->del(cursor, selectionEnd - cursor);
  226.     redrawPos = cursor;
  227.       } else if (cursor < text->getLength()) {
  228.     text->del(cursor);
  229.     redrawPos = cursor;
  230.       }
  231.       break;
  232.     case '\013':        // ^K
  233.       text->del(cursor, text->getLength() - cursor);
  234.       redrawPos = cursor;
  235.       break;
  236.     case '\025':        // ^U
  237.       text->clear();
  238.       newCursor = 0;
  239.       redrawPos = newCursor;
  240.       break;
  241.     case '\n':            // return, tab
  242.     case '\r':
  243.     case '\t':
  244.       activate(gFalse);
  245.       if (tabTarget)
  246.     if ((widget = parent->findWidget(tabTarget)))
  247.       widget->activate(gTrue);
  248.       newCursor = newSelectionEnd = cursor;
  249.       break;
  250.     default:            // insert char
  251.       if (s[0] >= 0x20) {
  252.     if (selectionEnd > cursor)
  253.       text->del(cursor, selectionEnd - cursor);
  254.     text->insert(cursor, s);
  255.     redrawPos = cursor;
  256.     ++newCursor;
  257.       }
  258.       break;
  259.     }
  260.   } else {            // ignore weird X keysyms
  261.     killSelection = gFalse;
  262.   }
  263.  
  264.   newSelectionEnd = killSelection ? newCursor : selectionEnd;
  265.   if (newCursor != cursor || newSelectionEnd != selectionEnd ||
  266.       redrawPos >= 0) {
  267.     xorCursor();
  268.     cursor = newCursor;
  269.     selectionEnd = newSelectionEnd;
  270.     redrawTail(redrawPos);
  271.     if (active)
  272.       xorCursor();
  273.   }
  274. }
  275.  
  276. void LTKTextIn::clearSelection() {
  277.   if (active)
  278.     xorCursor();
  279.   selectionEnd = cursor;
  280.   if (active)
  281.     xorCursor();
  282. }
  283.  
  284. void LTKTextIn::paste(GString *str) {
  285.   int redrawPos;
  286.  
  287.   if (active)
  288.     xorCursor();
  289.   text->insert(cursor, str);
  290.   redrawPos = cursor;
  291.   cursor += str->getLength();
  292.   selectionEnd = cursor;
  293.   redrawTail(redrawPos);
  294.   if (active)
  295.     xorCursor();
  296. }
  297.  
  298. int LTKTextIn::xToCursor(int mx) {
  299.   XCharStruct extents;
  300.   int direction, ascent, descent;
  301.   int x1, x2;
  302.   int pos;
  303.  
  304.   if (mx < horizBorder)
  305.     return firstChar > 0 ? firstChar - 1 : 0;
  306.  
  307.   x2 = horizBorder;
  308.   for (pos = firstChar; pos < text->getLength(); ++pos) {
  309.     XTextExtents(fontStruct, text->getCString() + pos, 1,
  310.          &direction, &ascent, &descent, &extents);
  311.     x1 = x2;
  312.     x2 += extents.width;
  313.     if (mx < (x1 + x2) / 2)
  314.       break;
  315.   }
  316.   return pos;
  317. }
  318.  
  319. int LTKTextIn::cursorToX(int cur) {
  320.   XCharStruct extents;
  321.   int direction, ascent, descent;
  322.   int x;
  323.  
  324.   x = horizBorder;
  325.   if (cur > firstChar) {
  326.     XTextExtents(fontStruct, text->getCString() + firstChar,
  327.          cur - firstChar,
  328.          &direction, &ascent, &descent, &extents);
  329.     x += extents.width;
  330.   }
  331.   return x;
  332. }
  333.  
  334. void LTKTextIn::xorCursor() {
  335.   int tx1, tx2, ty;
  336.   int i, j;
  337.  
  338.   ty = (height - textHeight) / 2;
  339.  
  340.   // draw cursor
  341.   if (cursor == selectionEnd) {
  342.     tx1 = cursorToX(cursor);
  343.     XDrawLine(getDisplay(), xwin, getXorGC(),
  344.           tx1 - 1, ty, tx1 - 1, ty + textHeight - 1);
  345.     XDrawLine(getDisplay(), xwin, getXorGC(),
  346.           tx1, ty, tx1, ty + textHeight - 1);
  347.  
  348.   // draw selection
  349.   } else {
  350.     i = (cursor >= firstChar) ? cursor : firstChar;
  351.     tx1 = cursorToX(i);
  352.     j = selectionEnd;
  353.     tx2 = cursorToX(j);
  354.     if (tx2 > width) {
  355.       tx2 = width;
  356.       j = xToCursor(tx2);
  357.       if (j < text->getLength())
  358.     ++j;
  359.     }
  360.     XFillRectangle(getDisplay(), xwin, getXorGC(),
  361.            tx1, ty, tx2 - tx1, textHeight);
  362.   }
  363. }
  364.  
  365. void LTKTextIn::moveCursor(int newCursor, int newSelectionEnd,
  366.                int visiblePos) {
  367.   GBool needRedraw;
  368.   int tx1, tx2, ty;
  369.   int i;
  370.  
  371.   // y coordinate
  372.   ty = (height - textHeight) / 2;
  373.  
  374.   // make sure moving end of selection is visible
  375.   needRedraw = gFalse;
  376.   if (visiblePos < firstChar) {
  377.     firstChar = visiblePos;
  378.     needRedraw = gTrue;
  379.   } else if (visiblePos > firstChar) {
  380.     tx1 = cursorToX(visiblePos);
  381.     if (tx1 > width - horizBorder - 1) {
  382.       do {
  383.     ++firstChar;
  384.     tx1 = cursorToX(visiblePos);
  385.       } while (tx1 > width - horizBorder - 1 && firstChar < visiblePos);
  386.       needRedraw = gTrue;
  387.     }
  388.   }
  389.   if (needRedraw) {
  390.     tx1 = horizBorder;
  391.     XFillRectangle(getDisplay(), xwin, getBgGC(),
  392.            tx1, ty, width - tx1, textHeight);
  393.     i = xToCursor(width);
  394.     if (i < text->getLength())
  395.       ++i;
  396.     XDrawString(getDisplay(), xwin, textGC, tx1, ty + textBase,
  397.         text->getCString() + firstChar, i - firstChar);
  398.     cursor = newCursor;
  399.     selectionEnd = newSelectionEnd;
  400.     xorCursor();
  401.   } else {
  402.  
  403.     // no selection previously
  404.     if (cursor == selectionEnd) {
  405.       xorCursor();
  406.  
  407.     } else {
  408.  
  409.       // shrank on the left
  410.       if (newCursor > cursor) {
  411.     tx1 = cursorToX(cursor);
  412.     tx2 = cursorToX(newCursor);
  413.     XFillRectangle(getDisplay(), xwin, getXorGC(),
  414.                tx1, ty, tx2 - tx1, textHeight);
  415.       }
  416.  
  417.       // shrank on the right
  418.       if (newSelectionEnd  < selectionEnd) {
  419.     tx1 = cursorToX(newSelectionEnd);
  420.     tx2 = cursorToX(selectionEnd);
  421.     XFillRectangle(getDisplay(), xwin, getXorGC(),
  422.                tx1, ty, tx2 - tx1, textHeight);
  423.       }
  424.     }
  425.  
  426.     // no selection left
  427.     if (newCursor == newSelectionEnd) {
  428.       cursor = newCursor;
  429.       selectionEnd = newSelectionEnd;
  430.       xorCursor();
  431.  
  432.     } else {
  433.  
  434.       // grew on the left
  435.       if (newCursor < cursor) {
  436.     tx1 = cursorToX(newCursor);
  437.     tx2 = cursorToX(cursor);
  438.     XFillRectangle(getDisplay(), xwin, getXorGC(),
  439.                tx1, ty, tx2 - tx1, textHeight);
  440.       }
  441.  
  442.       // grew on the right
  443.       if (newSelectionEnd > selectionEnd) {
  444.     tx1 = cursorToX(selectionEnd);
  445.     tx2 = cursorToX(newSelectionEnd);
  446.     XFillRectangle(getDisplay(), xwin, getXorGC(),
  447.                tx1, ty, tx2 - tx1, textHeight);
  448.       }
  449.  
  450.       cursor = newCursor;
  451.       selectionEnd = newSelectionEnd;
  452.     }
  453.   }
  454. }
  455.  
  456. void LTKTextIn::redrawTail(int i) {
  457.   int tx, ty;
  458.   int j;
  459.  
  460.   // make sure cursor is visible
  461.   if (cursor < firstChar) {
  462.     firstChar = cursor;
  463.     i = firstChar;
  464.   } else if (cursor > firstChar) {
  465.     tx = cursorToX(cursor);
  466.     if (tx > width - horizBorder - 1) {
  467.       do {
  468.     ++firstChar;
  469.     tx = cursorToX(cursor);
  470.       } while (tx > width - horizBorder - 1 && firstChar < cursor);
  471.       i = firstChar;
  472.     }
  473.   }
  474.  
  475.   // redraw if necessary
  476.   if (i >= 0) {
  477.     tx = cursorToX(i);
  478.     ty = (height - textHeight) / 2;
  479.     XFillRectangle(getDisplay(), xwin, getBgGC(), tx, 0, width - tx, height);
  480.     ty += textBase;
  481.     j = xToCursor(width);
  482.     if (j < text->getLength())
  483.       ++j;
  484.     XDrawString(getDisplay(), xwin, textGC, tx, ty,
  485.         text->getCString() + i, j - i);
  486.   }
  487. }
  488.