(librunview) Add right-click menu

This commit is contained in:
Jaidyn Ann 2021-07-14 22:10:23 -05:00
parent 9c2ab6ed0a
commit 67ea3cd760
4 changed files with 139 additions and 463 deletions

View File

@ -6,9 +6,16 @@
#include "RunView.h" #include "RunView.h"
#include <Cursor.h> #include <Cursor.h>
#include <Locale.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <Window.h> #include <Window.h>
const uint32 kSearchDdg = 'RVse';
const uint32 kSearchDict = 'RVdc';
RunView::RunView(const char* name) RunView::RunView(const char* name)
: :
BTextView(name), BTextView(name),
@ -33,26 +40,45 @@ RunView::RunView(const char* name)
void void
RunView::Append(const char* text, rgb_color color, uint16 fontFace) RunView::MessageReceived(BMessage* msg)
{ {
BFont font; switch (msg->what)
font.SetFace(fontFace); {
text_run run = { 0, font, color }; case kSearchDdg:
text_run_array array = { 1, {run} }; case kSearchDict:
{
int32 start = 0;
int32 end = 0;
GetSelection(&start, &end);
if (start == end)
break;
char* buffer = new char[end - start];
GetText(start, end - start, buffer);
Insert(text, &array); // Build query
fLastStyled = true; BString query;
} if (msg->what == kSearchDict)
query = "https://%lang%.wiktionary.org/w/index.php?search=%q%";
else
query = "https://duckduckgo.com/?q=%q%";
BLanguage lang;
if (BLocale().GetLanguage(&lang) == B_OK)
query.ReplaceAll("%lang%", lang.Code());
else
query.ReplaceAll("%lang", "eo");
void query.ReplaceAll("%q%", BUrl::UrlEncode(BString(buffer)));
RunView::Append(const char* text)
{ // Send query
if (fLastStyled == false) BUrl url(query.String());
Insert(text); if (url.IsValid())
else url.OpenWithPreferredApplication(true);
Insert(text, &fDefaultRun); break;
fLastStyled = false; }
default:
BTextView::MessageReceived(msg);
}
} }
@ -100,7 +126,9 @@ RunView::MouseDown(BPoint where)
uint32 buttons = 0; uint32 buttons = 0;
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
if (!(buttons & B_SECONDARY_MOUSE_BUTTON)) if (buttons & B_SECONDARY_MOUSE_BUTTON)
_RightClickPopUp(where)->Go(ConvertToScreen(where), true, false);
else
BTextView::MouseDown(where); BTextView::MouseDown(where);
BUrl url; BUrl url;
@ -150,26 +178,63 @@ RunView::Select(int32 startOffset, int32 endOffset)
} }
void
RunView::Append(const char* text, rgb_color color, uint16 fontFace)
{
BFont font;
font.SetFace(fontFace);
text_run run = { 0, font, color };
text_run_array array = { 1, {run} };
Insert(text, &array);
fLastStyled = true;
}
void
RunView::Append(const char* text)
{
if (fLastStyled == false)
Insert(text);
else
Insert(text, &fDefaultRun);
fLastStyled = false;
}
BString BString
RunView::WordAt(BPoint point) RunView::WordAt(BPoint point)
{ {
int32 wordOffset = OffsetAt(point); int32 start = 0;
int32 lineOffset = OffsetAt(LineAt(point)); int32 end = 0;
const char* lineBuff = GetLine(LineAt(point)); BString word;
FindWordAround(OffsetAt(point), &start, &end, &word);
return word;
}
void
RunView::FindWordAround(int32 offset, int32* start, int32* end, BString* _word)
{
int32 lineOffset = OffsetAt(LineAt(offset));
const char* lineBuff = GetLine(LineAt(offset));
BString line(lineBuff); BString line(lineBuff);
delete lineBuff; delete lineBuff;
int32 wordStart = line.FindLast(" ", wordOffset - lineOffset) + 1; int32 wordStart = line.FindLast(" ", offset - lineOffset) + 1;
int32 wordEnd = line.FindFirst(" ", wordOffset - lineOffset); int32 wordEnd = line.FindFirst(" ", offset - lineOffset);
if (wordStart == B_ERROR) if (wordStart == B_ERROR)
wordStart = 0; wordStart = 0;
if (wordEnd == B_ERROR) if (wordEnd == B_ERROR)
wordEnd = line.CountChars(); wordEnd = line.CountChars();
BString buffer; *start = lineOffset + wordStart;
line.CopyCharsInto(buffer, wordStart, wordEnd - wordStart); *end = lineOffset + wordEnd;
return buffer;
if (_word != NULL)
line.CopyCharsInto(*_word, wordStart, wordEnd - wordStart);
} }
@ -220,3 +285,41 @@ RunView::ScrollToBottom()
{ {
ScrollToOffset(TextLength()); ScrollToOffset(TextLength());
} }
BPopUpMenu*
RunView::_RightClickPopUp(BPoint where)
{
BPopUpMenu* menu = new BPopUpMenu("rightClickPopUp");
BMenuItem* ddgSearch =
new BMenuItem("Search" B_UTF8_ELLIPSIS, new BMessage(kSearchDdg));
BMenuItem* dictSearch =
new BMenuItem("Dictionary" B_UTF8_ELLIPSIS, new BMessage(kSearchDict));
BMenuItem* copy =
new BMenuItem("Copy", new BMessage(B_COPY), 'C', B_COMMAND_KEY);
BMenuItem* selectAll = new BMenuItem("Select all",
new BMessage(B_SELECT_ALL), 'A', B_COMMAND_KEY);
// Try and ensure we have something selected
int32 start = 0;
int32 end = 0;
GetSelection(&start, &end);
if (start == end && OverText(where) == true) {
start = 0;
end = 0;
FindWordAround(OffsetAt(where), &start, &end);
Select(start, end);
}
copy->SetEnabled(start < end);
dictSearch->SetEnabled(start < end);
ddgSearch->SetEnabled(start < end);
menu->AddItem(ddgSearch);
menu->AddItem(dictSearch);
menu->AddSeparatorItem();
menu->AddItem(copy);
menu->AddItem(selectAll);
menu->SetTargetForItems(this);
return menu;
}

View File

@ -8,14 +8,14 @@
#include <TextView.h> #include <TextView.h>
#include <Url.h> #include <Url.h>
class BPopUpMenu;
class RunView : public BTextView { class RunView : public BTextView {
public: public:
RunView(const char* name); RunView(const char* name);
void Append(const char* text, rgb_color color, virtual void MessageReceived(BMessage* msg);
uint16 fontFace = B_REGULAR_FACE);
void Append(const char* text);
// Only differs in that it changes font face and color of any URLs // Only differs in that it changes font face and color of any URLs
virtual void Insert(const char* text, const text_run_array* runs = NULL); virtual void Insert(const char* text, const text_run_array* runs = NULL);
@ -26,7 +26,13 @@ public:
virtual void Select(int32 startOffset, int32 endOffset); virtual void Select(int32 startOffset, int32 endOffset);
void Append(const char* text, rgb_color color,
uint16 fontFace = B_REGULAR_FACE);
void Append(const char* text);
BString WordAt(BPoint point); BString WordAt(BPoint point);
void FindWordAround(int32 offset, int32* start, int32* end,
BString* _word = NULL);
const char* GetLine(int32 line); const char* GetLine(int32 line);
bool OverText(BPoint where); bool OverText(BPoint where);
@ -35,6 +41,8 @@ public:
void ScrollToBottom(); void ScrollToBottom();
private: private:
BPopUpMenu* _RightClickPopUp(BPoint where);
bool fLastStyled; bool fLastStyled;
text_run_array fDefaultRun; text_run_array fDefaultRun;
text_run_array fUrlRun; text_run_array fUrlRun;

View File

@ -1,367 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Vision.
*
* The Initial Developer of the Original Code is The Vision Team.
* Portions created by The Vision Team are
* Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
* Reserved.
*
* Contributor(s): Wade Majors <wade@ezri.org>
* Todd Lair
* Andrew Bazan
*/
#include <stdio.h>
#include <time.h>
#include <Application.h>
#include <Roster.h>
#include <Entry.h>
#include <Path.h>
#include <String.h>
const float doubleClickThresh = 6;
BString
GetWord (const char* cData, int32 wordNeeded)
{
/*
* Function purpose: Get word number {wordNeeded} from {cData}
* (space delimited)
*/
BString data (cData);
BString buffer ("-9z99");
int32 wordAt (1), place (0);
while (wordAt != wordNeeded && place != B_ERROR) {
if ((place = data.FindFirst ('\x20', place)) != B_ERROR)
if (++place < data.Length()
&& data[place] != '\x20')
++wordAt;
}
if (wordAt == wordNeeded
&& place != B_ERROR
&& place < data.Length()) {
int32 end (data.FindFirst ('\x20', place));
if (end == B_ERROR)
end = data.Length();
data.CopyInto (buffer, place, end - place);
}
return buffer;
}
BString
GetWordColon (const char* cData, int32 wordNeeded)
{
/*
* Function purpose: Get word number {wordNeeded} from {cData}
* (colon delimited)
*/
BString data (cData);
BString buffer ("-9z99");
int32 wordAt (1), place (0);
while (wordAt != wordNeeded && place != B_ERROR) {
if ((place = data.FindFirst (':', place)) != B_ERROR)
if (++place < data.Length()
&& data[place] != ':')
++wordAt;
}
if (wordAt == wordNeeded
&& place != B_ERROR
&& place < data.Length()) {
int32 end (data.FindFirst (':', place));
if (end == B_ERROR)
end = data.Length();
data.CopyInto (buffer, place, end - place);
}
return buffer;
}
BString
RestOfString (const char* cData, int32 wordStart)
{
/*
* Function purpose: Get word number {wordStart} from {cData}
* append the rest of the string after {wordStart}
* (space delimited)
*/
BString data (cData);
int32 wordAt (1), place (0);
BString buffer ("-9z99");
while (wordAt != wordStart && place != B_ERROR) {
if ((place = data.FindFirst ('\x20', place)) != B_ERROR)
if (++place < data.Length()
&& data[place] != '\x20')
++wordAt;
}
if (wordAt == wordStart
&& place != B_ERROR
&& place < data.Length())
data.CopyInto (buffer, place, data.Length() - place);
return buffer;
}
BString
GetNick (const char* cData)
{
/*
* Function purpose: Get nickname from {cData}
*
* Expected format: nickname!user@host.name
*/
BString data (cData);
BString theNick;
for (int32 i = 1; i < data.Length() && data[i] != '!' && data[i] != '\x20'; ++i)
theNick += data[i];
return theNick;
}
BString
GetIdent (const char* cData)
{
/*
* Function purpose: Get identname/username from {cData}
*
* Expected format: nickname!user@host.name
*/
BString data (GetWord(cData, 1));
BString theIdent;
int32 place[2];
if ((place[0] = data.FindFirst ('!')) != B_ERROR
&& (place[1] = data.FindFirst ('@')) != B_ERROR) {
++(place[0]);
data.CopyInto (theIdent, place[0], place[1] - place[0]);
}
return theIdent;
}
BString
GetAddress (const char* cData)
{
/*
* Function purpose: Get address/hostname from {cData}
*
* Expected format: nickname!user@host.name
*/
BString data (GetWord(cData, 1));
BString address;
int32 place;
if ((place = data.FindFirst ('@')) != B_ERROR) {
int32 length (data.FindFirst ('\x20', place));
if (length == B_ERROR)
length = data.Length();
++place;
data.CopyInto (address, place, length - place);
}
return address;
}
BString
TimeStamp()
{
/*
* Function purpose: Return the timestamp string
*
*/
// if(!vision_app->GetBool ("timestamp"))
// return "";
// const char *ts_format (vision_app->GetString ("timestamp_format"));
const char* ts_format = "[%H:%M]";
time_t myTime (time (0));
tm curTime;
localtime_r (&myTime, &curTime);
char tempTime[32];
tempTime[strftime (tempTime, 31, ts_format, &curTime)] = '\0';
return BString (tempTime).Append('\x20', 1);
}
BString
ExpandKeyed (
const char* incoming,
const char* keys,
const char** expansions)
{
BString buffer;
while (incoming && *incoming) {
if (*incoming == '$') {
const char* place;
++incoming;
if ((place = strchr (keys, *incoming)) != 0)
buffer += expansions[place - keys];
else
buffer += *incoming;
} else
buffer += *incoming;
++incoming;
}
buffer += "\n";
return buffer;
}
BString
StringToURI (const char* string)
{
/*
* Function purpose: Converts {string} to a URI safe format
*
*/
BString buffer (string);
buffer.ToLower();
buffer.ReplaceAll ("%", "%25"); // do this first!
buffer.ReplaceAll ("\n", "%20");
buffer.ReplaceAll (" ", "%20");
buffer.ReplaceAll ("\"", "%22");
buffer.ReplaceAll ("#", "%23");
buffer.ReplaceAll ("@", "%40");
buffer.ReplaceAll ("`", "%60");
buffer.ReplaceAll (":", "%3A");
buffer.ReplaceAll ("<", "%3C");
buffer.ReplaceAll (">", "%3E");
buffer.ReplaceAll ("[", "%5B");
buffer.ReplaceAll ("\\", "%5C");
buffer.ReplaceAll ("]", "%5D");
buffer.ReplaceAll ("^", "%5E");
buffer.ReplaceAll ("{", "%7B");
buffer.ReplaceAll ("|", "%7C");
buffer.ReplaceAll ("}", "%7D");
buffer.ReplaceAll ("~", "%7E");
return buffer;
}
BString
DurationString (int64 value)
{
/*
* Function purpose: Return a duration string based on {value}
*
*/
BString duration;
bigtime_t micro = value;
bigtime_t milli = micro / 1000;
bigtime_t sec = milli / 1000;
bigtime_t min = sec / 60;
bigtime_t hours = min / 60;
bigtime_t days = hours / 24;
char message[512] = "";
if (days)
sprintf(message, "%Ld day%s ", days, days != 1 ? "s" : "");
if (hours % 24)
sprintf(message, "%s%Ld hr%s ", message, hours % 24, (hours % 24) != 1 ? "s" : "");
if (min % 60)
sprintf(message, "%s%Ld min%s ", message, min % 60, (min % 60) != 1 ? "s" : "");
sprintf(message, "%s%Ld.%Ld sec%s", message, sec % 60, (milli % 1000), (sec % 60) != 1 ? "s" : "");
duration += message;
return duration;
}
const char *
RelToAbsPath (const char* append_)
{
app_info ai;
be_app->GetAppInfo (&ai);
BEntry entry (&ai.ref);
BPath path;
entry.GetPath (&path);
path.GetParent (&path);
path.Append (append_);
return path.Path();
}
int32
Get440Len (const char* cData)
{
BString data (cData);
if (data.Length() < 440)
return data.Length();
else {
int32 place (data.FindLast ('\x20', 440));
if (place == B_ERROR)
return 440;
return place;
}
}
uint16
CheckClickCount(BPoint point, BPoint& lastClick, bigtime_t sysTime, bigtime_t& lastClickTime, int16& clickCount)
{
// check time and proximity
BPoint delta = point - lastClick;
bigtime_t timeDelta = sysTime - lastClickTime;
bigtime_t doubleClickSpeed;
get_click_speed(&doubleClickSpeed);
lastClickTime = sysTime;
if (timeDelta < doubleClickSpeed
&& fabs(delta.x) < doubleClickThresh
&& fabs(delta.y) < doubleClickThresh)
return (++clickCount);
lastClick = point;
clickCount = 1;
return clickCount;
}

View File

@ -1,68 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Vision.
*
* The Initial Developer of the Original Code is The Vision Team.
* Portions created by The Vision Team are
* Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
* Reserved.
*
* Contributor(s): Wade Majors <wade@ezri.org>
* Todd Lair
* Andrew Bazan
*/
#ifndef _UTILITIES_H
#define _UTILITIES_H_
#include <String.h>
template<class T> class AutoDestructor
{
public:
AutoDestructor(T* t) {
fObject = t;
}
virtual ~AutoDestructor(void) {
delete fObject;
}
void SetTo(T* t) {
delete fObject;
fObject = t;
}
private:
T* fObject;
};
class BMessage;
class BPoint;
BString GetWord (const char*, int32);
BString RestOfString (const char*, int32);
BString GetNick (const char*);
BString GetIdent (const char*);
BString GetAddress (const char*);
BString TimeStamp (void);
BString ExpandKeyed (const char*, const char*, const char**);
BString DurationString (int64);
BString StringToURI (const char*);
const char* RelToAbsPath (const char*);
BString GetWordColon (const char*, int32);
int32 Get440Len (const char*);
uint16 CheckClickCount(BPoint, BPoint&, bigtime_t, bigtime_t&, int16&);
#endif