home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / ZINC_5.ZIP / WINSRC.ZIP / NUMBER.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  20.4 KB  |  864 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.     // Match with the appropriate Windows 3.0 flags.
  100.     if (FlagSet(woFlags, WOF_BORDER) && !FlagSet(woFlags, WOF_NON_FIELD_REGION))
  101.         MSWindowsStyle |= WS_BORDER;
  102.     if (FlagSet(woFlags, WOF_JUSTIFY_CENTER))
  103.         MSWindowsStyle |= ES_CENTER | ES_MULTILINE;
  104.     if (FlagSet(woFlags, WOF_JUSTIFY_RIGHT))
  105.         MSWindowsStyle |= ES_RIGHT | ES_MULTILINE;
  106. }
  107.  
  108. void UIW_NUMBER::CopyBlock()
  109. {
  110.     char dText[40];
  111.     int  cursorColumn;
  112.  
  113.     Expand(dText, &cursorColumn);
  114.  
  115.     pasteLength = strlen(dText);
  116.     if (pasteBuffer)
  117.         delete pasteBuffer;
  118.     pasteBuffer = new char[pasteLength];
  119.     memcpy(pasteBuffer, dText, pasteLength);
  120.  
  121.     state.isMarked = FALSE;
  122. }
  123.  
  124. void UIW_NUMBER::CutBlock()
  125. {
  126.     pasteLength = ui_strlen(state.text);
  127.     if (pasteBuffer)
  128.         delete pasteBuffer;
  129.     pasteBuffer = new char[pasteLength];
  130.     memcpy(pasteBuffer, state.text, pasteLength);
  131.  
  132.     woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  133.     CopyBlock();
  134.     state.text[0] = '\0';
  135.     state.cursor = 0;
  136. }
  137.  
  138. void UIW_NUMBER::DataSet(void *newValue)
  139. {
  140.     if (newValue)
  141.     {
  142.         if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  143.             value = newValue;
  144.         else
  145.             memcpy(value, newValue, sizeof(double));
  146.     }
  147.     UI_WINDOW_OBJECT::Redisplay(FALSE);
  148. }
  149.  
  150. void UIW_NUMBER::DeleteChar()
  151. {
  152.     woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  153.     if (state.text[state.cursor] == 'E')        // Delete exponent.
  154.         state.text[state.cursor] = '\0';
  155.     else 
  156.         memmove(state.text + state.cursor, state.text + state.cursor + 1,
  157.             strlen(state.text + state.cursor) );
  158. }
  159.  
  160. #pragma argsused
  161. int UIW_NUMBER::Event(const UI_EVENT &event)
  162. {
  163.     int viewOnly = (FlagSet(woFlags, WOF_VIEW_ONLY) ||
  164.         FlagSet(woAdvancedStatus, WOAS_TOO_SMALL)) ? TRUE : FALSE;
  165.     int ccode = UI_WINDOW_OBJECT::LogicalEvent(event, ID_STRING);
  166.  
  167.     short cellWidth = display->cellWidth;
  168.     short width = (true.right + 1 - true.left) / cellWidth;
  169.     USHORT key;
  170.     NUM_STATE oldStateInfo = state;
  171.     UCHAR forceDisplay = FALSE;
  172.     int isCurrent = woStatus & WOS_CURRENT;
  173.     UCHAR reDisplay = TRUE;
  174.     UCHAR displayCheckRegion = FALSE;
  175.     int needValidate = NeedsValidation();
  176.  
  177.     if (!isCurrent)
  178.         state.isMarked = FALSE;
  179.     switch (ccode)
  180.     {
  181.     case S_CREATE:
  182.     case S_SIZE:
  183.         ccode = UI_WINDOW_OBJECT::Event(event);
  184.  
  185.         true.bottom += 1;
  186.         true.right += 1;
  187.         if (FlagSet(woFlags, WOF_BORDER))
  188.             true.bottom -= 2 * HIWORD(GetDialogBaseUnits()) / 8;
  189.  
  190.         width = (true.right + 1 - true.left) / cellWidth;
  191.         maxTextLen = Min(width, NUM_MAX_TEXT_LEN);
  192.         FormatNumber();
  193.  
  194.         UI_WINDOW_OBJECT *root = parent;
  195.         while (root->parent && !root->hWnd)
  196.             root = root->parent;
  197.         if (!root->hWnd)
  198.             break;
  199.         POINT client = { 0, 0 };
  200.         ClientToScreen(root->hWnd, &client);
  201.  
  202.         if (!hWnd)
  203.         {
  204.             hWnd = CreateWindow("Edit", NULL,
  205.                 WS_CHILD | WS_VISIBLE | MSWindowsStyle,
  206.                 true.left - client.x, true.top - client.y,
  207.                 true.right - true.left, true.bottom - true.top,
  208.                 root->hWnd, 1, ((UI_MSWINDOWS_DISPLAY *)display)->hInstance, NULL);
  209.             screenID = hWnd;
  210.  
  211.             SendMessage(hWnd, EM_LIMITTEXT, maxTextLen, 0L);
  212.         }
  213.         else if (hWnd)
  214.         {
  215.             RECT windowRect;
  216.             GetWindowRect(hWnd, &windowRect);
  217.             if (true.left != windowRect.left || true.top != windowRect.top ||
  218.                 true.right != windowRect.right || true.bottom != windowRect.bottom)
  219.             {
  220.                 MoveWindow(hWnd, true.left - client.x, true.top - client.y,
  221.                     true.right - true.left, true.bottom - true.top, TRUE);
  222.                 SendMessage(hWnd, WM_NCPAINT, 0, 0x0L);
  223.             }
  224.         }
  225.  
  226.         if (FlagSet(woAdvancedStatus, WOAS_TOO_SMALL))
  227.         {
  228.             SendMessage(hWnd, WM_KILLFOCUS, parent->hWnd, 0L);
  229.             SendMessage(hWnd, WM_ENABLE, 0, 0);
  230.         }
  231.         else
  232.             SendMessage(hWnd, WM_ENABLE, 1, 0);
  233.         break;
  234.  
  235.     case E_KEY:
  236.         key = event.rawCode & 0xFF;
  237.         if ((key == '\b' || key >= ' ') && !viewOnly)
  238.         {
  239.             if (key == '\b')
  240.                 BackspaceKey();
  241.             else
  242.                 RegularKey(key);
  243.         }
  244.         else
  245.         {
  246.             reDisplay = FALSE;
  247.             ccode = S_UNKNOWN;
  248.         }
  249.         break;
  250.  
  251.     case L_LEFT:
  252.         if (state.cursor > 0)
  253.         {
  254.             state.cursor--;
  255.             woStatus |= WOS_NO_AUTO_CLEAR;
  256.         }
  257.         else
  258.             ccode = S_UNKNOWN;
  259.         break;
  260.  
  261.     case L_RIGHT:
  262.         if (state.text[state.cursor])
  263.         {
  264.             state.cursor++;
  265.             woStatus |= WOS_NO_AUTO_CLEAR;
  266.         }
  267.         else
  268.             ccode = S_UNKNOWN;
  269.         break;
  270.  
  271.     case L_BOL:
  272.         state.cursor = 0;
  273.         woStatus |= WOS_NO_AUTO_CLEAR;
  274.         break;
  275.  
  276.     case L_EOL:
  277.         state.cursor = ui_strlen(state.text);
  278.         woStatus |= WOS_NO_AUTO_CLEAR;
  279.         break;
  280.  
  281.     case L_DELETE:
  282.         if (!viewOnly)
  283.         {
  284.             if (state.isMarked)
  285.                 CutBlock();
  286.             else if (state.text[state.cursor])
  287.                 DeleteChar();
  288.         }
  289.         break;
  290.  
  291.     case L_INSERT_TOGGLE:
  292.         insertMode = !insertMode;
  293.         woStatus |= WOS_NO_AUTO_CLEAR;
  294.         forceDisplay = TRUE;
  295.         break;
  296.  
  297.     case L_MARK:
  298.         state.isMarked = !state.isMarked;
  299.         break;
  300.  
  301.     case L_VIEW:
  302.         eventManager->DeviceState(event.type, DM_EDIT);
  303.         break;
  304.  
  305.     case L_CUT:
  306.         if (!viewOnly)
  307.         {
  308.             if (state.isMarked)
  309.                 CutBlock();
  310.             else
  311.                 reDisplay = FALSE;
  312.             break;
  313.         }
  314.         // Continue to L_COPY_MARK if view only field.
  315.  
  316.     case L_COPY_MARK:
  317.         if (state.isMarked)
  318.             CopyBlock();
  319.         else
  320.             reDisplay = FALSE;
  321.         break;
  322.  
  323.     case L_CUT_PASTE:
  324.         if (state.isMarked)
  325.         {
  326.             if (viewOnly)
  327.                 CopyBlock();
  328.             else
  329.                 CutBlock();
  330.             break;
  331.         }
  332.         // Continue to L_PASTE.
  333.  
  334.     case L_PASTE:
  335.         if (!viewOnly)
  336.         {
  337.             if (event.type != E_KEY)
  338.                 SetCursor((event.position.column - true.left) / cellWidth, width);
  339.             PasteBlock();
  340.         }
  341.         break;
  342.  
  343.     case L_CONTINUE_MARK:
  344.         if (markColumn != (event.position.column - true.left) / cellWidth)
  345.             state.isMarked = TRUE;
  346.         break;
  347.  
  348.     case L_BEGIN_MARK:
  349.         state.isMarked = FALSE;
  350.         markColumn = (event.position.column - true.left) / cellWidth;
  351.         SetCursor(markColumn, width);
  352.         forceDisplay = TRUE;            // Force cursor to get updated.
  353.         break;
  354.  
  355.     case S_CURRENT:
  356.         switchedToReplaceMode = FALSE;
  357.         if (needValidate)
  358.             (*Validate)(this, ccode);
  359.  
  360.         // Clear the WOS_UNANSWERED and WOS_NO_AUTO_CLEAR bits
  361.         woStatus &= ~(WOS_UNANSWERED | WOS_NO_AUTO_CLEAR);
  362.         isCurrent = TRUE;
  363.         displayCheckRegion = TRUE;
  364.         state.cursor = 0;
  365.         if (!FlagSet(woFlags, WOF_VIEW_ONLY))
  366.         {
  367.             SendMessage(hWnd, WM_KILLFOCUS, parent->hWnd, 0L);
  368.             SendMessage(hWnd, WM_SETFOCUS, parent->hWnd, 0L);
  369.         }
  370.         break;
  371.  
  372.     case S_DISPLAY_ACTIVE:
  373.         displayCheckRegion = TRUE;
  374.         if (FlagSet(woStatus, WOS_CURRENT) && !FlagSet(woFlags, WOF_VIEW_ONLY))
  375.         {
  376.             SendMessage(hWnd, WM_KILLFOCUS, parent->hWnd, 0L);
  377.             SendMessage(hWnd, WM_SETFOCUS, parent->hWnd, 0L);
  378.         }
  379.         break;
  380.  
  381.     case S_NON_CURRENT:
  382.         if (!FlagSet(woStatus, WOS_UNANSWERED))
  383.         {
  384.             if ((this->*ValidNumber)())
  385.                 (this->*AsciiToBinary)();
  386.             else
  387.                 ccode = S_ERROR;
  388.             if (ccode == S_ERROR ||
  389.                  (needValidate && (*Validate)(this, ccode) != 0))
  390.             {
  391.                 ccode = S_ERROR;
  392.                 woStatus |= WOS_INVALID;
  393.                 reDisplay = FALSE;
  394.                 break;
  395.             }
  396.         }
  397.         FormatNumber();                            // Re-format from the binary.
  398.         woStatus &= ~WOS_INVALID;
  399.         // Continue to S_DISPLAY_INACTIVE.
  400.  
  401.     case S_DISPLAY_INACTIVE:
  402.         state.isMarked = FALSE;
  403.         displayCheckRegion = TRUE;
  404.         SendMessage(hWnd, WM_KILLFOCUS, parent->hWnd, 0L);
  405.         break;
  406.  
  407.     case S_ERROR_RESPONSE:
  408.         forceDisplay = TRUE;
  409.         woStatus |= event.rawCode;
  410.         if (event.rawCode == WOS_UNANSWERED)
  411.         {
  412.             FormatNumber();
  413.             SetWindowText(hWnd, "");
  414.             GetWindowText(hWnd, state.text, maxTextLen);
  415.         }
  416.         displayCheckRegion = TRUE;
  417.         reDisplay = TRUE;
  418.         if (FlagSet(woStatus, WOS_CURRENT) && !FlagSet(woFlags, WOF_VIEW_ONLY))
  419.         {
  420.             SendMessage(hWnd, WM_KILLFOCUS, parent->hWnd, 0L);
  421.             SendMessage(hWnd, WM_SETFOCUS, parent->hWnd, 0L);
  422.         }
  423.         break;
  424.  
  425.     default:
  426.         ccode = UI_WINDOW_OBJECT::Event(event);
  427.         reDisplay = FALSE;
  428.         break;
  429.     }
  430.  
  431.     if (displayCheckRegion)
  432.     {
  433.         forceDisplay = TRUE;
  434.         if (!UI_WINDOW_OBJECT::NeedsUpdate(event, ccode) &&
  435.             oldStateInfo == state)
  436.             reDisplay = FALSE;
  437.     }
  438.  
  439.     char dText[40];
  440.     int cursorColumn;
  441.     if (reDisplay)
  442.     {
  443.         FixText();
  444.         Expand(dText, &cursorColumn);
  445.         int maxWidth = Min(maxTextLen - 1, width - 1);
  446.         if (strlen(dText) > maxWidth &&
  447.             (oldStateInfo != state || ccode == E_KEY))
  448.             _errorSystem->Beep();
  449.         if (forceDisplay || oldStateInfo != state)
  450.         {
  451.             Redisplay(true, width, dText);
  452.             UpdateCursor(true, width, dText, cursorColumn);
  453.         }
  454.     }
  455.     else if (ccode == S_CURRENT)
  456.     {
  457.         Expand(dText, &cursorColumn);
  458.         UpdateCursor(true, width, dText, cursorColumn);
  459.     }
  460.  
  461.     // Return the control code.
  462.     return (ccode);
  463. }
  464.  
  465. void UIW_NUMBER::Expand(char *expText, int *cursorColumn)
  466. {
  467.     char *currencyFmt;
  468.     char newText[40];
  469.  
  470.     newText[0] = '\0';
  471.     if (FlagSet(nmFlags, NMF_CURRENCY))
  472.     {
  473.         currencyFmt = (_countryInfo.co_currstyle < 2 ? "%s%s" : "%s %s");
  474.         if ( _countryInfo.co_currstyle == 0 ||
  475.             _countryInfo.co_currstyle == 2 )
  476.             sprintf(newText, currencyFmt, _countryInfo.co_curr, state.text);
  477.         else
  478.             sprintf(newText, currencyFmt, state.text, _countryInfo.co_curr);
  479.     }
  480.     else
  481.         strcpy(newText, state.text);
  482.     if (FlagSet(nmFlags, NMF_PERCENT))
  483.         strcat(newText, "%");
  484.     UIW_NUMBER::PlaceDecimal(newText, decimal);
  485.     if (FlagSet(nmFlags, NMF_COMMAS))
  486.         UIW_NUMBER::PlaceCommas(newText);
  487.     if (state.isNegative)
  488.         UIW_NUMBER::FixNegative(newText, nmFlags & NMF_CREDIT);
  489.     strcpy(expText, newText);
  490.     int match = 0;
  491.     for (int index = 0; index <= state.cursor && newText[match]; index++)
  492.     {
  493.         while (newText[match] != state.text[index] && newText[match] &&
  494.             newText[match] != '%' && newText[match] != ')')
  495.             match++;
  496.         if (index < state.cursor && newText[match] == state.text[index])
  497.             match++;
  498.     }
  499.     *cursorColumn = match;
  500. }
  501.  
  502. void UIW_NUMBER::FixNegative(char *buff, int credit)
  503. {
  504.     memmove(buff + 1, buff, strlen(buff) + 1);
  505.     *buff = credit ? '(' : '-';
  506.     if (credit)
  507.         strcat(buff, ")");
  508. }
  509.  
  510. void UIW_NUMBER::FixText()
  511. {
  512.     char *text = state.text;
  513.     if (text[0] == '\0')
  514.     {
  515.         strcpy(text, "0");
  516.         state.cursor = 1;
  517.     }
  518.     if (decimal && decimal != 0xFF)
  519.     {
  520.         while (strlen(text) <= decimal)
  521.         {
  522.             memmove(text + 1, text, strlen(text) + 1);
  523.             state.cursor++;
  524.             text[0] = '0';
  525.         }
  526.     }
  527.     // Strip leading zeroes, but only if we have enough decimal places.
  528.     while (text[0] == '0' && isdigit(text[1]) )
  529.     {
  530.         if (decimal && decimal != 0xFF && strlen(text) <= decimal + 1)
  531.             break;
  532.         memmove(text, text + 1, strlen(text));
  533.         if (state.cursor)
  534.             state.cursor--;
  535.     }
  536. }
  537.  
  538. void UIW_NUMBER::FormatNumber()
  539. {
  540.     (this->*BinaryToAscii)();
  541.     if (state.text[0] == '-')
  542.     {
  543.         strcpy(state.text, state.text + 1);
  544.         state.isNegative = TRUE;
  545.     }
  546.     else
  547.         state.isNegative = FALSE;
  548.     state.cursor = 0;                // Default to cursor at beginning.
  549.     FixText();
  550. }
  551.  
  552. void UIW_NUMBER::PasteBlock()
  553. {
  554.     char *src = pasteBuffer;
  555.     int src_len = pasteLength;
  556.  
  557.     if (pasteBuffer && !state.isMarked)
  558.     {
  559.         woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  560.         state.cursor = 0;
  561.         while (state.cursor < maxTextLen - 1 && src_len)
  562.         {
  563.             if (UIW_NUMBER::ValidNumChar(*src, decimal))
  564.                 state.text[state.cursor++] = *src;
  565.             src++;
  566.             src_len--;
  567.         }
  568.         state.text[state.cursor] = '\0';
  569.         state.cursor = 0;
  570.     }
  571. }
  572.  
  573. void UIW_NUMBER::PlaceCommas(char *buff)
  574. {
  575.     char tempBuff[40];
  576.     char *tempPtr = tempBuff;
  577.     char *buffPtr = buff;
  578.     int  digits;
  579.  
  580.     while (*buffPtr)
  581.     {
  582.         if (*buffPtr != _countryInfo.co_thsep[0])
  583.             *tempPtr++ = *buffPtr;
  584.         buffPtr++;
  585.     }
  586.     *tempPtr = '\0';
  587.     tempPtr = strrchr(tempBuff, _countryInfo.co_desep[0]);
  588.     if (!tempPtr)
  589.         tempPtr = strchr(tempBuff, '\0');
  590.     while (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1)))
  591.         tempPtr--;
  592.     digits = 0;
  593.     while (tempPtr > &tempBuff[0] && isdigit(*(tempPtr - 1)))
  594.     {
  595.         digits++;
  596.         tempPtr--;
  597.         if (digits % 3 == 0 && tempPtr > &tempBuff[0] &&
  598.             isdigit(*(tempPtr - 1)))
  599.         {
  600.             memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  601.             *tempPtr = _countryInfo.co_thsep[0];
  602.         }
  603.     }
  604.     tempPtr = strrchr(tempBuff, _countryInfo.co_desep[0]);
  605.     if (tempPtr && _countryInfo.co_thsep[0] != ',')
  606.     {
  607.         tempPtr++;
  608.         digits = 0;
  609.         while (isdigit(*tempPtr))
  610.         {
  611.             digits++;
  612.             tempPtr++;
  613.             if ( digits % 3 == 0 && isdigit(*(tempPtr + 1)) )
  614.             {
  615.                 memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  616.                 *tempPtr++ = _countryInfo.co_thsep[0];
  617.             }
  618.         }
  619.     }
  620.     strcpy(buff, tempBuff);
  621. }
  622.  
  623. void UIW_NUMBER::PlaceDecimal(char *buff, int decimal)
  624. {
  625.     char tempBuff[40];
  626.     char *tempPtr = tempBuff;
  627.     char *buffPtr = buff;
  628.  
  629.     if (decimal != 0xFF)
  630.     {
  631.         while (*buffPtr)
  632.         {
  633.             if (*buffPtr != _countryInfo.co_desep[0])
  634.                 *tempPtr++ = *buffPtr;
  635.             buffPtr++;
  636.         }
  637.         *tempPtr = '\0';
  638.         if (decimal)
  639.         {
  640.             while (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1)))
  641.                 tempPtr--;
  642.             while (tempPtr > &tempBuff[0] && decimal)
  643.             {
  644.                 if (isdigit(*(tempPtr - 1)))
  645.                     decimal--;
  646.                 else if (*(tempPtr - 1) != _countryInfo.co_thsep[0])
  647.                     break;
  648.                 tempPtr--;
  649.             }
  650.             if (decimal || tempPtr == &tempBuff[0] ||
  651.                 (tempPtr > &tempBuff[0] && !isdigit(*(tempPtr - 1))))
  652.             {
  653.                 memmove(tempPtr + decimal + 2, tempPtr, strlen(tempPtr) + 1);
  654.                 *tempPtr = '0';
  655.                 *(tempPtr + 1) = _countryInfo.co_desep[0];
  656.                 if (decimal)
  657.                     memset(tempPtr + 2, '0', decimal);
  658.             }
  659.             else
  660.             {
  661.                 memmove(tempPtr + 1, tempPtr, strlen(tempPtr) + 1);
  662.                 *tempPtr = _countryInfo.co_desep[0];
  663.             }
  664.         }
  665.         strcpy(buff, tempBuff);
  666.     }
  667. }
  668.  
  669. #pragma argsused
  670. void UIW_NUMBER::Redisplay(UI_REGION ®ion, int width, char *dText)
  671. {
  672.     if (!hWnd)
  673.         return;
  674.     SetWindowText(hWnd, dText);
  675.     if (state.isMarked)
  676.         SendMessage(hWnd, EM_SETSEL, 0, 0x7FFF0000L);
  677. }
  678.  
  679. void UIW_NUMBER::RegularChar(USHORT key)
  680. {
  681.     int autoClear = FALSE;
  682.     if (FlagSet(woFlags, WOF_AUTO_CLEAR) &&
  683.         !FlagSet(woStatus, WOS_NO_AUTO_CLEAR))
  684.     {
  685.         autoClear = TRUE;
  686.         int index = state.cursor;
  687.         while (index)
  688.         {
  689.             index--;
  690.             if (state.text[index] != '0')
  691.                 autoClear = FALSE;
  692.         }
  693.     }
  694.     if (autoClear)
  695.     {
  696.         state.text[0] = key;
  697.         state.text[1] = '\0';
  698.         state.cursor = 1;
  699.     }
  700.     else
  701.     {
  702.         if (!insertMode && state.text[state.cursor])
  703.             DeleteChar();        // Replace mode - delete and then insert.
  704.         if (ui_strlen(state.text) < maxTextLen - 1)
  705.         {
  706.             memmove(state.text + state.cursor + 1, state.text + state.cursor,
  707.                 strlen(state.text + state.cursor) + 1);
  708.             state.text[state.cursor++] = key;
  709.         }
  710.         if (state.text[state.cursor] == '\0' && switchedToReplaceMode)
  711.         {
  712.             insertMode = TRUE;
  713.             switchedToReplaceMode = FALSE;
  714.         }
  715.     }
  716. }
  717.  
  718. void UIW_NUMBER::RegularKey(USHORT key)
  719. {
  720.     char valid_list[80];
  721.  
  722.     sprintf(valid_list, "0123456789%c",
  723.         decimal ? _countryInfo.co_desep[0] : '\0');
  724.     if (!FlagSet(nmFlags, NMF_UNSIGNED))
  725.         strcat(valid_list, "-+");
  726.     if (FlagSet(nmFlags, NMF_SCIENTIFIC))
  727.         strcat(valid_list, "Ee");
  728.     if (strchr(valid_list, key))
  729.     {
  730.         if (key == _countryInfo.co_desep[0])
  731.         {
  732.             if (decimal == 0xFF)    // Floating decimal - replace the point.
  733.             {
  734.                 char *exp = strchr(state.text, 'E');
  735.                 if (!exp || exp >= state.text + state.cursor)
  736.                 {    // Don't allow decimal inside the exponent.
  737.                      char *dec = strchr(state.text, _countryInfo.co_desep[0]);
  738.                     if (dec && (insertMode || state.text[state.cursor] != *dec))
  739.                     {
  740.                         memmove(dec, dec + 1, strlen(dec));
  741.                         if (state.text + state.cursor > dec)
  742.                             state.cursor--;
  743.                     }
  744.                     RegularChar(key);
  745.                 }
  746.             }
  747.             else                    // Fixed decimal.
  748.             {
  749.                 int nullPos = ui_strlen(state.text);
  750.                 int position = (int)(nullPos - state.cursor);
  751.                 if (position < decimal)
  752.                 {
  753.                     int extra = decimal - position;
  754.                     memset(state.text + nullPos, '0', extra);
  755.                     state.text[nullPos + extra] = '\0';
  756.                 }
  757.                 else if (position > decimal)
  758.                 {
  759.                     int clip = position - decimal;
  760.                     state.text[nullPos - clip] = '\0';
  761.                 }
  762.                 if (insertMode)
  763.                 {
  764.                     insertMode = FALSE;
  765.                     switchedToReplaceMode = TRUE;
  766.                 }
  767.             }
  768.         }
  769.         else if (key == '-' || key == '+')
  770.         {
  771.             char *exp;
  772.             if (FlagSet(nmFlags, NMF_SCIENTIFIC) &&
  773.                 (exp = strchr(state.text, 'E')) &&
  774.                 state.text + state.cursor >= exp)
  775.             {
  776.                 exp++;        // Point just after the 'E'.
  777.                 if (*exp == '-')
  778.                 {
  779.                     memmove(exp, exp + 1, strlen(exp));
  780.                     if (state.text + state.cursor >= exp + 1)
  781.                         state.cursor--;
  782.                 }
  783.                 else if (key == '-')
  784.                 {
  785.                     memmove(exp + 1, exp, strlen(exp) + 1);
  786.                     *exp = '-';
  787.                     if (state.text + state.cursor >= exp)
  788.                         state.cursor++;
  789.                 }
  790.             }
  791.             else
  792.                 state.isNegative = key == '+' ? FALSE : !state.isNegative;
  793.         }
  794.         else if (toupper(key) == 'E')
  795.         {
  796.             char *exp = strchr(state.text, 'E');
  797.             if (exp)
  798.             {
  799.                 state.cursor = (UCHAR)(exp + 1 - state.text);
  800.                 if (state.text[state.cursor] == '-')
  801.                     state.cursor++;
  802.             }
  803.             else
  804.             {
  805.                 state.cursor = ui_strlen(state.text);
  806.                 RegularChar('E');
  807.             }
  808.         }
  809.         else // digit
  810.             RegularChar(key);
  811.         woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  812.     }
  813. }
  814.  
  815. void UIW_NUMBER::SetCursor(int column, int width)
  816. {
  817.     char expandedText[40];
  818.     int cursorColumn;
  819.     int maxWidth = Min(maxTextLen - 1, width - 1);
  820.  
  821.     Expand(expandedText, &cursorColumn);
  822.     int textLen = strlen(expandedText);
  823.     int leading = 0;
  824.     if (FlagSet(woFlags, WOF_JUSTIFY_CENTER))
  825.         leading = Min((maxWidth - textLen) / 2, width);
  826.     else if (FlagSet(woFlags, WOF_JUSTIFY_RIGHT))
  827.         leading = Min(maxWidth - textLen, width);
  828.     if (leading < 0)
  829.         leading = 0;
  830.     char *screen_cursor = expandedText + column - leading;
  831.     char *expNull = strchr(expandedText, '\0');
  832.     if (screen_cursor > expNull)
  833.         screen_cursor = expNull;
  834.     int match = 0;
  835.     for (char *cp = expandedText; cp < screen_cursor && state.text[match]; cp++)
  836.         if (strchr(state.text, *cp))
  837.             match++;
  838.     state.cursor = match;
  839. }
  840.  
  841. #pragma argsused
  842. void UIW_NUMBER::UpdateCursor(UI_REGION ®ion, int width, char *dText,
  843.     int cursorColumn)
  844. {
  845.     int leading = CalcLeading(width, dText);
  846.     if (FlagSet(woStatus, WOS_CURRENT) && (leading + cursorColumn < width))
  847.     {
  848.         dText[cursorColumn] = '\0';
  849.         POINT position;
  850.         GetCaretPos(&position);
  851.         position.x += display->TextWidth(dText, screenID);
  852.         SetCaretPos(position.x, position.y);
  853.     }
  854. }
  855.  
  856. int UIW_NUMBER::ValidNumChar(char val, int decimalPoint)
  857. {
  858.     if (isdigit(val) ||
  859.         (decimalPoint == 0xFF && val == _countryInfo.co_desep[0]))
  860.         return (TRUE);
  861.     return (FALSE);
  862. }
  863.  
  864.