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 / WINDOW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  23.4 KB  |  787 lines

  1. //    Zinc Interface Library - WINDOW.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 <string.h>
  7.  
  8. int UI_WINDOW_MANAGER::FindNumberID(void *object, void *matchName)
  9. {
  10.     return ((((UI_WINDOW_OBJECT *)object)->search.numberID == *(USHORT *)matchName) ? 0 : -1);
  11. }
  12.  
  13. int UI_WINDOW_MANAGER::FindStringID(void *object, void *matchName)
  14. {
  15.     return (strcmpi(((UI_WINDOW_OBJECT *)object)->search.stringID, (char *)matchName));
  16. }
  17.  
  18. UI_WINDOW_MANAGER::UI_WINDOW_MANAGER(UI_DISPLAY *_display,
  19.     UI_EVENT_MANAGER *_eventManager,
  20.     int (*_exitFunction)(UI_DISPLAY *display, UI_EVENT_MANAGER *eventManager,
  21.         UI_WINDOW_MANAGER *windowManager)) :
  22.     UI_LIST(), display(_display), eventManager(_eventManager),
  23.     exitFunction(_exitFunction)
  24. {
  25. }
  26.  
  27. UI_WINDOW_MANAGER::~UI_WINDOW_MANAGER()
  28. {
  29.     // Remove all non-destroy objects from the window manager.
  30.     for (UI_WINDOW_OBJECT *object = First(); object; )
  31.     {
  32.         object->display = 0;
  33.         object->eventManager = 0;
  34.         object->windowManager = 0;
  35.         object = (FlagSet(object->woAdvancedFlags, WOAF_NO_DESTROY)) ?
  36.             (UI_WINDOW_OBJECT *)UI_LIST::Subtract(object) : object->Next();
  37.     }
  38. }
  39.  
  40. void UI_WINDOW_MANAGER::Add(UI_WINDOW_OBJECT *object)
  41. {
  42.     // Fix the coordinate system.
  43.     int offset;
  44.     UI_REGION region = object->true;
  45.     display->RegionConvert(object->true, &object->woStatus, WOS_GRAPHICS);
  46.  
  47.     // Only new window objects have a screenID of -1.
  48.     if (object->screenID == -1)
  49.     {
  50.         int tLeft = region.left;
  51.         region.left = (region.left >= 0) ? object->true.left :
  52.             display->columns + region.left * display->cellWidth - 1;
  53.         int tTop = region.top;
  54.         region.top = (region.top >= 0) ? object->true.top :
  55.             display->lines + region.top * display->cellHeight - 1;
  56.         if (tLeft >= 0 && region.right > 0)
  57.             region.right = object->true.right;
  58.         else if (region.right <= 0)
  59.             region.right = display->columns + region.right * display->cellWidth - 1;
  60.         else
  61.             region.right = region.left + region.right * display->cellWidth - 1;
  62.         if (tTop >= 0 && region.bottom > 0)
  63.             region.bottom = object->true.bottom;
  64.         else if (region.bottom <= 0)
  65.             region.bottom = display->lines + region.bottom * display->cellHeight - 1;
  66.         else
  67.             region.bottom = region.top + region.bottom * display->cellHeight - 1;
  68.         if (region.left < 0)
  69.             offset = -region.left;
  70.         else if (region.right >= display->columns)
  71.             offset = display->columns - region.right;
  72.         else
  73.             offset = 0;
  74.         if (region.left + offset >= 0)
  75.         {
  76.             region.left += offset;
  77.             region.right += offset;
  78.         }
  79.         if (region.top < 0)
  80.             offset = -region.top;
  81.         else if (region.bottom >= display->lines)
  82.             offset = display->lines - region.bottom;
  83.         else
  84.             offset = 0;
  85.         if (region.top + offset >= 0)
  86.         {
  87.             region.top += offset;
  88.             region.bottom += offset;
  89.         }
  90.         object->true = object->relative = region;
  91.     }
  92.  
  93.     // Make sure the window object is on the screen.
  94.     region = object->true;
  95.     if (region.left >= display->columns)
  96.     {
  97.         offset = region.left - display->columns + 1;
  98.         region.left -= offset;
  99.         region.right -= offset;
  100.     }
  101.     if (region.top >= display->lines)
  102.     {
  103.         offset = region.top - display->lines + 1;
  104.         region.top -= offset;
  105.         region.bottom -= offset;
  106.     }
  107.  
  108.     // Initialize the window object and bring it to the screen front.
  109.     if (object->screenID == -1)
  110.         object->screenID = ++screenID;
  111.     object->display = display;
  112.     object->eventManager = eventManager;
  113.     object->windowManager = this;
  114.     object->woFlags |= WOF_NON_FIELD_REGION;
  115.     object->woAdvancedStatus &= ~WOAS_INVALID_REGION;
  116.     object->relative = object->true = region;
  117.  
  118.     // Paint the new window object.
  119.     UI_EVENT event;
  120.     event.type = S_CREATE;
  121.     object->Event(event);
  122.     ToFront(object, TRUE, TRUE);
  123. }
  124.  
  125. void UI_WINDOW_MANAGER::Erase(UI_WINDOW_OBJECT *object,
  126.     const UI_REGION *newRegion)
  127. {
  128.     // Redefine all the objects on the screen.
  129.     UI_REGION region;
  130.     UI_WINDOW_OBJECT *tObject;
  131.     region.left = region.top = 0;
  132.     region.right = display->columns - 1;
  133.     region.bottom = display->lines - 1;
  134.     display->RegionDefine(ID_SCREEN, region);
  135.     for (tObject = Last(); tObject; tObject = tObject->Previous())
  136.         if (FlagSet(tObject->woAdvancedFlags, WOAF_MULTIPLE_REGIONS))
  137.         {
  138.             UI_EVENT event;
  139.             event.type = S_DEFINE_REGION;
  140.             if (object != tObject)
  141.                 tObject->Event(event);
  142.         }
  143.         else if (tObject != object)
  144.             display->RegionDefine(tObject->screenID, tObject->true);
  145.         else if (newRegion)
  146.             display->RegionDefine(tObject->screenID, *newRegion);
  147.  
  148.     // Redraw the affected screen objects.
  149.     UI_EVENT event;
  150.     event.region = object->true;
  151.  
  152.     // Update the front window object.
  153.     eventManager->DeviceState(E_CURSOR, D_OFF);
  154.     event.type = S_CURRENT;
  155.     display->Rectangle(ID_SCREEN, object->true, _backgroundPalette, 0, TRUE);
  156.     if (object == First() && object->next && !newRegion)
  157.     {
  158.         object = object->Next();
  159.         object->Event(event);
  160.         if (object->true.left <= event.region.left &&
  161.             object->true.top <= event.region.top &&
  162.             object->true.right >= event.region.right &&
  163.             object->true.bottom >= event.region.bottom)
  164.             return;
  165.     }
  166.  
  167.     event.type = FlagSet(object->woAdvancedFlags, WOAF_TEMPORARY) ?
  168.         S_DISPLAY_ACTIVE : S_DISPLAY_INACTIVE;
  169.     for (tObject = object->Next(); tObject; tObject = tObject->Next())
  170.     {
  171.         if (tObject->Overlap(event.region))
  172.             tObject->Event(event);
  173.         if (tObject->true.left <= event.region.left &&
  174.             tObject->true.top <= event.region.top &&
  175.             tObject->true.right >= event.region.right &&
  176.             tObject->true.bottom >= event.region.bottom)
  177.             return;
  178.         if (event.type == S_DISPLAY_ACTIVE &&
  179.             !FlagSet(tObject->woAdvancedFlags, WOAF_TEMPORARY))
  180.             event.type = S_DISPLAY_INACTIVE;
  181.     }
  182. }
  183.  
  184. int UI_WINDOW_MANAGER::Event(const UI_EVENT &event)
  185. {
  186.     // Make sure there is an object.
  187.     int ccode = MapEvent(eventMapTable, event, ID_WINDOW_MANAGER,
  188.         ID_WINDOW_MANAGER, ID_WINDOW_MANAGER, ID_WINDOW_MANAGER,
  189.         ID_WINDOW_MANAGER, ID_WINDOW_MANAGER);
  190.     UI_WINDOW_OBJECT *firstObject = First();
  191.     if (!firstObject && ccode == L_EXIT)
  192.         return (L_EXIT);
  193.     else if (!firstObject && ccode != S_REDISPLAY && ccode != L_EXIT_FUNCTION)
  194.         return (S_NO_OBJECT);
  195.  
  196.     // Switch on the event type.
  197.     UI_EVENT tEvent = event;
  198.     UI_WINDOW_OBJECT *object = 0;
  199.     switch (ccode)
  200.     {
  201.     case S_RESET_DISPLAY:
  202.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  203.         {
  204.             UI_WINDOW_MANAGER::Subtract(firstObject);
  205.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  206.                 delete firstObject;
  207.             firstObject = First();
  208.         }
  209.         if (!event.data)
  210.             break;
  211.         display = (UI_DISPLAY *)event.data;
  212.         UI_WINDOW_OBJECT *tObject = Last();
  213.         first = current = last = NULL;
  214.         while (tObject)
  215.         {
  216.             object = tObject;
  217.             tObject = object->Previous();
  218.             UI_WINDOW_MANAGER::Add(object);
  219.         }
  220.         break;
  221.  
  222.     case L_MOVE:
  223.     case L_SIZE:
  224.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  225.         {
  226.             UI_WINDOW_MANAGER::Subtract(firstObject);
  227.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  228.                 delete firstObject;
  229.             firstObject = First();
  230.         }
  231.         object = First();
  232.         if (ccode == L_MOVE)
  233.         {
  234.             tEvent.type = S_MOVE;
  235.             tEvent.position.column = object->true.left;
  236.             tEvent.position.line = object->true.top;
  237.         }
  238.         else
  239.         {
  240.             tEvent.type = S_SIZE;
  241.             tEvent.rawCode = M_RIGHT_CHANGE | M_BOTTOM_CHANGE;
  242.             tEvent.position.column = object->true.right;
  243.             tEvent.position.line = object->true.bottom;
  244.         }
  245.         Modify(object, tEvent);
  246.         break;
  247.  
  248.     case S_MOVE:
  249.     case S_SIZE:
  250.     case S_CHANGE:
  251.         object = First();
  252.         if (ccode == S_MOVE && event.rawCode == 0xFFFF)
  253.         {
  254.             tEvent.position.column = object->true.left;
  255.             tEvent.position.line = object->true.top;
  256.         }
  257.         else if (ccode == S_SIZE && event.rawCode == 0xFFFF)
  258.         {
  259.             tEvent.rawCode = M_RIGHT_CHANGE | M_BOTTOM_CHANGE;
  260.             tEvent.position.column = object->true.right;
  261.             tEvent.position.line = object->true.bottom;
  262.         }
  263.         Modify(object, tEvent);
  264.         break;
  265.  
  266.     case S_MAXIMIZE:
  267.     case S_MINIMIZE:
  268.         object = First();
  269.         object->Event(event);
  270.         break;
  271.  
  272.     case S_CLOSE:
  273.     case S_CLOSE_TEMPORARY:
  274.         // Delete any temporary windows.
  275.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  276.         {
  277.             UI_WINDOW_MANAGER::Subtract(firstObject);
  278.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  279.                 delete firstObject;
  280.             if (ccode == S_CLOSE_TEMPORARY)
  281.                 return (ccode);
  282.             firstObject = First();
  283.         }
  284.         if (ccode == S_CLOSE_TEMPORARY)
  285.             return (ccode);
  286.  
  287.         // Try to delete the top window.
  288.         object = First();
  289.         if (!object)
  290.             return (S_ERROR);
  291.         else if (FlagSet(object->woAdvancedFlags, WOAF_LOCKED))
  292.             return (ccode);
  293.         UI_WINDOW_MANAGER::Subtract(object);
  294.         if (!FlagSet(object->woAdvancedFlags, WOAF_NO_DESTROY))
  295.             delete object;
  296.         ccode = First() ? S_CLOSE : S_NO_OBJECT;
  297.         break;
  298.  
  299.     case S_CLEAR:
  300.         for (object = First(); object; )
  301.         {
  302.             UI_WINDOW_OBJECT *tObject = object->Next();
  303.             if (!FlagSet(object->woAdvancedFlags, WOAF_LOCKED))
  304.                 UI_LIST::Subtract(object);
  305.             if (!FlagSet(object->woAdvancedFlags, WOAF_LOCKED | WOAF_NO_DESTROY))
  306.                 delete object;
  307.             object = tObject;
  308.         }
  309.         // Continue to S_CASCADE.
  310.  
  311.     case S_CASCADE:
  312.         {
  313.         firstObject = First();
  314.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  315.         {
  316.             UI_WINDOW_MANAGER::Subtract(firstObject);
  317.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  318.                 delete firstObject;
  319.             firstObject = First();
  320.         }
  321.         int column = 0;
  322.         int line = 0;
  323.         UI_EVENT tEvent;
  324.         for (object = Last(); object; object = object->Previous())
  325.         {
  326.             if (!FlagSet(object->woAdvancedStatus, WOAS_MINIMIZED))
  327.             {
  328.                 if (column + object->true.right - object->true.left > display->columns)
  329.                     column = 0;
  330.                 if (line + object->true.bottom - object->true.top > display->lines)
  331.                     line = 0;
  332.                 tEvent.type = S_MOVE;
  333.                 tEvent.position.column = column - object->true.left;
  334.                 tEvent.position.line = line - object->true.top;
  335.                 object->true.left += tEvent.position.column;
  336.                 object->true.top += tEvent.position.line;
  337.                 object->true.right += tEvent.position.column;
  338.                 object->true.bottom += tEvent.position.line;
  339.                 object->relative = object->true;
  340.                 object->Event(tEvent);
  341.                 column += display->cellWidth * 3;
  342.                 line += display->cellHeight * 3 / 2;
  343.             }
  344.         }
  345.         }
  346.         // Continue to S_REDISPLAY.
  347.  
  348.     case S_REDISPLAY:
  349.         firstObject = First();
  350.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  351.         {
  352.             UI_WINDOW_MANAGER::Subtract(firstObject);
  353.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  354.                 delete firstObject;
  355.             firstObject = First();
  356.         }
  357.         eventManager->DeviceState(E_CURSOR, D_OFF);
  358.         display->RegionDefine(ID_SCREEN, 0, 0, display->columns - 1, display->lines - 1);
  359.         display->Rectangle(ID_SCREEN, 0, 0, display->columns - 1, 
  360.             display->lines - 1, _backgroundPalette, 0, TRUE);
  361.         for (object = Last(); object; object = object->Previous())
  362.         {
  363.             tEvent.type = S_CREATE;
  364.             object->Event(tEvent);
  365.             if (FlagSet(object->woAdvancedFlags, WOAF_MULTIPLE_REGIONS))
  366.             {
  367.                 tEvent.type = S_DEFINE_REGION;
  368.                 tObject->Event(tEvent);
  369.             }
  370.             else
  371.                 display->RegionDefine(object->screenID, object->true);
  372.             tEvent.type = (object == First()) ? S_CURRENT : S_DISPLAY_INACTIVE;
  373.             tEvent.region = object->true;
  374.             object->Event(tEvent);
  375.         }
  376.         break;
  377.  
  378.     case L_EXIT_FUNCTION:
  379.         while (firstObject && FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  380.         {
  381.             UI_WINDOW_MANAGER::Subtract(firstObject);
  382.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  383.                 delete firstObject;
  384.             firstObject = First();
  385.         }
  386.         if (exitFunction)
  387.         {
  388.             ccode = (*exitFunction)(display, eventManager, this);
  389.             break;
  390.         }
  391.         else
  392.             ccode = L_EXIT;
  393.         break;
  394.  
  395.     case L_EXIT:
  396.         break;
  397.  
  398.     case L_NEXT:
  399.         // See if it is a modal window.
  400.         if (FlagSet(firstObject->woAdvancedFlags, WOAF_MODAL))
  401.         {
  402.             _errorSystem->Beep();
  403.             break;
  404.         }
  405.  
  406.         // Move to the proper window.
  407.         object = Last();
  408.         while (object->Previous() &&
  409.             (FlagSet(object->woFlags, WOF_NON_SELECTABLE) ||
  410.              FlagSet(object->woAdvancedFlags, WOAF_NON_CURRENT)))
  411.             object = object->Previous();
  412.         if (First() != object &&
  413.             !FlagSet(object->woFlags, WOF_NON_SELECTABLE) &&
  414.             !FlagSet(object->woAdvancedFlags, WOAF_NON_CURRENT))
  415.             ToFront(object, TRUE, FALSE);
  416.         break;
  417.  
  418.     case L_HELP:
  419.         _helpSystem->DisplayHelp(this, NO_HELP_CONTEXT);
  420.         break;
  421.  
  422.     case L_VIEW:
  423.     case L_BEGIN_SELECT:
  424.     case L_CONTINUE_SELECT:
  425.     case L_END_SELECT:
  426.         // Find the proper screen object.
  427.         for (object = First(); object; object = object->Next())
  428.             if (object->Overlap(event.position))
  429.                 break;
  430.             else if (FlagSet(object->woAdvancedFlags, WOAF_MODAL))
  431.             {
  432.                 if (ccode == L_BEGIN_SELECT)
  433.                     _errorSystem->Beep();
  434.                 object = NULL;
  435.                 break;
  436.             }
  437.  
  438.         // See which object should be current, if any.
  439.         if (object != firstObject &&
  440.             FlagSet(firstObject->woAdvancedFlags, WOAF_MODAL))
  441.         {
  442.             eventManager->DeviceState(event.type, DM_VIEW);
  443.             break;
  444.         }
  445.         else if (ccode == L_BEGIN_SELECT && object && object != First() &&
  446.             !FlagSet(object->woFlags, WOF_NON_SELECTABLE) &&
  447.             !FlagSet(object->woAdvancedFlags, WOAF_NON_CURRENT))
  448.             ToFront(object, TRUE, FALSE);
  449.         else if (ccode != L_BEGIN_SELECT && event.rawCode != 0)
  450.             object = First();
  451.         if (!object)
  452.         {
  453.             eventManager->DeviceState(event.type, DM_VIEW);
  454.             break;
  455.         }
  456.         // Continue to default.
  457.  
  458.     default:
  459.         // Get the front object.
  460.         if (!object)
  461.             object = First();
  462.         ccode = object->Event(event);
  463.         if (ccode != S_UNKNOWN && ccode != S_ERROR)
  464.             break;
  465.  
  466.         // Check for hot key matches.
  467.         int tHotKey = E_KEY;
  468.         if (!FlagSet(firstObject->woAdvancedFlags, WOAF_MODAL) &&
  469.             event.type == E_KEY && FlagSet(event.key.shiftState, S_ALT) &&
  470.             (tHotKey = MapEvent(_hotKeyMapTable, tEvent, ID_WINDOW_OBJECT)) != E_KEY)
  471.         {
  472.             tEvent.type = S_CHECK_HOT_KEY;
  473.             tEvent.key.value = tHotKey;
  474.             for (object = firstObject->Next(); object; object = object->Next())
  475.                 if (object->hotKey != 0 &&
  476.                     (tHotKey == object->hotKey ||
  477.                      (object->hotKey == HOT_KEY_SUB_WINDOW && object->Event(tEvent))))
  478.                 {
  479.                     ToFront(object, TRUE, FALSE);
  480.                     ccode = object->Event(event);
  481.                     break;
  482.                 }
  483.         }
  484.         break;
  485.     }
  486.  
  487.     // Return the control code.
  488.     return (ccode);
  489. }
  490.  
  491. void UI_WINDOW_MANAGER::Modify(UI_WINDOW_OBJECT *object,
  492.     const UI_EVENT &event)
  493. {
  494.     int xJump = display->cellWidth;
  495.     int yJump = display->cellHeight;
  496.  
  497.     // Make sure the object can be sized or moved.
  498.     int ccode = event.type;
  499.     if (ccode == S_SIZE && FlagSet(object->woAdvancedFlags, WOAF_NO_SIZE) ||
  500.         ccode == S_MOVE && FlagSet(object->woAdvancedFlags, WOAF_NO_MOVE))
  501.         return;
  502.  
  503.     // See if the new coordinates are already selected.
  504.     UI_EVENT tEvent = event;
  505.     if (ccode == S_CHANGE)
  506.     {
  507.         UI_WINDOW_MANAGER::Erase(object, &tEvent.region);
  508.         tEvent.type = S_SIZE;
  509.         object->true = tEvent.region;
  510.         object->Event(tEvent);
  511.         ToFront(object, FALSE, TRUE);
  512.         return;
  513.     }
  514.  
  515.     // Compute the absolute size of the object.
  516.     int minHeight, minWidth;
  517.     UI_REGION newRegion = object->true;
  518.     object->Information(GET_MINIMUM_HEIGHT, &minHeight);
  519.     object->Information(GET_MINIMUM_WIDTH, &minWidth);
  520.     int height = newRegion.bottom - newRegion.top + 1;
  521.     int width = newRegion.right - newRegion.left + 1;
  522.     UI_REGION absolute = newRegion;
  523.     UI_REGION oldRegion = newRegion;
  524.     USHORT sizeObject = (event.type == S_SIZE) ? event.rawCode : 0;
  525.     int deltaX = (FlagSet(sizeObject, M_RIGHT_CHANGE)) ? 
  526.         newRegion.right - event.position.column :
  527.         event.position.column - newRegion.left;
  528.     int deltaY = (FlagSet(sizeObject, M_BOTTOM_CHANGE)) ?
  529.         newRegion.bottom - event.position.line :
  530.         event.position.line - newRegion.top;
  531.     if (FlagSet(sizeObject, M_LEFT_CHANGE))
  532.         absolute.left = absolute.right + 1 - minWidth;
  533.     else if (FlagSet(sizeObject, M_RIGHT_CHANGE))
  534.         absolute.right = absolute.left + minWidth - 1;
  535.     if (FlagSet(sizeObject, M_TOP_CHANGE))
  536.         absolute.top = absolute.bottom + 1 - minHeight;
  537.     else if (FlagSet(sizeObject, M_BOTTOM_CHANGE))
  538.         absolute.bottom = absolute.top + minHeight - 1;
  539.  
  540.     // Reverse the window region.
  541.     int move = TRUE;
  542.     int xCount;
  543.     int yCount;
  544.     display->Rectangle(ID_SCREEN, newRegion, _xorPalette, 1, FALSE, TRUE);
  545.     do
  546.     {
  547.         eventManager->Get(tEvent, Q_NORMAL);
  548.         ccode = MapEvent(eventMapTable, tEvent, ID_WINDOW_OBJECT, ID_WINDOW_OBJECT);
  549.         switch (ccode)
  550.         {
  551.         case L_INSERT_TOGGLE:
  552.             xJump = (xJump == 1) ? display->cellWidth : 1;
  553.             yJump = (yJump == 1) ? display->cellHeight : 1;
  554.             break;
  555.  
  556.         case L_CANCEL:
  557.             display->Rectangle(ID_SCREEN, oldRegion, _xorPalette, 1, FALSE, TRUE);
  558.             return;
  559.  
  560.         case L_END_SELECT:
  561.         case L_SELECT:
  562.             move = FALSE;
  563.             break;
  564.  
  565.         case L_UP:
  566.         case L_DOWN:
  567.         case L_LEFT:
  568.         case L_RIGHT:
  569.             xCount = yCount = 0;
  570.             if (ccode == L_UP)
  571.                 yCount = -yJump;
  572.             else if (ccode == L_DOWN)
  573.                 yCount = yJump;
  574.             else if (ccode == L_LEFT)
  575.                 xCount = -xJump;
  576.             else if (ccode == L_RIGHT)
  577.                 xCount = xJump;
  578.             if (!sizeObject)
  579.             {
  580.                 tEvent.position.column = oldRegion.left + xCount;
  581.                 tEvent.position.line = oldRegion.top + yCount;
  582.             }
  583.             else
  584.             {
  585.                 tEvent.position.column = oldRegion.right + xCount;
  586.                 tEvent.position.line = oldRegion.bottom + yCount;
  587.             }
  588.             // Continue to L_CONTINUE_SELECT
  589.  
  590.         case L_BEGIN_SELECT:
  591.         case L_CONTINUE_SELECT:
  592.             if (!sizeObject)
  593.             {
  594.                 newRegion.left = tEvent.position.column - deltaX;
  595.                 newRegion.top = tEvent.position.line - deltaY;
  596.                 break;
  597.             }
  598.             if (FlagSet(sizeObject, M_LEFT_CHANGE) &&
  599.                 tEvent.position.column <= absolute.left + deltaX)
  600.                 newRegion.left = tEvent.position.column - deltaX;
  601.             else if (FlagSet(sizeObject, M_LEFT_CHANGE))
  602.                 newRegion.left = absolute.left;
  603.             else if (FlagSet(sizeObject, M_RIGHT_CHANGE) &&
  604.                 tEvent.position.column + deltaX >= absolute.right)
  605.                 newRegion.right = tEvent.position.column + deltaX;
  606.             else if (FlagSet(sizeObject, M_RIGHT_CHANGE))
  607.                 newRegion.right = absolute.right;
  608.  
  609.             if (FlagSet(sizeObject, M_TOP_CHANGE) &&
  610.                 tEvent.position.line <= absolute.top + deltaY)
  611.                 newRegion.top = tEvent.position.line - deltaY;
  612.             else if (FlagSet(sizeObject, M_TOP_CHANGE))
  613.                 newRegion.top = absolute.top;
  614.             else if (FlagSet(sizeObject, M_BOTTOM_CHANGE) &&
  615.                 tEvent.position.line + deltaY >= absolute.bottom)
  616.                 newRegion.bottom = tEvent.position.line + deltaY;
  617.             else if (FlagSet(sizeObject, M_BOTTOM_CHANGE))
  618.                 newRegion.bottom = absolute.bottom;
  619.             height = newRegion.bottom + 1 - newRegion.top;
  620.             width = newRegion.right + 1 - newRegion.left;
  621.             break;
  622.         }
  623.  
  624.         // Update the new region.
  625.         if (oldRegion.left != newRegion.left || oldRegion.top != newRegion.top ||
  626.             oldRegion.right != newRegion.right || oldRegion.bottom != newRegion.bottom)
  627.         {
  628.             // Compute the lower-right coordinates.
  629.             newRegion.right = newRegion.left + width - 1;
  630.             newRegion.bottom = newRegion.top + height - 1;
  631.  
  632.             // Remove the old region and update the new region.
  633.             if (eventManager->Get(tEvent, Q_NO_BLOCK | Q_NO_DESTROY) != 0 ||
  634.                 MapEvent(eventMapTable, tEvent, ID_WINDOW_OBJECT, ID_WINDOW_OBJECT) != L_CONTINUE_SELECT)
  635.             {
  636.                 display->RectangleXORDiff(oldRegion, newRegion);
  637.                 oldRegion = newRegion;
  638.             }
  639.         }
  640.     } while (move);
  641.  
  642.     // Restore the region.
  643.     display->RectangleXORDiff(newRegion, newRegion);
  644.     display->Rectangle(ID_SCREEN, oldRegion, _xorPalette, 1, FALSE, TRUE);
  645.     if (object->true.left == newRegion.left &&
  646.         object->true.top == newRegion.top &&
  647.         object->true.right == newRegion.right &&
  648.         object->true.bottom == newRegion.bottom)
  649.         return;
  650.  
  651.     // Deactivate the old window region.
  652.     if (!object->parent)
  653.         UI_WINDOW_MANAGER::Erase(object, &newRegion);
  654.     if (!sizeObject)
  655.     {
  656.         tEvent.position.column = newRegion.left - object->true.left;
  657.         tEvent.position.line = newRegion.top - object->true.top;
  658.         tEvent.type = S_MOVE;
  659.     }
  660.     else
  661.         tEvent.type = S_SIZE;
  662.     if (!object->parent)
  663.     {
  664.         object->true = object->relative = newRegion;
  665.         object->Event(tEvent);
  666.         ToFront(object, FALSE, TRUE);
  667.     }
  668.     else
  669.     {
  670.         deltaX = ((newRegion.right - object->true.right) / display->cellWidth) * display->cellWidth;
  671.         deltaY = ((newRegion.bottom - object->true.bottom) / display->cellHeight) * display->cellHeight;
  672.         UI_WINDOW_OBJECT *parentObject = object;
  673.         while (parentObject->parent)
  674.             parentObject = parentObject->parent;
  675.  
  676.         // Make sure the object fits in the window.
  677.         if (newRegion.left < parentObject->true.left ||
  678.             newRegion.top < parentObject->true.top ||
  679.             newRegion.left >= parentObject->true.right ||
  680.             newRegion.top >= parentObject->true.bottom ||
  681.             (tEvent.type == S_MOVE &&
  682.              (object->relative.left + deltaX < 0 ||
  683.              object->relative.top + deltaY < 0)))
  684.             return;
  685.  
  686.         tEvent.position.column = deltaX;
  687.         tEvent.position.line = deltaY;
  688.         if (tEvent.type == S_MOVE)
  689.         {
  690.             object->relative.left += deltaX;
  691.             object->relative.top += deltaY;
  692.         }
  693.         object->relative.right += deltaX;
  694.         object->relative.bottom += deltaY;
  695.         object->Event(tEvent);
  696.         ToFront(parentObject, FALSE, TRUE);
  697.     }
  698. }
  699.  
  700. void UI_WINDOW_MANAGER::Subtract(UI_WINDOW_OBJECT *object)
  701. {
  702.     // Make sure the object is in the window list.
  703.     if (UI_LIST::Index(object) != -1)
  704.     {
  705.         UI_WINDOW_MANAGER::Erase(object, 0);
  706.         UI_LIST::Subtract(object);
  707.         if (object == current)
  708.             current = NULL;
  709.     }
  710.     eventManager->DeviceState(E_DEVICE, DM_VIEW);
  711.  
  712.     UI_EVENT event;
  713.     event.type = S_CLEAR;
  714.     object->Event(event);
  715.     object->display = 0;
  716.     object->eventManager = 0;
  717.     object->windowManager = 0;
  718. }
  719.  
  720. void UI_WINDOW_MANAGER::ToFront(UI_WINDOW_OBJECT *object, int refreshOld,
  721.     int newWindow)
  722. {
  723.     // Find the maximum update region.
  724.     UI_WINDOW_OBJECT *tObject;
  725.     UI_REGION region = { 0x0FFF, 0x0FFF, 0x0000, 0x0000 };
  726.     for (tObject = First(); tObject && tObject != object; tObject = tObject->Next())
  727.         if (object->Overlap(tObject->true))
  728.         {
  729.             region.left = Min(region.left, tObject->true.left);
  730.             region.top = Min(region.top, tObject->true.top);
  731.             region.right = Max(region.right, tObject->true.right);
  732.             region.bottom = Max(region.bottom, tObject->true.bottom);
  733.         }
  734.  
  735.     // Delete any temporary windows.
  736.     UI_WINDOW_OBJECT *firstObject = First();
  737.     if (object != firstObject &&
  738.         (!FlagSet(object->woAdvancedFlags, WOAF_TEMPORARY) || !newWindow))
  739.     {
  740.         while (firstObject && firstObject != object &&
  741.             FlagSet(firstObject->woAdvancedFlags, WOAF_TEMPORARY))
  742.         {
  743.             firstObject->woStatus &= ~WOS_CURRENT;
  744.             UI_WINDOW_MANAGER::Subtract(firstObject);
  745.             if (!FlagSet(firstObject->woAdvancedFlags, WOAF_NO_DESTROY))
  746.                 delete firstObject;
  747.             firstObject = First();
  748.             if (!firstObject)
  749.                 return;
  750.         }
  751.     }
  752.  
  753.     // Bring the object to the front of the object queue.
  754.     if (firstObject != object)
  755.     {
  756.         if (UI_LIST::Index(object) != -1)
  757.             UI_LIST::Subtract(object);
  758.         UI_LIST::Add(firstObject, object);
  759.     }
  760.  
  761.     // Validate the object's region.
  762.     if (FlagSet(object->woAdvancedFlags, WOAF_MULTIPLE_REGIONS))
  763.     {
  764.         UI_EVENT event;
  765.         event.type = S_DEFINE_REGION;
  766.         object->Event(event);
  767.     }
  768.     else
  769.         display->RegionDefine(object->screenID, object->true);
  770.  
  771.     // Inactivate the old object, then activate the new object.
  772.     UI_EVENT event;
  773.     if (refreshOld && firstObject && firstObject != object &&
  774.         !FlagSet(object->woAdvancedFlags, WOAF_TEMPORARY))
  775.     {
  776.         event.type = S_DISPLAY_INACTIVE;
  777.         event.region.left = event.region.top = event.region.right =
  778.             event.region.bottom = -1;
  779.         firstObject->Event(event);
  780.     }
  781.     object->woStatus |= WOS_CURRENT;
  782.     event.type = S_CURRENT;
  783.     event.region = (newWindow) ? object->true : region;
  784.     object->Event(event);
  785. }
  786.  
  787.