/*
* Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "URLInputGroup.h"
#include <Bitmap.h>
#include <Button.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Clipboard.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <Locale.h>
#include <LayoutUtils.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <SeparatorView.h>
#include <TextView.h>
#include <Window.h>
#include <stdio.h>
#include <stdlib.h>
#include "BaseURL.h"
#include "BitmapButton.h"
#include "BrowsingHistory.h"
#include "IconButton.h"
#include "IconUtils.h"
#include "TextViewCompleter.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "URL Bar"
class URLChoice : public BAutoCompleter::Choice {
public:
URLChoice(const BString& choiceText, const BString& displayText,
int32 matchPos, int32 matchLen, int32 priority)
:
BAutoCompleter::Choice(choiceText, displayText, matchPos, matchLen),
fPriority(priority)
{
}
bool operator<(const URLChoice& other) const
{
if (fPriority > other.fPriority)
return true;
return DisplayText() < other.DisplayText();
}
bool operator==(const URLChoice& other) const
{
return fPriority == other.fPriority
&& DisplayText() < other.DisplayText();
}
private:
int32 fPriority;
};
class BrowsingHistoryChoiceModel : public BAutoCompleter::ChoiceModel {
virtual void FetchChoicesFor(const BString& pattern)
{
int32 count = CountChoices();
for (int32 i = 0; i < count; i++) {
delete reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAtFast(i));
}
fChoices.MakeEmpty();
// Search through BrowsingHistory for any matches.
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
if (!history->Lock())
return;
BString lastBaseURL;
int32 priority = INT_MAX;
count = history->CountItems();
for (int32 i = 0; i < count; i++) {
BrowsingHistoryItem item = history->HistoryItemAt(i);
const BString& choiceText = item.URL();
int32 matchPos = choiceText.IFindFirst(pattern);
if (matchPos < 0)
continue;
if (lastBaseURL.Length() > 0
&& choiceText.FindFirst(lastBaseURL) >= 0) {
priority--;
} else
priority = INT_MAX;
lastBaseURL = baseURL(choiceText);
fChoices.AddItem(new URLChoice(choiceText,
choiceText, matchPos, pattern.Length(), priority));
}
history->Unlock();
fChoices.SortItems(_CompareChoices);
}
virtual int32 CountChoices() const
{
return fChoices.CountItems();
}
virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
{
return reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAt(index));
}
static int _CompareChoices(const void* a, const void* b)
{
const URLChoice* aChoice
= *reinterpret_cast<const URLChoice* const *>(a);
const URLChoice* bChoice
= *reinterpret_cast<const URLChoice* const *>(b);
if (*aChoice < *bChoice)
return -1;
else if (*aChoice == *bChoice)
return 0;
return 1;
}
private:
BList fChoices;
};
// #pragma mark - URLTextView
static const float kHorizontalTextRectInset = 4.0;
class URLInputGroup::URLTextView : public BTextView {
private:
static const uint32 MSG_CLEAR = 'cler';
public:
URLTextView(URLInputGroup* parent);
virtual ~URLTextView();
virtual void MessageReceived(BMessage* message);
virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint where);
virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focused = true);
virtual BSize MinSize();
virtual BSize MaxSize();
void SetUpdateAutoCompleterChoices(bool update);
protected:
virtual void InsertText(const char* inText, int32 inLength,
int32 inOffset,
const text_run_array* inRuns);
virtual void DeleteText(int32 fromOffset, int32 toOffset);
private:
void _AlignTextRect();
private:
URLInputGroup* fURLInputGroup;
TextViewCompleter* fURLAutoCompleter;
bool fUpdateAutoCompleterChoices;
};
URLInputGroup::URLTextView::URLTextView(URLInputGroup* parent)
:
BTextView("url"),
fURLInputGroup(parent),
fURLAutoCompleter(new TextViewCompleter(this,
new BrowsingHistoryChoiceModel())),
fUpdateAutoCompleterChoices(true)
{
MakeResizable(true);
SetStylable(true);
fURLAutoCompleter->SetModificationsReported(true);
}
URLInputGroup::URLTextView::~URLTextView()
{
delete fURLAutoCompleter;
}
void
URLInputGroup::URLTextView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_CLEAR:
SetText("");
break;
default:
BTextView::MessageReceived(message);
break;
}
}
void
URLInputGroup::URLTextView::FrameResized(float width, float height)
{
BTextView::FrameResized(width, height);
_AlignTextRect();
}
void
URLInputGroup::URLTextView::MouseDown(BPoint where)
{
bool wasFocus = IsFocus();
if (!wasFocus)
MakeFocus(true);
int32 buttons;
if (Window()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
buttons = B_PRIMARY_MOUSE_BUTTON;
if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
// Display context menu
int32 selectionStart;
int32 selectionEnd;
GetSelection(&selectionStart, &selectionEnd);
bool canCutOrCopy = selectionEnd > selectionStart;
bool canPaste = false;
if (be_clipboard->Lock()) {
if (BMessage* data = be_clipboard->Data())
canPaste = data->HasData("text/plain", B_MIME_TYPE);
be_clipboard->Unlock();
}
BMenuItem* cutItem = new BMenuItem(B_TRANSLATE("Cut"),
new BMessage(B_CUT));
BMenuItem* copyItem = new BMenuItem(B_TRANSLATE("Copy"),
new BMessage(B_COPY));
BMenuItem* pasteItem = new BMenuItem(B_TRANSLATE("Paste"),
new BMessage(B_PASTE));
BMenuItem* clearItem = new BMenuItem(B_TRANSLATE("Clear"),
new BMessage(MSG_CLEAR));
cutItem->SetEnabled(canCutOrCopy);
copyItem->SetEnabled(canCutOrCopy);
pasteItem->SetEnabled(canPaste);
clearItem->SetEnabled(strlen(Text()) > 0);
BPopUpMenu* menu = new BPopUpMenu("url context");
menu->AddItem(cutItem);
menu->AddItem(copyItem);
menu->AddItem(pasteItem);
menu->AddItem(clearItem);
menu->SetTargetForItems(this);
menu->Go(ConvertToScreen(where), true, true, true);
return;
}
// Only pass through to base class if we already have focus.
if (!wasFocus)
return;
BTextView::MouseDown(where);
}
void
URLInputGroup::URLTextView::KeyDown(const char* bytes, int32 numBytes)
{
switch (bytes[0]) {
case B_TAB:
BView::KeyDown(bytes, numBytes);
break;
case B_ESCAPE:
// Text already unlocked && replaced in BrowserWindow,
// now select it.
SelectAll();
break;
case B_RETURN:
// Don't let this through to the text view.
break;
default:
{
BString currentText = Text();
BTextView::KeyDown(bytes, numBytes);
// Lock the URL input if it was modified
if (!fURLInputGroup->IsURLInputLocked()
&& Text() != currentText)
fURLInputGroup->LockURLInput();
break;
}
}
}
void
URLInputGroup::URLTextView::MakeFocus(bool focus)
{
// Unlock the URL input if focus was lost.
if (!focus)
fURLInputGroup->LockURLInput(false);
if (focus == IsFocus())
return;
BTextView::MakeFocus(focus);
if (focus)
SelectAll();
fURLInputGroup->Invalidate();
}
BSize
URLInputGroup::URLTextView::MinSize()
{
BSize min;
min.height = ceilf(LineHeight(0) + kHorizontalTextRectInset);
// we always add at least one pixel vertical inset top/bottom for
// the text rect.
min.width = min.height * 3;
return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
}
BSize
URLInputGroup::URLTextView::MaxSize()
{
BSize max(MinSize());
max.width = B_SIZE_UNLIMITED;
return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
}
void
URLInputGroup::URLTextView::SetUpdateAutoCompleterChoices(bool update)
{
fUpdateAutoCompleterChoices = update;
}
void
URLInputGroup::URLTextView::InsertText(const char* inText, int32 inLength,
int32 inOffset, const text_run_array* inRuns)
{
// Filter all line breaks, note that inText is not terminated.
if (inLength == 1) {
if (*inText == '\n' || *inText == '\r')
BTextView::InsertText(" ", 1, inOffset, inRuns);
else
BTextView::InsertText(inText, 1, inOffset, inRuns);
} else {
BString filteredText(inText, inLength);
filteredText.ReplaceAll('\n', ' ');
filteredText.ReplaceAll('\r', ' ');
BTextView::InsertText(filteredText.String(), inLength, inOffset,
inRuns);
}
// Make the base URL part bold.
BString text(Text(), TextLength());
int32 baseUrlStart = text.FindFirst("://");
if (baseUrlStart >= 0)
baseUrlStart += 3;
else
baseUrlStart = 0;
int32 baseUrlEnd = text.FindFirst("/", baseUrlStart);
if (baseUrlEnd < 0)
baseUrlEnd = TextLength();
BFont font;
GetFont(&font);
const rgb_color hostColor = ui_color(B_DOCUMENT_TEXT_COLOR);
const rgb_color urlColor = tint_color(hostColor,
(hostColor.Brightness() < 128 ? B_LIGHTEN_1_TINT : B_DARKEN_1_TINT));
if (baseUrlStart > 0)
SetFontAndColor(0, baseUrlStart, &font, B_FONT_ALL, &urlColor);
if (baseUrlEnd > baseUrlStart) {
font.SetFace(B_BOLD_FACE);
SetFontAndColor(baseUrlStart, baseUrlEnd, &font, B_FONT_ALL,
&hostColor);
}
if (baseUrlEnd < TextLength()) {
font.SetFace(B_REGULAR_FACE);
SetFontAndColor(baseUrlEnd, TextLength(), &font, B_FONT_ALL,
&urlColor);
}
fURLAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
}
void
URLInputGroup::URLTextView::DeleteText(int32 fromOffset, int32 toOffset)
{
BTextView::DeleteText(fromOffset, toOffset);
fURLAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
}
void
URLInputGroup::URLTextView::_AlignTextRect()
{
// Layout the text rect to be in the middle, normally this means there
// is one pixel spacing on each side.
BRect textRect(Bounds());
textRect.left = 0.0;
float vInset = max_c(1,
floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
float hInset = kHorizontalTextRectInset;
if (be_control_look)
hInset = be_control_look->DefaultLabelSpacing();
textRect.InsetBy(hInset, vInset);
SetTextRect(textRect);
}
const uint32 kGoBitmapWidth = 14;
const uint32 kGoBitmapHeight = 14;
const color_space kGoBitmapFormat = B_RGBA32;
const unsigned char kGoBitmapBits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0,
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x2f, 0x56, 0x50, 0x50, 0x50, 0xff, 0x4d, 0x4d, 0x4d, 0xed,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x50, 0x50, 0x50, 0xff, 0x37, 0x37, 0x37, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff,
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x50, 0x50, 0x50, 0xff, 0x4b, 0x4b, 0x4b, 0xec, 0x37, 0x37, 0x37, 0x77, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe1, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
0x49, 0x49, 0x49, 0xe1, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe1,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const unsigned char kPlaceholderIcon[] = {
0x6e, 0x63, 0x69, 0x66, 0x04, 0x04, 0x00, 0x66, 0x03, 0x00, 0x3f, 0x80,
0x02, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x3d, 0xa6, 0x64, 0xc2, 0x19,
0x98, 0x00, 0x00, 0x00, 0x4d, 0xce, 0x64, 0x49, 0xac, 0xcc, 0x00, 0xab,
0xd5, 0xff, 0xff, 0x00, 0x6c, 0xd9, 0x02, 0x00, 0x06, 0x02, 0x00, 0x00,
0x00, 0x3d, 0x26, 0x64, 0xc2, 0x19, 0x98, 0x00, 0x00, 0x00, 0x4d, 0xce,
0x64, 0x49, 0xac, 0xcc, 0x00, 0x80, 0xff, 0x80, 0xff, 0x00, 0xb2, 0x00,
0x04, 0x02, 0x04, 0x34, 0x22, 0xbd, 0x9b, 0x22, 0xb8, 0x53, 0x22, 0x28,
0x2e, 0x28, 0xb5, 0xef, 0x28, 0xbb, 0x37, 0x34, 0x3a, 0xb8, 0x53, 0x3a,
0xbd, 0x9b, 0x3a, 0x40, 0x2e, 0x40, 0xbb, 0x37, 0x40, 0xb5, 0xef, 0x02,
0x08, 0xbe, 0xb6, 0xb4, 0xac, 0xc1, 0x46, 0xb4, 0xac, 0xbc, 0x25, 0xb4,
0xac, 0xb8, 0x09, 0xb7, 0x35, 0xb9, 0xcf, 0xb5, 0xa0, 0xb8, 0x05, 0xbe,
0xb6, 0x35, 0xc2, 0xe5, 0x35, 0xbe, 0xb6, 0x35, 0xc5, 0x68, 0xb8, 0x09,
0xc6, 0x36, 0xb8, 0x09, 0xc6, 0x36, 0xb9, 0xcf, 0xc7, 0xca, 0xbe, 0xb6,
0xc8, 0xc1, 0xbc, 0x25, 0xc8, 0xc1, 0xc1, 0xb3, 0xc8, 0xc1, 0xc6, 0x3c,
0xc5, 0x5b, 0xc4, 0x65, 0xc7, 0x70, 0xc6, 0x3e, 0xbe, 0xb6, 0xc2, 0x0f,
0xba, 0x87, 0xc2, 0x0f, 0xbe, 0xb6, 0xc2, 0x0f, 0xb8, 0x05, 0xc5, 0x64,
0xb7, 0x37, 0xc5, 0x64, 0xb7, 0x37, 0xc3, 0x9e, 0xb5, 0xa2, 0x02, 0x04,
0xb8, 0x09, 0xb7, 0x35, 0xb8, 0x05, 0xbe, 0xb6, 0xb5, 0xf8, 0xb9, 0x0c,
0xb4, 0xac, 0xbe, 0xb6, 0xb4, 0xac, 0xbb, 0xba, 0xb4, 0xac, 0xc1, 0xb1,
0xb8, 0x09, 0xc6, 0x36, 0xb5, 0xf8, 0xc4, 0x5e, 0xb9, 0xcf, 0xc7, 0xca,
0x35, 0xc2, 0xe5, 0x35, 0xc5, 0x68, 0x35, 0xbe, 0xb6, 0x02, 0x04, 0x4d,
0x51, 0xc4, 0xf2, 0xbf, 0x04, 0x53, 0x4e, 0xc8, 0xc1, 0xbe, 0x58, 0xc8,
0xc1, 0xc1, 0x55, 0xc8, 0xc1, 0xbb, 0x5d, 0xc5, 0x64, 0xb6, 0xd9, 0xc7,
0x75, 0xb8, 0xb0, 0xc3, 0x9e, 0xb5, 0x44, 0xc2, 0x0f, 0xba, 0x29, 0xc2,
0x0f, 0xb7, 0xa6, 0xc2, 0x0f, 0xbe, 0x58, 0x04, 0x0a, 0x00, 0x01, 0x00,
0x12, 0x42, 0x19, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x19,
0x98, 0xc6, 0x19, 0x93, 0x44, 0x19, 0xa2, 0x01, 0x17, 0x84, 0x00, 0x04,
0x0a, 0x01, 0x01, 0x00, 0x12, 0x42, 0x19, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x42, 0x19, 0x98, 0xc7, 0x26, 0x5f, 0x28, 0x96, 0xf9, 0x01,
0x17, 0x83, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x01, 0x00, 0x0a, 0x03, 0x02,
0x02, 0x03, 0x00
};
// #pragma mark - PageIconView
class URLInputGroup::PageIconView : public BView {
public:
PageIconView()
:
BView("page icon view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
fIcon(NULL)
{
SetDrawingMode(B_OP_ALPHA);
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
}
~PageIconView()
{
delete fIcon;
}
virtual void Draw(BRect updateRect)
{
BRect bounds(Bounds());
BRect iconBounds(0, 0, 15, 15);
iconBounds.OffsetTo(
floorf((bounds.left + bounds.right
- (iconBounds.left + iconBounds.right)) / 2 + 0.5f),
floorf((bounds.top + bounds.bottom
- (iconBounds.top + iconBounds.bottom)) / 2 + 0.5f));
DrawBitmap(fIcon, fIcon->Bounds(), iconBounds,
B_FILTER_BITMAP_BILINEAR);
}
virtual BSize MinSize()
{
return BSize(18, 18);
}
virtual BSize MaxSize()
{
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
}
virtual BSize PreferredSize()
{
return MinSize();
}
void SetIcon(const BBitmap* icon)
{
delete fIcon;
if (icon)
fIcon = new BBitmap(icon);
else {
fIcon = new BBitmap(BRect(0, 0, 15, 15), B_RGB32);
BIconUtils::GetVectorIcon(kPlaceholderIcon,
sizeof(kPlaceholderIcon), fIcon);
}
Invalidate();
}
private:
BBitmap* fIcon;
};
// #pragma mark - URLInputGroup
URLInputGroup::URLInputGroup(BMessage* goMessage)
:
BGroupView(B_HORIZONTAL, 0.0),
fWindowActive(false),
fURLLocked(false)
{
GroupLayout()->SetInsets(2, 2, 2, 2);
fIconView = new PageIconView();
GroupLayout()->AddView(fIconView, 0.0f);
fTextView = new URLTextView(this);
AddChild(fTextView);
AddChild(new BSeparatorView(B_VERTICAL, B_PLAIN_BORDER));
// TODO: Fix in Haiku, no in-built support for archived BBitmaps from
// resources?
// fGoButton = new BitmapButton("kActionGo", NULL);
fGoButton = new BBitmapButton(kGoBitmapBits, kGoBitmapWidth,
kGoBitmapHeight, kGoBitmapFormat, goMessage);
GroupLayout()->AddView(fGoButton, 0.0f);
SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
SetLowColor(ViewColor());
SetViewColor(fTextView->ViewColor());
SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
B_ALIGN_VERTICAL_CENTER));
}
URLInputGroup::~URLInputGroup()
{
}
void
URLInputGroup::AttachedToWindow()
{
BGroupView::AttachedToWindow();
fWindowActive = Window()->IsActive();
}
void
URLInputGroup::WindowActivated(bool active)
{
BGroupView::WindowActivated(active);
if (fWindowActive != active) {
fWindowActive = active;
Invalidate();
}
}
void
URLInputGroup::Draw(BRect updateRect)
{
BRect bounds(Bounds());
rgb_color base(LowColor());
uint32 flags = 0;
if (fWindowActive && fTextView->IsFocus())
flags |= BControlLook::B_FOCUSED;
be_control_look->DrawTextControlBorder(this, bounds, updateRect, base,
flags);
}
void
URLInputGroup::MakeFocus(bool focus)
{
// Forward this to the text view, we never accept focus ourselves.
fTextView->MakeFocus(focus);
}
BTextView*
URLInputGroup::TextView() const
{
return fTextView;
}
void
URLInputGroup::SetText(const char* text)
{
// Ignore setting the text, if the input is locked.
if (fURLLocked)
return;
if (!text || !Text() || strcmp(Text(), text) != 0) {
fTextView->SetUpdateAutoCompleterChoices(false);
fTextView->SetText(text);
fTextView->SetUpdateAutoCompleterChoices(true);
}
}
const char*
URLInputGroup::Text() const
{
return fTextView->Text();
}
BButton*
URLInputGroup::GoButton() const
{
return fGoButton;
}
void
URLInputGroup::SetPageIcon(const BBitmap* icon)
{
fIconView->SetIcon(icon);
}
bool
URLInputGroup::IsURLInputLocked() const
{
return fURLLocked;
}
void
URLInputGroup::LockURLInput(bool lock)
{
fURLLocked = lock;
}
↑ V773 The function was exited without releasing the 'menu' pointer. A memory leak is possible.