Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

#include "std.h"

#include "emul.h"
#include "vars.h"
#include "debug.h"
#include "dbgpaint.h"
#include "dx.h"
#include "draw.h"
#include "dxrframe.h"
#include "font16.h"
#include "util.h"

#include "debug_tools.h"                // [NS]



//=============================================================================

// 640x480      80x30
// 768x586      96x36,625

//unsigned char gdi_dbg_buf[ 2 * 1048576]; //2MB

const int c8 = 8;                                                               // [NS]
const int c16 = 16;

//#define SB80  84      // в dbgpaint.h
//#define SB30  30

const int s80 = 80;//84;//80;
const int s30 = 30;//32;//30;


const int s192 = 192;
const int s640 = 640;//672;//640;
const int s480 = 480;//512;//480;

//unsigned char txtscr[ 80 * 30 * 2];
unsigned char txtscr[ SB80 * SB30 * 2]; // не принимает переменные

//=============================================================================



//=============================================================================
static struct
{
    unsigned char x;
    unsigned char y;
    unsigned char dx;
    unsigned char dy;
    unsigned char c;
} frames[ 20];

//=============================================================================


unsigned nfr;





//=============================================================================
void debugflip()
{

// printf("debugflip()\n");
// printf("temp.scx %d\n",temp.scx);
       
    //-------------------------------------------------------------------------
    // обновление debug tools-ов при активном дебагере
    for (int cnt = 0;    cnt < DEBUG_TOOLS_MAX_COUNT;    cnt++)
    {
        //---------------------------------------------------------------------
        // обновляем только открытые окна
        if (debug_tool_exist[ cnt])
        {
            InvalidateRect( debug_tool_hwnd[ cnt], NULL, FALSE); // не стирать фон
            UpdateWindow(   debug_tool_hwnd[ cnt]);              // [NS] test
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------



    /*
    if (!active)                        // [NS] неясно зачем пропускать отрисовку когдаа она нада?
    {                                   // может пушо этим занималсо WM_PAINT из dx.cpp
        printf("debugflip() skip\n");   // который обычно отрисовывал всяйик шлак
        return;                         // заскриншоченный 5 минут нназад
    }
    */

       
    setpal( 0);

//  unsigned char * const bptr = gdibuf;
    unsigned char * const bptr = gdi_dbg_buf;   // рисуем в свой отдельный буфер [NS]







    //-------------------------------------------------------------------------
    // отрисовка маленького превиева
    //          должна быть ИМЕННО ТУТ!!!
    //          пушо превиев может перекрыватсо всплывающими "окнами"
    //-------------------------------------------------------------------------
    if (show_scrshot)
    {
        //---------------------------------------------------------------------
        // для raypainted
        memcpy( save_buf,
                rbuf,
                rb2_offs
                );             
        //---------------------------------------------------------------------
        switch (show_scrshot)
        {
            case 1:     paint_scr( 0);  break;                  // [NS]
            case 2:     paint_scr( 1);  break;
            case 3:     paint_scr( 2);  break;
        }
        //---------------------------------------------------------------------
        unsigned char *dst = bptr + (wat_y * c16 * s640) + (wat_x * c8);
       
//      unsigned char *src = rbuf + (temp.scx / 4) * (temp.b_top +  (192 / 2) - (wat_sz *  16 / 2));
        unsigned char *src = rbuf + (temp.scx / 4) * (temp.b_top + (s192 / 2) - (wat_sz * c16 / 2));
     
        src += (temp.scx /  8) - (37 / 2 * 2);
//      src += (temp.scx / c8) - (37 / 2 * 2);
       
//      unsigned char *ray_pos = raypointer();  // [NS}
       
        // перекидывание zx экрана в экран дебагера
        //---------------------------------------------------------------------
        for (unsigned y = 0;    y < wat_sz * 16;    y++)        // wat_sz = 13 (Y размер знакомест в дебагере)
        {
            //-----------------------------------------------------------------
            // 1 байт на пиксель !!!!
            for (unsigned x = 0;    x < 37;    x++)             //37 знакомест
            {
                // НО все равно просто так не вырватсо из мерзского hardware multicolor-а [NS]
                //-------------------------------------------------------------
                // отрисованные пиксели
                //if (reinterpret_cast<int>(src+(2*x)) < reinterpret_cast<int>(ray_pos))
                //{
                //левые 4 пикселя
                *(unsigned*) (dst + x * 8 + 0) = t.sctab8[ 0][( src[ x * 2] >>  4) + src[ 2 * x + 1] * 16];    
                //правые 4 пикселя
                *(unsigned*) (dst + x * 8 + 4) = t.sctab8[ 0][( src[ x * 2] & 0xF) + src[ 2 * x + 1] * 16];
                //}
                //-------------------------------------------------------------
                // пиксели с предыдущего кадра
                //else
                //{
                ////левые 4 пикселя
                //*(unsigned*)(dst + x * 8 + 0) = (t.sctab8[0][(src[x * 2] >>  4) + src[2 * x + 1] * 16]);     
                ////правые 4 пикселя
                //*(unsigned*)(dst + x * 8 + 4) = (t.sctab8[0][(src[x * 2] & 0xF) + src[2 * x + 1] * 16]);
                //}
            } // x
            //-----------------------------------------------------------------
            src += temp.scx / 4;
            //dst += 640;
            dst += s640;
        } // y
        //---------------------------------------------------------------------
        // для raypainted
        memcpy( rbuf,
                save_buf,
                rb2_offs);
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------

       
       
       
       
       
       
       
       
       
       
       
    //-------------------------------------------------------------------------
    // print text mode
    //-------------------------------------------------------------------------
    int x;
    int y;
    unsigned char *tptr = txtscr;
    //-------------------------------------------------------------------------
//  for (y = 0;    y < (16 * 30 * 640);    y += (16 * 640))
    for (y = 0;    y < (c16 * s30 * s640);    y += (c16 * s640))
    {
        //---------------------------------------------------------------------
        // for (x = 0;    x < 80;    x++, tptr++)
        for (x = 0;    x < s80;    x++, tptr++)
        {
            unsigned ch = *tptr;
            //unsigned at = tptr[ 80 * 30];
            unsigned at = tptr[ s80 * s30];
            //-----------------------------------------------------------------
            //transparent color - НЕНУЖЕН
            if (at == 0xFF)
                continue;
            //-----------------------------------------------------------------
            //const unsigned char *fnt = &font16[ ch * 16];
            const unsigned char *fnt = &font16[ ch * c16];
            at <<= 4;
            //-----------------------------------------------------------------
            //for (int yy = 0;    yy < 16;    yy++, fnt++)
            for (int yy = 0;    yy < c16;    yy++, fnt++)
            {
            //  unsigned sctab8[2][16*0x100];  //4 bits data+pc-attribute -> 4 palette pixels
           
                //правые 4 пикселя
                //*(unsigned*) (bptr + y + (640 * yy) + (x * 8) + 0) = t.sctab8[ 0][( *fnt >>  4) + at];
                *(unsigned*) (bptr + y + (s640 * yy) + (x * 8) + 0) = t.sctab8[ 0][( *fnt >>  4) + at];
               
                //левые 4 пикселя
                //*(unsigned*) (bptr + y + (640 * yy) + (x * 8) + 4) = t.sctab8[ 0][( *fnt & 0xF) + at];
                *(unsigned*) (bptr + y + (s640 * yy) + (x * 8) + 4) = t.sctab8[ 0][( *fnt & 0xF) + at];
            }
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------





   
    //-------------------------------------------------------------------------
    // отрисовка "рамочек" из буфера
    // но РАМОЧКИ НЕНУЖНЫ
    /*
    for (unsigned i = 0;    i < nfr;    i++)
    {
        //unsigned char a1 = (frames[i].c | 0x08) * 0x11;
        unsigned char a1 = (frames[ i].c & 0x0F) | ((frames[ i].c & 0x0F) << 4);        //attr 256c ?
        //---------------------------------------------------------------------
        //y = frames[i].y * 16 - 1;
        y = frames[i].y * c16 - 1;
        //---------------------------------------------------------------------
        for (x = 8 * frames[ i].x - 1;    x < (frames[ i].x + frames[ i].dx) * 8;    x++)
        {
            // bptr[ y * 640 + x] = a1;
            bptr[ y * s640 + x] = a1;
        }
        //---------------------------------------------------------------------
        //y = (frames[ i].y + frames[ i].dy) * 16;
        y = (frames[ i].y + frames[ i].dy) * c16;
        //---------------------------------------------------------------------
        for (x = 8 * frames[ i].x - 1;    x < (frames[ i].x + frames[ i].dx) * 8;    x++)
        {
            // bptr[ y * 640 + x] = a1;
            bptr[ y * s640 + x] = a1;
        }
        //---------------------------------------------------------------------
        x = frames[i].x * 8 - 1;
        //---------------------------------------------------------------------
        for (y = 16 * frames[ i].y;    y < (frames[ i].y + frames[ i].dy) * 16;    y++)
        {
            // bptr[ y * 640 + x] = a1;
            bptr[ y * s640 + x] = a1;
        }
        //---------------------------------------------------------------------
        x = (frames[ i].x + frames[ i].dx) * 8;
        //---------------------------------------------------------------------
        for (y = 16 * frames[ i].y;    y < (frames[ i].y + frames[ i].dy) * 16;    y++)
        {
            //bptr[ y * 640 + x] = a1;
            bptr[ y * s640 + x] = a1;
        }
        //---------------------------------------------------------------------
    }
    */

    //-------------------------------------------------------------------------

//      //---------------------------------------------------------------------
//      //tzt
//      for (unsigned y = 0;    y < 50;    y++)         // wat_sz = 13 (Y размер знакомест в дебагере)
//      {
//              *(bptr + y + (y*s640)) = 0xFF;
//      }
//      //---------------------------------------------------------------------
       
       
       
       
       
       
       
       
       
       
       

       
       
       
       


       
       
       
       

//  gdibmp.header.bmiHeader.biBitCount = 8;
    gdi_dbg_bmp.header.bmiHeader.biBitCount = 8;

    //может нужно перенести выше до отррисовки?
    //-------------------------------------------------------------------------
    if (needclr)
        gdi_frame();
    //-------------------------------------------------------------------------
   
/*
   SetDIBitsToDevice(   temp.gdidc,             //ORIG
                        int(temp.gx),
                        int(temp.gy),
                        640,
                        480,
                       
                        0,
                        0,
                        0,
                        480,
                        bptr,
                        &gdibmp.header,
                        DIB_RGB_COLORS
                     );
*/

                //написано без доки !!!
                //нужно уточнение всех параметров
               
              //для дебагера отдельный

    gdi_dbg_bmp.header.bmiHeader.biSize = sizeof( BITMAPINFOHEADER);
    gdi_dbg_bmp.header.bmiHeader.biPlanes = 1;
    gdi_dbg_bmp.header.bmiHeader.biBitCount = 8;
   
    gdi_dbg_bmp.header.bmiHeader.biWidth = LONG( s640);         // [NS]
    gdi_dbg_bmp.header.bmiHeader.biHeight = -LONG( s480);
    gdi_dbg_bmp.header.bmiHeader.biBitCount = WORD( temp.obpp);
     
     
//      bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
//      bmi.bmiHeader.biPlanes = 1;
//      bmi.bmiHeader.biBitCount = 32;
//      bmi.bmiHeader.biCompression = BI_RGB;
//      bmi.bmiHeader.biWidth = 320;
//      bmi.bmiHeader.biHeight = 160;



// printf("temp.gx %d temp.gy %d\n",temp.gx,temp.gy);

    RECT current_mainwnd_size;
    GetClientRect( wnd, &current_mainwnd_size);
    int new_wnd_size_x = current_mainwnd_size.right - current_mainwnd_size.left;
    int new_wnd_size_y = current_mainwnd_size.bottom - current_mainwnd_size.top;

//  сделать на upscale COLORONCOLOR или HALFTONE
//  для downscale по выбору HALFTONE COLORONCOLOR WHITEONBLACK

  //SetStretchBltMode(temp.gdidc, BLACKONWHITE);        //так ниче не видно (и по дефолту)
  //SetStretchBltMode(temp.gdidc, WHITEONBLACK);        //так жирный белый шрифт
    SetStretchBltMode( temp.gdidc, COLORONCOLOR);       //так биения и наверно бысстрей всего
  //SetStretchBltMode(temp.gdidc, HALFTONE);            //так размывает но нагрузка на проц
  //SetStretchBltMode(temp.gdidc, 5);           //WHITEONBLACK
  //SetStretchBltMode(temp.gdidc, 0);           //WHITEONBLACK
 
 
   
    StretchDIBits(      temp.gdidc,                             //NS
                        0,      //int(temp.gx), //= 0   //куда вмещать
                        0,      //int(temp.gy), //= 0?
                        new_wnd_size_x, //temp.ox,//320,//640,
                        new_wnd_size_y, //temp.oy,//240,//480,
                               
                        0,      //какую часть кидить
                        0,
                        s640,   //640,
                        s480,   //480,
                        bptr,
                        &gdi_dbg_bmp.header,//&gdibmp.header,
                        DIB_RGB_COLORS,
                        SRCCOPY
                );

//  gdibmp.header.bmiHeader.biBitCount = u16(temp.obpp);
    gdi_dbg_bmp.header.bmiHeader.biBitCount = u16( temp.obpp);  // [NS]
}
//=============================================================================


//=============================================================================
void frame( unsigned x, unsigned y, unsigned dx, unsigned dy, unsigned char attr)
{
// DEPRECATED
    /*
    frames[ nfr].x =  u8( x);
    frames[ nfr].y =  u8( y);
    frames[ nfr].dx = u8( dx);
    frames[ nfr].dy = u8( dy);
    frames[ nfr].c = attr;
    nfr++;
    */

}
//=============================================================================


//=============================================================================
// Отрисовка строки с указанием атрибута
void tprint( unsigned x, unsigned y, const char *str, unsigned char attr)
{
    for (unsigned ptr = y * s80 + x;    *str;    str++, ptr++)
    {
        txtscr[ ptr] = u8( *str);
        txtscr[ ptr + s80 * s30] = attr;        //запись атрибута вместо
    }
}
//=============================================================================


//=============================================================================
// Отрисовка строки с указанием атрибута только ink-а (но можно влиять на paper !)
void tprint_fg( unsigned x, unsigned y, const char *str, unsigned char attr)
{
    for (unsigned ptr = y * s80 + x;    *str;    str++, ptr++)
    {
        txtscr[ ptr] = u8( *str);
        txtscr[ ptr + s80 * s30] = (txtscr[ ptr + s80 * s30] & 0xF0) + attr;
    }
}
//=============================================================================


// Новые цвета для дебагера [NS]

#define DBG_ATTR_BCKGRND                0x00    //0     0
#define DBG_ATTR_BCKGRND_ACTIVE         0x10    //blue

#define DBG_ATTR_WINDOW_FRAME           0x02    //

#define DBG_ATTR_INPUT_HIGHLIGHT        0xC0    //br+GREEN      0
#define DBG_ATTR_INPUT_CURSOR           0xE0    //br+YELLOW     9

#define DBG_ATTR_WINDOW_TITLE           0xF0//0x1F      //blue  br+WHITE

#define DBG_ATTR_WINDOW_BACK_COLOR      0x70//0x70//white       0
#define DBG_ATTR_WINDOW_TEXT            0x70
#define DBG_ATTR_WINDOW_TEXT_GRAY       0x7A            //почемуто юзаеттссо как error
#define DBG_ATTR_WINDOW_TEXT_ERROR      0x72            //white red
#define DBG_ATTR_WINDOW_TEXT_CURSOR     0xE0            //white red



//=============================================================================
// рисовалка текстовых окошек
void filledframe( unsigned x, unsigned y, unsigned dx, unsigned dy, unsigned char color)
{
    //-------------------------------------------------------------------------
    for (unsigned yy = y;    yy < (y + dy);    yy++)
    {
        for (unsigned xx = x;    xx < (x + dx);    xx++)
        {
            txtscr[ yy * s80 + xx] = ' ';
            txtscr[ yy * s80 + xx + s30 * s80] = color;
        }
    }
    //-------------------------------------------------------------------------
    nfr = 0; // delete other frames while dialog
    frame(      x,
                y,
                dx,
                dy,
                DBG_ATTR_WINDOW_FRAME   //FFRAME_FRAME
          );
}
//=============================================================================


//=============================================================================
void fillattr( unsigned x, unsigned y, unsigned dx, unsigned char color)
{
    for (unsigned xx = x;    xx < (x + dx);    xx++)
    {
        txtscr[ y * s80 + xx + s30 * s80] = color;
    }
}
//=============================================================================



//=============================================================================

char str[ 0x80];

//=============================================================================
unsigned inputhex( unsigned x, unsigned y, unsigned sz, bool hex, bool insert_mode)
{
// ВНЕЗАПНО ИСПОЛЬЗУЕТСО И ДЛЯ ТЕКСТА

//  insert_mode = TRUE; (by default) [NS]       для совместимости со старым вызовом без указания insert_mode
//                                              режим ввода заменой под курсором
    unsigned cr = 0;
    mousepos = 0;

    //-------------------------------------------------------------------------
    for (    ;    ;    )
    {
//      str[sz] = 0;
        str[ sz + 5] = 0;

        size_t i;
        //---------------------------------------------------------------------
        for (i = strlen( str);    i < sz;    i++)
        {
            //printf("*\n");
            str[ i] = ' ';
        }
        //---------------------------------------------------------------------
        for (i = 0;    i < sz;    i++)  //sz - количество символов для ввода
        {
            unsigned vl = (unsigned char) str[ i];
            tprint(     unsigned( x + i),
                        unsigned( y),
                        (char*) &vl,
                        (i == cr)   ?   DBG_ATTR_INPUT_CURSOR :         //W_INPUTCUR :
                                        DBG_ATTR_INPUT_HIGHLIGHT        //W_INPUTBG
                   );
        }
        //---------------------------------------------------------------------
        debugflip();
        //---------------------------------------------------------------------
        unsigned key;
        //---------------------------------------------------------------------
        // Ожидание нажатия клавиши infinity loop
        for (    ;    ;  Sleep( 20)  )
        {
            key = process_msgs();
            needclr = 0;  
            //-----------------------------------------------------------------
            //debugflip();      //зачем то без остановки перрерисовка
                                //wmpaint каким то хреном работает ии так
            //-----------------------------------------------------------------
            // выход из редактирования по клику в другое место
            if (mousepos)       //заменить на более осмысленное !!!!!
            {
                return 0;
            }
            //-----------------------------------------------------------------
            // выходи из цикла по нажатию клавиши
            if (key)
            {
                break;
            }
            //-----------------------------------------------------------------
        }

        debugflip();
        //---------------------------------------------------------------------
        switch (key)
        {
            //=================================================================
            case VK_ESCAPE:
                return 0;
            //=================================================================
            case VK_RETURN:
                //-------------------------------------------------------------
                for (char *ptr = str + sz - 1;    *ptr == ' ' && ptr >= str;    *ptr-- = 0);
                //-------------------------------------------------------------
                return 1;
            //=================================================================
            case VK_LEFT:
                //-------------------------------------------------------------
                if (cr)
                    cr--;
                //-------------------------------------------------------------
                continue;
            //=================================================================
            case VK_BACK:
                //-------------------------------------------------------------
                if (cr)
                {
                    //---------------------------------------------------------
                    for (i = cr;    i < sz;    i++)
                        str[ i - 1] = str[ i];
                    //---------------------------------------------------------
                    str[ sz - 1] = ' ';
                    --cr;
                }
                //-------------------------------------------------------------
                continue;
            //=================================================================
            case VK_RIGHT:
                //-------------------------------------------------------------
                if (cr != sz-1)
                    cr++;
                //-------------------------------------------------------------
                continue;
            //=================================================================
            case VK_HOME:
                cr = 0;
                continue;
            //=================================================================
            case VK_END:
                //-------------------------------------------------------------
                for (cr = sz - 1;    cr && (str[ cr] == ' ') && (str[ cr - 1] == ' ');    cr--);
                //-------------------------------------------------------------
                continue;       //?????????
            //=================================================================
            case VK_DELETE:
                //-------------------------------------------------------------
                for (i = cr;    i < sz - 1;    i++)
                    str[ i] = str[ i + 1];
                //-------------------------------------------------------------
                str[ sz - 1] = ' ';
                continue;
            //=================================================================
            case VK_INSERT:
                //-------------------------------------------------------------
                for (i = sz - 1;    i > cr;    i--)
                    str[ i] = str[ i - 1];
                //-------------------------------------------------------------
                str[ cr] = ' ';
                continue;
            //=================================================================
            case VK_UP:         // выход из редактирования
                //printf("VK_UP\n");
                PostThreadMessage( GetCurrentThreadId(), WM_KEYDOWN, VK_UP, 1);
                //PostThreadMessage(GetCurrentThreadId(), WM_KEYUP, input.lastkey, 1);
                return 0;       // тут еще надо шагание в эту же сторону
                break;          // но как его сделать?
            //=================================================================
            case VK_DOWN:       // так не работает вверх
                //printf("VK_DOWN\n");
                PostThreadMessage( GetCurrentThreadId(), WM_KEYDOWN, VK_DOWN, 1);
                return 0;
                break;
            //=================================================================
        }
        //---------------------------------------------------------------------
        u8 Kbd[ 256];
        GetKeyboardState( Kbd);
       
        unsigned short k = 0;
        //---------------------------------------------------------------------
        if ( ToAscii( key, 0, Kbd, &k, 0) == 1 )
        {
            char m;
            //-----------------------------------------------------------------
            if ( CharToOemBuff( (char *) &k, &m, 1) )
            {
                //-------------------------------------------------------------
                // нормальнный людской ввод
                if (!insert_mode)                       // [NS]
                {
                    for (i = sz - 1;    i > cr;    i--)
                        str[ i] = str[ i - 1];
                }
                //-------------------------------------------------------------
                int u = toupper(m);
                //-------------------------------------------------------------
                if (!hex || (((u >= '0') && (u <= '9')) || ((u >= 'A') && (u <= 'F'))))
                {
                    str[ cr++] = char( hex  ?  u :
                                               m );
                }
                //-------------------------------------------------------------
            }
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
        if (cr == sz)   //тут надо выход вообще
        {
            cr--;
                //return 1;     //так выход
                //              //НО так начинаютсо дополнительные прроблемы
                //              //особенно когда введенное невалидно
                //              // и тогда курсор перескакиивает в начало и...
        }
        //---------------------------------------------------------------------
    } //for (;;)
    //-------------------------------------------------------------------------
}
//=============================================================================



//=============================================================================
int input6dec( unsigned x, unsigned y, unsigned val)    // [NS]
{
    sprintf(    str,
                "%06d",
                val
            );
    //-------------------------------------------------------------------------
    if (inputhex( x, y, 6, false ))     // не ясно за 4-й параметр true/false !!!!
    {                                   // тк результат тот же
        sscanf(     str,
                    "%d",
                    &val
                );
        return int( val);
    }
    //-------------------------------------------------------------------------
    return -1;
}
//=============================================================================
int input4( unsigned x, unsigned y, unsigned val)
{
    sprintf(    str,
                "%04X",
                val
            );
    //-------------------------------------------------------------------------
    if (inputhex( x, y, 4, true ))
    {
        sscanf(     str,
                    "%x",
                    &val
                );
        return int( val);
    }
    //-------------------------------------------------------------------------
    return -1;
}
//=============================================================================
int input2( unsigned x, unsigned y, unsigned val)
{
    sprintf(    str,
                "%02X",
                val
            );
    //-------------------------------------------------------------------------
    if (inputhex( x, y, 2, true ))
    {
        sscanf(     str,
                    "%x",
                    &val
                );
        return int( val);
    }
    //-------------------------------------------------------------------------
    return -1;
}
//=============================================================================
int input1( unsigned x, unsigned y, unsigned val)
{
    sprintf(    str,
                "%01X",
                val
           );
    //-------------------------------------------------------------------------
    if (inputhex( x, y, 1, true ))
    {
        sscanf(     str,
                    "%x",
                    &val
              );
        return int( val);
    }
    //-------------------------------------------------------------------------
    return -1;
}
//=============================================================================




//=============================================================================
static void format_item( char *dst, size_t width, const char *text, MENUITEM::FLAGS flags)
{
    memset(     dst,
                ' ',
                width + 2);
    dst[ width + 2] = 0;
   
    size_t sz = strlen( text), left = 0;
    //-------------------------------------------------------------------------
    if (sz > width)
        sz = width;
    //-------------------------------------------------------------------------
    if (flags & MENUITEM::RIGHT)
        left = width - sz;
    //-------------------------------------------------------------------------
    else if (flags & MENUITEM::CENTER)
        left = (width - sz) / 2;
    //-------------------------------------------------------------------------
    memcpy(     dst + left + 1,
                text,
                sz
           );
}
//=============================================================================


//=============================================================================
// рисование некоторых менюшек
static void paint_items( MENUDEF *menu)
{

    char ln[ 80];
    unsigned item;

    size_t maxlen = strlen( menu->title);
    //-------------------------------------------------------------------------
    for (item = 0;    item < menu->n_items;    item++)
    {
        size_t sz = strlen( menu->items[ item].text);
        maxlen = max( maxlen, sz);
    }
    //-------------------------------------------------------------------------
    unsigned menu_dx = unsigned( maxlen + 2), menu_dy = menu->n_items + 3;
    //unsigned menu_x = (80 - menu_dx) / 2, menu_y = (30 - menu_dy) / 2;
    unsigned menu_x = (s80 - menu_dx) / 2, menu_y = (s30 - menu_dy) / 2;
    filledframe(        menu_x,
                        menu_y,
                        menu_dx,
                        menu_dy,
                        DBG_ATTR_WINDOW_TEXT    //MENU_INSIDE
                );
    format_item(        ln,
                        maxlen,
                        menu->title,
                        MENUITEM::CENTER
                );
    tprint(     menu_x,
                menu_y,
                ln,
                DBG_ATTR_WINDOW_TITLE           //MENU_HEADER
           );
    //-------------------------------------------------------------------------
    for (/*unsigned*/ item = 0;    item < menu->n_items;    item++)
    {
        unsigned char color = DBG_ATTR_WINDOW_TEXT;     //MENU_ITEM;
        //---------------------------------------------------------------------
        if (menu->items[ item].flags & MENUITEM::DISABLED)
            color = DBG_ATTR_WINDOW_TEXT_GRAY;          //MENU_ITEM_DIS;        //ERROR?
        //---------------------------------------------------------------------
        else if (item == menu->pos)
            color = DBG_ATTR_WINDOW_TEXT_CURSOR;        //MENU_CURSOR;
        //---------------------------------------------------------------------
        format_item(    ln,
                        maxlen,
                        menu->items[ item].text,
                        menu->items[ item].flags
                    );
        tprint(         menu_x,
                        menu_y + item + 2,
                        ln,
                        color
                );
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
static void menu_move( MENUDEF *menu, int dir)
{
    unsigned start = menu->pos;
    //-------------------------------------------------------------------------
    for (    ;    ;    )
    {
        menu->pos = unsigned( int( menu->pos) + dir);
        //---------------------------------------------------------------------
        if ((int) menu->pos == -1) menu->pos = menu->n_items-1;
        //---------------------------------------------------------------------
        if (menu->pos >= menu->n_items) menu->pos = 0;
        //---------------------------------------------------------------------
        if (!(menu->items[ menu->pos].flags & MENUITEM::DISABLED)) return;
        //---------------------------------------------------------------------
        if (menu->pos == start) return;
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
char handle_menu( MENUDEF *menu)
{
    //-------------------------------------------------------------------------
    if (menu->items[ menu->pos].flags & MENUITEM::DISABLED)
        menu_move( menu, 1 );
    //-------------------------------------------------------------------------
    for (    ;    ;    )
    {
        paint_items( menu);
        debugflip();

        unsigned key;
        //---------------------------------------------------------------------
        for (    ;    ;    Sleep( 20))  //20
        {
            key = process_msgs();
            needclr =  0;
            debugflip();
            //-----------------------------------------------------------------
            if (mousepos)
                return 0;
            //-----------------------------------------------------------------
            if (key)
                break;
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
        if (key == VK_ESCAPE)
            return 0;
        //---------------------------------------------------------------------
        if (key == VK_RETURN || key == VK_SPACE)
            return 1;
        //---------------------------------------------------------------------
        if (key == VK_UP || key == VK_LEFT)
            menu_move( menu, -1);
        //---------------------------------------------------------------------
        if (key == VK_DOWN || key == VK_RIGHT)
            menu_move( menu, 1);
        //---------------------------------------------------------------------
        if (key == VK_HOME || key == VK_PRIOR)
        {
            menu->pos = -1U;
            menu_move( menu, 1);
        }
        //---------------------------------------------------------------------
        if (key == VK_END || key == VK_NEXT)
        {
            menu->pos = menu->n_items;
            menu_move( menu, -1);
        }
        //---------------------------------------------------------------------
    }
}
//=============================================================================