/* Remove one line from buffer. */ void textbuffer_view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) { GSList *tmp; unsigned char update_counter; int linecount; g_return_if_fail(view != NULL); g_return_if_fail(line != NULL); signal_emit("gui textbuffer line removed", 3, view, line, line->prev); linecount = view_get_linecount(view, line); update_counter = view->cache->update_counter+1; view_remove_line(view, line, linecount); view_remove_cache(view, line, update_counter); for (tmp = view->siblings; tmp != NULL; tmp = tmp->next) { TEXT_BUFFER_VIEW_REC *rec = tmp->data; view_remove_line(rec, line, linecount); view_remove_cache(rec, line, update_counter); } textbuffer_remove(view->buffer, line); }
static void view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, int linecount) { int realcount; view_bookmarks_check(view, line); if (view->buffer->cur_line == line) { /* the last line is being removed */ LINE_REC *prevline; prevline = view->buffer->first_line == line ? NULL : textbuffer_line_last(view->buffer); view->cache->last_linecount = prevline == NULL ? 0 : view_get_linecount(view, prevline); } if (view->buffer->first_line == line) { /* first line in the buffer - this is the most commonly removed line.. */ if (view->bottom_startline == line) { /* very small scrollback.. */ view->bottom_startline = view->bottom_startline->next; view->bottom_subline = 0; } if (view->startline == line) { /* removing the first line in screen */ int is_last = view->startline->next == NULL; realcount = view_scroll(view, &view->startline, &view->subline, linecount, FALSE); view->ypos -= realcount; view->empty_linecount += linecount-realcount; if (is_last == 1) view->startline = NULL; } } else { if (textbuffer_line_exists_after(view->bottom_startline, line)) { realcount = view_scroll(view, &view->bottom_startline, &view->bottom_subline, -linecount, FALSE); view->empty_linecount += linecount-realcount; } if (textbuffer_line_exists_after(view->startline, line)) { view_remove_line_update_startline(view, line, linecount); } } view->bottom = view_is_bottom(view); if (view->bottom) view->more_text = FALSE; if (view->window != NULL) term_refresh(view->window); }
static void view_update_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, unsigned char update_counter) { view_remove_cache(view, line, update_counter); if (view->buffer->cur_line == line) view->cache->last_linecount = view_get_linecount(view, line); }
static void textbuffer_view_init_ypos(TEXT_BUFFER_VIEW_REC *view) { LINE_REC *line; g_return_if_fail(view != NULL); view->ypos = -view->subline-1; for (line = view->startline; line != NULL; line = line->next) view->ypos += view_get_linecount(view, line); }
static int view_get_linecount_all(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) { int linecount; linecount = 0; while (line != NULL) { linecount += view_get_linecount(view, line); line = line->next; } return linecount; }
/* Clear the view, don't actually remove any lines from buffer. */ void textbuffer_view_clear(TEXT_BUFFER_VIEW_REC *view) { g_return_if_fail(view != NULL); view->ypos = -1; view->bottom_startline = view->startline = textbuffer_line_last(view->buffer); view->bottom_subline = view->subline = view->buffer->cur_line == NULL ? 0 : view_get_linecount(view, view->buffer->cur_line); view->empty_linecount = view->height; view->bottom = TRUE; view->more_text = FALSE; textbuffer_view_redraw(view); }
/* Return number of real lines `lines' list takes - stops counting when the height reaches the view height */ static int view_get_lines_height(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, int subline, LINE_REC *skip_line) { int height, linecount; height = -subline; while (line != NULL && height < view->height) { if (line != skip_line) { linecount = view_get_linecount(view, line); height += linecount; } line = line->next; } return height < view->height ? height : view->height; }
static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines) { LINE_REC *line; int ypos, maxline, subline, linecount; maxline = view->height-lines; line = view->startline; ypos = -view->subline; subline = 0; while (line != NULL && ypos < maxline) { linecount = view_get_linecount(view, line); ypos += linecount; if (ypos > maxline) { subline = maxline-(ypos-linecount); break; } line = line->next; } view_draw(view, line, subline, maxline, lines, TRUE); }
/* Recalculate view's bottom line information - try to keep the original if possible */ static void textbuffer_view_init_bottom(TEXT_BUFFER_VIEW_REC *view) { LINE_REC *line; int linecount, total; if (view->empty_linecount == 0) { /* no empty lines in screen, no need to try to keep the old bottom startline */ view->bottom_startline = NULL; } total = 0; line = textbuffer_line_last(view->buffer); for (; line != NULL; line = line->prev) { linecount = view_get_linecount(view, line); if (line == view->bottom_startline) { /* keep the old one, make sure that subline is ok */ if (view->bottom_subline > linecount) view->bottom_subline = linecount; view->empty_linecount = view->height - total - (linecount-view->bottom_subline); return; } total += linecount; if (total >= view->height) { view->bottom_startline = line; view->bottom_subline = total - view->height; view->empty_linecount = 0; return; } } /* not enough lines so we must be at the beginning of the buffer */ view->bottom_startline = view->buffer->first_line; view->bottom_subline = 0; view->empty_linecount = view->height - total; }
/* Resize the view. */ void textbuffer_view_resize(TEXT_BUFFER_VIEW_REC *view, int width, int height) { int linecount; g_return_if_fail(view != NULL); g_return_if_fail(width > 0); if (view->width != width) { /* line cache needs to be recreated */ textbuffer_cache_unref(view->cache); view->cache = textbuffer_cache_get(view->siblings, width); } view->width = width > 10 ? width : 10; view->height = height > 1 ? height : 1; if (view->buffer->first_line == NULL) { view->empty_linecount = height; return; } textbuffer_view_init_bottom(view); /* check that we didn't scroll lower than bottom startline.. */ if (textbuffer_line_exists_after(view->bottom_startline->next, view->startline)) { view->startline = view->bottom_startline; view->subline = view->bottom_subline; } else if (view->startline == view->bottom_startline && view->subline > view->bottom_subline) { view->subline = view->bottom_subline; } else { /* make sure the subline is still in allowed range */ linecount = view_get_linecount(view, view->startline); if (view->subline > linecount) view->subline = linecount; } textbuffer_view_init_ypos(view); if (view->bottom && !view_is_bottom(view)) { /* we scrolled to far up, need to get down. go right over the empty lines if there's any */ view->startline = view->bottom_startline; view->subline = view->bottom_subline; if (view->empty_linecount > 0) { view_scroll(view, &view->startline, &view->subline, -view->empty_linecount, FALSE); } textbuffer_view_init_ypos(view); } view->bottom = view_is_bottom(view); if (view->bottom) { /* check if we left empty space at the bottom.. */ linecount = view_get_linecount_all(view, view->startline) - view->subline; if (view->empty_linecount < view->height-linecount) view->empty_linecount = view->height-linecount; view->more_text = FALSE; } view->dirty = TRUE; }
/* Returns number of lines actually scrolled */ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines, int *subline, int scrollcount, int draw_nonclean) { int linecount, realcount, scroll_visible; if (*lines == NULL) return 0; /* scroll down */ scroll_visible = lines == &view->startline; realcount = -*subline; scrollcount += *subline; *subline = 0; while (scrollcount > 0) { linecount = view_get_linecount(view, *lines); if ((scroll_visible && *lines == view->bottom_startline) && (scrollcount >= view->bottom_subline)) { *subline = view->bottom_subline; realcount += view->bottom_subline; scrollcount = 0; break; } realcount += linecount; scrollcount -= linecount; if (scrollcount < 0) { realcount += scrollcount; *subline = linecount+scrollcount; scrollcount = 0; break; } if ((*lines)->next == NULL) break; *lines = (*lines)->next; } /* scroll up */ while (scrollcount < 0 && (*lines)->prev != NULL) { *lines = (*lines)->prev; linecount = view_get_linecount(view, *lines); realcount -= linecount; scrollcount += linecount; if (scrollcount > 0) { realcount += scrollcount; *subline = scrollcount; break; } } if (scroll_visible && realcount != 0 && view->window != NULL) { if (realcount <= -view->height || realcount >= view->height) { /* scrolled more than screenful, redraw the whole view */ textbuffer_view_redraw(view); } else { term_set_color(view->window, ATTR_RESET); term_window_scroll(view->window, realcount); if (draw_nonclean) { if (realcount < 0) view_draw_top(view, -realcount, TRUE); else view_draw_bottom(view, realcount); } term_refresh(view->window); } } return realcount >= 0 ? realcount : -realcount; }
static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) { int linecount, ypos, subline; if (!view->bottom) view->more_text = TRUE; if (view->bottom_startline == NULL) { view->startline = view->bottom_startline = view->buffer->first_line; } if (view->buffer->cur_line != line && !textbuffer_line_exists_after(view->bottom_startline, line)) return; linecount = view_get_linecount(view, line); view->ypos += linecount; if (view->empty_linecount > 0) { view->empty_linecount -= linecount; if (view->empty_linecount >= 0) linecount = 0; else { linecount = -view->empty_linecount; view->empty_linecount = 0; } } if (linecount > 0) { view_scroll(view, &view->bottom_startline, &view->bottom_subline, linecount, FALSE); } if (view->bottom) { if (view->scroll && view->ypos >= view->height) { linecount = view->ypos-view->height+1; view_scroll(view, &view->startline, &view->subline, linecount, FALSE); view->ypos -= linecount; } else { view->bottom = view_is_bottom(view); } if (view->window != NULL) { ypos = view->ypos+1 - view_get_linecount(view, line); if (ypos >= 0) subline = 0; else { subline = -ypos; ypos = 0; } if (ypos < view->height) { view_line_draw(view, line, subline, ypos, view->height - ypos); } } } if (view->window != NULL) term_refresh(view->window); }