home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / ZINC_6.ZIP / DOSSRC.ZIP / NUMBER.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  19.9 KB  |  828 lines

  1. //    Zinc Interface Library - NUMBER.CPP
  2. //    COPYRIGHT (C) 1990, 1991.  All Rights Reserved.
  3. //    Zinc Software Incorporated.  Pleasant Grove, Utah  USA
  4.  
  5. #include "ui_win.hpp"
  6. #include <mem.h>
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. int NUM_STATE::operator == (NUM_STATE& rightOperand)
  13. {
  14.     return (memcmp(this, &rightOperand, sizeof(NUM_STATE)) == 0);
  15. }
  16.  
  17. int NUM_STATE::operator != (NUM_STATE& rightOperand)
  18. {
  19.     return (memcmp(this, &rightOperand, sizeof(NUM_STATE)) != 0);
  20. }
  21.  
  22. UIW_NUMBER::~UIW_NUMBER()
  23. {
  24.     if (!FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  25.         delete value;
  26.     if (range)
  27.         delete range;
  28. }
  29.  
  30. void UIW_NUMBER::BackspaceKey()
  31. {
  32.     if (state.cursor > 0)
  33.     {
  34.         state.cursor--;
  35.         DeleteChar();
  36.     }
  37. }
  38.  
  39. int UIW_NUMBER::CalcLeading(int width, char *dText)
  40. {
  41.     int maxWidth = Min(maxTextLen - 1, width - 1);
  42.     int textLen = strlen(dText);
  43.     int leading = 0;
  44.     if (woFlags & WOF_JUSTIFY_CENTER)
  45.         leading = Min((maxWidth - textLen) / 2, width);
  46.     else if (woFlags & WOF_JUSTIFY_RIGHT)
  47.         leading = Min(maxWidth - textLen, width);
  48.     if (leading < 0)
  49.         leading = 0;
  50.     return leading;
  51. }
  52.  
  53. void UIW_NUMBER::Constructor(void *a_value, int width, USHORT flags,
  54.     char *a_range, void (UIW_NUMBER::*a_BinaryToAscii)(),
  55.     void (UIW_NUMBER::*a_AsciiToBinary)(),
  56.     int (UIW_NUMBER::*a_ValidNumber)(),
  57.     int (*a_Validate)(void *object, int ccode))
  58. {
  59.     windowID[0] = ID_NUMBER;
  60.     windowID[1] = ID_STRING;
  61.     search.type = ID_NUMBER;
  62.  
  63.     if (type < NUM_FLOAT)
  64.         flags &= ~NMF_SCIENTIFIC;    // Scientific not allowed for whole nums.
  65.     if ( FlagSet(flags, NMF_SCIENTIFIC) )
  66.     {
  67.         flags |= NMF_DECIMAL_FLOAT;    // Fixed-point not allowed w/scientific.
  68.         flags &= ~NMF_COMMAS;        // Nor are commas.
  69.     }
  70.     BinaryToAscii = a_BinaryToAscii;
  71.     AsciiToBinary = a_AsciiToBinary;
  72.     ValidNumber   = a_ValidNumber;
  73.     Validate = a_Validate;
  74.     if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  75.         value = a_value;
  76.     else
  77.     {
  78.         value = new double;        // NOTE: This doesn't suck floating point code.
  79.         if (a_value)
  80.             memcpy(value, a_value, sizeof(double));
  81.         else
  82.             woStatus |= WOS_UNANSWERED;
  83.     }
  84.     ui_getcountryinfo();            // Insure we have country info.
  85.     insertMode = TRUE;
  86.     decimal = flags & NMF_DECIMAL_FLAGS;
  87.     if ((type >= NUM_FLOAT && decimal == 0) || decimal == NMF_DECIMAL_FLAGS)
  88.         decimal = 0xFF;
  89.     else if (decimal)
  90.         decimal--;
  91.     // Disallow floating decimal point with whole number types.
  92.     if (type < NUM_FLOAT && decimal == 0xFF)
  93.         decimal = 0;
  94.     nmFlags = flags;
  95.     range = (a_range) ? ui_strdup(a_range) : 0;
  96.     state.isMarked = FALSE;
  97.     maxTextLen = Min(width + 1, NUM_MAX_TEXT_LEN);
  98. }
  99.  
  100. void UIW_NUMBER::CopyBlock()
  101. {
  102.     char dText[40];
  103.     int  cursorColumn;
  104.  
  105.     Expand(dText, &cursorColumn);
  106.  
  107.     pasteLength = strlen(dText);
  108.     if (pasteBuffer)
  109.         delete pasteBuffer;
  110.     pasteBuffer = new char[pasteLength];
  111.     memcpy(pasteBuffer, dText, pasteLength);
  112.  
  113.     state.isMarked = FALSE;
  114. }
  115.  
  116. void UIW_NUMBER::CutBlock()
  117. {
  118.     pasteLength = ui_strlen(state.text);
  119.     if (pasteBuffer)
  120.         delete pasteBuffer;
  121.     pasteBuffer = new char[pasteLength];
  122.     memcpy(pasteBuffer, state.text, pasteLength);
  123.  
  124.     woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  125.     CopyBlock();
  126.     state.text[0] = '\0';
  127.     state.cursor = 0;
  128. }
  129.  
  130. void UIW_NUMBER::DataSet(void *newValue)
  131. {
  132.     if (newValue)
  133.     {
  134.         if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  135.             value = newValue;
  136.         else
  137.             memcpy(value, newValue, sizeof(double));
  138.     }
  139.     UI_WINDOW_OBJECT::Redisplay(FALSE);
  140. }
  141.  
  142. void UIW_NUMBER::DeleteChar()
  143. {
  144.     woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  145.     if (state.text[state.cursor] == 'E')        // Delete exponent.
  146.         state.text[state.cursor] = '\0';
  147.     else 
  148.         memmove(state.text + state.cursor, state.text + state.cursor + 1,
  149.             strlen(state.text + state.cursor) );
  150. }
  151.  
  152. int UIW_NUMBER::Event(const UI_EVENT &event)
  153. {
  154.     int viewOnly = (FlagSet(woFlags, WOF_VIEW_ONLY) ||
  155.         FlagSet(woAdvancedStatus, WOAS_TOO_SMALL)) ? TRUE : FALSE;
  156.     int ccode = UI_WINDOW_OBJECT::LogicalEvent(event, ID_STRING);
  157.     if (ccode == S_CREATE)
  158.     {
  159.         UI_WINDOW_OBJECT::Event(event);
  160.         int width = (relative.right + 1 - relative.left) / display->cellWidth;
  161.         if (FlagSet(woFlags, WOF_BORDER))
  162.             if (display->isText)
  163.                 width -= 2;
  164.             else
  165.                 width -= 1;
  166.         maxTextLen = Min(width + 1, NUM_MAX_TEXT_LEN);
  167.  
  168.         FormatNumber();
  169.     }
  170.     short cellWidth = display->cellWidth;
  171.     UI_REGION region;
  172.     UI_WINDOW_OBJECT::Border(0, region, 0);
  173.     short width = (region.right + 1 - region.left) / cellWidth;
  174.     USHORT key;
  175.     NUM_STATE oldStateInfo = state;
  176.     UCHAR forceDisplay = FALSE;
  177.     UI_PALETTE *palette;
  178.     int isCurrent = woStatus & WOS_CURRENT;
  179.     UCHAR reDisplay = TRUE;
  180.     UCHAR displayCheckRegion = FALSE;
  181.     int needValidate = NeedsValidation();
  182.  
  183.     if (!isCurrent)
  184.         state.isMarked = FALSE;
  185.     switch (ccode)
  186.     {
  187.     case E_KEY:
  188.         key = event.rawCode & 0xFF;
  189.         if ((key == '\b' || key >= ' ') && !viewOnly)
  190.         {
  191.             if (key == '\b')
  192.                 BackspaceKey();
  193.             else
  194.                 RegularKey(key);
  195.         }
  196.         else
  197.         {
  198.             reDisplay = FALSE;
  199.             ccode = S_UNKNOWN;
  200.         }
  201.         break;
  202.  
  203.     case L_LEFT:
  204.         if (state.cursor > 0)
  205.         {
  206.             state.cursor--;
  207.             woStatus |= WOS_NO_AUTO_CLEAR;
  208.         }
  209.         else
  210.             ccode = S_UNKNOWN;
  211.         break;
  212.  
  213.     case L_RIGHT:
  214.         if (state.text[state.cursor])
  215.         {
  216.             state.cursor++;
  217.             woStatus |= WOS_NO_AUTO_CLEAR;
  218.         }
  219.         else
  220.             ccode = S_UNKNOWN;
  221.         break;
  222.  
  223.     case L_BOL:
  224.         state.cursor = 0;
  225.         woStatus |= WOS_NO_AUTO_CLEAR;
  226.         break;
  227.  
  228.     case L_EOL:
  229.         state.cursor = ui_strlen(state.text);
  230.         woStatus |= WOS_NO_AUTO_CLEAR;
  231.         break;
  232.  
  233.     case L_DELETE:
  234.         if (!viewOnly)
  235.         {
  236.             if (state.isMarked)
  237.                 CutBlock();
  238.             else if (state.text[state.cursor])
  239.                 DeleteChar();
  240.         }
  241.         break;
  242.  
  243.     case L_INSERT_TOGGLE:
  244.         insertMode = !insertMode;
  245.         woStatus |= WOS_NO_AUTO_CLEAR;
  246.         forceDisplay = TRUE;
  247.         break;
  248.  
  249.     case L_MARK:
  250.         state.isMarked = !state.isMarked;
  251.         break;
  252.  
  253.     case L_VIEW:
  254.         eventManager->DeviceState(event.type, DM_EDIT);
  255.         break;
  256.  
  257.     case L_CUT:
  258.         if (!viewOnly)
  259.         {
  260.             if (state.isMarked)
  261.                 CutBlock();
  262.             else
  263.                 reDisplay = FALSE;
  264.             break;
  265.         }
  266.         // Continue to L_COPY_MARK if view only field.
  267.  
  268.     case L_COPY_MARK:
  269.         if (state.isMarked)
  270.             CopyBlock();
  271.         else
  272.             reDisplay = FALSE;
  273.         break;
  274.  
  275.     case L_CUT_PASTE:
  276.         if (state.isMarked)
  277.         {
  278.             if (viewOnly)
  279.                 CopyBlock();
  280.             else
  281.                 CutBlock();
  282.             break;
  283.         }
  284.         // Continue to L_PASTE.
  285.  
  286.     case L_PASTE:
  287.         if (!viewOnly)
  288.         {
  289.             if (event.type != E_KEY)
  290.                 SetCursor((event.position.column - region.left) / cellWidth, width);
  291.             PasteBlock();
  292.         }
  293.         break;
  294.  
  295.     case L_CONTINUE_MARK:
  296.         if (markColumn != (event.position.column - region.left) / cellWidth)
  297.             state.isMarked = TRUE;
  298.         break;
  299.  
  300.     case L_BEGIN_MARK:
  301.         state.isMarked = FALSE;
  302.         markColumn = (event.position.column - region.left) / cellWidth;
  303.         SetCursor(markColumn, width);
  304.         forceDisplay = TRUE;            // Force cursor to get updated.
  305.         break;
  306.  
  307.     case S_CURRENT:
  308.         switchedToReplaceMode = FALSE;
  309.         if (needValidate)
  310.             (*Validate)(this, ccode);
  311.  
  312.         // Clear the WOS_UNANSWERED and WOS_NO_AUTO_CLEAR bits
  313.         woStatus &= ~(WOS_UNANSWERED | WOS_NO_AUTO_CLEAR);
  314.         isCurrent = TRUE;
  315.         palette = UI_WINDOW_OBJECT::LogicalPalette(ccode);
  316.         displayCheckRegion = TRUE;
  317.         state.cursor = 0;
  318.         break;
  319.  
  320.     case S_DISPLAY_ACTIVE:
  321.         palette = UI_WINDOW_OBJECT::LogicalPalette(ccode);
  322.         displayCheckRegion = TRUE;
  323.         break;
  324.  
  325.     case S_NON_CURRENT:
  326.         if (!FlagSet(woStatus, WOS_UNANSWERED))
  327.         {
  328.             if ((this->*ValidNumber)())
  329.                 (this->*AsciiToBinary)();
  330.             else
  331.                 ccode = S_ERROR;
  332.             if (ccode == S_ERROR ||
  333.                  (needValidate && (*Validate)(this, ccode) != 0))
  334.             {
  335.                 ccode = S_ERROR;
  336.                 woStatus |= WOS_INVALID;
  337.                 reDisplay = FALSE;
  338.                 break;
  339.             }
  340.         }
  341.         FormatNumber();                            // Re-format from the binary.
  342.         woStatus &= ~WOS_INVALID;
  343.         // Continue to S_DISPLAY_INACTIVE.
  344.  
  345.     case S_DISPLAY_INACTIVE:
  346.         state.isMarked = FALSE;
  347.         palette = UI_WINDOW_OBJECT::LogicalPalette(ccode);
  348.         displayCheckRegion = TRUE;
  349.         break;
  350.  
  351.     case S_ERROR_RESPONSE:
  352.         forceDisplay = TRUE;
  353.         woStatus |= event.rawCode;
  354.         if (event.rawCode == WOS_UNANSWERED)
  355.             FormatNumber();
  356.         break;
  357.  
  358.     default:
  359.         ccode = UI_WINDOW_OBJECT::Event(event);
  360.         reDisplay = FALSE;
  361.         break;
  362.     }
  363.  
  364.     if (displayCheckRegion)
  365.     {
  366.         forceDisplay = TRUE;
  367.         if (!UI_WINDOW_OBJECT::NeedsUpdate(event, ccode) &&
  368.             oldStateInfo == state)
  369.             reDisplay = FALSE;
  370.         else
  371.             UI_WINDOW_OBJECT::Border(ccode, region, palette);
  372.     }
  373.  
  374.     char dText[40];
  375.     int cursorColumn;
  376.     if (reDisplay)
  377.     {
  378.         FixText();
  379.         Expand(dText, &cursorColumn);
  380.         int maxWidth = Min(maxTextLen - 1, width - 1);
  381.         if (strlen(dText) > maxWidth &&
  382.             (oldStateInfo != state || ccode == E_KEY))
  383.             _errorSystem->Beep();
  384.         if (forceDisplay || oldStateInfo != state)
  385.         {
  386.             Redisplay(region, width, dText);
  387.             UpdateCursor(region, width, dText, cursorColumn);
  388.         }
  389.     }
  390.     else if (ccode == S_CURRENT)
  391.     {
  392.         Expand(dText, &cursorColumn);
  393.         UpdateCursor(region, width, dText, cursorColumn);
  394.     }
  395.  
  396.     // Return the control code.
  397.     return (ccode);
  398. }
  399.  
  400. void UIW_NUMBER::Expand(char *expText, int *cursorColumn)
  401. {
  402.     char *currencyFmt;
  403.     char newText[40];
  404.  
  405.     newText[0] = '\0';
  406.     if (FlagSet(nmFlags, NMF_CURRENCY))
  407.     {
  408.         currencyFmt = (_countryInfo.co_currstyle < 2 ? "%s%s" : "%s %s");
  409.         if ( _countryInfo.co_currstyle == 0 ||
  410.             _countryInfo.co_currstyle == 2 )
  411.             sprintf(newText, currencyFmt, _countryInfo.co_curr, state.text);
  412.         else
  413.             sprintf(newText, currencyFmt, state.text, _countryInfo.co_curr);
  414.     }
  415.     else
  416.         strcpy(newText, state.text);
  417.     if (FlagSet(nmFlags, NMF_PERCENT))
  418.         strcat(newText, "%");
  419.     UIW_NUMBER::PlaceDecimal(newText, decimal);
  420.     if (FlagSet(nmFlags, NMF_COMMAS))
  421.         UIW_NUMBER::PlaceCommas(newText);
  422.     if (state.isNegative)
  423.         UIW_NUMBER::FixNegative(newText, nmFlags & NMF_CREDIT);
  424.     strcpy(expText, newText);
  425.     int match = 0;
  426.     for (int index = 0; index <= state.cursor && newText[match]; index++)
  427.     {
  428.         while (newText[match] != state.text[index] && newText[match] &&
  429.             newText[match] != '%' && newText[match] != ')')
  430.             match++;
  431.         if (index < state.cursor && newText[match] == state.text[index])
  432.             match++;
  433.     }
  434.     *cursorColumn = match;
  435. }
  436.  
  437. void UIW_NUMBER::FixNegative(char *buff, int credit)
  438. {
  439.     memmove(buff + 1, buff, strlen(buff) + 1);
  440.     *buff = credit ? '(' : '-';
  441.     if (credit)
  442.         strcat(buff, ")");
  443. }
  444.  
  445. void UIW_NUMBER::FixText()
  446. {
  447.     char *text = state.text;
  448.     if (text[0] == '\0')
  449.     {
  450.         strcpy(text, "0");
  451.         state.cursor = 1;
  452.     }
  453.     if (decimal && decimal != 0xFF)
  454.     {
  455.         while (strlen(text) <= decimal)
  456.         {
  457.             memmove(text + 1, text, strlen(text) + 1);
  458.             state.cursor++;
  459.             text[0] = '0';
  460.         }
  461.     }
  462.     // Strip leading zeroes, but only if we have enough decimal places.
  463.     while (text[0] == '0' && isdigit(text[1]) )
  464.     {
  465.         if (decimal && decimal != 0xFF && strlen(text) <= decimal + 1)
  466.             break;
  467.         memmove(text, text + 1, strlen(text));
  468.         if (state.cursor)
  469.             state.cursor--;
  470.     }
  471. }
  472.  
  473. void UIW_NUMBER::FormatNumber()
  474. {
  475.     (this->*BinaryToAscii)();
  476.     if (state.text[0] == '-')
  477.     {
  478.         strcpy(state.text, state.text + 1);
  479.         state.isNegative = TRUE;
  480.     }
  481.     else
  482.         state.isNegative = FALSE;
  483.     state.cursor = 0;                // Default to cursor at beginning.
  484.     FixText();
  485. }
  486.  
  487. void UIW_NUMBER::PasteBlock()
  488. {
  489.     char *src = pasteBuffer;
  490.     int src_len = pasteLength;
  491.  
  492.     if (pasteBuffer && !state.isMarked)
  493.     {
  494.         woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  495.         state.cursor = 0;
  496.         while (state.cursor < maxTextLen - 1 && src_len)
  497.         {
  498.             if (UIW_NUMBER::ValidNumChar(*src, decimal))
  499.                 state.text[state.cursor++] = *src;
  500.             src++;
  501.             src_len--;
  502.         }
  503.         state.text[state.cursor] = '\0';
  504.         state.cursor = 0;
  505.     }
  506. }
  507.  
  508. void UIW_NUMBER::PlaceCommas(char *buff)
  509. {
  510.     char tempBuff[40];
  511.     char *tempPtr = tempBuff;
  512.     char *buffPtr = buff;
  513.     int  digits;
  514.  
  515.     while (*buffPtr)
  516.     {
  517.         if (*buffPtr != _countryInfo.co_thsep[0])
  518.             *tempPtr++ = *buffPtr;
  519.         buffPtr++;
  520.     }
  521.     *tempPtr = '\0';
  522.     tempPtr = strrchr(tempBuff, _countryInfo.co_desep[0]);
  523.     if (!tempPtr)
  524.         tempPtr = strchr(tempBuff, '\0');
  525.     while (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1)))
  526.         tempPtr--;
  527.     digits = 0;
  528.     while (tempPtr > &tempBuff[0] && isdigit(*(tempPtr - 1)))
  529.     {
  530.         digits++;
  531.         tempPtr--;
  532.         if (digits % 3 == 0 && tempPtr > &tempBuff[0] &&
  533.             isdigit(*(tempPtr - 1)))
  534.         {
  535.             memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  536.             *tempPtr = _countryInfo.co_thsep[0];
  537.         }
  538.     }
  539.     tempPtr = strrchr(tempBuff, _countryInfo.co_desep[0]);
  540.     if (tempPtr && _countryInfo.co_thsep[0] != ',')
  541.     {
  542.         tempPtr++;
  543.         digits = 0;
  544.         while (isdigit(*tempPtr))
  545.         {
  546.             digits++;
  547.             tempPtr++;
  548.             if ( digits % 3 == 0 && isdigit(*(tempPtr + 1)) )
  549.             {
  550.                 memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  551.                 *tempPtr++ = _countryInfo.co_thsep[0];
  552.             }
  553.         }
  554.     }
  555.     strcpy(buff, tempBuff);
  556. }
  557.  
  558. void UIW_NUMBER::PlaceDecimal(char *buff, int decimal)
  559. {
  560.     char tempBuff[40];
  561.     char *tempPtr = tempBuff;
  562.     char *buffPtr = buff;
  563.  
  564.     if (decimal != 0xFF)
  565.     {
  566.         while (*buffPtr)
  567.         {
  568.             if (*buffPtr != _countryInfo.co_desep[0])
  569.                 *tempPtr++ = *buffPtr;
  570.             buffPtr++;
  571.         }
  572.         *tempPtr = '\0';
  573.         if (decimal)
  574.         {
  575.             while (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1)))
  576.                 tempPtr--;
  577.             while (tempPtr > &tempBuff[0] && decimal)
  578.             {
  579.                 if (isdigit(*(tempPtr - 1)))
  580.                     decimal--;
  581.                 else if (*(tempPtr - 1) != _countryInfo.co_thsep[0])
  582.                     break;
  583.                 tempPtr--;
  584.             }
  585.             if (decimal || tempPtr == &tempBuff[0] ||
  586.                 (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1))))
  587.             {
  588.                 memmove(tempPtr + decimal + 2, tempPtr, strlen(tempPtr) + 1);
  589.                 *tempPtr = '0';
  590.                 *(tempPtr + 1) = _countryInfo.co_desep[0];
  591.                 if (decimal)
  592.                     memset(tempPtr + 2, '0', decimal);
  593.             }
  594.             else
  595.             {
  596.                 memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  597.                 *tempPtr = _countryInfo.co_desep[0];
  598.             }
  599.         }
  600.         strcpy(buff, tempBuff);
  601.     }
  602. }
  603.  
  604. void UIW_NUMBER::Redisplay(UI_REGION ®ion, int width, char *dText)
  605. {
  606.     UI_PALETTE *palette = lastPalette;
  607.     // Pre-fill for graphics or unanswered field.
  608.     if (!display->isText || (woStatus & WOS_UNANSWERED))
  609.         display->Rectangle(screenID, region, palette, 0, TRUE);
  610.     int textLen = strlen(dText);
  611.     int leading = CalcLeading(width, dText);
  612.     textLen = Min(textLen, width - leading);
  613.     int trailing = width - textLen - leading;
  614.     int textHeight = display->TextHeight("W");
  615.     int bottom = region.top + textHeight - 1;
  616.     if (bottom <= region.bottom && (woStatus & WOS_UNANSWERED) == 0)
  617.     {
  618.         if (!display->isText)            // Center text vertically.
  619.         {
  620.             int vertRoom = region.bottom + 1 - region.top - textHeight;
  621.             region.top += (vertRoom + 1) / 2;
  622.             region.bottom += (vertRoom + 1) / 2;
  623.         }
  624.         if (leading && display->isText)
  625.             display->Rectangle(screenID, region.left, region.top,
  626.                 region.left + leading - 1, region.bottom, palette, 0, TRUE);
  627.         display->Text(screenID, region.left + leading * display->cellWidth,
  628.             region.top, dText, palette, textLen, FALSE);
  629.         if (trailing && display->isText)
  630.             display->Rectangle(screenID, region.left + leading + textLen,
  631.                 region.top, region.left + leading + textLen + trailing - 1,
  632.                 region.bottom, palette, 0, TRUE);
  633.         if (state.isMarked)
  634.             display->Text(screenID, region.left, region.top, NULL,
  635.                 _xorPalette, width, TRUE, TRUE);
  636.     }
  637. }
  638.  
  639. void UIW_NUMBER::RegularChar(USHORT key)
  640. {
  641.     int autoClear = FALSE;
  642.     if (FlagSet(woFlags, WOF_AUTO_CLEAR) &&
  643.         !FlagSet(woStatus, WOS_NO_AUTO_CLEAR))
  644.     {
  645.         autoClear = TRUE;
  646.         int index = state.cursor;
  647.         while (index)
  648.         {
  649.             index--;
  650.             if (state.text[index] != '0')
  651.                 autoClear = FALSE;
  652.         }
  653.     }
  654.     if (autoClear)
  655.     {
  656.         state.text[0] = key;
  657.         state.text[1] = '\0';
  658.         state.cursor = 1;
  659.     }
  660.     else
  661.     {
  662.         if (!insertMode && state.text[state.cursor])
  663.             DeleteChar();        // Replace mode - delete and then insert.
  664.         if (ui_strlen(state.text) < maxTextLen - 1)
  665.         {
  666.             memmove(state.text + state.cursor + 1, state.text + state.cursor,
  667.                 strlen(state.text + state.cursor) + 1);
  668.             state.text[state.cursor++] = key;
  669.         }
  670.         if (state.text[state.cursor] == '\0' && switchedToReplaceMode)
  671.         {
  672.             insertMode = TRUE;
  673.             switchedToReplaceMode = FALSE;
  674.         }
  675.     }
  676. }
  677.  
  678. void UIW_NUMBER::RegularKey(USHORT key)
  679. {
  680.     char valid_list[80];
  681.  
  682.     sprintf(valid_list, "0123456789%c",
  683.         decimal ? _countryInfo.co_desep[0] : '\0');
  684.     if (!FlagSet(nmFlags, NMF_UNSIGNED))
  685.         strcat(valid_list, "-+");
  686.     if (FlagSet(nmFlags, NMF_SCIENTIFIC))
  687.         strcat(valid_list, "Ee");
  688.     if (strchr(valid_list, key))
  689.     {
  690.         if (key == _countryInfo.co_desep[0])
  691.         {
  692.             if (decimal == 0xFF)    // Floating decimal - replace the point.
  693.             {
  694.                 char *exp = strchr(state.text, 'E');
  695.                 if (!exp || exp >= state.text + state.cursor)
  696.                 {    // Don't allow decimal inside the exponent.
  697.                      char *dec = strchr(state.text, _countryInfo.co_desep[0]);
  698.                     if (dec && (insertMode || state.text[state.cursor] != *dec))
  699.                     {
  700.                         memmove(dec, dec + 1, strlen(dec));
  701.                         if (state.text + state.cursor > dec)
  702.                             state.cursor--;
  703.                     }
  704.                     RegularChar(key);
  705.                 }
  706.             }
  707.             else                    // Fixed decimal.
  708.             {
  709.                 int nullPos = ui_strlen(state.text);
  710.                 int position = (int)(nullPos - state.cursor);
  711.                 if (position < decimal)
  712.                 {
  713.                     int extra = decimal - position;
  714.                     memset(state.text + nullPos, '0', extra);
  715.                     state.text[nullPos + extra] = '\0';
  716.                 }
  717.                 else if (position > decimal)
  718.                 {
  719.                     int clip = position - decimal;
  720.                     state.text[nullPos - clip] = '\0';
  721.                 }
  722.                 if (insertMode)
  723.                 {
  724.                     insertMode = FALSE;
  725.                     switchedToReplaceMode = TRUE;
  726.                 }
  727.             }
  728.         }
  729.         else if (key == '-' || key == '+')
  730.         {
  731.             char *exp;
  732.             if (FlagSet(nmFlags, NMF_SCIENTIFIC) &&
  733.                 (exp = strchr(state.text, 'E')) &&
  734.                 state.text + state.cursor >= exp)
  735.             {
  736.                 exp++;        // Point just after the 'E'.
  737.                 if (*exp == '-')
  738.                 {
  739.                     memmove(exp, exp + 1, strlen(exp));
  740.                     if (state.text + state.cursor >= exp + 1)
  741.                         state.cursor--;
  742.                 }
  743.                 else if (key == '-')
  744.                 {
  745.                     memmove(exp + 1, exp, strlen(exp) + 1);
  746.                     *exp = '-';
  747.                     if (state.text + state.cursor >= exp)
  748.                         state.cursor++;
  749.                 }
  750.             }
  751.             else
  752.                 state.isNegative = key == '+' ? FALSE : !state.isNegative;
  753.         }
  754.         else if (toupper(key) == 'E')
  755.         {
  756.             char *exp = strchr(state.text, 'E');
  757.             if (exp)
  758.             {
  759.                 state.cursor = (UCHAR)(exp + 1 - state.text);
  760.                 if (state.text[state.cursor] == '-')
  761.                     state.cursor++;
  762.             }
  763.             else
  764.             {
  765.                 state.cursor = ui_strlen(state.text);
  766.                 RegularChar('E');
  767.             }
  768.         }
  769.         else // digit
  770.             RegularChar(key);
  771.         woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  772.     }
  773. }
  774.  
  775. void UIW_NUMBER::SetCursor(int column, int width)
  776. {
  777.     char expandedText[40];
  778.     int cursorColumn;
  779.     int maxWidth = Min(maxTextLen - 1, width - 1);
  780.  
  781.     Expand(expandedText, &cursorColumn);
  782.     int textLen = strlen(expandedText);
  783.     int leading = 0;
  784.     if (FlagSet(woFlags, WOF_JUSTIFY_CENTER))
  785.         leading = Min((maxWidth - textLen) / 2, width);
  786.     else if (FlagSet(woFlags, WOF_JUSTIFY_RIGHT))
  787.         leading = Min(maxWidth - textLen, width);
  788.     if (leading < 0)
  789.         leading = 0;
  790.     char *screen_cursor = expandedText + column - leading;
  791.     char *expNull = strchr(expandedText, '\0');
  792.     if (screen_cursor > expNull)
  793.         screen_cursor = expNull;
  794.     int match = 0;
  795.     for (char *cp = expandedText; cp < screen_cursor && state.text[match]; cp++)
  796.         if (strchr(state.text, *cp))
  797.             match++;
  798.     state.cursor = match;
  799. }
  800.  
  801. void UIW_NUMBER::UpdateCursor(UI_REGION ®ion, int width, char *dText,
  802.     int cursorColumn)
  803. {
  804.     int leading = CalcLeading(width, dText);
  805.     if (FlagSet(woStatus, WOS_CURRENT) && (leading + cursorColumn < width))
  806.     {
  807.         int trueColumn =
  808.             region.left + (leading + cursorColumn) * display->cellWidth;
  809.         if (!FlagSet(woFlags, WOF_VIEW_ONLY) &&
  810.             !FlagSet(woAdvancedStatus, WOAS_TOO_SMALL) && trueColumn >= 0 && 
  811.             trueColumn < display->columns && region.top >= 0 && 
  812.             region.top < display->lines)
  813.         {
  814.             eventManager->DevicePosition(E_CURSOR, trueColumn, region.top);
  815.             eventManager->DeviceState(E_CURSOR, ((insertMode) ? DC_INSERT : DC_OVERTYPE));
  816.         }
  817.     }
  818. }
  819.  
  820. int UIW_NUMBER::ValidNumChar(char val, int decimalPoint)
  821. {
  822.     if (isdigit(val) ||
  823.         (decimalPoint == 0xFF && val == _countryInfo.co_desep[0]))
  824.         return (TRUE);
  825.     return (FALSE);
  826. }
  827.  
  828.