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

  1. //    Zinc Interface Library - TXTDSP.CPP
  2. //    COPYRIGHT (C) 1990, 1991.  All Rights Reserved.
  3. //    Zinc Software Incorporated.  Pleasant Grove, Utah  USA
  4.  
  5. #include "ui_dsp.hpp"
  6. #include <dos.h>
  7. #include <mem.h>
  8. #include <conio.h>
  9. #include <string.h>
  10.  
  11. int UI_DOS_TEXT_DISPLAY::forceMono = FALSE;
  12. UCHAR UI_DOS_TEXT_DISPLAY::displayCode = DC_NO_DISPLAY;
  13. UCHAR UI_DOS_TEXT_DISPLAY::oldVideoMode;
  14.  
  15. // VideoInt executes BIOS interrupt 10H and insures BP is preserved.
  16. void VideoInt(void)
  17. {
  18.     asm        push    bp                // Save BP
  19.     asm        int        10H                // because INT 10H may clobber it
  20.     asm        pop        bp                // due to bug in older BIOS versions
  21. }
  22.  
  23. static void EgaCursor(void)
  24. {
  25.     _DX = *((USHORT far *)0x463L);
  26.     asm        mov        al, 14H
  27.     asm        out        dx, al
  28.     asm        inc        dx
  29.     asm        mov        al, 7
  30.     asm        out        dx, al
  31. }
  32.  
  33. // TopViewUpdate - Update the screen from the internal TopView buffer.
  34. static void TopViewUpdate(void)
  35. {
  36.     asm        push    bp
  37.     asm        push    di
  38.     asm        push    si
  39.     asm        mov        ah, 0FFH
  40.     asm        int        10H
  41.     asm        pop        si
  42.     asm        pop        di
  43.     asm        pop        bp
  44. }
  45.  
  46. #pragma argsused
  47. UI_DOS_TEXT_DISPLAY::UI_DOS_TEXT_DISPLAY(int mode) :
  48.     UI_DISPLAY(TRUE, 1, 1)
  49. {
  50.     UCHAR equipmentFlags;
  51.  
  52.     // Save the current video state.
  53.     equipmentFlags = *((UCHAR far *)0x410L);
  54.     _AX = 0x1A00;
  55.     VideoInt();
  56.     if (_AL != 0x1A)        // Display Combination Code call not supported.
  57.     {
  58.         UCHAR egaCode;
  59.         _AH = 0x12;
  60.         _BL = 0x10;
  61.         VideoInt();
  62.         egaCode = (_BL == 0x10) ? 0 : DC_EGA_COLOR + _BH;
  63.         if ((equipmentFlags & 0x30) == 0x30)        // Primary mono
  64.         {
  65.             displayCode = DC_MONOCHROME;
  66.             if (egaCode == DC_EGA_MONO)
  67.                 displayCode = DC_EGA_MONO;
  68.         }
  69.         else
  70.         {
  71.             displayCode = egaCode ? egaCode : DC_CGA;
  72.         }
  73.     }
  74.     else
  75.     {
  76.         displayCode = _BL;
  77.     }
  78.     // Save the current video state.
  79.     _AH = 0x0F;
  80.     VideoInt();
  81.     _DL = _AL;
  82.     oldVideoMode = _DL;
  83.     // oldVideoMode = _AL;        // Borland Bug: Doesn't work in large model
  84.     USHORT newSegment;
  85.     USHORT newOffset;
  86.  
  87.     if ((mode == TDM_43x80 && displayCode < DC_EGA_COLOR) ||
  88.         (mode == TDM_25x40 && displayCode == DC_MONOCHROME))
  89.            return;
  90.     retraceWait = (displayCode == DC_CGA) ? TRUE : FALSE;
  91.  
  92.     _BH = 0;
  93.     _AH = 3;
  94.     VideoInt();
  95.     originalCursorValue = _CX;            // Save original cursor value.
  96.     originalCursorEmulationBit = *((UCHAR far *)0x487L) & 1;
  97.  
  98.     // Set the new video mode.
  99.     if (((equipmentFlags & 0x30) == 0x10) || mode == TDM_25x40)
  100.         videoMode = forceMono ? 0x00 : 0x01;        // 40 column mode.
  101.     else if (displayCode == DC_MONOCHROME)
  102.         videoMode = 7;
  103.     else
  104.         videoMode = forceMono ? 0x02 : 0x03;
  105.     _AX = (USHORT)videoMode;
  106.     VideoInt();
  107.     delay(60);                      // For benefit of suspected VEGA VGA BIOS bug.
  108.  
  109.     // Check the new video state.
  110.     _AH = 0x0F;
  111.     VideoInt();
  112.     if (_AL == 7)
  113.     {
  114.         segment = 0xB000;
  115.         isMono = TRUE;
  116.         onCursorValue = 0x0B0C;
  117.         offCursorValue = 0x2000;
  118.     }
  119.     else
  120.     {
  121.         segment = 0xB800;
  122.         isMono = FALSE;
  123.         onCursorValue = 0x0607;
  124.         offCursorValue = 0x2000;
  125.     }
  126.     _AH = 1;
  127.     VideoInt();                    // Turn off the cursor.
  128.  
  129.     // Put in check for Hercules In-Color Card later.
  130.     desqview = FALSE;
  131.     topview = FALSE;
  132.     offset = 0;
  133.     _DX = segment;
  134.     _DI = offset;
  135.     _ES = _DX;
  136.     _AH = 0xFE;
  137.     VideoInt();
  138.     newSegment = _ES;
  139.     newOffset = _DI;
  140.     if (newSegment != segment || newOffset != offset)
  141.     {
  142.         segment = newSegment;
  143.         offset = newOffset;
  144.         retraceWait = FALSE;
  145.         _CX = 'ED';
  146.         _DX = 'QS';
  147.         _AX = 0x2B01;
  148.         geninterrupt(0x21);
  149.         if (_AL == 0xFF)
  150.             topview = TRUE;
  151.         else
  152.             desqview = TRUE;
  153.     }
  154.     if (mode == TDM_43x80 && displayCode >= DC_EGA_COLOR)
  155.     {
  156.         if (displayCode == DC_EGA_COLOR || displayCode == DC_EGA_MONO)
  157.             lines = 43;
  158.         else
  159.             lines = 50;
  160.         _BL = 0;
  161.         _AX = 0x1112;                // Load ROM BIOS 8x8 characters
  162.         VideoInt();
  163.         if (displayCode <= DC_EGA_MONO)
  164.         {
  165.             *((UCHAR far *)0x487L) |= 1;    // Inhibit cursor emulation.
  166.             _CX = 0x0607;                       // (start on 6, off on 7)
  167.             _AH = 0x01;
  168.             VideoInt();
  169.             EgaCursor();
  170.         }
  171.         _BL = 0x20;
  172.         _AH = 0x12;
  173.         VideoInt();                        // Set alternate print screen routine.
  174.     }
  175.     else
  176.         lines = 25;
  177.     columns = *((USHORT far *)0x44AL);
  178.     if (*((UCHAR far *)0x484L))
  179.         lines = *((UCHAR far *)0x484L) + 1;
  180.     SetBlink(FALSE);                    // Turn off blink by default.
  181.  
  182.     // Check for special text mode monitors.
  183.     struct text_info textInfo;
  184.     gettextinfo(&textInfo);
  185.     if (textInfo.currmode == BW80 || textInfo.currmode == BW40)
  186.         isMono = TRUE;
  187.  
  188.     // Fill the screen according to the specified palette.
  189.     for (int i = 0; i < lines; i++)
  190.         FillLine(0, i, columns, _backgroundPalette);
  191.  
  192.     // Define the screen display region.
  193.     Add(0, new UI_REGION_ELEMENT(ID_SCREEN, 0, 0, columns - 1, lines - 1));
  194.     installed = TRUE;
  195. }
  196.  
  197. UI_DOS_TEXT_DISPLAY::~UI_DOS_TEXT_DISPLAY(void)
  198. {
  199.     _AX = (USHORT)oldVideoMode;
  200.     VideoInt();
  201.     if (displayCode == DC_EGA_MONO || displayCode == DC_EGA_COLOR)
  202.         *((UCHAR far *)0x487) = (*((UCHAR far *)0x487L) & ~1) | originalCursorEmulationBit;
  203.     _CX = originalCursorValue;
  204.     _AH = 1;
  205.     VideoInt();
  206. }
  207.  
  208. #pragma argsused
  209. void UI_DOS_TEXT_DISPLAY::Bitmap(SCREENID screenID, int column, int line,
  210.     int bitmapWidth, int bitmapHeight, const UCHAR *bitmapArray,
  211.     const UI_PALETTE *palette, const UI_REGION *clipRegion)
  212. {
  213. }
  214.  
  215. #pragma argsused
  216. void UI_DOS_TEXT_DISPLAY::Ellipse(SCREENID screenID, int column, int line,
  217.     int startAngle, int endAngle, int xRadius, int yRadius,
  218.     const UI_PALETTE *palette, int fill, int xor, const UI_REGION *clipRegion)
  219. {
  220. }
  221.  
  222. #pragma argsused
  223. void UI_DOS_TEXT_DISPLAY::Line(SCREENID screenID, int column1, int line1,
  224.     int column2, int line2, const UI_PALETTE *palette, int width, int xor,
  225.     const UI_REGION *clipRegion)
  226. {
  227.     if (xor)
  228.     {
  229.         Rectangle(screenID, column1, line1, column2, line2, palette, 0,
  230.             FALSE, TRUE, clipRegion);
  231.         return;
  232.     }
  233.  
  234.     // Ensure a left-top to right-bottom line.
  235.     if (column2 < column1)
  236.     {
  237.         int column = column1;
  238.         column1 = column2;
  239.         column2 = column;
  240.     }
  241.     if (line2 < line1)
  242.     {
  243.         int line = line1;
  244.         line1 = line2;
  245.         line2 = line;
  246.     }
  247.  
  248.     // Set up the line region.
  249.     UI_REGION region;
  250.     region.left = column1;
  251.     region.top = line1;
  252.     region.right = column2;
  253.     region.bottom = line2;
  254.     if (clipRegion)
  255.     {
  256.         region.left = Max(region.left, clipRegion->left);
  257.         region.top = Max(region.top, clipRegion->top);
  258.         region.right = Min(region.right, clipRegion->right);
  259.         region.bottom = Min(region.bottom, clipRegion->bottom);
  260.     }
  261.  
  262.     // Hide the screen devices.
  263.     if (eventManager)
  264.         eventManager->DevicesHide(region);
  265.  
  266.     // Compute the display character.
  267.     UI_PALETTE t_palette = *palette;
  268.     if (column1 == column2)                    // Vertical line
  269.         t_palette.fillCharacter = (width == 1) ? 0xB3 : 0xBA;
  270.     else if (line1 == line2)                // Horizontal line
  271.         t_palette.fillCharacter = (width == 1) ? 0xC4 : 0xCD;
  272.     else
  273.         t_palette.fillCharacter = 0;
  274.  
  275.     // Draw a line on the display.
  276.     if (t_palette.fillCharacter)
  277.         Fill(screenID, region, &t_palette);
  278.     if (topview)
  279.         TopViewUpdate();
  280.  
  281.     // Show the screen devices.
  282.     if (eventManager)
  283.         eventManager->DevicesShow(region);
  284. }
  285.  
  286. #pragma argsused
  287. void UI_DOS_TEXT_DISPLAY::Polygon(SCREENID screenID, int numPoints,
  288.     const int *polygonPoints, const UI_PALETTE *palette, int fill, int xor,
  289.     const UI_REGION *clipRegion)
  290. {
  291. }
  292.  
  293. #pragma argsused
  294. void UI_DOS_TEXT_DISPLAY::Rectangle(SCREENID screenID, int left, int top, int right,
  295.     int bottom, const UI_PALETTE *palette, int width, int fill, int xor,
  296.     const UI_REGION *clipRegion)
  297. {
  298.     UI_REGION region;
  299.  
  300.     region.left = left;
  301.     region.top = top;
  302.     region.right = right;
  303.     region.bottom = bottom;
  304.     if (clipRegion)
  305.     {
  306.         region.left = Max(region.left, clipRegion->left);
  307.         region.top = Max(region.top, clipRegion->top);
  308.         region.right = Min(region.right, clipRegion->right);
  309.         region.bottom = Min(region.bottom, clipRegion->bottom);
  310.     }
  311.     if (xor)
  312.     {
  313.         if (fill)
  314.             FillXOR(region);
  315.         else
  316.             RectangleXOR(region);
  317.     }
  318.     else
  319.     {
  320. #if 0
  321.         RectangleOnly(screenID, region, palette, width);
  322.         if (fill) {
  323.             region.left++;
  324.             region.right--;
  325.             region.top++;
  326.             region.bottom--;
  327.             Fill(screenID, region, palette);
  328.         }
  329. #else
  330.         if (fill)
  331.             Fill(screenID, region, palette);
  332.         else
  333.             RectangleOnly(screenID, region, palette, width);
  334. #endif
  335.     }
  336. }
  337.  
  338. void UI_DOS_TEXT_DISPLAY::RectangleXOR(const UI_REGION ®ion)
  339. {
  340.     // See if it is a 1 cell rectangle.
  341.     if (region.left == region.right && region.top == region.bottom)
  342.     {
  343.         UI_DOS_TEXT_DISPLAY::FillXOR(region);
  344.         return;
  345.     }
  346.  
  347.     // Hide the screen devices.
  348.     if (eventManager)
  349.         eventManager->DevicesHide(region);
  350.  
  351.     // Draw an XOR rectangle on the display.
  352.     if (region.top >= 0 && region.top < lines)
  353.     {
  354.         for (int column = Max(region.left, 0); column <= Min(region.right, columns - 1); column++)
  355.             XorAttribute(column, region.top);
  356.     }
  357.     if (region.top < region.bottom)
  358.     {
  359.         for (int row = Max(region.top + 1, 0); row < Min(region.bottom, lines); row++)
  360.         {
  361.             if (region.left >= 0)
  362.                 XorAttribute(region.left, row);
  363.             if ((region.left != region.right || region.left < 0) && region.right < columns)
  364.                 XorAttribute(region.right, row);
  365.         }
  366.         if (region.bottom < lines)
  367.         {
  368.             for (int column = Max(region.left, 0); column <= Min(region.right, columns - 1); column++)
  369.                 XorAttribute(column, region.bottom);
  370.         }
  371.     }
  372.     if (topview)
  373.         TopViewUpdate();
  374.  
  375.     // Show the screen devices.
  376.     if (eventManager)
  377.         eventManager->DevicesShow(region);
  378. }
  379.  
  380. #pragma argsused
  381. void UI_DOS_TEXT_DISPLAY::RectangleXORDiff(const UI_REGION &oldRegion,
  382.     const UI_REGION &newRegion)
  383. {
  384.     static char *cell = 0;
  385.  
  386.     // Allocate space for the XOR region.
  387.     if (&oldRegion == &newRegion)
  388.     {
  389.         if (cell)
  390.             delete cell;
  391.         cell = 0;
  392.         return;
  393.     }
  394.     else if (!cell)
  395.          cell = new char[lines * columns];
  396.  
  397.     // Set up the hide region.
  398.     if (oldRegion.left == newRegion.left && oldRegion.top == newRegion.top &&
  399.         oldRegion.right == newRegion.right && oldRegion.bottom == newRegion.bottom)
  400.         return;
  401.     UI_REGION region;
  402.     region.left = Min(oldRegion.left, newRegion.left);
  403.     region.top = Min(oldRegion.top, newRegion.top);
  404.     region.right = Max(oldRegion.right, newRegion.right);
  405.     region.bottom = Max(oldRegion.bottom, newRegion.bottom);
  406.  
  407.     // Hide the screen devices.
  408.     if (eventManager)
  409.         eventManager->DevicesHide(region);
  410.  
  411.     // Clear the array.
  412.     char *tCell;
  413.     int i, j, iMin, iMax, jMin, jMax;
  414.     memset(cell, 0, lines * columns);
  415.  
  416.     // Find the difference of the two regions.
  417.     iMin = Max(oldRegion.top, 0);
  418.     iMax = Min(oldRegion.bottom, lines - 1);
  419.     jMin = Max(oldRegion.left + 1, 0);
  420.     jMax = Min(oldRegion.right, columns);
  421.     for (i = iMin; i <= iMax; i++)
  422.     {
  423.         if (oldRegion.left >= 0)
  424.             cell[i * columns + oldRegion.left] ^= 1;
  425.         if (oldRegion.right < columns)
  426.             cell[i * columns + oldRegion.right] ^= 1;
  427.         if (i == oldRegion.top || i == oldRegion.bottom)
  428.             for (j = jMin, tCell = &cell[i * columns + jMin]; j < jMax; j++, tCell++)
  429.                 *tCell ^= 1;
  430.     }
  431.     iMin = Max(newRegion.top, 0);
  432.     iMax = Min(newRegion.bottom, lines - 1);
  433.     jMin = Max(newRegion.left + 1, 0);
  434.     jMax = Min(newRegion.right, columns);
  435.     for (i = iMin; i <= iMax; i++)
  436.     {
  437.         if (newRegion.left >= 0)
  438.             cell[i * columns + newRegion.left] ^= 1;
  439.         if (newRegion.right < columns)
  440.             cell[i * columns + newRegion.right] ^= 1;
  441.         if (i == newRegion.top || i == newRegion.bottom)
  442.             for (j = jMin, tCell = &cell[i * columns + jMin]; j < jMax; j++, tCell++)
  443.                 *tCell ^= 1;
  444.     }
  445.  
  446.     // XOR the cell differences.
  447.     iMin = Max(0, Min(oldRegion.top, newRegion.top));
  448.     iMax = Min(lines - 1, Max(oldRegion.bottom, newRegion.bottom));
  449.     jMin = Max(0, Min(oldRegion.left, newRegion.left));
  450.     jMax = Min(columns - 1, Max(oldRegion.right, newRegion.right));
  451.     for (i = iMin; i <= iMax; i++)
  452.         for (j = jMin, tCell = &cell[i * columns + jMin]; j <= jMax; j++, tCell++)
  453.             if (*tCell)
  454.                 XorAttribute(j, i);
  455.     if (topview)
  456.         TopViewUpdate();
  457.  
  458.     // Show the screen devices.
  459.     if (eventManager)
  460.         eventManager->DevicesShow(region);
  461. }
  462.  
  463. #pragma argsused
  464. void UI_DOS_TEXT_DISPLAY::RegionConvert(UI_REGION ®ion, USHORT *oldFlags, USHORT newFlags)
  465. {
  466.     // Check for a convertable region.
  467.     if (!FlagSet(*oldFlags, newFlags))
  468.         return;
  469.  
  470.     // These variables handle Text<-->Graphics coordinate problems.
  471.     region.left /= 8;
  472.     region.top /= 14;
  473.     region.right /= 8;
  474.     region.bottom /= 14;
  475.  
  476.     *oldFlags &= ~newFlags;
  477. }
  478.  
  479. #pragma argsused
  480. void UI_DOS_TEXT_DISPLAY::RegionMove(const UI_REGION &oldRegion, int newColumn, int newLine,
  481.     SCREENID oldScreenID, SCREENID newScreenID)
  482. {
  483.     unsigned width = oldRegion.right - oldRegion.left + 1;
  484.     unsigned height = oldRegion.bottom - oldRegion.top + 1;
  485.     char *buffer = new char[width * height * 2];
  486.     gettext(oldRegion.left + 1, oldRegion.top + 1, oldRegion.right + 1,
  487.         oldRegion.bottom + 1, buffer);
  488.     puttext(newColumn, newLine, newColumn + width - 1, newLine + height - 1,
  489.         buffer);
  490.     delete buffer;
  491. }
  492.  
  493. #pragma argsused
  494. void UI_DOS_TEXT_DISPLAY::Text(SCREENID screenID, int left, int top,
  495.     const char *text, const UI_PALETTE *palette, int length,
  496.     int fill, int xor, const UI_REGION *clipRegion)
  497. {
  498.     int start;
  499.     UI_REGION region;
  500.     UI_REGION t_region;
  501.     UI_REGION dRegion;
  502.  
  503.     if (xor)
  504.     {
  505.         TextXOR(left, top, length);
  506. //        Rectangle(screenID, left, top, left + length - 1, top,
  507. //            palette, 1, TRUE, TRUE);
  508.         return;
  509.     }
  510.     // Draw the text on the display.
  511.     region.left = left;
  512.     region.top = top;
  513.     region.right = left + (length == -1 ? strlen(text) : length) - 1;
  514.     region.bottom = top;
  515.     if (clipRegion)
  516.     {
  517.         region.left = Max(region.left, clipRegion->left);
  518.         region.top = Max(region.top, clipRegion->top);
  519.         region.right = Min(region.right, clipRegion->right);
  520.         region.bottom = Min(region.bottom, clipRegion->bottom);
  521.     }
  522.     dRegion = region;
  523.  
  524.     // Hide the screen devices.
  525.     if (eventManager)
  526.         eventManager->DevicesHide(dRegion);
  527.  
  528.     // Display the text.
  529.     for (UI_REGION_ELEMENT *d_region = First(); d_region; d_region = d_region->Next())
  530.         if (d_region->screenID == screenID &&
  531.             d_region->Overlap(region, t_region) &&
  532.             region.top >= t_region.top)
  533.         {
  534.             int right = (region.right > t_region.right) ? t_region.right : region.right;
  535.             if (region.left < t_region.left)
  536.             {
  537.                 start = t_region.left - region.left;
  538.                 DrawText(palette, t_region.left, region.top, &text[start],
  539.                     right + 1 - t_region.left);
  540.             }
  541.             else
  542.                 DrawText(palette, region.left, region.top, text,
  543.                     right + 1 - region.left);
  544.         }
  545.     if (topview)
  546.         TopViewUpdate();
  547.  
  548.     // Show the screen devices.
  549.     if (eventManager)
  550.         eventManager->DevicesShow(dRegion);
  551. }
  552.  
  553. #pragma argsused
  554. int UI_DOS_TEXT_DISPLAY::TextHeight(const char *string, SCREENID screenID)
  555. {
  556.     return (1);
  557. }
  558.  
  559. #pragma argsused
  560. int UI_DOS_TEXT_DISPLAY::TextWidth(const char *string, SCREENID screenID)
  561. {
  562.     return (strlen(string));
  563. }
  564.  
  565. void UI_DOS_TEXT_DISPLAY::DrawText(const UI_PALETTE *palette, int column,
  566.     int line, const char *text, int length)
  567. {
  568.     USHORT t_segment = segment;
  569.     USHORT t_offset = offset + line * columns * 2 + column * 2;
  570.  
  571.     _DL = retraceWait;
  572.     _DH = isMono ? palette->monoAttribute : palette->colorAttribute;
  573.     _CX = length;
  574.     _DI = t_offset;
  575.     _ES = t_segment;
  576. #if sizeof(text) == 4
  577.     asm        push    ds
  578.     asm        mov        si, WORD PTR text
  579.     asm        mov        ds, WORD PTR text + 2
  580. #else
  581.     asm        mov        si, text
  582. #endif
  583.     asm        mov        bh, dh            // Save attribute in BH
  584.     asm        or        dl, dl
  585.     asm        jz        fast_draw
  586.  
  587.     asm        mov        dx, 3DAH        // Get address of Motorola 6845 to DX
  588.  
  589. next_char:
  590.     asm        lodsb
  591.     asm        mov        bl, al
  592. wait_lo:
  593.     asm        in        al, dx
  594.     asm        rcr        al, 1
  595.     asm        jc        wait_lo
  596.  
  597.     asm        cli
  598.  
  599. wait_hi:
  600.     asm        in        al, dx
  601.     asm        rcr        al, 1
  602.     asm        jnc        wait_hi
  603.  
  604.     asm        mov        ax, bx
  605.     asm        stosw
  606.     asm        sti
  607.     asm        loop    next_char
  608.  
  609.     asm        jmp        short draw_done
  610.  
  611. fast_draw:
  612.     asm        mov        ah, bh
  613.  
  614. fast_loop:
  615.     asm        lodsb
  616.     asm        stosw
  617.     asm        loop    fast_loop
  618.  
  619. draw_done:;
  620. #if    sizeof(text) == 4
  621.     asm        pop        ds
  622. #endif
  623. }
  624.  
  625. void UI_DOS_TEXT_DISPLAY::SetBlink(int enableBlink)
  626. {
  627.     if (displayCode >= DC_EGA_COLOR)
  628.     {
  629.         _BL = enableBlink ? 1 : 0;
  630.         _AX = 0x1003;
  631.         VideoInt();
  632.     }
  633.     else
  634.     {
  635.         UCHAR newSetting = *((UCHAR far *)0x465L);
  636.         newSetting = (enableBlink) ? newSetting | 0x20 : newSetting & ~0x20;
  637.         outportb(*((USHORT far *)0x463L) + 4, newSetting);
  638.         *((UCHAR far *)0x465L) = newSetting;        // Update BIOS data area
  639.     }
  640.     blinkState = enableBlink;
  641. }
  642.  
  643. void UI_DOS_TEXT_DISPLAY::Fill(SCREENID screenID, const UI_REGION ®ion,
  644.     const UI_PALETTE *palette)
  645. {
  646.     UI_REGION t_region;
  647.  
  648.     // Hide the screen devices.
  649.     if (eventManager)
  650.         eventManager->DevicesHide(region);
  651.  
  652.     // Fill a zone on the display.
  653.     for (UI_REGION_ELEMENT *d_region = First(); d_region; d_region = d_region->Next())
  654.         if (d_region->screenID == screenID &&
  655.             d_region->Overlap(region, t_region))
  656.         {
  657.             for (int i = t_region.top; i <= t_region.bottom; i++)
  658.                 FillLine(t_region.left, i, t_region.right + 1 - t_region.left, palette);
  659.         }
  660.     if (topview)
  661.         TopViewUpdate();
  662.  
  663.     // Show the screen devices.
  664.     if (eventManager)
  665.         eventManager->DevicesShow(region);
  666. }
  667.  
  668. void UI_DOS_TEXT_DISPLAY::FillXOR(const UI_REGION ®ion)
  669. {
  670.     int i, j;
  671.     for (i = region.left; i <= region.right; i++)
  672.         for (j = region.top; j <= region.bottom; j++)
  673.             XorAttribute(i, j);
  674.     if (topview)
  675.         TopViewUpdate();
  676. }
  677.  
  678. void UI_DOS_TEXT_DISPLAY::FillLine(int column, int line, int noOfCharacters,
  679.     const UI_PALETTE *palette)
  680. {
  681.     USHORT t_segment = segment;
  682.     USHORT t_offset = offset + line * columns * 2 + column * 2;
  683.  
  684.     _DL = retraceWait;
  685.     _CH = isMono ? palette->monoAttribute : palette->colorAttribute;
  686.     _CL = palette->fillCharacter;
  687.     _BX = _CX;                        // Save to BX.
  688.     _CX = noOfCharacters;
  689.     _DI = t_offset;
  690.     _ES = t_segment;
  691.     asm        or        dl, dl
  692.     asm        jz        fast_fill
  693.  
  694.     asm        mov        dx, 3DAH        // Get address of Motorola 6845 to DX
  695.  
  696. wait_lo:
  697.     asm        in        al, dx
  698.     asm        rcr        al, 1
  699.     asm        jc        wait_lo
  700.  
  701.     asm        cli
  702.  
  703. wait_hi:
  704.     asm        in        al, dx
  705.     asm        rcr        al, 1
  706.     asm        jnc        wait_hi
  707.  
  708.     asm        mov        ax, bx
  709.     asm        stosw
  710.     asm        sti
  711.     asm        loop    wait_lo
  712.  
  713.     asm        jmp        short fill_done
  714.  
  715. fast_fill:
  716.     asm        mov        ax, bx
  717.     asm        rep        stosw
  718. fill_done:;
  719. }
  720.  
  721. void UI_DOS_TEXT_DISPLAY::RectangleOnly(SCREENID screenID, const UI_REGION ®ion,
  722.     const UI_PALETTE *palette, int width)
  723. {
  724.     static char cornerUL[] = { 0xDA, 0, 0xC9, 0 };
  725.     static char cornerUR[] = { 0xBF, 0, 0xBB, 0 };
  726.     static char cornerLL[] = { 0xC0, 0, 0xC8, 0 };
  727.     static char cornerLR[] = { 0xD9, 0, 0xBC, 0 };
  728.  
  729.     // Hide the screen devices.
  730.     if (eventManager)
  731.         eventManager->DevicesHide(region);
  732.  
  733.     // Draw a box on the display.
  734.     if (region.right > region.left && region.bottom > region.top)
  735.     {
  736.         if (region.right > region.left + 1)
  737.         {
  738.             // NOTE: The next two lines of code are a kludge to get around
  739.             // the problem that Line() has with drawing a line which consists of
  740.             // a single character.  It doesn't know whether to use the
  741.             // horizontal or vertical character.  Currently it defaults to
  742.             // vertical.  To get around this problem, this code makes it draw one
  743.             // extra character to force the line to be horizontal.  The extra
  744.             // character is overwritten anyway when the corners are drawn.
  745.             int rightEdge = region.right - 1;
  746.             if (rightEdge == region.left + 1)
  747.                 rightEdge++;
  748.             Line(screenID, region.left + 1, region.top, rightEdge, region.top, palette, width);
  749.             Line(screenID, region.left + 1, region.bottom, rightEdge, region.bottom, palette, width);
  750.         }
  751.         if (region.bottom > region.top + 1)
  752.         {
  753.             Line(screenID, region.left, region.top + 1, region.left, region.bottom - 1, palette, width);
  754.             Line(screenID, region.right, region.top + 1, region.right, region.bottom - 1, palette, width);
  755.         }
  756.         width = 2 * (width - 1);
  757.         Text(screenID, region.left,  region.top, &cornerUL[width], palette, -1, FALSE);
  758.         Text(screenID, region.right, region.top, &cornerUR[width], palette, -1, FALSE);
  759.         Text(screenID, region.left,  region.bottom, &cornerLL[width], palette, -1, FALSE);
  760.         Text(screenID, region.right, region.bottom, &cornerLR[width], palette, -1, FALSE);
  761.     }
  762.     if (topview)
  763.         TopViewUpdate();
  764.  
  765.     // Show the screen devices.
  766.     if (eventManager)
  767.         eventManager->DevicesShow(region);
  768. }
  769.  
  770. void UI_DOS_TEXT_DISPLAY::TextXOR(int left, int top, int length)
  771. {
  772.     // Set up the text region.
  773.     UI_REGION region;
  774.     region.left = left;
  775.     region.top = top;
  776.     region.right = left + length - 1;
  777.     region.bottom = top;
  778.  
  779.     // Hide the screen devices.
  780.     if (eventManager)
  781.         eventManager->DevicesHide(region);
  782.  
  783.     // Draw an XOR rectangle on the display.
  784.     if (region.top >= 0 && region.top < lines)
  785.     {
  786.         for (int column = Max(region.left, 0); column <= Min(region.right, columns - 1); column++)
  787.             XorAttribute(column, region.top, TRUE);
  788.     }
  789.     if (topview)
  790.         TopViewUpdate();
  791.  
  792.     // Show the screen devices.
  793.     if (eventManager)
  794.         eventManager->DevicesShow(region);
  795. }
  796.  
  797. void UI_DOS_TEXT_DISPLAY::XorAttribute(int column, int line, int swapNibbles)
  798. {
  799.     USHORT t_segment = segment;
  800.     USHORT t_offset = offset + line * columns * 2 + column * 2;
  801.  
  802.     asm        push ds
  803.     _DH = swapNibbles;
  804.     _CH = retraceWait;
  805.     _DI = t_offset;
  806.     _DS = t_segment;
  807.     if (_DH)
  808.     {
  809.         _CL = 4;
  810.         if (_CH != 0)
  811.         {
  812.             asm        mov        dx, 3DAH        // Get address of Motorola 6845 to DX
  813.  
  814. waitL1:        asm        in        al, dx
  815.             asm        rcr        al, 1
  816.             asm        jc        waitL1
  817.  
  818.             asm        cli
  819.  
  820. waitH1:        asm        in        al, dx
  821.             asm        rcr        al, 1
  822.             asm        jnc        waitH1
  823.  
  824.             asm        mov        bl, BYTE PTR [di + 1]
  825.             asm        ror        bl, cl
  826.  
  827. waitL2:        asm        in        al, dx
  828.             asm        rcr        al, 1
  829.             asm        jc        waitL2
  830.  
  831. waitH2:        asm        in        al, dx
  832.             asm        rcr        al, 1
  833.             asm        jnc        waitH2
  834.  
  835.             asm        mov        BYTE PTR [di + 1], bl
  836.         }
  837.         else
  838.             asm        ror        BYTE PTR [di + 1], cl
  839.     }
  840.     else
  841.     {
  842.         asm        or        ch, ch
  843.         asm        jz         do_xor
  844.  
  845.         asm        mov        dx, 3DAH        // Get address of Motorola 6845 to DX
  846.  
  847. waitL3:    asm        in        al, dx
  848.         asm        rcr        al, 1
  849.         asm        jc        waitL3
  850.  
  851.         asm        cli
  852.  
  853. waitH3:    asm        in        al, dx
  854.         asm        rcr        al, 1
  855.         asm        jnc        waitH3
  856.  
  857. do_xor:    asm        xor        BYTE PTR [di + 1], 0FFH
  858.     }
  859.     asm        sti
  860.     asm        pop        ds
  861. }
  862.