#help_index "DolDoc"

I64 DocWordWrapDel(CDoc *doc, CDocEntry *doc_e, Bool full_refresh, Bool same_win, I64 left_margin, I64 right_margin, 
                   CDocEntry **_best_doc_e, I64 *_best_col)
{
    CDocEntry   *doc_e2;
    U8          *ptr;
    I64          j, k;

    if (doc_e->de_flags & DOCEF_TAG && doc_e->tag)
        k = StrLen(doc_e->tag);
    else
        k = 0;
    if (full_refresh)
        while (TRUE)
        {
            doc_e2 = doc_e->next;
            if (doc_e2->type_u8 == DOCT_SOFT_NEW_LINE && !same_win)
            {
                if (doc->cur_entry == doc_e2)
                {
                    doc->cur_entry  = doc_e2->next;
                    doc->cur_col    = doc->cur_entry->min_col;
                }
                if (*_best_doc_e == doc_e2)
                {
                    *_best_doc_e = doc_e2->next;
                    *_best_col = 0;
                }
                DocEntryDel(doc, doc_e2);
            }
            else if (IsEditableText(doc_e) && doc_e->de_flags == doc_e2->de_flags && doc_e->type == doc_e2->type)
            {
                j = StrLen(doc_e2->tag);
                ptr =  MAlloc(k + j + 1, doc->mem_task);
                MemCopy(ptr, doc_e->tag, k);
                MemCopy(ptr + k, doc_e2->tag, j + 1);
                Free(doc_e->tag);
                doc_e->tag = ptr;
                if (doc->cur_entry == doc_e2)
                {
                    doc->cur_entry  =  doc_e;
                    doc->cur_col    += k;
                }
                if (*_best_doc_e == doc_e2)
                {
                    *_best_doc_e = doc_e;
                    *_best_col = 0;
                }
                DocEntryDel(doc, doc_e2);
                k += j;
                if (k > (right_margin - left_margin + 1) << 1)
                    break;
            }
            else
                break;
        }
    if (doc_e->de_flags & DOCEF_SCROLLING_X)
        k = doc_e->scroll_len;

    return k;
}

U0 DocRecalcXY(CDoc *doc, CDocEntry *doc_e, I64 k, I64 left, I64 width, I64 height, I64 left_margin, I64 right_margin, 
               I64 x0, I64 y0, I64 *_x, I64 *_y)
{
    I64 i, x = *_x, y = *_y;

    if (doc_e->de_flags & DOCEF_MARGIN_REL_X)
    {
        if (doc_e->de_flags & DOCEF_LEFT_X)
            x = left_margin - left;
        else if (doc_e->de_flags & DOCEF_RIGHT_X)
            x = right_margin - (k - 1) - left;
        else if (doc_e->de_flags & DOCEF_CENTER_X)
            x = (right_margin + left_margin) >> 1 - k >> 1 - left;
    }
    else
    {
        if (doc_e->de_flags & DOCEF_LEFT_X)
            x = x0;
        else if (doc_e->de_flags & DOCEF_RIGHT_X)
            x = width + x0 - k;
        else if (doc_e->de_flags & DOCEF_CENTER_X)
            x = (width + x0 - k) >> 1;
    }
    i = y;
    if (doc_e->de_flags & DOCEF_PAGE_REL_Y)
    {
        doc->flags |= DOCF_BWD_MOVEMENT;
        if (doc_e->de_flags & DOCEF_TOP_Y)
            y -= doc_e->page_line_num;
        else if (doc_e->de_flags & DOCEF_BOTTOM_Y)
            y += doc_e->settings.page_len - doc_e->page_line_num;
        else if (doc_e->de_flags & DOCEF_CENTER_Y)
            y += doc_e->settings.page_len >> 1 - doc_e->page_line_num;
    }
    else
    {
        doc->flags |= DOCF_BWD_MOVEMENT;
        if (doc_e->de_flags & DOCEF_TOP_Y)
            y = y0;
        else if (doc_e->de_flags & DOCEF_BOTTOM_Y)
            y = height - 1 + y0;
        else if (doc_e->de_flags & DOCEF_CENTER_Y)
            y = height >> 1 + y0;
    }
    if (y != i)
    {
        doc->page_line_num += y - i;
        if (doc->page_line_num < 0)
            doc->page_line_num = doc_e->settings.page_len + doc->page_line_num % doc_e->settings.page_len;
        else
            doc->page_line_num = doc->page_line_num % doc_e->settings.page_len;
        if (doc_e->settings.header != DOC_DEFAULT && doc->page_line_num < doc_e->settings.header)
        {
            y += doc_e->settings.header - doc->page_line_num;
            doc->page_line_num = doc_e->settings.header;
        }
        if (doc_e->settings.footer == DOC_DEFAULT)
        {
            if (doc->page_line_num >= doc_e->settings.page_len)
            {
                if (doc_e->settings.header == DOC_DEFAULT)
                    doc->page_line_num = 0;
                else
                {
                    doc->page_line_num = doc_e->settings.header;
                    y += doc_e->settings.header;
                }
            }
        }
        else
        {
            if (doc->page_line_num >= doc_e->settings.page_len - doc_e->settings.footer)
            {
                y += doc_e->settings.footer;
                if (doc_e->settings.header == DOC_DEFAULT)
                    doc->page_line_num = 0;
                else
                {
                    doc->page_line_num = doc_e->settings.header;
                    y += doc_e->settings.header;
                }
            }
        }
    }
    *_x = x;
    *_y = y;
}

CDocEntry *DocSplitTag(CDoc *doc, CDocEntry *doc_e, I64 i, I64 x, I64 y, I64 type_u8)
{//Split tag at i, insert DOCT_SOFT_NEW_LINE, DOCT_MARKER or DOCT_CURSOR
    U8          *ptr;
    CDocEntry   *doc_e2;

    if (doc_e->type_u8 == DOCT_TEXT && i)
    {
        if (i < StrLen(doc_e->tag))
        {
            doc_e2 = MAllocIdent(doc_e, doc->mem_task);
            doc_e2->tag      = StrNew(doc_e->tag + i, doc->mem_task);
            doc_e2->de_flags = doc_e->de_flags & ~DOCEG_HAS_ALLOC | DOCEF_TAG;
            QueueInsert(doc_e2, doc_e);
            if (doc->cur_entry == doc_e && doc->cur_col>=i)
            {
                doc->cur_entry  = doc_e2;
                doc->cur_col    = doc->cur_col - i;
            }
            doc_e->tag[i] = 0;
            ptr = StrNew(doc_e->tag, doc->mem_task);
            Free(doc_e->tag);
            doc_e->tag = ptr;
        }
    }
    else
        doc_e = doc_e->last;
    doc_e2 = DocEntryNewBase(doc, type_u8 | doc_e->type & 0xFFFFFF00, doc_e->de_flags & ~DOCEG_HAS_ARG,
                             x, y, doc_e->page_line_num);
    MemCopy(&doc_e2->settings, &doc_e->settings, sizeof(CDocSettings));
    QueueInsert(doc_e2, doc_e);

    return doc_e2;
}

CDocEntry *DocWordWrapAdd(CDoc *doc, CDocEntry *doc_e, I64 *_k, I64 left, I64 right_margin, I64 x, I64 y)
{
    CDocEntry   *doc_e2;
    I64          j,
                 i = right_margin + 1 - (x + left), //Space left on line
                 ii = x + 1 - doc_e->settings.left_margin;

    if (IsEditableText(doc_e))
    {
        if (doc->cur_entry == doc_e->next)
        {
            if (doc->cur_col == doc_e->next->min_col)
                i--;
        }
        else
        {
            if (doc->cur_entry == doc_e && doc->cur_col == i)
                i--;
        }
        if (*_k > i)
        {
            for (j = i; j > 8 - ii && j >= 0; j--)
                if (doc_e->tag[j] == CH_SPACE)
                {
                    i = j + 1;
                    break;
                }
            if (0 < i < *_k)
            {
                DocSplitTag(doc, doc_e, i, x, y, DOCT_SOFT_NEW_LINE);
                *_k = StrLen(doc_e->tag);
                return NULL;
            }
        }
        if (*_k == i)
            return NULL;
    }
    if (*_k >= i)
    {
        doc_e2 = doc_e->last;
        if (doc_e2->type_u8 != DOCT_SOFT_NEW_LINE &&
            doc_e2->type_u8 != DOCT_NEW_LINE &&
            doc_e2->type_u8 != DOCT_CURSOR_MOVEMENT)
        {
            doc_e2 = DocEntryNewBase(doc, DOCT_SOFT_NEW_LINE | doc_e->type & 0xFFFFFF00, 
                       DOCEF_WORD_WRAP | doc_e->de_flags & (DOCEF_HIGHLIGHT | DOCG_BL_IV_UL | DOCEF_SKIP | DOCEF_FILTER_SKIP),
                       x, y, doc_e->last->page_line_num);
            MemCopy(&doc_e2->settings, &doc_e->settings, sizeof(CDocSettings));
            QueueInsert(doc_e2, doc_e->last);
            return doc_e2;
        }
    }

    return NULL;
}

I64 DocTmpAttr(CDoc *doc, CDocEntry *doc_e, I64 cur_u8_attr)
{
    I64 tmp_u32_attr;

    doc_e->de_flags = doc->flags & (DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT) |
                      doc_e->de_flags & ~(DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT);

    tmp_u32_attr =  (cur_u8_attr & 0xF0) << 8 |
                    doc->flags & DOCG_BL_IV_UL |
                    (doc_e->settings.shifted_x & 0x1F) << 16 |
                    (doc_e->settings.shifted_y & 0x1F) << 21;

    if (doc_e->de_flags & DOCEF_HAS_BIN && *doc_e->tag == '<')
        tmp_u32_attr.u8[1] |= DOC_COLOR_BIN;
    else
        switch (doc_e->type_u8)
        {
            case DOCT_SPRITE:
                if (doc_e->de_flags & DOCEF_LEFT_EXP)
                    tmp_u32_attr.u8[1] |= cur_u8_attr & 15;
                else if (doc_e->de_flags & DOCEF_LINK)
                    tmp_u32_attr.u8[1] |= DOC_COLOR_LINK;
                else if (doc_e->de_flags & DOCEF_LEFT_MACRO)
                    tmp_u32_attr.u8[1] |= DOC_COLOR_MACRO;
                else if (doc_e->de_flags & (DOCEF_TREE | DOCEF_LIST))
                    tmp_u32_attr.u8[1] |= DOC_COLOR_TREE;
                else
                    tmp_u32_attr.u8[1] |= DOC_COLOR_BIN;
                break;

            case DOCT_HTML_CODE:
                tmp_u32_attr.u8[1] |= DOC_COLOR_BIN;
                break;

            case DOCT_LINK:
                tmp_u32_attr.u8[1] |= DOC_COLOR_LINK;
                break;

            case DOCT_MACRO:
                tmp_u32_attr.u8[1] |= DOC_COLOR_MACRO;
                break;

            case DOCT_ANCHOR:
                tmp_u32_attr.u8[1] |= DOC_COLOR_ANCHOR;
                break;

            case DOCT_TREE:
            case DOCT_LIST:
                tmp_u32_attr.u8[1] |= DOC_COLOR_TREE;
                break;

            default:
                tmp_u32_attr.u8[1] |= cur_u8_attr & 15;
        }
    doc_e->type.u8[1] = tmp_u32_attr.u8[1];
    tmp_u32_attr |= doc_e->type & 0xFFFF0000;
    if (doc_e == doc->cur_entry && !(doc->flags & DOCF_DONT_HIGHLIGHT_CURSOR) && doc_e->type_u8 != DOCT_TEXT)
        tmp_u32_attr ^= 0xFF00;
    doc_e->settings.final_u32_attr = tmp_u32_attr;

    return tmp_u32_attr;
}

public Bool DocRecalc(CDoc *doc, I64 recalc_flags=RECALCt_NORMAL)
{//Recalc and format.  Also used by WinMgr to draw on screen.
    I64              i, ii, j, k, x, x0, y, y0, D, d2, col, col2, best_col = 0, best_d = I64_MAX, xx, yy, zz, 
                     num_entries = 0, i_jif, cur_u8_attr, tmp_u32_attr, 
                     cursor_y = I64_MIN, left_margin, right_margin, y_plot_top, y_plot_bottom, 
                     top, left, bottom, right, width, height, scroll_x, scroll_y, pix_top, pix_left;
    CDocEntry   reg *doc_e, reg *doc_e2, *best_doc_e, *next_clear_found = NULL, *added_cursor = NULL;
    CDocBin         *tmpb;
    CDocSettings    *s;
    Bool             del_doc_e, skipped_update, tree_collapsed, same_win, more = FALSE, 
                     find_cursor = FALSE, blink_flag, full_refresh = TRUE, unlock, clear_holds;
    CTask           *win_task, *mem_task;
    CDC             *dc;
    U8              *bptr, *ptr, buf[STR_LEN], ch;
    U32             *u32_ptr, *hl;
    I32             *depth_buf = NULL;
    F64              cur_time = tS;
    CWinScroll      *vss, *hss;
    CHashDefineStr  *tmph;

    if (!doc || doc->doc_signature != DOC_SIGNATURE_VAL)
        return FALSE;

        //WinMgr updates all wins (60000.0 / 1001), 33.33333mS
    if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && doc->owning_task != Fs)
    {
        i_jif = counts.jiffies + JIFFY_FREQ / 250; //4 mouse
        while (Bt(&doc->locked_flags, DOClf_LOCKED))
        {
            if (counts.jiffies >= i_jif)
                return FALSE; //Bail-out if doc locked.
            Yield;
        }
    }

    unlock = DocLock(doc);
    if (doc->doc_signature != DOC_SIGNATURE_VAL)
    {
        DocUnlock(doc);
        return FALSE;
    }

    win_task = doc->win_task;
    mem_task = doc->mem_task;
    blink_flag = Blink;
    dc = NULL;
    switch [recalc_flags & RECALCG_MASK]
    {
        case RECALCt_FIND_CURSOR:
            find_cursor = TRUE;
            if (win_task)
                dc = DCAlias(gr.dc2, win_task); //Necessary for sprites
            break;

        case RECALCt_TO_SCREEN:
            if (doc->updates_count++ % (ToI64(winmgr.fps / 10) + 1) &&
                    !Bt(&doc->flags, DOCf_DO_FULL_REFRESH) &&
                    !(doc->flags & DOCF_BWD_MOVEMENT))
                full_refresh = FALSE;
            if (win_task)
                dc = DCAlias(gr.dc2, win_task);
            break;
    }

    PUSHFD
    CLI
    left            = win_task->win_left;
    right           = win_task->win_right;
    width           = win_task->win_width;
    scroll_x        = win_task->scroll_x;
    scroll_y        = win_task->scroll_y;
    top             = win_task->win_top;
    bottom          = win_task->win_bottom;
    height          = win_task->win_height;
    pix_left        = win_task->pix_left;
    pix_top         = win_task->pix_top;
    left_margin     = left;
    right_margin    = right;
    POPFD
    if (doc->flags & DOCF_BORDER_DOC)
    {
        scroll_x = 0;
        scroll_y = 0;
    }
    best_doc_e = doc->cur_entry;

    if (!(doc->flags & (DOCF_PLAIN_TEXT | DOCF_PLAIN_TEXT_TABS)) && FilesFindMatch(doc->filename.name, FILEMASK_SRC))
        doc->flags |= DOCF_HIGHLIGHT;
    else
        doc->flags &= ~DOCF_HIGHLIGHT;

    x = y = 0;
    doc->page_line_num = 0;
    if (full_refresh && !find_cursor)
    {
        doc->x = x;
        doc->y = y;
    }

    hss = &win_task->horz_scroll;
    vss = &win_task->vert_scroll;
    if (doc->flags & DOCF_BORDER_DOC)
    {
        doc->top_line_num   = 0;
        doc->line_start_col = 0;
        recalc_flags &= ~RECALCF_HAS_CURSOR;
        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN)
            doc->settings_head.cur_text_attr = doc->settings_head.default_text_attr = win_task->border_attr;
    }
    else
    {
        if (recalc_flags & RECALCF_HAS_CURSOR && full_refresh)
        {
            if (Bt(&hss->flags, WSSf_SET_TO_POS) || Bt(&vss->flags, WSSf_SET_TO_POS))
            {
                if (!(doc->flags & DOCF_NO_SCROLL_BARS))
                {
                    if (Bt(&hss->flags, WSSf_SET_TO_POS))
                    {
                        doc->line_start_col = hss->pos;
                        LBtr(&hss->flags, WSSf_SET_TO_POS);
                    }
                    if (Bt(&vss->flags, WSSf_SET_TO_POS))
                    {
                        doc->top_line_num = vss->pos;
                        LBtr(&vss->flags, WSSf_SET_TO_POS);
                    }
                }
                doc->x = doc->line_start_col + width  / 2;
                doc->y = doc->top_line_num   + height / 2;
                find_cursor = TRUE;
            }
        }
        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN)
            doc->settings_head.cur_text_attr = doc->settings_head.default_text_attr = win_task->text_attr;
    }
    x0 = doc->line_start_col;
    y0 = doc->top_line_num;
    same_win =  top             == doc->old_win_top     &&
                bottom          == doc->old_win_bottom  &&
                left            == doc->old_win_left    &&
                right           == doc->old_win_right   &&
                doc->cur_entry  == doc->old_cur_entry   &&
                doc->cur_col    == doc->old_cur_col;

    if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN)
    {
        y_plot_top = y0 - scroll_y / FONT_HEIGHT;
        y_plot_bottom = y0 + height - 1 - scroll_y / FONT_HEIGHT;
        if (!(doc->flags & DOCF_BORDER_DOC) && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
            DocBorderListDraw(doc);
    }

    if (doc->cur_col <= doc->cur_entry->min_col)
        doc->cur_col = doc->cur_entry->min_col;
    doc_e = doc->head.next;
    doc_e->de_flags &= ~(DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT);
    if (doc_e == doc->head.next)
        s = &doc->settings_head;
    else
        s = &doc_e->last->settings;
    doc->flags = doc_e->de_flags & (DOCG_BL_IV_UL | DOCEF_WORD_WRAP) | doc->flags & ~(DOCG_BL_IV_UL | DOCEF_WORD_WRAP);
    cur_u8_attr = s->cur_text_attr;
    if (doc_e == doc->head.next)
    {
        doc->flags &= ~DOCF_BWD_MOVEMENT;
        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && full_refresh)
            doc->flags &= ~DOCF_HAS_SONG;
    }
    else
        doc->flags = doc_e->de_flags & DOCEF_HIGHLIGHT | doc->flags & ~DOCEF_HIGHLIGHT;

    if (doc->head.next == doc)
    {
        best_doc_e = doc;
        best_col = 0;
        doc->cur_entry  = doc;
        doc->cur_col    = 0;
        doc_e = doc;
    }
    skipped_update = doc_e == doc && doc->head.next != doc;

    if (full_refresh)
    {
        doc->min_x = I32_MAX;
        doc->min_y = I32_MAX;
        doc->max_x = I32_MIN;
        doc->max_y = I32_MIN;
    }
    while (doc_e != doc)
    {
        while (TRUE)
        {
            del_doc_e = FALSE;
            if (doc_e->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP))
            {
                doc_e2 = doc_e;
                goto rc_skip;
            }
            MemCopy(&doc_e->settings, s, sizeof(CDocSettings));
            s = &doc_e->settings;
            if (doc_e->de_flags & (DOCEF_TAG_CB | DOCEF_DEFINE) && !(doc_e->de_flags & DOCEF_LIST))
            {
                Free(doc_e->tag);
                if (doc_e->de_flags & DOCEF_TAG_CB)
                {
                    if (doc_e->tag_cb)
                        doc_e->tag = (*doc_e->tag_cb)(doc, doc_e, mem_task);
                    else
                        doc_e->tag = StrNew("", mem_task);
                }
                else
                {
                    if (tmph = HashFind(doc_e->define_str, win_task->hash_table, HTT_DEFINE_STR))
                        doc_e->tag = StrNew(tmph->data, mem_task);
                    else
                        doc_e->tag = CAlloc(1, mem_task);
                }
                doc_e->max_col = StrLen(doc_e->tag);
                if (doc->cur_entry == doc_e && doc->cur_col >= doc_e->max_col)
                {
                    if (doc_e->max_col)
                        doc->cur_col = doc_e->max_col - 1;
                    else
                        doc->cur_col = 0;
                }
            }
            k = DocWordWrapDel(doc, doc_e, full_refresh, same_win, left_margin, right_margin, &best_doc_e, &best_col);
            if (doc_e->de_flags &
                    (DOCEF_LEFT_X | DOCEF_RIGHT_X | DOCEF_CENTER_X | DOCEF_TOP_Y | DOCEF_BOTTOM_Y | DOCEF_CENTER_Y))
                DocRecalcXY(doc, doc_e, k, left, width, height, left_margin, right_margin, x0, y0, &x, &y);
            if (full_refresh && k > 0 && doc->flags & DOCF_WORD_WRAP &&
                    (doc_e2 = DocWordWrapAdd(doc, doc_e, &k, left, right_margin, x, y)))
                doc_e = doc_e2;
            else
                break;
        }

        if (full_refresh)
        {
            doc_e->x             = x;
            doc_e->y             = y;
            doc_e->page_line_num = doc->page_line_num;
            if (x < doc->min_x)
                doc->min_x = x;
            if (y < doc->min_y)
                doc->min_y = y;
            if (find_cursor)
            {
                D = DocCharDist(doc, x, y);
                col = 0;
            }
        }
        col2 = 0;

        tmp_u32_attr = DocTmpAttr(doc, doc_e, cur_u8_attr);
        if (doc_e == doc->cur_entry)
        {
            cursor_y = doc_e->y;
            if (recalc_flags & RECALCF_ADD_CURSOR && !added_cursor)
            {
                if (doc_e->type_u8 == DOCT_TEXT && 0 < doc->cur_col < k &&
                    !(doc_e->de_flags &
                        ~(DOCEF_TAG|DOCG_BL_IV_UL|DOCEF_WORD_WRAP|DOCEF_HIGHLIGHT|DOCEF_SKIP|DOCEF_FILTER_SKIP)) &&
                    !(doc_e->type & DOCG_BL_IV_UL))
                {
                    added_cursor = DocSplitTag(doc, doc_e, doc->cur_col, x, y, DOCT_CURSOR);
                    k = StrLen(doc_e->tag);
                }
                else
                {
                    added_cursor = doc_e2 = DocEntryNewBase(doc, DOCT_CURSOR | doc_e->type & 0xFFFFFF00, 
                                                                 doc_e->de_flags & ~DOCEG_HAS_ARG, x, y, doc->page_line_num);
                    MemCopy(&doc_e2->settings, &doc_e->settings, sizeof(CDocSettings));
                    if (doc_e->type_u8 == DOCT_TEXT && doc->cur_col >= k)
                        QueueInsert(doc_e2, doc_e);
                    else
                        QueueInsertRev(doc_e2, doc_e);
                }
            }
        }

        if (doc_e->de_flags & DOCEF_REFRESH_DATA &&
            (doc_e->type_u8 == DOCT_DATA || doc_e->type_u8 == DOCT_CHECK_BOX || doc_e->de_flags & DOCEF_LIST))
        {
            DocDataFormat(doc, doc_e);
            k = StrLen(doc_e->tag);
        }
        if (doc_e->de_flags & DOCEF_TAG)
        {
            ptr = doc_e->tag;
            if (doc_e->de_flags & DOCEF_TREE)
            {
                if (k >= 2)
                {
                    if (doc_e->de_flags & DOCEF_CHECKED_COLLAPSED)
                        *ptr++ = '+';
                    else
                        *ptr++ = '-';
                    *ptr++ = ']';
                    ptr = doc_e->tag;
                }
            }
            else if (doc_e->de_flags & DOCEF_HAS_BIN)
            {
                if (*ptr == '<' && full_refresh && '0' <= ptr[1] <= '9')
                {
                    ptr = MStrPrint("<%d>", doc_e->bin_num);
                    Free(doc_e->tag);
                    doc_e->tag = StrNew(ptr, mem_task);
                    Free(ptr);
                    ptr = doc_e->tag;
                    k = StrLen(ptr);
                }
            }
            else if (doc_e->type_u8 == DOCT_CHECK_BOX)
            {
                if (k >= 3)
                {
                    *ptr++ = '[';
                    if (doc_e->de_flags & DOCEF_CHECKED_COLLAPSED)
                        *ptr++ = 'X';
                    else
                        *ptr++ = CH_SPACE;
                    *ptr++ = ']';
                    ptr = doc_e->tag;
                }
            }
            if (doc_e->de_flags & DOCEF_SCROLLING_X)
            {
                j = StrLen(doc_e->tag);
                if (j && doc_e->scroll_len)
                {
                    i_jif = ToI64(cur_time * FONT_WIDTH * DOC_SCROLL_SPEED) % (j * FONT_WIDTH);
                    tmp_u32_attr = tmp_u32_attr & 0xFFE0FF00 | (FONT_WIDTH - 1 - i_jif & (FONT_WIDTH - 1)) << 16;
#assert FONT_WIDTH == 8
                    i_jif >>= 3;
                    for (k = 0; k < doc_e->scroll_len; k++)
                    {
                        ch = ptr[(i_jif + k) % j];
                        if (!Bt(char_bmp_displayable, ch))
                            ch = '.';
                        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                        {
                            if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                                TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + ch);
                            else
                                TextChar(win_task, FALSE, x - x0, y - y0, tmp_u32_attr + ch);
                        }
                        x++;
                    }
                }
                if (find_cursor)
                {
                    D = DocCharDist(doc, doc_e->x, doc_e->y);
                    col = doc_e->min_col;
                }
                col2 = doc_e->scroll_len; //TODO This is flawed
            }
            else
            {
                if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                {
                    while (ch = *ptr++)
                    {
                        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                            TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + ch);
                        else
                            if (find_cursor)
                            {
                                d2 = DocCharDist(doc, x, y);
                                if (d2 < D)
                                {
                                    D = d2;
                                    col = col2;
                                }
                            }
                        col2++;
                        x++;
                    }
                }
                else
                {
                    if (doc_e->type_u8 == DOCT_TEXT && doc_e->de_flags & DOCEF_HIGHLIGHT)
                        hl = DocHighlight(doc_e, ptr, k, tmp_u32_attr);
                    else
                        hl = NULL;
                    if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                    {
//Technically we should do this for scrolling_x, too.
                        if (y > y_plot_bottom)
                            more = TRUE;
                        else if (y >= y_plot_top)
                        {
                            if (hl)
                                TextLenAttrStr(win_task, x - x0, y - y0, k, hl);
                            else
                                TextLenStr(win_task, x - x0, y - y0, k, tmp_u32_attr, ptr);
                        }
                        col2 += k;
                        x += k;
                    }
                    else
                    {
                        if (find_cursor)
                        {
                            while (k--)
                            {
                                d2 = DocCharDist(doc, x, y);
                                if (d2 < D)
                                {
                                    D = d2;
                                    col = col2;
                                }
                                col2++;
                                x++;
                            }
                        }
                        else
                        {
                            col2 += k;
                            x += k;
                        }
                    }
                    Free(hl);
                }
            }
        }
        switch [doc_e->type_u8]
        {
            case DOCT_TEXT:
                if (!col2 &&
                        !(doc_e->de_flags &
                        (DOCEF_TREE | DOCEF_LIST | DOCEF_TAG_CB |
                         DOCEF_DEFINE | DOCEF_AUX_STR | DOCEF_HTML_LINK | DOCEF_BIN_PTR_LINK)))
                    del_doc_e = TRUE;
                break;

            case DOCT_HEX_ED:
                if (doc_e->de_flags & DOCEF_DEREF_DATA && !(doc_e->de_flags & DOCEF_REMALLOC_DATA))
                    bptr = doc_e->data;
                else
                    bptr = &doc_e->data;
                k = doc_e->hex_ed_width; //columns
                for (i = 0; i < doc_e->len; i += k)
                {
                    if (doc_e->de_flags & DOCEF_ZERO_BASED)
                        StrPrint(buf, "%08tX ", i);
                    else
                        StrPrint(buf, "%08tX ", bptr);
                    ptr = buf;
                    while (ch = *ptr++)
                    {
                        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                        {
                            if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                                TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + ch);
                            else
                                TextChar(win_task, FALSE, x - x0, y - y0, tmp_u32_attr + ch);
                        }
                        if (find_cursor)
                        {
                            d2 = DocCharDist(doc, x, y);
                            if (d2 < D)
                            {
                                D = d2;
                                col = i * 3;
                            }
                        }
                        x++;
                    }
                    if (i + k > doc_e->len)
                        k = doc_e->len - i;
                    for (j = 0; j < k; j++)
                    {
                        StrPrint(buf, "%02tX", *bptr++);
                        ptr = buf;
                        while (ch = *ptr++)
                        {
                            if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                            {
                                if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                                    TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + ch);
                                else
                                    TextChar(win_task, FALSE, x - x0, y - y0, tmp_u32_attr + ch);
                            }
                            if (find_cursor)
                            {
                                d2 = DocCharDist(doc, x, y);
                                if (d2 < D)
                                {
                                    D = d2;
                                    col = col2;
                                }
                            }
                            col2++;
                            x++;
                        }
                        x++;
                    }
                    bptr -= j;
                    x += (doc_e->hex_ed_width - k) * 3;
                    for (j = 0; j < k; j++)
                    {
                        ch = *bptr++;
                        if (!Bt(char_bmp_displayable, ch))
                            ch = '.';
                        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                        {
                            if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                                TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + ch);
                            else
                                TextChar(win_task, FALSE, x - x0, y - y0, tmp_u32_attr + ch);
                        }
                        if (find_cursor)
                        {
                            d2 = DocCharDist(doc, x, y);
                            if (d2 < D)
                            {
                                D = d2;
                                col = col2;
                            }
                        }
                        col2++;
                        x++;
                    }
                    y++;
                    x -= doc_e->hex_ed_width * 3 + k + 9;
                }
                break;

            case DOCT_NEW_LINE:
            case DOCT_SOFT_NEW_LINE:
                if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW)&&
                        y_plot_top <= y <= y_plot_bottom)
                    TextLenAttr(win_task, x - x0, y - y0, width - (x - x0), cur_u8_attr << 8);
                if (doc_e->de_flags & DOCEF_HIGHLIGHT && s->state == DOCSS_CPP_Z_COMMENT)
                    s->state = DOCSS_NORMAL;
                y++;
                doc->page_line_num++;
rc_start_of_line:
                if (s->left_margin == DOC_DEFAULT)
                    x = s->indent;
                else
                    x = s->indent + s->left_margin;
rc_adjust_xy:
                i = s->indent + s->left_margin;
                if (x < i)
                    x = i;
                if (doc->page_line_num < 0)
                    doc->page_line_num = s->page_len + doc->page_line_num % s->page_len;
                else
                {
                    if (doc->page_line_num >= s->page_len)
                    {
                        doc->page_line_num -= s->page_len;
                        if (doc->page_line_num >= s->page_len) //avoid extra divide
                            doc->page_line_num = doc->page_line_num % s->page_len;
                    }
                }
                if (s->header != DOC_DEFAULT)
                {
                    if (doc->page_line_num < s->header)
                    {
                        y += s->header - doc->page_line_num;
                        doc->page_line_num = s->header;
                        goto rc_start_of_line;
                    }
                }
                if (s->footer == DOC_DEFAULT)
                {
                    if (doc->page_line_num >= s->page_len)
                    {
                        if (s->header == DOC_DEFAULT)
                            doc->page_line_num = 0;
                        else
                        {
                            doc->page_line_num = s->header;
                            y += s->header;
                        }
                        goto rc_start_of_line;
                    }
                }
                else
                {
                    if (doc->page_line_num >= s->page_len - s->footer)
                    {
                        y += s->footer;
                        if (s->header == DOC_DEFAULT)
                            doc->page_line_num = 0;
                        else
                        {
                            doc->page_line_num = s->header;
                            y += s->header;
                        }
                        goto rc_start_of_line;
                    }
                }
                break;

            case DOCT_TAB:
                k = (x + 4) & ~3;
                if (doc_e->de_flags & DOCEF_BORDER_PLOT && !Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
                {
                    while (x < k)
                    {
                        if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                            TextChar(win_task, TRUE, x - x0, y - y0, tmp_u32_attr + CH_SPACE);
                        if (find_cursor)
                        {
                            d2 = DocCharDist(doc, x, y);
                            if (d2 < D)
                                D = d2;
                        }
                        x++;
                    }
                }
                else
                {
                    k -= x;
                    if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && !(doc_e->de_flags & DOCEF_DONT_DRAW))
                    {
                        if (y_plot_top <= y <= y_plot_bottom)
                            TextLenStr(win_task, x - x0, y - y0, k, tmp_u32_attr, "    ");
                        x += k;
                    }
                    else
                    {
                        if (find_cursor)
                        {
                            while (k--)
                            {
                                d2 = DocCharDist(doc, x, y);
                                if (d2 < D)
                                    D = d2;
                                x++;
                            }
                        }
                        else
                            x += k;
                    }
                }
                break;

            case DOCT_PAGE_BREAK:
                doc->flags |= DOCF_BWD_MOVEMENT;
                y += s->page_len - doc_e->page_line_num;
                doc->page_line_num = 0;
                goto rc_start_of_line;

            case DOCT_CURSOR:
                if (!find_cursor && !(doc->flags & DOCF_NO_CURSOR))
                {
                    doc->cur_entry  = doc_e->next;
                    doc->cur_col    = doc->cur_entry->min_col;
                }
                if (doc_e != added_cursor)
                    del_doc_e = TRUE;
                break;

            case DOCT_PROMPT:
                cur_u8_attr = cur_u8_attr & 0xF0 | DOC_COLOR_PROMPT;
                if (y == cursor_y)
                {
                    doc->cur_entry  = doc_e->next;
                    doc->cur_col    = doc->cur_entry->min_col;
                }
                break;

            case DOCT_CLEAR:
                next_clear_found = doc_e;
                if (doc_e->de_flags & DOCEF_HOLD)
                    clear_holds = TRUE;
                else
                    clear_holds = FALSE;
                break;

            case DOCT_PAGE_LEN:
                s->page_len = doc_e->attr;
                if (doc_e->de_flags & DOCEF_WIN_REL)
                    s->page_len += height;
                goto rc_adjust_xy;

            case DOCT_LEFT_MARGIN:
                i = doc_e->attr;
                left_margin = left+i;
                s->left_margin = i;
                goto rc_start_of_line;

            case DOCT_RIGHT_MARGIN:
                if (doc_e->de_flags & DOCEF_WIN_REL)
                    i = width - 1 - doc_e->attr;
                else
                    i = doc_e->attr;
                right_margin = left + i;
                s->right_margin = i;
                goto rc_adjust_xy;

            case DOCT_HEADER:
                s->header = doc_e->attr;
                goto rc_adjust_xy;

            case DOCT_FOOTER:
                s->footer = doc_e->attr;
                goto rc_adjust_xy;

            case DOCT_INDENT:
                if (doc_e->de_flags & DOCEF_LEFT_X)
                    i = doc_e->attr;
                else
                    i = s->indent + doc_e->attr;
                s->indent=i;
                goto rc_start_of_line;

            case DOCT_FOREGROUND:
                cur_u8_attr &= 0xF0;
                if (doc_e->attr == DOC_DEFAULT)
                    cur_u8_attr |= s->default_text_attr & 0x0F;
                else
                    cur_u8_attr |= doc_e->attr;
                s->cur_text_attr = cur_u8_attr;
                break;

            case DOCT_BACKGROUND:
                cur_u8_attr &= 0x0F;
                if (doc_e->attr == DOC_DEFAULT)
                    cur_u8_attr |= s->default_text_attr & 0xF0;
                else
                    cur_u8_attr |= doc_e->attr << 4;
                s->cur_text_attr = cur_u8_attr;
                break;

            case DOCT_DEFAULT_FOREGROUND:
                cur_u8_attr &= 0xF0;
                if (doc_e->attr == DOC_DEFAULT)
                    cur_u8_attr |= s->default_text_attr & 0xF;
                else
                    cur_u8_attr |= doc_e->attr;
                s->default_text_attr = s->default_text_attr & 0xF0 | cur_u8_attr & 0x0F;
                s->cur_text_attr     = cur_u8_attr;
                break;

            case DOCT_DEFAULT_BACKGROUND:
                cur_u8_attr &= 0x0F;
                if (doc_e->attr == DOC_DEFAULT)
                    cur_u8_attr |= s->default_text_attr & 0xF0;
                else
                    cur_u8_attr |= doc_e->attr << 4;
                s->default_text_attr = s->default_text_attr & 0x0F | cur_u8_attr & 0xF0;
                s->cur_text_attr     = cur_u8_attr;
                break;


            case DOCT_WORD_WRAP:
                if (doc_e->attr)
                    doc->flags |= DOCF_WORD_WRAP;
                else
                    doc->flags &= ~DOCF_WORD_WRAP;
                break;


            case DOCT_HIGHLIGHT:
                if (doc_e->attr)
                    doc->flags |= DOCF_HIGHLIGHT;
                else
                    doc->flags &= ~DOCF_HIGHLIGHT;
                break;

            case DOCT_BLINK:
                if (doc_e->attr)
                    doc->flags |= DOCF_BLINK;
                else
                    doc->flags &= ~DOCF_BLINK;
                break;

            case DOCT_INVERT:
                if (doc_e->attr)
                    doc->flags |= DOCF_INVERT;
                else
                    doc->flags &= ~DOCF_INVERT;
                break;

            case DOCT_UNDERLINE:
                if (doc_e->attr)
                    doc->flags |= DOCF_UNDERLINE;
                else
                    doc->flags &= ~DOCF_UNDERLINE;
                break;

            case DOCT_SHIFTED_X:
                s->shifted_x = doc_e->attr;
                break;

            case DOCT_SHIFTED_Y:
                s->shifted_y = doc_e->attr;
                break;

            case DOCT_CURSOR_MOVEMENT:
                doc->flags |= DOCF_BWD_MOVEMENT;
                x += doc_e->cursor_x_offset;
                if (doc_e->de_flags & DOCEF_PAGE_REL_Y)
                {
                    i = doc->page_line_num;
                    if (doc_e->de_flags & DOCEF_TOP_Y)
                        doc->page_line_num = 0;
                    else if (doc_e->de_flags & DOCEF_BOTTOM_Y)
                        doc->page_line_num = s->page_len - 1;
                    else if (doc_e->de_flags & DOCEF_CENTER_Y)
                        doc->page_line_num = s->page_len >> 1;
                    y += doc->page_line_num - i;
                }
                y += doc_e->cursor_y_offset;
                doc->page_line_num += doc_e->cursor_y_offset;
                goto rc_adjust_xy;

            case DOCT_SPRITE:
                if (!doc_e->bin_data && doc->flags & DOCEF_HAS_BIN)
                    doc_e->bin_data = DocBinFindNum(doc, doc_e->bin_num);
                if ((tmpb = doc_e->bin_data) && !tmpb->tag && doc_e->tag && *doc_e->tag)
                    tmpb->tag = StrNew(doc_e->tag, mem_task);
                if (tmpb && dc)
                {
                    DCReset(dc);
                    dc->flags &= ~(DCF_DONT_DRAW | DCF_LOCATE_NEAREST);
                    if (recalc_flags & RECALCG_MASK != RECALCt_TO_SCREEN || doc_e->de_flags & DOCEF_DONT_DRAW)
                        dc->flags |= DCF_DONT_DRAW;
                    bptr = tmpb->data;
                    ii = SpriteTypeMask(bptr);
                    if (ii & 1 << SPT_TYPES_NUM)
                    {
                        bptr = gr.empty_sprite;
                        ii = SpriteTypeMask(bptr);
                    }
                    if (ii & (1 << SPT_FLOOD_FILL | 1 << SPT_FLOOD_FILL_NOT))
                        i = cur_u8_attr >> 4 & 0xF ^ win_task->text_attr >> 4 & 0xF;
                    else
                    {
                        i = tmp_u32_attr >> 12 & 0xF ^ win_task->text_attr >> 4 & 0xF;
                        if (tmp_u32_attr & DOCET_SEL)
                            i ^= 0xF;
                        if (tmp_u32_attr & DOCET_INVERT)
                            i ^= 0xF;
                        if (blink_flag && (doc_e == doc->cur_entry || tmp_u32_attr & DOCET_BLINK))
                            i ^= 0xF;
                    }
                    dc->color = i;
                    if (find_cursor)
                        dc->flags |= DCF_LOCATE_NEAREST;
                    dc->cur_x = (doc->x - x0) * FONT_WIDTH  + pix_left + scroll_x;
                    dc->cur_y = (doc->y - y0) * FONT_HEIGHT + pix_top  + scroll_y;
                    dc->cur_z = 0;
                    dc->bkcolor = i;
                    if (doc_e->de_flags & DOCEF_FROM_START)
                    {
                        xx = (x - k - x0) * FONT_WIDTH; //TODO: scrolling text is not length k
                        yy = (y - y0) * FONT_HEIGHT;
                        zz = 0;
                    }
                    else
                    {
                        xx = (x - x0) * FONT_WIDTH;
                        yy = (y - y0) * FONT_HEIGHT;
                        zz = 0;
                    }
                    if (ii & (1 << SPT_MESH | 1 << SPT_SHIFTABLE_MESH))
                    {
                        if (!depth_buf)
                        {
                            DCDepthBufAlloc(dc);
                            depth_buf = dc->depth_buf;
                        }
                        else
                            dc->depth_buf = depth_buf;
                        Mat4x4IdentEqu(dc->r);
                        Mat4x4RotZ(dc->r, cur_time * 3.1);
                        Mat4x4RotY(dc->r, cur_time * 1.9);
                        Mat4x4RotX(dc->r, cur_time);
                        dc->flags |= DCF_TRANSFORMATION;
                        dc->x = xx;
                        dc->y = yy;
                        dc->z = GR_Z_ALL;
                        xx = 0;
                        yy = 0;
                        zz = 0;
                    }
                    Sprite3(dc, xx, yy, zz, bptr);
                    dc->depth_buf = NULL;
                    dc->flags &= ~(DCF_LOCATE_NEAREST | DCF_DONT_DRAW | DCF_TRANSFORMATION);
                    if (dc->nearest_dist <= D)
                    {
                        D = dc->nearest_dist;
                        col = doc_e->min_col;
                    }
                }
                break;

            case DOCT_SONG:
                if (sys_focus_task == win_task && recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN &&
                    !(doc_e->de_flags & DOCEF_DONT_DRAW))
                {
                    if (doc_e->aux_str && (!music.cur_song || StrCompare(music.cur_song, doc_e->aux_str)))
                    {
                        Free(music.cur_song);
                        MusicSettingsReset;
                        music.cur_song = SysStrNew(doc_e->aux_str);
                    }
                }
                doc->flags |= DOCF_HAS_SONG;
                break;
            case DOCT_HTML_CODE:
                if (recalc_flags & RECALCF_TO_HTML && doc_e->de_flags & DOCEF_TAG && doc_e->tag)
                    x -= StrLen(doc_e->tag);
                break;
            case DOCT_TYPES_NUM - 1: //nobound switch
            default:
                break;
        }

        if (doc_e->de_flags & DOCEF_HAS_BORDER)
            TextBorder(win_task, doc_e->x - x0, x - x0 - 1, doc_e->y - y0, y - y0,
                       tmp_u32_attr.u8[1], ToBool(doc_e->de_flags & DOCEF_SOLID_BORDER));
        if (full_refresh)
        {
            switch (doc_e->type_u8)
            {
                case DOCT_CHECK_BOX:
                    doc_e->max_col = 2;
                    break;

                case DOCT_LIST:
                case DOCT_TREE:
                case DOCT_BTTN:
                case DOCT_LINK:
                case DOCT_MENU_VAL:
                case DOCT_MACRO:
                    doc_e->max_col = 1;
                    break;

                default:
                    if (doc_e->de_flags & (DOCEF_TREE | DOCEF_LIST))
                        doc_e->max_col = 1;
                    else
                        doc_e->max_col = col2;
            }

            if (x > doc->max_x)
                doc->max_x = x;
            if (y > doc->max_y)
                doc->max_y = y;
            if (D <= best_d && !(doc_e->de_flags & DOCEF_NO_CLICK_ON))
            {
                best_d = D;
                best_doc_e = doc_e;
                best_col = col;
            }
            if (doc_e->de_flags & DOCEF_TREE)
            {
                if (doc_e->de_flags & DOCEF_CHECKED_COLLAPSED)
                    tree_collapsed = TRUE;
                else
                    tree_collapsed = FALSE;
                doc_e2 = doc_e->next;
                while (doc_e2 != doc && doc_e2->type_u8 != DOCT_INDENT && !(doc_e2->de_flags & DOCEF_TREE))
                    doc_e2 = doc_e2->next;
                if (doc_e2->type_u8 == DOCT_INDENT)
                {
                    j = i = s->indent;
                    do
                    {
                        if (tree_collapsed)
                            doc_e2->de_flags |= DOCEF_SKIP;
                        else
                            doc_e2->de_flags &= ~DOCEF_SKIP;
                        if (doc_e2->type_u8 == DOCT_INDENT)
                        {
                            if (doc_e2->de_flags & DOCEF_LEFT_X)
                                j = doc_e2->attr;
                            else
                                j += doc_e2->attr;
                        }
                        doc_e2 = doc_e2->next;
                    }
                    while (doc_e2 != doc && j > i);
                }
            }
        }

        doc_e2 = doc_e->next;
rc_skip:
        while (doc_e2 != doc && doc_e2->de_flags & (DOCEF_SKIP | DOCEF_FILTER_SKIP))
        {
            if (doc_e2 == doc->cur_entry)
            {
                doc->cur_entry  = doc_e2->next;
                doc->cur_col    = doc->cur_entry->min_col;
            }
            if (full_refresh)
            {
                doc_e2->x               = x;
                doc_e2->y               = y;
                doc_e2->page_line_num   = doc->page_line_num;
                MemCopy(&doc_e2->settings, s, sizeof(CDocSettings));
                doc_e2->type.u8[1]      = cur_u8_attr;
                doc_e2->de_flags        = doc->flags &
                                            (DOCG_BL_IV_UL|DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT) |
                                            doc_e2->de_flags & ~(DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT);
            }
            doc_e2 = doc_e2->next;
        }

        if (full_refresh)
        {
            if (del_doc_e)
            {
                if (!(doc_e->de_flags & (DOCEF_HOLD | DOCEF_FILTER_SKIP)))
                {
                    if (doc_e == doc->cur_entry)
                    {
                        doc->cur_entry  = doc_e2;
                        doc->cur_col    = doc_e2->min_col;
                    }
                    if (best_doc_e == doc_e)
                    {
                        best_doc_e  = doc_e2;
                        best_col    = doc_e2->min_col;  //TODO: might be bug
                    }
                    DocEntryDel(doc, doc_e);
                }
            }
        }
        num_entries++;
        if (!full_refresh && doc_e->y > y_plot_bottom)
            break;
        doc_e = doc_e2;
    }

    if (full_refresh)
    {
        if (doc->cur_entry == doc && recalc_flags & RECALCF_ADD_CURSOR)
        {
            doc_e2 = DocEntryNewBase(doc, DOCT_CURSOR,, x, y, doc->page_line_num);
            MemCopy(&doc_e2->settings, s, sizeof(CDocSettings));
            QueueInsertRev(doc_e2, doc);
        }

        if (doc->min_x > doc->max_x)
        {
            doc->max_x = 0;
            doc->min_x = 0;
        }
        if (doc->min_y > doc->max_y)
        {
            doc->max_y = 0;
            doc->min_y = 0;
        }

        //Update header
        if (!skipped_update)
        {
            doc_e->x                = x;
            doc_e->y                = y;
            doc_e->page_line_num    = doc->page_line_num;
            MemCopy(&doc_e->settings, s, sizeof(CDocSettings));
            doc_e->type.u8[1]       = cur_u8_attr;
            if (find_cursor)
            {
                D = DocCharDist(doc, x, y);
                if (D < best_d && !(doc_e->de_flags & DOCEF_NO_CLICK_ON))
                {
                    best_d = D;
                    best_doc_e = doc_e;
                    best_col = 0;
                }
            }
        }
        if (doc->flags & DOCF_SIZE_MIN)
        {
            if (Bt(&win_task->display_flags, DISPLAYf_NO_BORDER))
            {
                if (left < 0)
                    left = 0;
                i = left + doc->max_x - doc->min_x;
                if (i > TEXT_COLS - 1)
                    i = TEXT_COLS - 1;
                WinHorz(left, i, win_task);
                if (top < 0)
                    top = 0;
                i = top + doc->max_y - doc->min_y;
                if (i > TEXT_ROWS - 1)
                    i = TEXT_ROWS - 1;
                WinVert(top, i, win_task);
            }
            else
            {
                if (left < 1)
                    left = 1;
                i = left + doc->max_x - doc->min_x;
                if (i > TEXT_COLS - 2)
                    i = TEXT_COLS - 2;
                WinHorz(left, i, win_task);
                if (top < 1)
                    top = 1;
                i = top + doc->max_y - doc->min_y;
                if (i > TEXT_ROWS - 2)
                    i = TEXT_ROWS - 2;
                WinVert(top, i, win_task);
            }
        }
        if (find_cursor)
        {
            doc->cur_entry  = best_doc_e;
            doc->cur_col    = best_col;
            DocFormBwd(doc);
//We need this because text coordinates are used
            if (best_d < FONT_WIDTH)
                best_d = 0;
            doc->best_d = best_d;
        }

        if (doc->cur_entry->type_u8 != DOCT_HEX_ED)
        {
            doc->y = doc->cur_entry->y;
            doc->x = doc->cur_entry->x + doc->cur_col;
        }
        else
        {
            doc->y = doc->cur_entry->y + doc->cur_col / 3 / doc->cur_entry->hex_ed_width;
            x = doc->cur_col % (doc->cur_entry->hex_ed_width * 3);
            i = x / doc->cur_entry->hex_ed_width;
            doc->x = doc->cur_entry->x + 9;
            if (i < 2)
                doc->x += x >> 1 * 3 + x & 1;
            else
                doc->x += doc->cur_entry->hex_ed_width * 3 + (x - doc->cur_entry->hex_ed_width << 1);
        }
        doc->line = doc->y + 1;
        doc->col  = doc->x + 1;

        if (recalc_flags & RECALCF_HAS_CURSOR)
        {
            if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN)
            {
                x = 0;
                y = 0;
            }
            else
            {
                x = scroll_x / FONT_WIDTH;
                y = scroll_y / FONT_HEIGHT;
            }
            if (doc->top_line_num - y + height - 1 > doc->max_y)
                doc->top_line_num = doc->max_y - (height - 1) + y;
            if (doc->top_line_num - y < doc->min_y)
                doc->top_line_num = doc->min_y + y;

            if (doc->y - doc->top_line_num + y > height - 1)
                doc->top_line_num = doc->y - (height - 1) + y;
            if (doc->y - doc->top_line_num + y < 0)
                doc->top_line_num = doc->y + y;

            if (doc->line_start_col - x + width - 1 > doc->max_x)
                doc->line_start_col = doc->max_x - (width - 1) + x;
            if (doc->line_start_col - x < doc->min_x)
                doc->line_start_col = doc->min_x + x;

            if (doc->x - doc->line_start_col + x > width - 1)
                doc->line_start_col = doc->x-(width - 1) + x;
            if (doc->x - doc->line_start_col + x < 0)
                doc->line_start_col = doc->x + x;
        }
    }
    if (recalc_flags & RECALCG_MASK == RECALCt_TO_SCREEN && recalc_flags & RECALCF_HAS_CURSOR)
    {
        x = doc->x - doc->line_start_col + left + scroll_x / FONT_WIDTH;
        y = doc->y - doc->top_line_num   + top  + scroll_y / FONT_HEIGHT;
        if (0 <= x <= right && 0 <= y <= bottom && x < TEXT_COLS && y < TEXT_ROWS && !(doc->flags & DOCF_HIDE_CURSOR))
        {
            u32_ptr = gr.text_base + y * TEXT_COLS + x;
            *u32_ptr |= DOCET_BLINK;
            *u32_ptr ^= 0xFF00;
        }
        if (full_refresh)
        {
            if (!(doc->flags & DOCF_NO_SCROLL_BARS))
            {
                if (!Bt(&hss->flags, WSSf_SET_TO_POS))
                {
                    hss->min = doc->min_x;
                    if (doc->max_x - width + 1 < hss->min)
                        hss->max = hss->min;
                    else
                        hss->max = doc->max_x - width + 1;
                    hss->pos = doc->line_start_col;
                }
                if (!Bt(&vss->flags, WSSf_SET_TO_POS))
                {
                    vss->min = doc->min_y;
                    if (doc->max_y - height + 1 < vss->min)
                        vss->max = vss->min;
                    else
                        vss->max = doc->max_y - height + 1;
                    vss->pos = doc->top_line_num;
                }
            }
            LBEqual(&doc->flags, DOCf_MORE, more);
        }
    }
    if (!same_win)
    {
        doc->old_win_top    = top;
        doc->old_win_bottom = bottom;
        doc->old_win_left   = left;
        doc->old_win_right  = right;
        doc->old_cur_entry  = doc->cur_entry;
        doc->old_cur_col    = doc->old_cur_col;
    }
    if (doc->flags & DOCF_HAS_SONG)
        LBts(&win_task->task_flags, TASKf_HAS_SONG);
    if (full_refresh)
    {
        i = num_entries - doc->max_entries;
        if (next_clear_found)
        {
            DocDelToEntry(doc, next_clear_found, clear_holds);
            DocRecalc(doc, recalc_flags);
        }
        else if (i > 1024)
        {
            DocDelToNum(doc, i);
            DocRecalc(doc, recalc_flags);
        }
    }
    DCDel(dc);
    Free(depth_buf);
    if (unlock)
        DocUnlock(doc);

    return TRUE;
}