Slight RunView reformatting

This commit is contained in:
Jaidyn Ann 2021-06-07 13:34:20 -05:00
parent c8a62610ca
commit 2d34b4edde

View File

@ -30,33 +30,35 @@
#define ABS(x) (x * ((x<0) ? -1 : 1))
#define SOFTBREAK_STEP 5
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include "RunView.h"
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <Bitmap.h>
#include <Clipboard.h>
#include <Cursor.h>
#include <MenuItem.h>
#include <Message.h>
#include <Messenger.h>
#include <MessageRunner.h>
#include <PopUpMenu.h>
#include <MenuItem.h>
#include <ObjectList.h>
#include <ScrollView.h>
#include <PopUpMenu.h>
#include <ScrollBar.h>
#include <ScrollView.h>
#include <Region.h>
#include <Window.h>
#include <Roster.h>
#include "Theme.h"
#include "RunView.h"
#include "URLCrunch.h"
#include "Utilities.h"
#include <Roster.h>
#include <stdlib.h>
#define _T(str) (str)
@ -69,40 +71,44 @@ static unsigned char URLCursorData[] = {16, 1, 2, 2,
15, 255, 63, 255, 127, 255, 127, 255, 63, 255, 15, 255, 3, 254, 1, 248
};
struct SoftBreak {
int fOffset;
float fHeight;
float fAscent;
};
struct URL {
int fOffset;
int fLength;
BString fUrl;
URL(const char* address, int off, int len)
:
fOffset (off),
fLength (len),
fUrl (address) {}
: fOffset (off), fLength (len), fUrl (address)
{ }
};
typedef BObjectList<URL> urllist;
struct SoftBreakEnd {
float fOffset;
SoftBreakEnd(float offset)
:
fOffset(offset) {}
: fOffset(offset)
{ }
};
struct FontColor {
int fOffset;
int fWhich;
int fIndex;
};
struct Line {
char* fText;
time_t fStamp;
@ -121,41 +127,34 @@ struct Line {
int fSoftie_size;
int fSoftie_used;
Line (
const char* buffer,
int fLength,
float top,
float width,
Theme* fTheme,
const char* fStamp_format,
int fore,
int back,
int font);
Line(const char* buffer, int fLength, float top, float width, Theme* fTheme,
const char* fStamp_format, int fore, int back, int font);
~Line (void);
~Line ();
void Append(const char* buffer, int len,
float width, Theme* fTheme,
int fore, int back, int font);
void Append(const char* buffer, int len, float width,
Theme* fTheme, int fore, int back, int font);
void FigureSpaces (void);
void FigureSpaces();
void FigureFontColors(int pos, int fore, int back, int font);
void FigureEdges(Theme* fTheme, float width);
void SoftBreaks(Theme* fTheme, float width);
void AddSoftBreak(SoftBreakEnd , float&,
int&, int16&, float&, float&, Theme*);
void AddSoftBreak(SoftBreakEnd, float&, int&, int16&, float&,
float&, Theme*);
int CountChars(int pos, int len);
size_t SetStamp(const char*, bool);
void SelectWord(int*, int*);
};
inline int32
UTF8_CHAR_LEN (uchar c)
{
return (((0xE5000000 >> (((c) >> 3) & 0x1E)) & 3) + 1);
}
RunView::RunView(BRect frame, const char* name, Theme* theme,
uint32 resizingMode, uint32 flags)
:
@ -178,7 +177,6 @@ RunView::RunView(BRect frame, const char* name, Theme* theme,
fLastClick (0, 0),
fLastClickTime (0)
{
memset (fLines, 0, sizeof (fLines));
fURLCursor = new BCursor (URLCursorData);
@ -190,7 +188,7 @@ RunView::RunView(BRect frame, const char* name, Theme* theme,
}
RunView::~RunView (void)
RunView::~RunView()
{
for (int16 i = 0; i < fLine_count; ++i)
delete fLines[i];
@ -201,8 +199,9 @@ RunView::~RunView (void)
delete [] fClipping_name;
}
void
RunView::AttachedToWindow (void)
RunView::AttachedToWindow()
{
BView::AttachedToWindow();
RecalcScrollBar (false);
@ -211,14 +210,16 @@ RunView::AttachedToWindow (void)
fTheme->WriteUnlock();
}
void
RunView::DetachedFromWindow (void)
RunView::DetachedFromWindow()
{
fTheme->WriteLock();
fTheme->RemoveView (this);
fTheme->WriteUnlock();
}
void
RunView::FrameResized(float start_width, float height)
{
@ -231,6 +232,7 @@ RunView::FrameResized (float start_width, float height)
ResizeRecalc();
}
void
RunView::TargetedByScrollView (BScrollView* s)
{
@ -238,8 +240,9 @@ RunView::TargetedByScrollView (BScrollView* s)
BView::TargetedByScrollView (fScroller);
}
void
RunView::Show (void)
RunView::Show()
{
if (fFontsdirty) {
FontChangeRecalc();
@ -254,6 +257,7 @@ RunView::Show (void)
BView::Show();
}
void
RunView::Draw(BRect frame)
{
@ -274,23 +278,22 @@ RunView::Draw (BRect frame)
fTheme->ReadLock();
view_color = fTheme->BackgroundAt (Theme::NormalBack);
sel_color = fTheme->BackgroundAt (Theme::SelectionBack);
if (((sel_color.red + sel_color.blue + sel_color.green) / 3) >= 127) {
sel_fText.red = sel_fText.green = sel_fText.blue = 0;
sel_fText.alpha = 255;
} else {
}
else {
sel_fText.red = sel_fText.green = sel_fText.blue = sel_fText.alpha = 255;
}
BRect remains;
if (fLine_count == 0)
remains = frame;
else if (frame.bottom >= fLines[fLine_count - 1]->fBottom + 1.0)
remains.Set (
frame.left,
fLines[fLine_count - 1]->fBottom + 1,
frame.right,
frame.bottom);
remains.Set(frame.left, fLines[fLine_count - 1]->fBottom + 1,
frame.right, frame.bottom);
if (remains.IsValid()) {
SetLowColor (view_color);
@ -437,10 +440,7 @@ RunView::Draw (BRect frame)
while (line->fEdges[k] == 0)
--k;
r.Set (
left,
height,
line->fEdges[k] + indent - start,
r.Set(left, height, line->fEdges[k] + indent - start,
height + line->fSofties[sit].fHeight - 1);
SetDrawingMode (B_OP_COPY);
@ -456,15 +456,12 @@ RunView::Draw (BRect frame)
SetDrawingMode (B_OP_OVER);
if ( sit >= line->fSoftie_used ) {
if ( sit >= line->fSoftie_used )
printf("bah. sit is %d and fSoftie_used is %d\n", sit, line->fSoftie_used);
} else {
tr->Render(this,
line->fText + place,
else
tr->Render(this, line->fText + place,
min_c(fLength, line->fLength - place - 1),
BPoint(left, height + line->fSofties[sit].fAscent));
}
left = line->fEdges[k] + indent - start;
@ -476,11 +473,7 @@ RunView::Draw (BRect frame)
// Margin after fText
SetDrawingMode(B_OP_COPY);
SetLowColor(view_color);
FillRect (
BRect (
left + 1,
height,
bounds.right,
FillRect(BRect(left + 1, height, bounds.right,
height + line->fSofties[sit].fHeight - 1),
B_SOLID_LOW);
@ -497,6 +490,7 @@ RunView::Draw (BRect frame)
ConstrainClippingRegion (NULL);
}
void
RunView::SetViewColor(rgb_color color)
{
@ -504,8 +498,9 @@ RunView::SetViewColor (rgb_color color)
BView::SetViewColor(color);
}
void
RunView::BuildPopUp (void)
RunView::BuildPopUp()
{
// This function checks certain criteria (fText is selected,
// TextView is editable, etc) to determine fWhich MenuItems
@ -574,6 +569,7 @@ RunView::BuildPopUp (void)
fMyPopUp->SetFont(be_plain_font);
}
bool
RunView::CheckClickBounds(const SelectPos& s, const BPoint& point) const
{
@ -581,6 +577,7 @@ RunView::CheckClickBounds (const SelectPos& s, const BPoint& point) const
&& (point.y <= fLines[s.fLine]->fBottom));
}
void
RunView::MouseDown(BPoint point)
{
@ -640,7 +637,6 @@ RunView::MouseDown (BPoint point)
if (inBounds) {
// select word
fLines[s.fLine]->SelectWord(&start.fOffset, &end.fOffset);
Select(start, end);
return;
}
@ -685,6 +681,7 @@ RunView::MouseDown (BPoint point)
}
}
void
RunView::CheckURLCursor(BPoint point)
{
@ -713,6 +710,7 @@ RunView::CheckURLCursor (BPoint point)
SetViewCursor (B_CURSOR_SYSTEM_DEFAULT);
}
void
RunView::MouseMoved(BPoint point, uint32 transit, const BMessage* msg)
{
@ -861,6 +859,7 @@ RunView::MouseMoved (BPoint point, uint32 transit, const BMessage* msg)
}
}
void
RunView::MouseUp(BPoint point)
{
@ -896,9 +895,9 @@ RunView::MouseUp (BPoint point)
}
fTracking = 0;
}
void
RunView::ExtendTrackingSelect(BPoint point)
{
@ -913,6 +912,7 @@ RunView::ExtendTrackingSelect (BPoint point)
}
}
void
RunView::ShiftTrackingSelect(BPoint point, bool move, bigtime_t timer)
{
@ -997,30 +997,33 @@ RunView::ShiftTrackingSelect (BPoint point, bool move, bigtime_t timer)
ExtendTrackingSelect (point);
}
void
RunView::MessageReceived(BMessage* msg)
{
switch (msg->what) {
switch (msg->what)
{
case M_THEME_FOREGROUND_CHANGE:
case M_THEME_BACKGROUND_CHANGE:
{
if (!IsHidden())
Invalidate (Bounds());
break;
case M_THEME_FONT_CHANGE: {
}
case M_THEME_FONT_CHANGE:
{
Theme* save (fTheme);
fTheme = NULL;
SetTheme (save);
break;
}
case B_SELECT_ALL:
SelectAll();
break;
case B_COPY:
{
if (fSp_start != fSp_end
&& be_clipboard->Lock()) {
BString fText;
@ -1035,8 +1038,9 @@ RunView::MessageReceived (BMessage* msg)
be_clipboard->Unlock();
}
break;
case M_OFFVIEW_SELECTION: {
}
case M_OFFVIEW_SELECTION:
{
BPoint point;
float delta;
bool bottom;
@ -1053,38 +1057,36 @@ RunView::MessageReceived (BMessage* msg)
ShiftTrackingSelect (point, true, OFFVIEW_TIMER);
break;
}
case M_LOOKUP_WEBSTER: {
case M_LOOKUP_WEBSTER:
{
BString lookup;
msg->FindString ("string", &lookup);
lookup = StringToURI (lookup.String());
lookup.Prepend ("http://www.m-w.com/cgi-bin/dictionary?va=");
LoadURL (lookup.String());
}
break;
case M_LOOKUP_GOOGLE: {
}
case M_LOOKUP_GOOGLE:
{
BString lookup;
msg->FindString ("string", &lookup);
lookup = StringToURI (lookup.String());
lookup.Prepend ("http://www.google.com/search?q=");
LoadURL (lookup.String());
}
break;
case M_LOOKUP_ACRONYM: {
}
case M_LOOKUP_ACRONYM:
{
BString lookup;
msg->FindString ("string", &lookup);
lookup = StringToURI (lookup.String());
lookup.Prepend ("http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=");
lookup.Append ("&Find=Find");
LoadURL (lookup.String());
}
break;
case M_CLEAR: {
Clear();
}
case M_CLEAR:
Clear();
break;
default:
@ -1092,8 +1094,9 @@ RunView::MessageReceived (BMessage* msg)
}
}
void
RunView::ResizeRecalc (void)
RunView::ResizeRecalc()
{
float width (Bounds().Width() - (fTheme->TextMargin() * 2));
int fSoftie_size (0), fSoftie_used (0);
@ -1153,8 +1156,9 @@ RunView::ResizeRecalc (void)
delete [] fSofties;
}
void
RunView::FontChangeRecalc (void)
RunView::FontChangeRecalc()
{
float width (Bounds().Width() - (fTheme->TextMargin() * 2));
float top (0.0);
@ -1177,6 +1181,7 @@ RunView::FontChangeRecalc (void)
if (Window()) Window()->UpdateIfNeeded();
}
bool
RunView::RecalcScrollBar(bool constrain)
{
@ -1227,33 +1232,24 @@ RunView::RecalcScrollBar (bool constrain)
return changed;
}
void
RunView::Append (
const char* buffer,
int fore,
int back,
int font)
RunView::Append(const char* buffer, int fore, int back, int font)
{
Append(buffer, strlen(buffer), fore, back, font);
}
void
RunView::Append (
const char* buffer,
int32 len,
int fore,
int back,
int font)
RunView::Append(const char* buffer, int32 len, int fore, int back, int font)
{
if (buffer == NULL)
return;
float width(Bounds().Width() - 10);
int32 place(0);
assert (fore != Theme::TimestampFore);
assert(back != Theme::TimestampBack);
assert(font != Theme::TimestampFont);
assert (fore != Theme::TimespaceFore);
assert(back != Theme::TimespaceBack);
assert(font != Theme::TimespaceFont);
assert(back != Theme::SelectionBack);
@ -1266,63 +1262,39 @@ RunView::Append (
while (end < len && buffer[end] != '\n')
++end;
if (end < len) ++end;
if (end < len)
++end;
if (fWorking) {
URLCrunch crunch (buffer + place, end - place);
BString temp;
int32 url_offset (0),
last_offset (0);
while ((url_offset = crunch.Crunch (&temp)) != B_ERROR) {
fWorking->Append (buffer + place,
(url_offset - last_offset),
width,
fTheme,
fore,
back,
font);
fWorking->Append(buffer + place, (url_offset - last_offset),
width, fTheme, fore, back, font);
fWorking->Append (temp.String(),
temp.Length(),
width,
fTheme,
C_URL,
back,
F_URL);
fWorking->Append(temp.String(), temp.Length(), width, fTheme,
C_URL, back, F_URL);
place += (url_offset - last_offset) + temp.Length();
last_offset = url_offset + temp.Length();
}
if (place < end)
fWorking->Append (
buffer + place,
end - place,
width,
fTheme,
fore,
back,
font);
} else {
fWorking->Append(buffer + place, end - place, width,
fTheme, fore, back, font);
}
else {
float top(0.0);
if (fLine_count > 0)
top = fLines[fLine_count - 1]->fBottom + (float) 1.0;
//HERE
fWorking = new Line (
buffer + place,
0,
top,
width,
fTheme,
fStamp_format,
fore,
back,
font);
fWorking = new Line(buffer + place, 0, top, width, fTheme,
fStamp_format, fore, back, font);
URLCrunch crunch(buffer + place, end - place);
BString temp;
@ -1330,33 +1302,18 @@ RunView::Append (
last_offset(0);
while ((url_offset = crunch.Crunch(&temp)) != B_ERROR) {
fWorking->Append (buffer + place,
(url_offset - last_offset),
width,
fTheme,
fore,
back,
font);
fWorking->Append (temp.String(),
temp.Length(),
width,
fTheme,
C_URL,
back,
F_URL);
fWorking->Append(buffer + place, (url_offset - last_offset),
width, fTheme, fore, back, font);
fWorking->Append(temp.String(), temp.Length(),
width, fTheme, C_URL, back, F_URL);
place += (url_offset - last_offset) + temp.Length();
last_offset = url_offset + temp.Length();
}
if (place < end)
fWorking->Append (buffer + place,
end - place,
width,
fTheme,
fore,
back,
font);
fWorking->Append(buffer + place, end - place, width,
fTheme, fore, back, font);
}
if (fWorking->fLength
@ -1416,8 +1373,9 @@ RunView::Append (
fTheme->ReadUnlock();
}
void
RunView::Clear (void)
RunView::Clear()
{
for (int16 i = 0; i < fLine_count; ++i)
delete fLines[i];
@ -1434,12 +1392,14 @@ RunView::Clear (void)
fWorking->fTop = 0.0;
}
int16
RunView::LineCount (void) const
RunView::LineCount() const
{
return fLine_count;
}
const char *
RunView::LineAt(int which) const
{
@ -1449,6 +1409,7 @@ RunView::LineAt (int which) const
return fLines[which]->fText;
}
void
RunView::SetTimeStampFormat(const char* format)
{
@ -1495,6 +1456,7 @@ RunView::SetTimeStampFormat (const char* format)
if (Window()) Window()->UpdateIfNeeded();
}
void
RunView::SetTheme(Theme* t)
{
@ -1510,6 +1472,7 @@ RunView::SetTheme (Theme* t)
FontChangeRecalc();
}
SelectPos
RunView::PositionAt(BPoint point) const
{
@ -1566,12 +1529,14 @@ RunView::PositionAt (BPoint point) const
return pos;
}
BPoint
RunView::PointAt(SelectPos s) const
{
return BPoint(fLines[s.fLine]->fTop + fLines[s.fLine]->fBottom / 2, fLines[s.fLine]->fEdges[s.fOffset]);
}
void
RunView::GetSelectionText(BString& string) const
{
@ -1597,6 +1562,7 @@ RunView::GetSelectionText (BString& string) const
}
}
bool
RunView::IntersectSelection(const SelectPos& start, const SelectPos& end) const
{
@ -1623,6 +1589,7 @@ RunView::IntersectSelection (const SelectPos& start, const SelectPos& end) const
return false;
}
BRect
RunView::GetTextFrame(const SelectPos& start, const SelectPos& end) const
{
@ -1630,6 +1597,7 @@ RunView::GetTextFrame(const SelectPos& start, const SelectPos& end) const
Bounds().Width(), fLines[end.fLine]->fBottom);
}
void
RunView::Select(const SelectPos& start, const SelectPos& end)
{
@ -1683,8 +1651,9 @@ RunView::Select (const SelectPos& start, const SelectPos& end)
}
}
void
RunView::SelectAll (void)
RunView::SelectAll()
{
if (fLine_count) {
fSp_start = SelectPos (0, 0);
@ -1693,6 +1662,7 @@ RunView::SelectAll (void)
}
}
void
RunView::SetClippingName(const char* name)
{
@ -1702,17 +1672,84 @@ RunView::SetClippingName (const char* name)
fClipping_name[strlen(name)] = '\0';
}
Line::Line (
const char* buffer,
int len,
float top,
float width,
Theme* theme,
const char* stamp_format,
int fore,
int back,
int font)
: fText (NULL),
bool
RunView::FindText(const char* text)
{
bool result (false);
if (text != NULL) {
for (int32 i = 0; i < fLine_count; i++) {
char* offset (NULL);
if ((offset = strstr((const char*)fLines[i], text)) != NULL) {
SelectPos start (i, offset - text),
end (i, (offset - text) + strlen(text));
Select(start, end);
ScrollTo(0.0, fLines[i]->fTop);
result = true;
break;
}
}
}
return result;
}
void RunView::LoadURL(const char* url)
{
BString argument (url);
if (argument.FindFirst ("://") == B_ERROR) {
if (argument.IFindFirst ("www") == 0)
argument.Prepend ("http://");
else if (argument.IFindFirst ("ftp") == 0)
argument.Prepend ("ftp://");
}
const char* args[] = { argument.String(), 0 };
if (argument.IFindFirst ("file:") == 0) {
// The URL is guaranteed to be at least "file:/"
BString file(argument.String() + 5);
// todo: Should probably see if the file exists before going through
// all this, but, oh well... ;)
file.Prepend("/boot/beos/system/Tracker ");
file += " &"; // just in case
system(file.String());
} else if (argument.IFindFirst ("mailto:") == 0) {
be_roster->Launch ("text/x-email", 1, const_cast<char**>(args));
} else {
be_roster->Launch ("text/html", 1, const_cast<char**>(args));
}
}
void RunView::ScrollToBottom()
{
if (fLine_count != 0) {
BScrollBar* scroll = fScroller->ScrollBar(B_VERTICAL);
if (scroll != NULL) scroll->SetValue(fLines[fLine_count - 1]->fBottom);
ScrollTo(0.0, fLines[fLine_count - 1]->fBottom);
};
};
void RunView::ScrollToSelection()
{
if (fLine_count == 0) return;
if (fSp_start != fSp_end)
ScrollTo(0.0, fLines[fSp_start.fLine]->fTop);
};
Line::Line(const char* buffer, int len, float top, float width, Theme* theme,
const char* stamp_format, int fore, int back, int font)
:
fText (NULL),
fStamp (time(NULL)),
fUrls (NULL),
fSpaces (NULL),
@ -1730,11 +1767,11 @@ Line::Line (
{
// Very important to call SetStamp before Append, It would look real funny otherwise!
SetStamp(stamp_format, false );
Append(buffer, len, width, theme, fore, back, font );
}
Line::~Line (void)
Line::~Line()
{
delete [] fSpaces;
delete [] fEdges;
@ -1749,15 +1786,10 @@ Line::~Line (void)
}
}
void
Line::Append (
const char* buffer,
int len,
float width,
Theme* theme,
int fore,
int back,
int font)
Line::Append(const char* buffer, int len, float width, Theme* theme,
int fore, int back, int font)
{
int save (fLength);
char* new_fText;
@ -1798,8 +1830,9 @@ Line::Append (
}
}
void
Line::FigureSpaces (void)
Line::FigureSpaces()
{
const char spacers[] = " \t\n-\\/";
const char* buffer (fText);
@ -1822,12 +1855,9 @@ Line::FigureSpaces (void)
}
}
void
Line::FigureFontColors (
int pos,
int fore,
int back,
int font)
Line::FigureFontColors(int pos, int fore, int back, int font)
{
if (fFc_count) {
int last_fore = -1;
@ -1904,10 +1934,9 @@ Line::FigureFontColors (
}
}
void
Line::FigureEdges (
Theme* theme,
float width)
Line::FigureEdges(Theme* theme, float width)
{
delete [] fEdges;
fEdges = new float [fLength];
@ -2100,6 +2129,7 @@ Line::AddSoftBreak (SoftBreakEnd sbe, float& start, int& fText_place,
width = start_width - (theme->SoftLineIndent());
}
void
Line::SoftBreaks(Theme* theme, float start_width)
{
@ -2191,6 +2221,7 @@ Line::SoftBreaks (Theme* theme, float start_width)
fBottom -= 1;
}
int
Line::CountChars(int pos, int len)
{
@ -2211,6 +2242,7 @@ Line::CountChars (int pos, int len)
return ccount;
}
size_t
Line::SetStamp(const char* format, bool was_on)
{
@ -2301,6 +2333,7 @@ Line::SetStamp (const char* format, bool was_on)
return size;
}
void
Line::SelectWord(int* start, int* end)
{
@ -2319,71 +2352,4 @@ Line::SelectWord (int* start, int* end)
*end = end_tmp;
}
bool
RunView::FindText(const char* text)
{
bool result (false);
if (text != NULL) {
for (int32 i = 0; i < fLine_count; i++) {
char* offset (NULL);
if ((offset = strstr((const char*)fLines[i], text)) != NULL) {
SelectPos start (i, offset - text),
end (i, (offset - text) + strlen(text));
Select(start, end);
ScrollTo(0.0, fLines[i]->fTop);
result = true;
break;
}
}
}
return result;
}
void RunView::LoadURL(const char* url)
{
BString argument (url);
if (argument.FindFirst ("://") == B_ERROR) {
if (argument.IFindFirst ("www") == 0)
argument.Prepend ("http://");
else if (argument.IFindFirst ("ftp") == 0)
argument.Prepend ("ftp://");
}
const char* args[] = { argument.String(), 0 };
if (argument.IFindFirst ("file:") == 0) {
// The URL is guaranteed to be at least "file:/"
BString file(argument.String() + 5);
// todo: Should probably see if the file exists before going through
// all this, but, oh well... ;)
file.Prepend("/boot/beos/system/Tracker ");
file += " &"; // just in case
system(file.String());
} else if (argument.IFindFirst ("mailto:") == 0) {
be_roster->Launch ("text/x-email", 1, const_cast<char**>(args));
} else {
be_roster->Launch ("text/html", 1, const_cast<char**>(args));
}
}
void RunView::ScrollToBottom(void)
{
if (fLine_count != 0) {
BScrollBar* scroll = fScroller->ScrollBar(B_VERTICAL);
if (scroll != NULL) scroll->SetValue(fLines[fLine_count - 1]->fBottom);
ScrollTo(0.0, fLines[fLine_count - 1]->fBottom);
};
};
void RunView::ScrollToSelection(void)
{
if (fLine_count == 0) return;
if (fSp_start != fSp_end)
ScrollTo(0.0, fLines[fSp_start.fLine]->fTop);
};