summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Text_Display.cxx233
1 files changed, 157 insertions, 76 deletions
diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx
index 5298e796e..78e34ce57 100644
--- a/src/Fl_Text_Display.cxx
+++ b/src/Fl_Text_Display.cxx
@@ -1,7 +1,7 @@
//
// "$Id$"
//
-// Copyright 2001-2015 by Bill Spitzak and others.
+// Copyright 2001-2016 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
//
@@ -40,6 +40,19 @@
#undef min
#undef max
+// #define DEBUG
+// #define DEBUG2
+
+#define LINENUM_LEFT_OF_VSCROLL // uncomment this line ...
+// ... if you want the line numbers to be drawn left of the vertical
+// scrollbar (only if the vertical scrollbar is aligned left).
+// This is the default.
+// If not defined and the vertical scrollbar is aligned left, then the
+// scrollbar is positioned at the left border and the line numbers are
+// drawn between the scrollbar (left) and the text area (right).
+// If the vertical scrollbar is aligned right, then the line number
+// position is not affected by this definition.
+
// Text area margins. Left & right margins should be at least 3 so that
// there is some room for the overhanging parts of the cursor!
#define TOP_MARGIN 1
@@ -198,7 +211,7 @@ Fl_Text_Display::~Fl_Text_Display() {
/**
Set width of screen area for line numbers.
Use to also enable/disable line numbers.
- A value of 0 disables line numbering, values >0 enables them.
+ A value of 0 disables line numbering, values >0 enable the line number display.
\param width The new width of the area for line numbers to appear, in pixels.
0 disables line numbers (default)
*/
@@ -471,55 +484,96 @@ int Fl_Text_Display::longest_vline() const {
\param X, Y, W, H new position and size of this widget
*/
void Fl_Text_Display::resize(int X, int Y, int W, int H) {
-#ifdef DEBUG
+
+#ifdef DEBUG2
+ printf("\n");
printf("Fl_Text_Display::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H);
-#endif // DEBUG
- const int oldWidth = w();
-#ifdef DEBUG
- printf(" oldWidth=%d, mContinuousWrap=%d, mWrapMarginPix=%d\n", oldWidth, mContinuousWrap, mWrapMarginPix);
-#endif // DEBUG
+ printf(" current size(x=%d, y=%d, w=%d, h=%d)\n", x(), y(), w(), h());
+ printf(" box_d* size(x=%d, y=%d, w=%d, h=%d)\n",
+ Fl::box_dx(box()),Fl::box_dy(box()),Fl::box_dw(box()),Fl::box_dh(box()));
+ printf(" text_area size(x=%d, y=%d, w=%d, h=%d)\n",
+ text_area.x, text_area.y, text_area.w, text_area.h);
+ printf(" mContinuousWrap=%d, mWrapMarginPix=%d\n",
+ mContinuousWrap, mWrapMarginPix);
+ fflush(stdout);
+#endif // DEBUG2
+
Fl_Widget::resize(X,Y,W,H);
if (!buffer()) return;
+
+ // did we have scrollbars initially?
+ unsigned int hscrollbarvisible = mHScrollBar->visible();
+ unsigned int vscrollbarvisible = mVScrollBar->visible();
+
+ int oldTAWidth = text_area.w;
+
X += Fl::box_dx(box());
Y += Fl::box_dy(box());
W -= Fl::box_dw(box());
H -= Fl::box_dh(box());
- text_area.x = X+LEFT_MARGIN;
- text_area.y = Y+TOP_MARGIN;
- text_area.w = W-LEFT_MARGIN-RIGHT_MARGIN;
- text_area.h = H-TOP_MARGIN-BOTTOM_MARGIN;
- const int oldTAWidth = text_area.w;
- int i;
+ text_area.x = X + LEFT_MARGIN + mLineNumWidth;
+ text_area.y = Y + TOP_MARGIN;
+ text_area.w = W - LEFT_MARGIN - RIGHT_MARGIN - mLineNumWidth;
+ text_area.h = H - TOP_MARGIN - BOTTOM_MARGIN;
- /* Find the new maximum font height for this text display */
+ // Find the new maximum font height for this text display
+ int i;
for (i = 0, mMaxsize = fl_height(textfont(), textsize()); i < mNStyles; i++)
mMaxsize = max(mMaxsize, fl_height(mStyleTable[i].font, mStyleTable[i].size));
- // did we have scrollbars initially?
- unsigned int hscrollbarvisible = mHScrollBar->visible();
- unsigned int vscrollbarvisible = mVScrollBar->visible();
-
// try without scrollbars first
mVScrollBar->clear_visible();
mHScrollBar->clear_visible();
+#if (1) // optimization (experimental - seems to work well)
+
+ // Optimization: if the number of lines in the buffer does not fit in
+ // the display area, then we need a vertical scrollbar regardless of
+ // word wrapping. If we switch it on here, this saves one line counting
+ // run in wrap mode in the loop below ("... again ..."). This is important
+ // for large buffers that suffer from slow calculations of character width
+ // to determine line wrapping.
+
+ if (mContinuousWrap && !mWrapMarginPix) {
+
+ int nvlines = (text_area.h + mMaxsize - 1) / mMaxsize;
+ int nlines = buffer()->count_lines(0,buffer()->length());
+ if (nvlines < 1) nvlines = 1;
+ if (nlines >= nvlines-1) {
+ mVScrollBar->set_visible(); // we need a vertical scrollbar
+ text_area.w -= scrollbar_width();
+ }
+ }
+
+#endif // optimization
+
for (int again = 1; again;) {
again = 0;
/* In continuous wrap mode, a change in width affects the total number of
lines in the buffer, and can leave the top line number incorrect, and
the top character no longer pointing at a valid line start */
- if (mContinuousWrap && !mWrapMarginPix && (W!=oldWidth || text_area.w!=oldTAWidth)) {
+
+#ifdef DEBUG2
+ printf("*** again ... text_area.w = %d, oldTAWidth = %d, diff = %d\n",
+ text_area.w, oldTAWidth, text_area.w - oldTAWidth);
+#endif // DEBUG2
+
+ if (mContinuousWrap && !mWrapMarginPix && text_area.w != oldTAWidth) {
+
int oldFirstChar = mFirstChar;
mNBufferLines = count_lines(0, buffer()->length(), true);
mFirstChar = line_start(mFirstChar);
mTopLineNum = count_lines(0, mFirstChar, true)+1;
absolute_top_line_number(oldFirstChar);
-#ifdef DEBUG
+#ifdef DEBUG2
printf(" mNBufferLines=%d\n", mNBufferLines);
-#endif // DEBUG
+#endif // DEBUG2
+
}
+ oldTAWidth = text_area.w;
+
/* reallocate and update the line starts array, which may have changed
size and / or contents. */
int nvlines = (text_area.h + mMaxsize - 1) / mMaxsize;
@@ -535,25 +589,16 @@ void Fl_Text_Display::resize(int X, int Y, int W, int H) {
// figure the scrollbars
if (scrollbar_width()) {
+
/* Decide if the vertical scrollbar needs to be visible */
- uchar vbvis = mVScrollBar->visible();
- if (scrollbar_align() & (FL_ALIGN_LEFT|FL_ALIGN_RIGHT) &&
- mNBufferLines >= mNVisibleLines - 1)
+ if (!mVScrollBar->visible() &&
+ scrollbar_align() & (FL_ALIGN_LEFT|FL_ALIGN_RIGHT) &&
+ mNBufferLines >= mNVisibleLines-1)
{
- mVScrollBar->set_visible();
- if (scrollbar_align() & FL_ALIGN_LEFT) {
- text_area.x = X+scrollbar_width()+LEFT_MARGIN;
- text_area.w = W-scrollbar_width()-LEFT_MARGIN-RIGHT_MARGIN;
- mVScrollBar->resize(X, text_area.y-TOP_MARGIN, scrollbar_width(),
- text_area.h+TOP_MARGIN+BOTTOM_MARGIN);
- } else {
- text_area.x = X+LEFT_MARGIN;
- text_area.w = W-scrollbar_width()-LEFT_MARGIN-RIGHT_MARGIN;
- mVScrollBar->resize(X+W-scrollbar_width(), text_area.y-TOP_MARGIN,
- scrollbar_width(), text_area.h+TOP_MARGIN+BOTTOM_MARGIN);
- }
+ mVScrollBar->set_visible();
+ text_area.w -= scrollbar_width();
+ again = 1;
}
- if (vbvis != mVScrollBar->visible()) again = 1;
/*
Decide if the horizontal scrollbar needs to be visible. If the text
@@ -577,35 +622,66 @@ void Fl_Text_Display::resize(int X, int Y, int W, int H) {
/* WAS: Suggestion: Try turning the horizontal scrollbar on when
you first see a line that is too wide in the window, but then
don't turn it off (ie mix both of your solutions). */
- if (scrollbar_align() & (FL_ALIGN_TOP|FL_ALIGN_BOTTOM) &&
+
+ if (!mHScrollBar->visible() &&
+ scrollbar_align() & (FL_ALIGN_TOP|FL_ALIGN_BOTTOM) &&
(mVScrollBar->visible() || longest_vline() > text_area.w))
{
char wrap_at_bounds = mContinuousWrap && (mWrapMarginPix<text_area.w);
- if (!mHScrollBar->visible() && !wrap_at_bounds) {
+ if (!wrap_at_bounds) {
mHScrollBar->set_visible();
+ text_area.h -= scrollbar_width();
again = 1; // loop again to see if we now need vert. & recalc sizes
}
- if (scrollbar_align() & FL_ALIGN_TOP) {
- text_area.y = Y + scrollbar_width()+TOP_MARGIN;
- text_area.h = H - (wrap_at_bounds?0:scrollbar_width())-TOP_MARGIN-BOTTOM_MARGIN;
- mHScrollBar->resize(text_area.x-LEFT_MARGIN, Y,
- text_area.w+LEFT_MARGIN+RIGHT_MARGIN, scrollbar_width());
- } else {
- text_area.y = Y+TOP_MARGIN;
- text_area.h = H - (wrap_at_bounds?0:scrollbar_width())-TOP_MARGIN-BOTTOM_MARGIN;
- mHScrollBar->resize(text_area.x-LEFT_MARGIN, Y+H-scrollbar_width(),
- text_area.w+LEFT_MARGIN+RIGHT_MARGIN, scrollbar_width());
- }
}
}
+ } // (... again ...)
+
+ // Calculate text area position, dependent on scrollbars and line numbers.
+ // Note: width and height have been calculated above.
+ text_area.x = X + mLineNumWidth + LEFT_MARGIN;
+ if (mVScrollBar->visible() && scrollbar_align() & FL_ALIGN_LEFT)
+ text_area.x += scrollbar_width();
+
+ text_area.y = Y + TOP_MARGIN;
+ if (mHScrollBar->visible() &&
+ scrollbar_align() & FL_ALIGN_TOP)
+ text_area.y += scrollbar_width();
+
+ // position and resize scrollbars
+ if (mVScrollBar->visible()) {
+ if (scrollbar_align() & FL_ALIGN_LEFT) {
+#ifdef LINENUM_LEFT_OF_VSCROLL
+ mVScrollBar->resize(text_area.x - LEFT_MARGIN - scrollbar_width(),
+#else
+ mVScrollBar->resize(X,
+#endif
+ text_area.y - TOP_MARGIN,
+ scrollbar_width(),
+ text_area.h + TOP_MARGIN + BOTTOM_MARGIN);
+ } else {
+ mVScrollBar->resize(X+W-scrollbar_width(),
+ text_area.y - TOP_MARGIN,
+ scrollbar_width(),
+ text_area.h + TOP_MARGIN + BOTTOM_MARGIN);
+ }
}
- // add linenum width to the text area - LZA / STR#2621
- if (mLineNumWidth > 0) {
- text_area.x += mLineNumWidth;
- text_area.w -= mLineNumWidth;
+ if (mHScrollBar->visible()) {
+ if (scrollbar_align() & FL_ALIGN_TOP) {
+ mHScrollBar->resize(text_area.x - LEFT_MARGIN,
+ Y,
+ text_area.w + LEFT_MARGIN + RIGHT_MARGIN,
+ scrollbar_width());
+ } else {
+ mHScrollBar->resize(text_area.x - LEFT_MARGIN,
+ Y + H - scrollbar_width(),
+ text_area.w + LEFT_MARGIN + RIGHT_MARGIN,
+ scrollbar_width());
+ }
}
+
// user request to change viewport
if (mTopLineNumHint != mTopLineNum || mHorizOffsetHint != mHorizOffset)
scroll_(mTopLineNumHint, mHorizOffsetHint);
@@ -1322,10 +1398,10 @@ int Fl_Text_Display::move_down() {
/**
\brief Count the number of lines between two positions.
- Same as BufCountLines, but takes into account wrapping if wrapping is
- turned on. If the caller knows that \p startPos is at a line start, it
- can pass \p startPosIsLineStart as True to make the call more efficient
- by avoiding the additional step of scanning back to the last newline.
+ Same as Fl_Text_Buffer::count_lines(), but takes into account wrapping if
+ wrapping is turned on. If the caller knows that \p startPos is at a line
+ start, it can pass \p startPosIsLineStart as True to make the call more
+ efficient by avoiding the additional step of scanning back to the last newline.
\param startPos index to first character
\param endPos index after last character
@@ -1344,7 +1420,7 @@ int Fl_Text_Display::count_lines(int startPos, int endPos,
startPos, endPos, startPosIsLineStart);
#endif // DEBUG
- /* If we're not wrapping use simple (and more efficient) BufCountLines */
+ /* If we're not wrapping use simple (and more efficient) Fl_Text_Buffer::count_lines() */
if (!mContinuousWrap)
return buffer()->count_lines(startPos, endPos);
@@ -2802,7 +2878,7 @@ int Fl_Text_Display::scroll_(int topLineNum, int horizOffset) {
\brief Update vertical scrollbar.
Update the minimum, maximum, slider size, page increment, and value
- for vertical scrollbar.
+ for the vertical scrollbar.
*/
void Fl_Text_Display::update_v_scrollbar() {
/* The vertical scrollbar value and slider size directly represent the top
@@ -2821,7 +2897,7 @@ void Fl_Text_Display::update_v_scrollbar() {
/**
- \brief Update vertical scrollbar.
+ \brief Update horizontal scrollbar.
Update the minimum, maximum, slider size, page increment, and value
for the horizontal scrollbar.
@@ -2834,7 +2910,7 @@ void Fl_Text_Display::update_h_scrollbar() {
/**
- \brief Callbacks for drag or valueChanged on scrollbars.
+ \brief Callbacks for drag or valueChanged on vertical scrollbar.
*/
void Fl_Text_Display::v_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) {
if (b->value() == textD->mTopLineNum) return;
@@ -2844,7 +2920,7 @@ void Fl_Text_Display::v_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) {
/**
- \brief Callbacks for drag or valueChanged on scrollbars.
+ \brief Callbacks for drag or valueChanged on horizontal scrollbar.
*/
void Fl_Text_Display::h_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) {
if (b->value() == textD->mHorizOffset) return;
@@ -2876,22 +2952,29 @@ void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) {
if (mLineNumWidth <= 0 || !visible_r())
return;
- // Make sure we reset clipping range for line number's GC;
- // it may be shared (e.g. if line numbers and text have same color)
- // and therefore clipping ranges may be invalid.
- int xoff = Fl::box_dx(box());
+ // Make sure we set the correct clipping range for line numbers.
+ // Take scrollbars and positions into account.
int hscroll_h = mHScrollBar->visible() ? mHScrollBar->h() : 0;
+ int vscroll_w = mVScrollBar->visible() ? mVScrollBar->w() : 0;
+ int xoff = Fl::box_dx(box());
+ int yoff = Fl::box_dy(box()) + ((scrollbar_align()&FL_ALIGN_TOP)?hscroll_h:0);
+
+#ifndef LINENUM_LEFT_OF_VSCROLL
+ if (scrollbar_align()&FL_ALIGN_LEFT)
+ xoff += vscroll_w;
+#endif
+
Fl_Color fgcolor = isactive ? linenumber_fgcolor() : fl_inactive(linenumber_fgcolor());
Fl_Color bgcolor = isactive ? linenumber_bgcolor() : fl_inactive(linenumber_bgcolor());
fl_push_clip(x() + xoff,
- y() + Fl::box_dy(box()),
- mLineNumWidth - xoff,
- h() - Fl::box_dh(box()) - hscroll_h);
+ y() + yoff,
+ mLineNumWidth,
+ h() - Fl::box_dw(box()) - hscroll_h);
{
// Set background color for line number area -- LZA / STR# 2621
// Erase background
fl_color(bgcolor);
- fl_rectf(x(), y(), mLineNumWidth, h());
+ fl_rectf(x()+xoff, y(), mLineNumWidth, h());
// Draw separator line
//fl_color(180,180,180);
@@ -2900,7 +2983,7 @@ void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) {
// Draw line number text
fl_font(linenumber_font(), linenumber_size());
- Y = y();
+ Y = y() + yoff;
line = get_absolute_top_line_number();
// set font color for line numbers
@@ -2911,7 +2994,7 @@ void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) {
sprintf(lineNumString, linenumber_format(), line);
int xx = x() + xoff + 3,
yy = Y + 3,
- ww = mLineNumWidth - xoff - (3*2),
+ ww = mLineNumWidth - (3*2),
hh = lineHeight;
fl_draw(lineNumString, xx, yy, ww, hh, linenumber_align(), 0, 0);
//DEBUG fl_rect(xx, yy, ww, hh);
@@ -4052,8 +4135,6 @@ double Fl_Text_Display::col_to_x(double col) const
}
-
-
//
// End of "$Id$".
//