(librunview) URL hover-over/visited colouring
This commit is contained in:
parent
67ea3cd760
commit
b7c7ad6064
|
@ -9,6 +9,8 @@
|
||||||
#include <Locale.h>
|
#include <Locale.h>
|
||||||
#include <MenuItem.h>
|
#include <MenuItem.h>
|
||||||
#include <PopUpMenu.h>
|
#include <PopUpMenu.h>
|
||||||
|
#include <ScrollBar.h>
|
||||||
|
#include <TextView.h>
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +38,12 @@ RunView::RunView(const char* name)
|
||||||
urlFont.SetFace(B_UNDERSCORE_FACE);
|
urlFont.SetFace(B_UNDERSCORE_FACE);
|
||||||
text_run urlRun = { 0, urlFont, ui_color(B_LINK_TEXT_COLOR) };
|
text_run urlRun = { 0, urlFont, ui_color(B_LINK_TEXT_COLOR) };
|
||||||
fUrlRun = { 1, {urlRun} };
|
fUrlRun = { 1, {urlRun} };
|
||||||
|
|
||||||
|
text_run urlHoverRun = { 0, urlFont, ui_color(B_LINK_HOVER_COLOR) };
|
||||||
|
fUrlHoverRun = { 1, {urlHoverRun} };
|
||||||
|
|
||||||
|
text_run urlVisitedRun = { 0, urlFont, ui_color(B_LINK_VISITED_COLOR) };
|
||||||
|
fUrlVisitedRun = { 1, {urlVisitedRun} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,35 +95,27 @@ RunView::Insert(const char* text, const text_run_array* runs)
|
||||||
{
|
{
|
||||||
BString buf(text);
|
BString buf(text);
|
||||||
|
|
||||||
int32 urlOffset = 0;
|
int32 specStart = 0;
|
||||||
|
int32 specEnd = 0;
|
||||||
int32 lastEnd = 0;
|
int32 lastEnd = 0;
|
||||||
while (lastEnd < buf.CountChars() && urlOffset != B_ERROR)
|
int32 length = buf.CountChars();
|
||||||
{
|
|
||||||
urlOffset = buf.FindFirst("://", lastEnd);
|
|
||||||
|
|
||||||
int32 urlStart = buf.FindLast(" ", urlOffset) + 1;
|
while (_FindUrlString(buf, &specStart, &specEnd, lastEnd) == true) {
|
||||||
int32 urlEnd = buf.FindFirst(" ", urlOffset);
|
if (lastEnd < specStart) {
|
||||||
if (urlStart == B_ERROR || urlOffset == B_ERROR)
|
BString normie;
|
||||||
urlStart = lastEnd;
|
buf.CopyCharsInto(normie, lastEnd, specStart - lastEnd);
|
||||||
if (urlEnd == B_ERROR || urlOffset == B_ERROR)
|
BTextView::Insert(normie.String(), runs);
|
||||||
urlEnd = buf.CountChars();
|
|
||||||
|
|
||||||
BString url;
|
|
||||||
BString nonurl;
|
|
||||||
if (urlOffset == B_ERROR)
|
|
||||||
buf.CopyCharsInto(nonurl, urlStart, urlEnd - urlStart);
|
|
||||||
else {
|
|
||||||
buf.CopyCharsInto(nonurl, lastEnd, urlStart - lastEnd);
|
|
||||||
buf.CopyCharsInto(url, urlStart, urlEnd - urlStart);
|
|
||||||
}
|
}
|
||||||
|
BString special;
|
||||||
|
buf.CopyCharsInto(special, specStart, specEnd - specStart);
|
||||||
|
BTextView::Insert(special.String(), &fUrlRun);
|
||||||
|
|
||||||
// Actually insert the text
|
lastEnd = specEnd;
|
||||||
if (nonurl.IsEmpty() == false)
|
}
|
||||||
BTextView::Insert(nonurl.String(), runs);
|
if (lastEnd < length) {
|
||||||
if (url.IsEmpty() == false)
|
BString remaining;
|
||||||
BTextView::Insert(url.String(), &fUrlRun);
|
buf.CopyCharsInto(remaining, lastEnd, length - lastEnd);
|
||||||
|
BTextView::Insert(remaining.String(), runs);
|
||||||
lastEnd = urlEnd;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +131,13 @@ RunView::MouseDown(BPoint where)
|
||||||
else
|
else
|
||||||
BTextView::MouseDown(where);
|
BTextView::MouseDown(where);
|
||||||
|
|
||||||
BUrl url;
|
if ((buttons & B_PRIMARY_MOUSE_BUTTON) && OverUrl(where)) {
|
||||||
if ((buttons & B_PRIMARY_MOUSE_BUTTON) && OverUrl(where, &url)) {
|
|
||||||
fMouseDown = true;
|
fMouseDown = true;
|
||||||
if (url.IsValid() == true)
|
|
||||||
|
BUrl url(WordAt(where));
|
||||||
|
if (url.IsValid() == true) {
|
||||||
fLastClicked = url;
|
fLastClicked = url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +150,8 @@ RunView::MouseUp(BPoint where)
|
||||||
if (fMouseDown && fSelecting == false && fLastClicked.IsValid() == true) {
|
if (fMouseDown && fSelecting == false && fLastClicked.IsValid() == true) {
|
||||||
fLastClicked.OpenWithPreferredApplication(true);
|
fLastClicked.OpenWithPreferredApplication(true);
|
||||||
fLastClicked = BUrl();
|
fLastClicked = BUrl();
|
||||||
|
// When cursor moves off URL, change color
|
||||||
|
fCurrentUrlRuns = fUrlVisitedRun;
|
||||||
}
|
}
|
||||||
fMouseDown = false;
|
fMouseDown = false;
|
||||||
fSelecting = false;
|
fSelecting = false;
|
||||||
|
@ -160,11 +164,29 @@ RunView::MouseMoved(BPoint where, uint32 code, const BMessage* drag)
|
||||||
if (fSelecting == true)
|
if (fSelecting == true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Change the cursor and "hover-over" highlight for URLs
|
||||||
if (code == B_INSIDE_VIEW)
|
if (code == B_INSIDE_VIEW)
|
||||||
if (OverUrl(where) == true)
|
if (OverUrl(where) == true) {
|
||||||
|
int32 start = 0;
|
||||||
|
int32 end = 0;
|
||||||
|
FindWordAround(OffsetAt(where), &start, &end);
|
||||||
|
if (fCurrentUrlEnd == 0) {
|
||||||
|
fCurrentUrlRuns = *RunArray(start, end);
|
||||||
|
fCurrentUrlStart = start;
|
||||||
|
fCurrentUrlEnd = end;
|
||||||
|
|
||||||
|
ReplaceRuns(start, end, &fUrlHoverRun);
|
||||||
|
}
|
||||||
SetViewCursor(fUrlCursor);
|
SetViewCursor(fUrlCursor);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
|
if (fCurrentUrlEnd != 0) {
|
||||||
|
ReplaceRuns(fCurrentUrlStart, fCurrentUrlEnd, &fCurrentUrlRuns);
|
||||||
|
fCurrentUrlStart = 0;
|
||||||
|
fCurrentUrlEnd = 0;
|
||||||
|
}
|
||||||
SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
|
SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,6 +224,26 @@ RunView::Append(const char* text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RunView::Replace(int32 start, int32 end, const char* text, text_run_array* runs)
|
||||||
|
{
|
||||||
|
Delete(start, end);
|
||||||
|
BTextView::Insert(start, text, strlen(text), runs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RunView::ReplaceRuns(int32 start, int32 end, text_run_array* runs)
|
||||||
|
{
|
||||||
|
char* buffer = new char[end - start];
|
||||||
|
GetText(start, end - start, buffer);
|
||||||
|
|
||||||
|
float current = ScrollBar(B_VERTICAL)->Value();
|
||||||
|
Replace(start, end, buffer, runs);
|
||||||
|
ScrollBar(B_VERTICAL)->SetValue(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
RunView::WordAt(BPoint point)
|
RunView::WordAt(BPoint point)
|
||||||
{
|
{
|
||||||
|
@ -265,17 +307,23 @@ RunView::OverText(BPoint where)
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RunView::OverUrl(BPoint where, BUrl* url)
|
RunView::OverUrl(BPoint where)
|
||||||
{
|
{
|
||||||
if (OverText(where) == false)
|
if (OverText(where) == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
BString word = WordAt(where);
|
int32 offset = OffsetAt(where);
|
||||||
if (BUrl(word.String()).IsValid() == true) {
|
text_run_array* rArray = RunArray(offset, offset + 1);
|
||||||
if (url != NULL)
|
text_run run = rArray->runs[0];
|
||||||
url->SetUrlString(word);
|
text_run urlRun = fUrlRun.runs[0];
|
||||||
|
text_run urlHover = fUrlHoverRun.runs[0];
|
||||||
|
text_run urlVisit = fUrlVisitedRun.runs[0];
|
||||||
|
|
||||||
|
if ((run.font == urlRun.font || run.font == urlHover.font
|
||||||
|
|| run.font == urlVisit.font)
|
||||||
|
&& (run.color == urlRun.color || run.color == urlHover.color
|
||||||
|
|| run.color == urlVisit.color))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,3 +371,21 @@ RunView::_RightClickPopUp(BPoint where)
|
||||||
menu->SetTargetForItems(this);
|
menu->SetTargetForItems(this);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
RunView::_FindUrlString(BString text, int32* start, int32* end, int32 offset)
|
||||||
|
{
|
||||||
|
int32 urlOffset = text.FindFirst("://", offset);
|
||||||
|
int32 urlStart = text.FindLast(" ", urlOffset) + 1;
|
||||||
|
int32 urlEnd = text.FindFirst(" ", urlOffset);
|
||||||
|
if (urlStart == B_ERROR) urlStart = 0;
|
||||||
|
if (urlEnd == B_ERROR) urlEnd = text.CountChars();
|
||||||
|
|
||||||
|
if (urlOffset != B_ERROR) {
|
||||||
|
*start = urlStart;
|
||||||
|
*end = urlEnd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -30,24 +30,42 @@ public:
|
||||||
uint16 fontFace = B_REGULAR_FACE);
|
uint16 fontFace = B_REGULAR_FACE);
|
||||||
void Append(const char* text);
|
void Append(const char* text);
|
||||||
|
|
||||||
|
void Replace(int32 start, int32 end, const char* text,
|
||||||
|
text_run_array* runs);
|
||||||
|
void ReplaceRuns(int32 start, int32 end, text_run_array* runs);
|
||||||
|
|
||||||
BString WordAt(BPoint point);
|
BString WordAt(BPoint point);
|
||||||
void FindWordAround(int32 offset, int32* start, int32* end,
|
void FindWordAround(int32 offset, int32* start, int32* end,
|
||||||
BString* _word = NULL);
|
BString* _word = NULL);
|
||||||
const char* GetLine(int32 line);
|
const char* GetLine(int32 line);
|
||||||
|
|
||||||
bool OverText(BPoint where);
|
bool OverText(BPoint where);
|
||||||
bool OverUrl(BPoint where, BUrl* url = NULL);
|
bool OverUrl(BPoint where);
|
||||||
|
|
||||||
void ScrollToBottom();
|
void ScrollToBottom();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BPopUpMenu* _RightClickPopUp(BPoint where);
|
BPopUpMenu* _RightClickPopUp(BPoint where);
|
||||||
|
|
||||||
bool fLastStyled;
|
bool _FindUrlString(BString text, int32* start, int32* end,
|
||||||
|
int32 offset);
|
||||||
|
|
||||||
|
// For safe-keeping
|
||||||
text_run_array fDefaultRun;
|
text_run_array fDefaultRun;
|
||||||
text_run_array fUrlRun;
|
text_run_array fUrlRun;
|
||||||
|
text_run_array fUrlHoverRun;
|
||||||
|
text_run_array fUrlVisitedRun;
|
||||||
BCursor* fUrlCursor;
|
BCursor* fUrlCursor;
|
||||||
|
|
||||||
|
// Whether or not the run was changed from default
|
||||||
|
bool fLastStyled;
|
||||||
|
|
||||||
|
// Used for the "hover over" URL highlighting
|
||||||
|
text_run_array fCurrentUrlRuns;
|
||||||
|
int32 fCurrentUrlStart;
|
||||||
|
int32 fCurrentUrlEnd;
|
||||||
|
|
||||||
|
// Information between MouseDown and MouseUp
|
||||||
BUrl fLastClicked;
|
BUrl fLastClicked;
|
||||||
bool fMouseDown;
|
bool fMouseDown;
|
||||||
bool fSelecting;
|
bool fSelecting;
|
||||||
|
|
Ŝarĝante…
Reference in New Issue