[haiku-commits] haiku: hrev49614 - src/apps/mail

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 4 Sep 2015 17:36:51 +0200 (CEST)

hrev49614 adds 15 changesets to branch 'master'
old head: fa89878a70f7795615f55d16c7669f0a4c71b402
new head: 9ed8f484983a77a3b88adfa41e4136501b6df4b3
overview:
http://cgit.haiku-os.org/haiku/log/?qt=range&q=9ed8f484983a+%5Efa89878a70f7

----------------------------------------------------------------------------

e047b40a2fd1: Interface Kit: use different spacing constants.

* While this breaks binary compatibility with earlier Haiku releases,
use values that are less likely to clash with actual use cases.
* Specifically, using a negative spacing is one way to get rid of the
border of BScrollViews, to put them into a window neatly.
* Also, BControlLook now uses a switch to resolve them.

df946869a12e: Mail: work in progress to use the layout API.

d89192365031: BMenuField: use layout rect for the label.

* Instead of just laying it out as without the layout API.

8b1aaf348c30: Mail: properly disable prev/next buttons without Tracker.

* The prev/next buttons will only work when invoked via an actual
mail file from Tracker.

cc7e5aac407f: Mail: fAccount text control is no longer used.

19d8cb703c30: BDate: added time_t constructor.

* This class is pretty much useless as it is.

66078c791135: BMailComponent: made a few methods const.

7bdee8beab1a: BEmailMessage: added missing const, Date() returns time_t.

* Added missing const to some getter methods.
* Date() now tries to parse the date of the mail, and return it as
a time_t; you can still retrieve the actual string via
HeaderField("Date") if you have to.
* Mail now shows the time in the local time zone, and with the
current locale.

4182c53bc4cf: Mail: change look of disabled text controls.

* Added HeaderTextControl that draws the text in black, and uses the
panel background without a frame when it's disabled. Only the label
is still drawn as disabled.
* Changed AddressTextControl to behave in the same way.
* The date view is now a HeaderTextControl, too.
* Unfortunately, the label is not vertically aligned with the contents.

62c1b01661eb: Mail: temporary workaround for the label placing issue.

* Does not work for all font sizes.

15c105624258: BMailSettings: removed debug message dump.

31c65be10901: Mail: fixed crash on resend.

* Seems to have been there for quite some time. Probably a good
reason to remove that feature altogether.

50d381e8620a: Mail: use layout version of BMenuBar.

* Fixes layout issue: the minimal size was incorrect.
* Moved variable declaration to where it is actually used.

6b8712663acc: BToolBar: made FindButton() public.

9ed8f484983a: Mail: show icons only setting works again.

* It will show the label as tool tip when the labels are hidden.

[ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

33 files changed, 2783 insertions(+), 3899 deletions(-)
headers/os/interface/InterfaceDefs.h | 24 +-
headers/os/mail/MailComponent.h | 6 +-
headers/os/mail/MailMessage.h | 14 +-
headers/os/support/DateTime.h | 2 +
headers/private/shared/ToolBar.h | 3 +-
src/apps/mail/AddressTextControl.cpp | 991 +++++++++++++++
src/apps/mail/AddressTextControl.h | 62 +
src/apps/mail/ComboBox.cpp | 1984 ------------------------------
src/apps/mail/ComboBox.h | 233 ----
src/apps/mail/Content.cpp | 198 ++-
src/apps/mail/Content.h | 33 +-
src/apps/mail/Header.cpp | 1443 +++++++---------------
src/apps/mail/Header.h | 133 +-
src/apps/mail/Jamfile | 12 +-
src/apps/mail/MailApp.cpp | 8 +-
src/apps/mail/MailApp.h | 15 +
src/apps/mail/MailSupport.cpp | 1 -
src/apps/mail/MailWindow.cpp | 645 +++++-----
src/apps/mail/MailWindow.h | 6 +-
src/apps/mail/People.cpp | 194 +++
src/apps/mail/People.h | 94 ++
src/apps/mail/Prefs.cpp | 7 +-
src/apps/mail/QueryList.cpp | 245 ++++
src/apps/mail/QueryList.h | 75 ++
src/apps/mail/Settings.cpp | 36 +-
src/apps/mail/Settings.h | 4 +
src/kits/interface/ControlLook.cpp | 27 +-
src/kits/interface/MenuField.cpp | 73 +-
src/kits/mail/MailComponent.cpp | 11 +-
src/kits/mail/MailMessage.cpp | 22 +-
src/kits/mail/MailSettings.cpp | 2 -
src/kits/shared/ToolBar.cpp | 46 +-
src/kits/support/DateTime.cpp | 33 +-

############################################################################

Commit: e047b40a2fd11728e4f7ac83d121299c89e9e658
URL: http://cgit.haiku-os.org/haiku/commit/?id=e047b40a2fd1
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Tue Aug 25 16:06:46 2015 UTC

Interface Kit: use different spacing constants.

* While this breaks binary compatibility with earlier Haiku releases,
use values that are less likely to clash with actual use cases.
* Specifically, using a negative spacing is one way to get rid of the
border of BScrollViews, to put them into a window neatly.
* Also, BControlLook now uses a switch to resolve them.

----------------------------------------------------------------------------

diff --git a/headers/os/interface/InterfaceDefs.h
b/headers/os/interface/InterfaceDefs.h
index accef2c..46f3a83 100644
--- a/headers/os/interface/InterfaceDefs.h
+++ b/headers/os/interface/InterfaceDefs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2008, Haiku, Inc. All rights reserved.
+ * Copyright 2001-2015, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _INTERFACE_DEFS_H
@@ -228,17 +228,17 @@ enum vertical_alignment {


enum {
- B_USE_DEFAULT_SPACING = -2,
- B_USE_ITEM_SPACING = -3,
- B_USE_ITEM_INSETS = -3,
- B_USE_HALF_ITEM_SPACING = -4,
- B_USE_HALF_ITEM_INSETS = -4,
- B_USE_WINDOW_INSETS = -5,
- B_USE_WINDOW_SPACING = -5,
- B_USE_SMALL_INSETS = -6,
- B_USE_SMALL_SPACING = -6,
- B_USE_BIG_INSETS = -7,
- B_USE_BIG_SPACING = -7
+ B_USE_DEFAULT_SPACING = -1002,
+ B_USE_ITEM_SPACING = -1003,
+ B_USE_ITEM_INSETS = -1003,
+ B_USE_HALF_ITEM_SPACING = -1004,
+ B_USE_HALF_ITEM_INSETS = -1004,
+ B_USE_WINDOW_INSETS = -1005,
+ B_USE_WINDOW_SPACING = -1005,
+ B_USE_SMALL_INSETS = -1006,
+ B_USE_SMALL_SPACING = -1006,
+ B_USE_BIG_INSETS = -1007,
+ B_USE_BIG_SPACING = -1007
};


diff --git a/src/kits/interface/ControlLook.cpp
b/src/kits/interface/ControlLook.cpp
index 9f329a4..3cfad71 100644
--- a/src/kits/interface/ControlLook.cpp
+++ b/src/kits/interface/ControlLook.cpp
@@ -1,6 +1,6 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@xxxxxx>
- * Copyright 2012-2014 Haiku, Inc. All rights reserved.
+ * Copyright 2012-2015 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -71,17 +71,20 @@ BControlLook::DefaultItemSpacing() const
float
BControlLook::ComposeSpacing(float spacing)
{
- if (spacing == B_USE_DEFAULT_SPACING || spacing == B_USE_ITEM_SPACING) {
- return be_control_look->DefaultItemSpacing();
- } else if (spacing == B_USE_HALF_ITEM_SPACING) {
- return ceilf(be_control_look->DefaultItemSpacing() * 0.5f);
- } else if (spacing == B_USE_WINDOW_INSETS) {
- return be_control_look->DefaultItemSpacing();
- } else if (spacing == B_USE_SMALL_SPACING) {
- return ceilf(be_control_look->DefaultItemSpacing() * 0.7f);
- } else if (spacing == B_USE_BIG_SPACING) {
- return ceilf(be_control_look->DefaultItemSpacing() * 1.3f);
+ switch ((int)spacing) {
+ case B_USE_DEFAULT_SPACING:
+ case B_USE_ITEM_SPACING:
+ return be_control_look->DefaultItemSpacing();
+ case B_USE_HALF_ITEM_SPACING:
+ return ceilf(be_control_look->DefaultItemSpacing() *
0.5f);
+ case B_USE_WINDOW_SPACING:
+ return be_control_look->DefaultItemSpacing();
+ case B_USE_SMALL_SPACING:
+ return ceilf(be_control_look->DefaultItemSpacing() *
0.7f);
+ case B_USE_BIG_SPACING:
+ return ceilf(be_control_look->DefaultItemSpacing() *
1.3f);
}
+
return spacing;
}

@@ -2567,7 +2570,7 @@ BControlLook::_DrawNonFlatButtonBackground(BView* view,
BRect& rect,
rgb_color separatorBaseColor = base;
if ((flags & B_ACTIVATED) != 0)
separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
-
+
rgb_color separatorLightColor =
_EdgeLightColor(separatorBaseColor,
(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
rgb_color separatorShadowColor =
_EdgeShadowColor(separatorBaseColor,

############################################################################

Commit: df946869a12e27082370ec23b9bfc3f2893fe8ab
URL: http://cgit.haiku-os.org/haiku/commit/?id=df946869a12e
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Sun Aug 30 19:14:35 2015 UTC

Mail: work in progress to use the layout API.

----------------------------------------------------------------------------

diff --git a/src/apps/mail/AddressTextControl.cpp
b/src/apps/mail/AddressTextControl.cpp
new file mode 100644
index 0000000..8fec665
--- /dev/null
+++ b/src/apps/mail/AddressTextControl.cpp
@@ -0,0 +1,987 @@
+/*
+ * Copyright 2015, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2010 Stephan Aßmus <superstippi@xxxxxx>
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "AddressTextControl.h"
+
+#include <Autolock.h>
+#include <Button.h>
+#include <Catalog.h>
+#include <ControlLook.h>
+#include <Clipboard.h>
+#include <File.h>
+#include <LayoutBuilder.h>
+#include <Locale.h>
+#include <LayoutUtils.h>
+#include <NodeInfo.h>
+#include <PopUpMenu.h>
+#include <SeparatorView.h>
+#include <TextView.h>
+#include <Window.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MailApp.h"
+#include "Messages.h"
+#include "QueryList.h"
+#include "TextViewCompleter.h"
+
+
+#undef B_TRANSLATION_CONTEXT
+#define B_TRANSLATION_CONTEXT "AddressTextControl"
+
+
+static const uint32 kMsgAddAddress = 'adad';
+static const float kHorizontalTextRectInset = 4.0;
+static const float kVerticalTextRectInset = 2.0;
+
+
+class AddressTextControl::TextView : public BTextView {
+private:
+ static const uint32 MSG_CLEAR = 'cler';
+
+public:
+
TextView(AddressTextControl* parent);
+ virtual ~TextView();
+
+ virtual void MessageReceived(BMessage*
message);
+ virtual void FrameResized(float width, float
height);
+ virtual void KeyDown(const char* bytes,
int32 numBytes);
+ virtual void MakeFocus(bool focused = true);
+
+ virtual BSize MinSize();
+ virtual BSize MaxSize();
+
+ const BMessage* ModificationMessage() const;
+ void
SetModificationMessage(BMessage* message);
+
+ void
SetUpdateAutoCompleterChoices(bool update);
+
+protected:
+ virtual void InsertText(const char* text,
int32 length,
+ int32
offset,
+ const
text_run_array* runs);
+ virtual void DeleteText(int32 fromOffset,
int32 toOffset);
+
+private:
+ void _AlignTextRect();
+
+private:
+ AddressTextControl* fAddressTextControl;
+ TextViewCompleter* fAutoCompleter;
+ BString fPreviousText;
+ bool
fUpdateAutoCompleterChoices;
+ BMessage* fModificationMessage;
+};
+
+
+class AddressPopUpMenu : public BPopUpMenu, public QueryListener {
+public:
+
AddressPopUpMenu();
+ virtual ~AddressPopUpMenu();
+
+protected:
+ virtual void EntryCreated(QueryList& source,
+ const
entry_ref& ref, ino_t node);
+ virtual void EntryRemoved(QueryList& source,
+ const
node_ref& nodeRef);
+
+private:
+ void _RebuildMenu();
+ void _AddGroup(const char*
label, const char* group,
+
PersonList& peopleList);
+ void _AddPeople(BMenu* menu,
PersonList& peopleList,
+ const
char* group,
+ bool
addSeparator = false);
+ bool _MatchesGroup(const
Person& person,
+ const
char* group);
+};
+
+
+class AddressTextControl::PopUpButton : public BControl {
+public:
+ PopUpButton();
+ virtual ~PopUpButton();
+
+ virtual BSize MinSize();
+ virtual BSize PreferredSize();
+ virtual BSize MaxSize();
+
+ virtual void MouseDown(BPoint where);
+ virtual void Draw(BRect updateRect);
+
+private:
+ AddressPopUpMenu* fPopUpMenu;
+};
+
+
+class PeopleChoiceModel : public BAutoCompleter::ChoiceModel {
+public:
+ PeopleChoiceModel()
+ :
+ fChoices(5, true)
+ {
+ }
+
+ ~PeopleChoiceModel()
+ {
+ }
+
+ virtual void FetchChoicesFor(const BString& pattern)
+ {
+ // Remove all existing choices
+ fChoices.MakeEmpty();
+
+ // Search through the people list for any matches
+ PersonList& peopleList =
static_cast<TMailApp*>(be_app)->People();
+ BAutolock locker(peopleList);
+
+ for (int32 index = 0; index < peopleList.CountPersons();
index++) {
+ const Person* person = peopleList.PersonAt(index);
+
+ const BString& baseText = person->Name();
+ for (int32 addressIndex = 0;
+ addressIndex <
person->CountAddresses(); addressIndex++) {
+ BString choiceText = baseText;
+ choiceText << " <" <<
person->AddressAt(addressIndex) << ">";
+
+ int32 match = choiceText.IFindFirst(pattern);
+ if (match < 0)
+ continue;
+
+ fChoices.AddItem(new
BAutoCompleter::Choice(choiceText,
+ choiceText, match, pattern.Length()));
+ }
+ }
+
+ locker.Unlock();
+ fChoices.SortItems(_CompareChoices);
+ }
+
+ virtual int32 CountChoices() const
+ {
+ return fChoices.CountItems();
+ }
+
+ virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
+ {
+ return fChoices.ItemAt(index);
+ }
+
+ static int _CompareChoices(const BAutoCompleter::Choice* a,
+ const BAutoCompleter::Choice* b)
+ {
+ return a->DisplayText().Compare(b->DisplayText());
+ }
+
+private:
+ BObjectList<BAutoCompleter::Choice> fChoices;
+};
+
+
+// #pragma mark - TextView
+
+
+AddressTextControl::TextView::TextView(AddressTextControl* parent)
+ :
+ BTextView("mail"),
+ fAddressTextControl(parent),
+ fAutoCompleter(new TextViewCompleter(this,
+ new PeopleChoiceModel())),
+ fPreviousText(""),
+ fUpdateAutoCompleterChoices(true)
+{
+ MakeResizable(true);
+ SetStylable(true);
+ fAutoCompleter->SetModificationsReported(true);
+}
+
+
+AddressTextControl::TextView::~TextView()
+{
+ delete fAutoCompleter;
+}
+
+
+void
+AddressTextControl::TextView::MessageReceived(BMessage* message)
+{
+ switch (message->what) {
+ case MSG_CLEAR:
+ SetText("");
+ break;
+
+ default:
+ BTextView::MessageReceived(message);
+ break;
+ }
+}
+
+
+void
+AddressTextControl::TextView::FrameResized(float width, float height)
+{
+ BTextView::FrameResized(width, height);
+ _AlignTextRect();
+}
+
+
+void
+AddressTextControl::TextView::KeyDown(const char* bytes, int32 numBytes)
+{
+ switch (bytes[0]) {
+ case B_TAB:
+ BView::KeyDown(bytes, numBytes);
+ break;
+
+ case B_ESCAPE:
+ // Revert to text as it was when we received keyboard
focus.
+ SetText(fPreviousText.String());
+ SelectAll();
+ break;
+
+ case B_RETURN:
+ // Don't let this through to the text view.
+ break;
+
+ default:
+ BTextView::KeyDown(bytes, numBytes);
+ break;
+ }
+}
+
+void
+AddressTextControl::TextView::MakeFocus(bool focus)
+{
+ if (focus == IsFocus())
+ return;
+
+ BTextView::MakeFocus(focus);
+
+ if (focus) {
+ fPreviousText = Text();
+ SelectAll();
+ }
+
+ fAddressTextControl->Invalidate();
+}
+
+
+BSize
+AddressTextControl::TextView::MinSize()
+{
+ BSize min;
+ min.height = ceilf(LineHeight(0) + kVerticalTextRectInset);
+ // 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
+AddressTextControl::TextView::MaxSize()
+{
+ BSize max(MinSize());
+ max.width = B_SIZE_UNLIMITED;
+ return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
+}
+
+
+const BMessage*
+AddressTextControl::TextView::ModificationMessage() const
+{
+ return fModificationMessage;
+}
+
+
+void
+AddressTextControl::TextView::SetModificationMessage(BMessage* message)
+{
+ fModificationMessage = message;
+}
+
+
+void
+AddressTextControl::TextView::SetUpdateAutoCompleterChoices(bool update)
+{
+ fUpdateAutoCompleterChoices = update;
+}
+
+
+void
+AddressTextControl::TextView::InsertText(const char* text,
+ int32 length, int32 offset, const text_run_array* runs)
+{
+ if (!strncmp(text, "mailto:";, 7)) {
+ text += 7;
+ length -= 7;
+ if (runs != NULL)
+ runs = NULL;
+ }
+
+ // Filter all line breaks, note that text is not terminated.
+ if (length == 1) {
+ if (*text == '\n' || *text == '\r')
+ BTextView::InsertText(" ", 1, offset, runs);
+ else
+ BTextView::InsertText(text, 1, offset, runs);
+ } else {
+ BString filteredText(text, length);
+ filteredText.ReplaceAll('\n', ' ');
+ filteredText.ReplaceAll('\r', ' ');
+ BTextView::InsertText(filteredText.String(), length, offset,
+ runs);
+ }
+
+ // TODO: change E-mail representation
+/*
+ // 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 black = (rgb_color) { 0, 0, 0, 255 };
+ const rgb_color gray = (rgb_color) { 60, 60, 60, 255 };
+ if (baseUrlStart > 0)
+ SetFontAndColor(0, baseUrlStart, &font, B_FONT_ALL, &gray);
+ if (baseUrlEnd > baseUrlStart) {
+ font.SetFace(B_BOLD_FACE);
+ SetFontAndColor(baseUrlStart, baseUrlEnd, &font, B_FONT_ALL,
&black);
+ }
+ if (baseUrlEnd < TextLength()) {
+ font.SetFace(B_REGULAR_FACE);
+ SetFontAndColor(baseUrlEnd, TextLength(), &font, B_FONT_ALL,
&gray);
+ }
+*/
+ fAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
+ fAddressTextControl->InvokeNotify(fModificationMessage,
+ B_CONTROL_MODIFIED);
+}
+
+
+void
+AddressTextControl::TextView::DeleteText(int32 fromOffset,
+ int32 toOffset)
+{
+ BTextView::DeleteText(fromOffset, toOffset);
+
+ fAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
+ fAddressTextControl->InvokeNotify(fModificationMessage,
+ B_CONTROL_MODIFIED);
+}
+
+
+void
+AddressTextControl::TextView::_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);
+}
+
+
+// #pragma mark - PopUpButton
+
+
+AddressTextControl::PopUpButton::PopUpButton()
+ :
+ BControl(NULL, NULL, NULL, B_WILL_DRAW)
+{
+ fPopUpMenu = new AddressPopUpMenu();
+}
+
+
+AddressTextControl::PopUpButton::~PopUpButton()
+{
+ delete fPopUpMenu;
+}
+
+
+BSize
+AddressTextControl::PopUpButton::MinSize()
+{
+ // TODO: BControlLook does not give us any size information!
+ return BSize(10, 10);
+}
+
+
+BSize
+AddressTextControl::PopUpButton::PreferredSize()
+{
+ return BSize(10, B_SIZE_UNSET);
+}
+
+
+BSize
+AddressTextControl::PopUpButton::MaxSize()
+{
+ return BSize(10, B_SIZE_UNLIMITED);
+}
+
+
+void
+AddressTextControl::PopUpButton::MouseDown(BPoint where)
+{
+ if (fPopUpMenu->Parent() != NULL)
+ return;
+
+ float width;
+ fPopUpMenu->GetPreferredSize(&width, NULL);
+ fPopUpMenu->SetTargetForItems(Parent());
+
+ BPoint point(Bounds().Width() - width, Bounds().Height() + 2);
+ ConvertToScreen(&point);
+ fPopUpMenu->Go(point, true, true, true);
+}
+
+
+void
+AddressTextControl::PopUpButton::Draw(BRect updateRect)
+{
+ uint32 flags = 0;
+ if (!IsEnabled())
+ flags |= BControlLook::B_DISABLED;
+
+ if (IsFocus() && Window()->IsActive())
+ flags |= BControlLook::B_FOCUSED;
+
+ rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
+ BRect rect = Bounds();
+ be_control_look->DrawMenuFieldBackground(this, rect,
+ updateRect, base, true, flags);
+}
+
+
+// #pragma mark - PopUpMenu
+
+
+AddressPopUpMenu::AddressPopUpMenu()
+ :
+ BPopUpMenu("", true)
+{
+ static_cast<TMailApp*>(be_app)->PeopleQueryList().AddListener(this);
+}
+
+
+AddressPopUpMenu::~AddressPopUpMenu()
+{
+ static_cast<TMailApp*>(be_app)->PeopleQueryList().RemoveListener(this);
+}
+
+
+void
+AddressPopUpMenu::EntryCreated(QueryList& source,
+ const entry_ref& ref, ino_t node)
+{
+ _RebuildMenu();
+}
+
+
+void
+AddressPopUpMenu::EntryRemoved(QueryList& source,
+ const node_ref& nodeRef)
+{
+ _RebuildMenu();
+}
+
+
+void
+AddressPopUpMenu::_RebuildMenu()
+{
+ // Remove all items
+ int32 index = CountItems();
+ while (index-- > 0) {
+ delete RemoveItem(index);
+ }
+
+ // Rebuild contents
+ PersonList& peopleList = static_cast<TMailApp*>(be_app)->People();
+ BAutolock locker(peopleList);
+
+ if (peopleList.CountPersons() > 0)
+ _AddGroup(B_TRANSLATE("All people"), NULL, peopleList);
+
+ GroupList& groupList = static_cast<TMailApp*>(be_app)->PeopleGroups();
+ BAutolock groupLocker(groupList);
+
+ for (int32 index = 0; index < groupList.CountGroups(); index++) {
+ BString group = groupList.GroupAt(index);
+ _AddGroup(group, group, peopleList);
+ }
+
+ groupLocker.Unlock();
+
+ _AddPeople(this, peopleList, "", true);
+}
+
+
+void
+AddressPopUpMenu::_AddGroup(const char* label, const char* group,
+ PersonList& peopleList)
+{
+ BMenu* menu = new BMenu(label);
+ AddItem(menu);
+ menu->Superitem()->SetMessage(new BMessage(kMsgAddAddress));
+
+ _AddPeople(menu, peopleList, group);
+}
+
+
+void
+AddressPopUpMenu::_AddPeople(BMenu* menu, PersonList& peopleList,
+ const char* group, bool addSeparator)
+{
+ for (int32 index = 0; index < peopleList.CountPersons(); index++) {
+ const Person* person = peopleList.PersonAt(index);
+ if (!_MatchesGroup(*person, group))
+ continue;
+
+ if (person->CountAddresses() != 0 && addSeparator) {
+ menu->AddSeparatorItem();
+ addSeparator = false;
+ }
+
+ for (int32 addressIndex = 0; addressIndex <
person->CountAddresses();
+ addressIndex++) {
+ BString email = person->Name();
+ email << " <" << person->AddressAt(addressIndex) << ">";
+
+ BMessage* message = new BMessage(kMsgAddAddress);
+ message->AddString("email", email);
+ menu->AddItem(new BMenuItem(email, message));
+
+ if (menu->Superitem() != NULL)
+
menu->Superitem()->Message()->AddString("email", email);
+ }
+ }
+}
+
+
+bool
+AddressPopUpMenu::_MatchesGroup(const Person& person, const char* group)
+{
+ if (group == NULL)
+ return true;
+
+ if (group[0] == '\0')
+ return person.CountGroups() == 0;
+
+ return person.IsInGroup(group);
+}
+
+
+// TODO: sort lists!
+/*
+void
+AddressTextControl::PopUpMenu::_AddPersonItem(const entry_ref *ref, ino_t
node, BString &name,
+ BString &email, const char *attr, BMenu *groupMenu, BMenuItem
*superItem)
+{
+ BString label;
+ BString sortKey;
+ // For alphabetical order sorting, usually last name.
+
+ // if we have no Name, just use the email address
+ if (name.Length() == 0) {
+ label = email;
+ sortKey = email;
+ } else {
+ // otherwise, pretty-format it
+ label << name << " (" << email << ")";
+
+ // Extract the last name (last word in the name),
+ // removing trailing and leading spaces.
+ const char *nameStart = name.String();
+ const char *string = nameStart + strlen(nameStart) - 1;
+ const char *wordEnd;
+
+ while (string >= nameStart && isspace(*string))
+ string--;
+ wordEnd = string + 1; // Points to just after last word.
+ while (string >= nameStart && !isspace(*string))
+ string--;
+ string++; // Point to first letter in the word.
+ if (wordEnd > string)
+ sortKey.SetTo(string, wordEnd - string);
+ else // Blank name, pretend that the last name is after it.
+ string = nameStart + strlen(nameStart);
+
+ // Append the first names to the end, so that people with the
same last
+ // name get sorted by first name. Note no space between the
end of the
+ // last name and the start of the first names, but that
shouldn't
+ // matter for sorting.
+ sortKey.Append(nameStart, string - nameStart);
+ }
+}
+*/
+
+// #pragma mark - AddressTextControl
+
+
+AddressTextControl::AddressTextControl(const char* name, BMessage* message)
+ :
+ BControl(name, NULL, message, B_WILL_DRAW),
+ fRefDropMenu(NULL),
+ fWindowActive(false),
+ fEditable(true)
+{
+ fTextView = new TextView(this);
+ fTextView->SetExplicitMinSize(BSize(100, B_SIZE_UNSET));
+ fPopUpButton = new PopUpButton();
+
+ BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
+ .SetInsets(2)
+ .Add(fTextView)
+ .Add(fPopUpButton);
+
+ 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));
+}
+
+
+AddressTextControl::~AddressTextControl()
+{
+}
+
+
+void
+AddressTextControl::AttachedToWindow()
+{
+ BControl::AttachedToWindow();
+ fWindowActive = Window()->IsActive();
+}
+
+
+void
+AddressTextControl::WindowActivated(bool active)
+{
+ BControl::WindowActivated(active);
+ if (fWindowActive != active) {
+ fWindowActive = active;
+ Invalidate();
+ }
+}
+
+
+void
+AddressTextControl::Draw(BRect updateRect)
+{
+ BRect bounds(Bounds());
+ rgb_color base(LowColor());
+ uint32 flags = 0;
+ if (!IsEnabled())
+ flags |= BControlLook::B_DISABLED;
+ if (fWindowActive && fTextView->IsFocus())
+ flags |= BControlLook::B_FOCUSED;
+ be_control_look->DrawTextControlBorder(this, bounds, updateRect, base,
+ flags);
+}
+
+
+void
+AddressTextControl::MakeFocus(bool focus)
+{
+ // Forward this to the text view, we never accept focus ourselves.
+ fTextView->MakeFocus(focus);
+}
+
+
+void
+AddressTextControl::SetEnabled(bool enabled)
+{
+ BControl::SetEnabled(enabled);
+ fTextView->MakeEditable(enabled && fEditable);
+ if (enabled)
+ fTextView->SetFlags(fTextView->Flags() | B_NAVIGABLE);
+ else
+ fTextView->SetFlags(fTextView->Flags() & ~B_NAVIGABLE);
+
+ fPopUpButton->SetEnabled(enabled);
+
+ _UpdateTextViewColors(enabled);
+}
+
+
+void
+AddressTextControl::MessageReceived(BMessage* message)
+{
+ switch (message->what) {
+ case B_SIMPLE_DATA:
+ {
+ int32 buttons = -1;
+ BPoint point;
+ if (message->FindInt32("buttons", &buttons) != B_OK)
+ buttons = B_PRIMARY_MOUSE_BUTTON;
+
+ if (buttons != B_PRIMARY_MOUSE_BUTTON
+ && message->FindPoint("_drop_point_", &point)
!= B_OK)
+ return;
+
+ BMessage forwardRefs(B_REFS_RECEIVED);
+ bool forward = false;
+
+ entry_ref ref;
+ for (int32 index = 0;message->FindRef("refs", index,
&ref) == B_OK; index++) {
+ BFile file(&ref, B_READ_ONLY);
+ if (file.InitCheck() == B_NO_ERROR) {
+ BNodeInfo info(&file);
+ char type[B_FILE_NAME_LENGTH];
+ info.GetType(type);
+
+ if
(!strcmp(type,"application/x-person")) {
+ // add person's E-mail address
to the To: field
+
+ BString attr = "";
+ if (buttons ==
B_PRIMARY_MOUSE_BUTTON) {
+ if
(message->FindString("attr", &attr) < B_OK)
+ attr =
"META:email";
+ } else {
+ BNode node(&ref);
+ node.RewindAttrs();
+
+ char
buffer[B_ATTR_NAME_LENGTH];
+
+ delete fRefDropMenu;
+ fRefDropMenu = new
BPopUpMenu("RecipientMenu");
+
+ while
(node.GetNextAttrName(buffer) == B_OK) {
+ if
(strstr(buffer, "email") <= 0)
+
continue;
+
+ attr = buffer;
+
+ BString address;
+
node.ReadAttrString(buffer, &address);
+ if
(address.Length() <= 0)
+
continue;
+
+ BMessage*
itemMsg
+ = new
BMessage(kMsgAddAddress);
+
itemMsg->AddString("email", address.String());
+
+ BMenuItem* item
= new BMenuItem(
+
address.String(), itemMsg);
+
fRefDropMenu->AddItem(item);
+ }
+
+ if
(fRefDropMenu->CountItems() > 1) {
+
fRefDropMenu->SetTargetForItems(this);
+
fRefDropMenu->Go(point, true, true, true);
+ return;
+ } else {
+ delete
fRefDropMenu;
+ fRefDropMenu =
NULL;
+ }
+ }
+
+ BString email;
+
file.ReadAttrString(attr.String(), &email);
+
+ // we got something...
+ if (email.Length() > 0) {
+ // see if we can get a
username as well
+ BString name;
+
file.ReadAttrString("META:name", &name);
+
+ BString address;
+ if (name.Length() == 0)
{
+ // if we have
no Name, just use the email address
+ address = email;
+ } else {
+ // otherwise,
pretty-format it
+ address << "\""
<< name << "\" <" << email << ">";
+ }
+
+ _AddAddress(address);
+ }
+ } else {
+ forward = true;
+ forwardRefs.AddRef("refs",
&ref);
+ }
+ }
+ }
+
+ if (forward) {
+ // Pass on to parent
+ Window()->PostMessage(&forwardRefs, Parent());
+ }
+ break;
+ }
+
+ case M_SELECT:
+ {
+ BTextView *textView = (BTextView *)ChildAt(0);
+ if (textView != NULL)
+ textView->Select(0, textView->TextLength());
+ break;
+ }
+
+ case kMsgAddAddress:
+ {
+ const char* email;
+ for (int32 index = 0;
+ message->FindString("email", index++,
&email) == B_OK;)
+ _AddAddress(email);
+ break;
+ }
+
+ default:
+ BControl::MessageReceived(message);
+ break;
+ }
+}
+
+
+const BMessage*
+AddressTextControl::ModificationMessage() const
+{
+ return fTextView->ModificationMessage();
+}
+
+
+void
+AddressTextControl::SetModificationMessage(BMessage* message)
+{
+ fTextView->SetModificationMessage(message);
+}
+
+
+bool
+AddressTextControl::IsEditable() const
+{
+ return fEditable;
+}
+
+
+void
+AddressTextControl::SetEditable(bool editable)
+{
+ fTextView->MakeEditable(IsEnabled() && editable);
+ fEditable = editable;
+
+ if (editable && fPopUpButton->IsHidden(this))
+ fPopUpButton->Show();
+ else if (!editable && !fPopUpButton->IsHidden(this))
+ fPopUpButton->Hide();
+}
+
+
+void
+AddressTextControl::SetText(const char* text)
+{
+ if (text == NULL || Text() == NULL || strcmp(Text(), text) != 0) {
+ fTextView->SetUpdateAutoCompleterChoices(false);
+ fTextView->SetText(text);
+ fTextView->SetUpdateAutoCompleterChoices(true);
+ }
+}
+
+
+const char*
+AddressTextControl::Text() const
+{
+ return fTextView->Text();
+}
+
+
+int32
+AddressTextControl::TextLength() const
+{
+ return fTextView->TextLength();
+}
+
+
+void
+AddressTextControl::GetSelection(int32* start, int32* end) const
+{
+ fTextView->GetSelection(start, end);
+}
+
+
+void
+AddressTextControl::Select(int32 start, int32 end)
+{
+ fTextView->Select(start, end);
+}
+
+
+void
+AddressTextControl::SelectAll()
+{
+ fTextView->Select(0, TextLength());
+}
+
+
+bool
+AddressTextControl::HasFocus()
+{
+ return fTextView->IsFocus();
+}
+
+
+void
+AddressTextControl::_AddAddress(const char* text)
+{
+ int last = fTextView->TextLength();
+ if (last != 0) {
+ fTextView->Select(last, last);
+ // TODO: test if there is already a ','
+ fTextView->Insert(", ");
+ }
+ fTextView->Insert(text);
+}
+
+
+void
+AddressTextControl::_UpdateTextViewColors(bool enabled)
+{
+ BFont font;
+ fTextView->GetFontAndColor(0, &font);
+
+ rgb_color textColor;
+ if (enabled)
+ textColor = ui_color(B_DOCUMENT_TEXT_COLOR);
+ else {
+ textColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
+ B_DISABLED_LABEL_TINT);
+ }
+
+ fTextView->SetFontAndColor(&font, B_FONT_ALL, &textColor);
+
+ rgb_color color;
+ if (enabled)
+ color = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
+ else {
+ color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
+ B_LIGHTEN_2_TINT);
+ }
+
+ fTextView->SetViewColor(color);
+ fTextView->SetLowColor(color);
+}
diff --git a/src/apps/mail/AddressTextControl.h
b/src/apps/mail/AddressTextControl.h
new file mode 100644
index 0000000..0ba6074
--- /dev/null
+++ b/src/apps/mail/AddressTextControl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef ADDRESS_TEXT_CONTROL_H
+#define ADDRESS_TEXT_CONTROL_H
+
+
+#include <Control.h>
+
+
+class BButton;
+class BPopUpMenu;
+class BTextView;
+
+
+class AddressTextControl : public BControl {
+public:
+
AddressTextControl(const char* name,
+
BMessage* message);
+ virtual ~AddressTextControl();
+
+ virtual void AttachedToWindow();
+ virtual void WindowActivated(bool active);
+ virtual void Draw(BRect updateRect);
+ virtual void MakeFocus(bool focus = true);
+ virtual void SetEnabled(bool enabled);
+ virtual void MessageReceived(BMessage*
message);
+
+ const BMessage* ModificationMessage() const;
+ void
SetModificationMessage(BMessage* message);
+
+ bool IsEditable() const;
+ void SetEditable(bool
editable);
+
+ void SetText(const char*
text);
+ const char* Text() const;
+ int32 TextLength() const;
+ void GetSelection(int32*
start, int32* end) const;
+ void Select(int32 start,
int32 end);
+ void SelectAll();
+
+ bool HasFocus();
+
+private:
+ void _AddAddress(const char*
text);
+ void
_UpdateTextViewColors(bool enabled);
+
+private:
+ class TextView;
+ class PopUpButton;
+
+ TextView* fTextView;
+ PopUpButton* fPopUpButton;
+ BPopUpMenu* fRefDropMenu;
+ bool fWindowActive;
+ bool fEditable;
+};
+
+
+#endif // ADDRESS_TEXT_CONTROL_H
+
diff --git a/src/apps/mail/ComboBox.cpp b/src/apps/mail/ComboBox.cpp
deleted file mode 100644
index 0424ac0..0000000
--- a/src/apps/mail/ComboBox.cpp
+++ /dev/null
@@ -1,1984 +0,0 @@
-/*
-Open Tracker License
-
-Terms and Conditions
-
-Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice applies to all licensees
-and shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN
CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of Be Incorporated shall not be
-used in advertising or otherwise to promote the sale, use or other dealings in
-this Software without prior written authorization from Be Incorporated.
-
-BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or
registered trademarks
-of Be Incorporated in the United States and other countries. Other brand
product
-names are registered trademarks or trademarks of their respective holders.
-All rights reserved.
-*/
-
-//
-// ComboBox.cpp
-//
-//
-
-/*
- TODO:
- - Better up/down arrow handling (if text in input box matches a
list item,
- pressing down should select the next item, pressing up should
select the
- previous. If no item matched, the first or last item should
be selected.
- In any case, pressing up or down should show the popup if it
is hidden
- - Properly draw the label, taking alignment into account
- - Draw nicer border around text input and popup window
- - Escaping out of the popup menu should restore the text in the
input to the
- value it had previous to popping up the menu.
- - Fix popup behavior when the widget is near the bottom of the
screen. The
- popup window should be able to go above the text input area.
Also, the popup
- should size itself in a smart manner so that it is small if
there are few
- choices and large if there are many and the window under it
is big. Perhaps
- the developer should be able to influence the size of the
popup.
- - Improve button drawing and (?) button behavior
- - Fix and test enable/disable behavior
- - Add auto-scrolling and/or drag-scrolling to the poup-menu
- - Add support for other navigation keys, like page up, page
down, home, end.
- - Fix up choice functions (remove choice, add at index, etc)
and make sure they
- properly invalidate/scroll/etc the list when it is visible
- - Change auto-complete behavior to be non-greedy, or perhaps
add some type of
- tab-cycling to the choices
- - Add mode whereby you can pop up a list of only those items
that match
-*/
-
-#include <Button.h>
-#include <Debug.h>
-#include <InterfaceDefs.h>
-#include <ListItem.h>
-#include <ListView.h>
-#include <Menu.h> // for menu_info
-#include <MessageFilter.h>
-#include "ObjectList.h"
-#include <ScrollBar.h>
-#include <String.h>
-#include <TextControl.h>
-#include <Window.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "ComboBox.h"
-
-//static const uint32 kTextControlInvokeMessage = 'tCIM';
-static const uint32 kTextInputModifyMessage = 'tIMM';
-static const uint32 kPopupButtonInvokeMessage = 'pBIM';
-static const uint32 kPopupWindowHideMessage = 'pUWH';
-static const uint32 kWindowMovedMessage = 'wMOV';
-
-static const float kTextInputMargin = (float)3.0;
-static const float kLabelRightMargin = (float)6.0;
-static const float kButtonWidth = (float)15.0;
-
-#define disable_color(_c_) tint_color(_c_, B_DISABLED_LABEL_TINT)
-
-#define TV_MARGIN 3.0
-#define TV_DIVIDER_MARGIN 6.0
-
-rgb_color create_color(uchar r, uchar g, uchar b, uchar a = 255);
-
-rgb_color create_color(uchar r, uchar g, uchar b, uchar a) {
- rgb_color col;
- col.red = r;
- col.green = g;
- col.blue = b;
- col.alpha = a;
- return col;
-}
-
-class StringObjectList : public BObjectList<BString> {};
-
-// ----------------------------------------------------------------------------
-
-// ChoiceListView is similar to a BListView, but it's implementation is tied to
-// BComboBox. BListView is not used because it requires that a BStringItem be
-// created for each choice. ChoiceListView just pulls the choice strings
-// directly from the BComboBox and draws them.
-class BComboBox::ChoiceListView : public BView
-{
- public:
- ChoiceListView( BRect frame, BComboBox *parent);
- virtual ~ChoiceListView();
-
- virtual void Draw(BRect update);
- virtual void MouseDown(BPoint where);
- virtual void MouseUp(BPoint where);
- virtual void MouseMoved(BPoint where, uint32 transit,
- const BMessage *dragMessage);
- virtual void KeyDown(const char *bytes, int32 numBytes);
- virtual void SetFont(const BFont *font, uint32 properties =
B_FONT_ALL);
-
- void ScrollToSelection();
- void InvalidateItem(int32 index, bool force = false);
- BRect ItemFrame(int32 index);
- void AdjustScrollBar();
- // XXX: add BArchivable functionality
-
- private:
- inline float LineHeight();
-
- BPoint fClickLoc;
- font_height fFontHeight;
- bigtime_t fClickTime;
- rgb_color fForeCol;
- rgb_color fBackCol;
- rgb_color fSelCol;
- int32 fSelIndex;
- BComboBox *fParent;
- bool fTrackingMouseDown;
-};
-
-
-// ----------------------------------------------------------------------------
-
-// TextInput is a somewhat modified version of the _BTextInput_ class defined
-// in TextControl.cpp.
-
-class BComboBox::TextInput : public BTextView {
- public:
- TextInput(BRect rect, BRect trect, ulong rMask, ulong flags);
- TextInput(BMessage *data);
- virtual ~TextInput();
- static BArchivable *Instantiate(BMessage *data);
- virtual status_t Archive(BMessage *data, bool deep = true)
const;
-
- virtual void KeyDown(const char *bytes, int32 numBytes);
- virtual void MakeFocus(bool state);
- virtual void FrameResized(float x, float y);
- virtual void Paste(BClipboard *clipboard);
-
- void AlignTextRect();
-
- void SetInitialText();
- void SetFilter(text_input_filter_hook hook);
-
- // XXX: add BArchivable functionality
-
- protected:
- virtual void InsertText(const char *inText, int32 inLength,
int32 inOffset,
- const text_run_array *inRuns);
- virtual void DeleteText(int32 fromOffset, int32 toOffset);
-
- private:
- char *fInitialText;
- text_input_filter_hook fFilter;
- bool fClean;
-};
-
-// ----------------------------------------------------------------------------
-
-class BComboBox::ComboBoxWindow : public BWindow
-{
- public:
- ComboBoxWindow(BComboBox *box);
- virtual ~ComboBoxWindow();
- virtual void WindowActivated(bool active);
- virtual void FrameResized(float width, float height);
-
- void DoPosition();
- BComboBox::ChoiceListView *ListView();
- BScrollBar *ScrollBar();
-
- // XXX: add BArchivable functionality
-
- private:
- BScrollBar *fScrollBar;
- ChoiceListView *fListView;
- BComboBox *fParent;
-};
-
-// ----------------------------------------------------------------------------
-
-// In BeOS R4.5, SetEventMask(B_POINTER_EVENTS, ...) does not work for getting
-// all mouse events as they happen. Specifically, when the user clicks on the
-// window dressing (the borders or the title tab) no mouse event will be
-// delivered until after the user releases the mouse button. This has the
-// unfortunate side effect of allowing the user to move the window that
-// contains the BComboBox around with no notification being sent to the
-// BComboBox. We need to intercept the B_WINDOW_MOVED messages so that we can
-// hide the popup window when the window moves.
-
-class BComboBox::MovedMessageFilter : public BMessageFilter
-{
- public:
- MovedMessageFilter(BHandler *target);
- virtual filter_result Filter(BMessage *message, BHandler
**target);
-
- private:
- BHandler *fTarget;
-};
-
-
-// ----------------------------------------------------------------------------
-
-
-BComboBox::ChoiceListView::ChoiceListView(BRect frame, BComboBox *parent)
- : BView(frame, "_choice_list_view_", B_FOLLOW_ALL_SIDES, B_WILL_DRAW
- | B_NAVIGABLE),
- fClickLoc(-100, -100)
-{
- fParent = parent;
- GetFontHeight(&fFontHeight);
- menu_info mi;
- get_menu_info(&mi);
- fForeCol = create_color(0, 0, 0);
- fBackCol = mi.background_color;
- fSelCol = create_color(144, 144, 144);
- SetViewColor(B_TRANSPARENT_COLOR);
- SetHighColor(fForeCol);
- fTrackingMouseDown = false;
- fClickTime = 0;
-}
-
-
-BComboBox::ChoiceListView::~ChoiceListView()
-{
-}
-
-
-void BComboBox::ChoiceListView::Draw(BRect update)
-{
- float h = LineHeight();
- BRect rect(Bounds());
- int32 index;
- int32 choices = fParent->fChoiceList->CountChoices();
- int32 selected = (fTrackingMouseDown) ? fSelIndex :
fParent->CurrentSelection();
-
- // draw each visible item
- for (index = (int32)floor(update.top / h); index < choices; index++)
- {
- rect.top = index * h;
- rect.bottom = rect.top + h;
- SetLowColor((index == selected) ? fSelCol : fBackCol);
- FillRect(rect, B_SOLID_LOW);
- DrawString(fParent->fChoiceList->ChoiceAt(index),
BPoint(rect.left + 2,
- rect.bottom - fFontHeight.descent - 1));
- }
-
- // draw empty area on bottom
- if (rect.bottom < update.bottom)
- {
- update.top = rect.bottom;
- SetLowColor(fBackCol);
- FillRect(update, B_SOLID_LOW);
- }
-}
-
-
-void BComboBox::ChoiceListView::MouseDown(BPoint where)
-{
- BRect rect(Window()->Frame());
- ConvertFromScreen(&rect);
- if (!rect.Contains(where))
- {
- // hide the popup window when the user clicks outside of it
- if (fParent->Window()->Lock())
- {
- fParent->HidePopupWindow();
- fParent->Window()->Unlock();
- }
-
- // HACK: the window is locked and unlocked so that it will get
- // activated before we potentially send the mouse down event in
the
- // code below. Is there a way to wait until the window is
activated
- // before sending the mouse down? Should we call
- // fParent->Window()->MakeActive(true) here?
-
- if (fParent->Window()->Lock())
- {
- // resend the mouse event to the textinput, if necessary
- BTextView *text = fParent->TextView();
- BPoint screenWhere(ConvertToScreen(where));
- rect = text->Window()->ConvertToScreen(text->Frame());
- if (rect.Contains(screenWhere))
- {
- //printf(" resending mouse down to
textinput\n");
- BMessage *msg = new
BMessage(*Window()->CurrentMessage());
- msg->RemoveName("be:view_where");
- text->ConvertFromScreen(&screenWhere);
- msg->AddPoint("be:view_where", screenWhere);
- text->Window()->PostMessage(msg, text);
- delete msg;
- }
- fParent->Window()->Unlock();
- }
-
- return;
- }
-
- rect = Bounds();
- if (!rect.Contains(where))
- return;
-
- fTrackingMouseDown = true;
- // check for double click
- bigtime_t now = system_time();
- bigtime_t clickSpeed;
- get_click_speed(&clickSpeed);
- if ((now - fClickTime < clickSpeed)
- && ((abs((int)(fClickLoc.x - where.x)) < 3)
- && (abs((int)(fClickLoc.y - where.y)) < 3)))
- {
- // this is a double click
- // XXX: what to do here?
- printf("BComboBox::ChoiceListView::MouseDown() -- unhandled
double click\n");
- }
- fClickTime = now;
- fClickLoc = where;
-
- float h = LineHeight();
- int32 oldIndex = fSelIndex;
- fSelIndex = (int32)floor(where.y / h);
- int32 choices = fParent->fChoiceList->CountChoices();
- if (fSelIndex < 0 || fSelIndex >= choices)
- fSelIndex = -1;
-
- if (oldIndex != fSelIndex)
- {
- InvalidateItem(oldIndex);
- InvalidateItem(fSelIndex);
- }
- // XXX: this probably isn't necessary since we are doing a SetEventMask
- // whenever the popup window becomes visible which routes all mouse
events
- // to this view
-// SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
-}
-
-
-void BComboBox::ChoiceListView::MouseUp(BPoint /*where*/)
-{
- if (fTrackingMouseDown)
- {
- fTrackingMouseDown = false;
- if (fSelIndex >= 0)
- fParent->Select(fSelIndex, true);
- else
- fParent->Deselect();
- }
-// fClickLoc = where;
-}
-
-
-void BComboBox::ChoiceListView::MouseMoved(BPoint where, uint32 /*transit*/,
- const BMessage */*dragMessage*/)
-{
- if (fTrackingMouseDown)
- {
- float h = LineHeight();
- int32 oldIndex = fSelIndex;
- fSelIndex = (int32)floor(where.y / h);
- int32 choices = fParent->fChoiceList->CountChoices();
- if (fSelIndex < 0 || fSelIndex >= choices)
- fSelIndex = -1;
-
- if (oldIndex != fSelIndex)
- {
- InvalidateItem(oldIndex);
- InvalidateItem(fSelIndex);
- }
- }
-}
-
-
-void BComboBox::ChoiceListView::KeyDown(const char *bytes, int32 /*numBytes*/)
-{
- BComboBox *cb = fParent;
- BWindow *win = cb->Window();
- BComboBox::TextInput *text =
dynamic_cast<BComboBox::TextInput*>(cb->TextView());
- uchar aKey = bytes[0];
-
- switch (aKey)
- {
- case B_UP_ARROW: // fall through
- case B_DOWN_ARROW:
- if (win->Lock())
- {
- // change the selection
- int32 index = cb->CurrentSelection();
- int32 choices = cb->fChoiceList->CountChoices();
- if (choices > 0)
- {
- if (index < 0)
- {
- // no previous selection, so
select first or last item
- // depending on whether this is
a up or down arrow
- cb->Select((aKey == B_UP_ARROW)
? choices - 1 : 0);
- }
- else
- {
- // select the previous or the
next item, if possible,
- // depending on whether this is
an up or down arrow
- if (aKey == B_UP_ARROW &&
(index - 1 >= 0))
- cb->Select(index - 1,
true);
- else if (aKey == B_DOWN_ARROW
&& (index + 1 < choices))
- cb->Select(index + 1,
true);
- }
- }
- win->Unlock();
- }
- break;
- default:
- { // send all other key down events to the text input view
- BMessage *msg = Window()->DetachCurrentMessage();
- if (msg) {
- win->PostMessage(msg, text);
- delete msg;
- }
- break;
- }
- }
-}
-
-
-void BComboBox::ChoiceListView::SetFont(const BFont *font, uint32 properties)
-{
- BView::SetFont(font, properties);
- GetFontHeight(&fFontHeight);
- Invalidate();
-}
-
-
-void BComboBox::ChoiceListView::ScrollToSelection()
-{
- int32 selected = fParent->CurrentSelection();
- if (selected >= 0)
- {
- BRect frame(ItemFrame(selected));
- BRect bounds(Bounds());
- float newY = -1.0; // dummy value -- not used
- bool doScroll = false;
-
- if (frame.bottom > bounds.bottom)
- {
- newY = frame.bottom - bounds.Height();
- doScroll = true;
- }
- else if (frame.top < bounds.top)
- {
- newY = frame.top;
- doScroll = true;
- }
- if (doScroll)
- ScrollTo(bounds.left, newY);
- }
-}
-
-// InvalidateItem() only does a real invalidate if the index is valid or the
-// force flag is turned on
-
-void BComboBox::ChoiceListView::InvalidateItem(int32 index, bool force)
-{
- int32 choices = fParent->fChoiceList->CountChoices();
- if ((index >= 0 && index < choices) || force) {
- Invalidate(ItemFrame(index));
- }
-}
-
-// This method doesn't check the index to see if it is valid, it just returns
-// the BRect that an item and the index would have if it existed.
-
-BRect BComboBox::ChoiceListView::ItemFrame(int32 index)
-{
- BRect rect(Bounds());
- float h = LineHeight();
- rect.top = index * h;
- rect.bottom = rect.top + h;
- return rect;
-}
-
-// The window must be locked before this method is called
-
-void BComboBox::ChoiceListView::AdjustScrollBar()
-{
- BScrollBar *sb = ScrollBar(B_VERTICAL);
- if (sb) {
- float h = LineHeight();
- float max = h * fParent->fChoiceList->CountChoices();
- BRect frame(Frame());
- float diff = max - frame.Height();
- float prop = frame.Height() / max;
- if (diff < 0) {
- diff = 0.0;
- prop = 1.0;
- }
- sb->SetSteps(h, h * (frame.IntegerHeight() / h));
- sb->SetRange(0.0, diff);
- sb->SetProportion(prop);
- }
-}
-
-
-float BComboBox::ChoiceListView::LineHeight()
-{
- return fFontHeight.ascent + fFontHeight.descent + fFontHeight.leading +
2;
-}
-
-
-// ----------------------------------------------------------------------------
-// #pragma mark -
-
-
-BComboBox::TextInput::TextInput(BRect rect, BRect textRect, ulong rMask,
- ulong flags)
- : BTextView(rect, "_input_", textRect, be_plain_font, NULL, rMask,
flags),
- fFilter(NULL)
-{
- MakeResizable(true);
- fInitialText = NULL;
- fClean = false;
-}
-
-
-BComboBox::TextInput::TextInput(BMessage *data)
- : BTextView(data),
- fFilter(NULL)
-{
- MakeResizable(true);
- fInitialText = NULL;
- fClean = false;
-}
-
-
-BComboBox::TextInput::~TextInput()
-{
- free(fInitialText);
-}
-
-
-status_t
-BComboBox::TextInput::Archive(BMessage* data, bool /*deep*/) const
-{
- return BTextView::Archive(data);
-}
-
-
-BArchivable *
-BComboBox::TextInput::Instantiate(BMessage* data)
-{
- // XXX: is "TextInput" the correct name for this class? Perhaps
- // BComboBox::TextInput?
- if (!validate_instantiation(data, "TextInput"))
- return NULL;
-
- return new TextInput(data);
-}
-
-
-void
-BComboBox::TextInput::SetInitialText()
-{
- if (fInitialText) {
- free(fInitialText);
- fInitialText = NULL;
- }
- if (Text())
- fInitialText = strdup(Text());
-}
-
-
-void
-BComboBox::TextInput::SetFilter(text_input_filter_hook hook)
-{
- fFilter = hook;
-}
-
-
-void
-BComboBox::TextInput::KeyDown(const char *bytes, int32 numBytes)
-{
- BComboBox* cb;
- uchar aKey = bytes[0];
-
- switch (aKey) {
- case B_RETURN:
- cb = dynamic_cast<BComboBox*>(Parent());
- ASSERT(cb);
-
- if (!cb->IsEnabled())
- break;
-
- ASSERT(fInitialText);
- if (strcmp(fInitialText, Text()) != 0)
- cb->CommitValue();
- free(fInitialText);
- fInitialText = strdup(Text());
- {
- int32 end = TextLength();
- Select(end, end);
- }
- // hide popup window if it's showing when the user
presses the
- // enter key
- if (cb->fPopupWindow && cb->fPopupWindow->Lock()) {
- if (!cb->fPopupWindow->IsHidden()) {
- cb->HidePopupWindow();
- }
- cb->fPopupWindow->Unlock();
- }
- break;
- case B_TAB:
-// cb = dynamic_cast<BComboBox*>Parent());
-// ASSERT(cb);
-// if (cb->fAutoComplete && cb->fCompletionIndex >= 0) {
-// int32 from, to;
-// cb->fText->GetSelection(&from, &to);
-// if (from == to) {
-// // HACK: this should never happen. The
rest of the class
-// // should be fixed so that
fCompletionIndex is set to -1 if the
-// // text is modified
-// printf("BComboBox::TextInput::KeyDown()
-- HACK! this shouldn't happen!");
-// cb->fCompletionIndex = -1;
-// }
-//
-// const char *text = cb->fText->Text();
-// BString prefix;
-// prefix.Append(text, from);
-//
-// int32 match;
-// const char *completion;
-// if (cb->fChoiceList->GetMatch( prefix.String(),
-//
cb->fCompletionIndex + 1,
-//
&match,
-//
&completion) == B_OK)
-// {
-// cb->fText->Delete();
// delete the selection
-// cb->fText->Insert(completion);
-// cb->fText->Select(from, from +
strlen(completion));
-// cb->fCompletionIndex = match;
-// cb->Select(cb->fCompletionIndex);
-// } else {
-// //system_beep();
-// }
-// } else {
- BView::KeyDown(bytes, numBytes);
-// }
- break;
-#if 0
- case B_UP_ARROW: // fall through
- case B_DOWN_ARROW:
- cb = dynamic_cast<BComboBox*>(Parent());
- ASSERT(cb);
- if (cb->fChoiceList) {
- cb = dynamic_cast<BComboBox*>(Parent());
- ASSERT(cb);
- if (!(cb->fPopupWindow)) {
- cb->fPopupWindow =
cb->CreatePopupWindow();
- }
- if (cb->fPopupWindow->Lock()) {
- // show popup window, if needed
- if (cb->fPopupWindow->IsHidden()) {
- cb->ShowPopupWindow();
- } else {
- printf("Whoa!!! Erroneously got
up/down arrow key down in TextInput::KeyDown()!\n");
- }
- int32 index = cb->CurrentSelection();
- int32 choices =
cb->fChoiceList->CountChoices();
- // select something, if no selection
- if (index < 0 && choices > 0) {
- if (aKey == B_UP_ARROW) {
- cb->Select(choices - 1);
- } else {
- cb->Select(0);
- }
- }
- cb->fPopupWindow->Unlock();
- }
- }
- break;
-#endif
- case B_ESCAPE:
- cb = dynamic_cast<BComboBox*>(Parent());
- ASSERT(cb);
- if (cb->fChoiceList)
- {
- cb = dynamic_cast<BComboBox*>(Parent());
- ASSERT(cb);
- if (cb->fPopupWindow &&
cb->fPopupWindow->Lock())
- {
- if (!cb->fPopupWindow->IsHidden())
- cb->HidePopupWindow();
-
- cb->fPopupWindow->Unlock();
- }
- }
- break;
- case ',':
- {
- int32 startSel, endSel;
- GetSelection(&startSel, &endSel);
- int32 length = TextLength();
- if (endSel == length)
- Select(endSel, endSel);
- BTextView::KeyDown(bytes, numBytes);
- }
- break;
- default:
- BTextView::KeyDown(bytes, numBytes);
- break;
- }
-}
-
-
-void
-BComboBox::TextInput::MakeFocus(bool state)
-{
-//+ PRINT(("_BTextInput_::MakeFocus(state=%d, view=%s)\n", state,
-//+ Parent()->Name()));
- if (state == IsFocus())
- return;
-
- BComboBox* parent = dynamic_cast<BComboBox*>(Parent());
- ASSERT(parent);
-
- BTextView::MakeFocus(state);
-
- if (state) {
- SetInitialText();
- fClean = true; // text hasn't been dirtied yet.
-
- BMessage *m;
- if (Window() && (m = Window()->CurrentMessage()) != 0
- && m->what == B_KEY_DOWN) {
- // we're being focused by a keyboard event, so
- // select all...
- SelectAll();
- }
- } else {
- ASSERT(fInitialText);
- if (strcmp(fInitialText, Text()) != 0)
- parent->CommitValue();
-
- free(fInitialText);
- fInitialText = NULL;
- fClean = false;
- BMessage *m;
- if (Window() && (m = Window()->CurrentMessage()) != 0 &&
m->what == B_MOUSE_DOWN)
- Select(0,0);
-
- // hide popup window if it's showing when the text input loses
focus
- if (parent->fPopupWindow && parent->fPopupWindow->Lock()) {
- if (!parent->fPopupWindow->IsHidden())
- parent->HidePopupWindow();
-
- parent->fPopupWindow->Unlock();
- }
- }
-
- // make sure the focus indicator gets drawn or undrawn
- if (Window()) {
- BRect invalRect(Bounds());
- invalRect.InsetBy(-kTextInputMargin, -kTextInputMargin);
- parent->Draw(invalRect);
- parent->Flush();
- }
-}
-
-
-void
-BComboBox::TextInput::FrameResized(float x, float y)
-{
- BTextView::FrameResized(x, y);
- AlignTextRect();
-}
-
-
-void
-BComboBox::TextInput::Paste(BClipboard *clipboard)
-{
- BTextView::Paste(clipboard);
- Invalidate();
-}
-
-
-// What a hack...
-void
-BComboBox::TextInput::AlignTextRect()
-{
- BRect bounds = Bounds();
- BRect textRect = TextRect();
-
- switch (Alignment()) {
- default:
- case B_ALIGN_LEFT:
- textRect.OffsetTo(B_ORIGIN);
- break;
-
- case B_ALIGN_CENTER:
- textRect.OffsetTo((bounds.Width() - textRect.Width()) /
2,
- textRect.top);
- break;
-
- case B_ALIGN_RIGHT:
- textRect.OffsetTo(bounds.Width() - textRect.Width(),
textRect.top);
- break;
- }
-
- SetTextRect(textRect);
-}
-
-
-void
-BComboBox::TextInput::InsertText(const char *inText, int32 inLength,
- int32 inOffset, const text_run_array *inRuns)
-{
- char* ptr = NULL;
-
- // strip out any return characters
- // limiting to a reasonable amount of chars for a text control.
- // otherwise this code could malloc some huge amount which isn't good.
- if (strpbrk(inText, "\r\n") && inLength <= 1024) {
- int32 len = inLength;
- ptr = (char *)malloc(len + 1);
- if (ptr) {
- strncpy(ptr, inText, len);
- ptr[len] = '\0';
-
- char *p = ptr;
-
- while (len--) {
- if (*p == '\n')
- *p = ' ';
- else if (*p == '\r')
- *p = ' ';
-
- p++;
- }
- }
- }
-
- if (fFilter != NULL)
- inText = fFilter(inText, inLength, inRuns);
- BTextView::InsertText(ptr ? ptr : inText, inLength, inOffset, inRuns);
-
- BComboBox *parent = dynamic_cast<BComboBox *>(Parent());
- if (parent) {
- if (parent->fModificationMessage)
- parent->Invoke(parent->fModificationMessage);
-
- BMessage *msg;
- parent->Window()->PostMessage(msg = new
BMessage(kTextInputModifyMessage),
- parent);
- delete msg;
- }
-
- if (ptr)
- free(ptr);
-}
-
-
-void
-BComboBox::TextInput::DeleteText(int32 fromOffset, int32 toOffset)
-{
- BTextView::DeleteText(fromOffset, toOffset);
- BComboBox *parent = dynamic_cast<BComboBox *>(Parent());
- if (parent) {
- if (parent->fModificationMessage)
- parent->Invoke(parent->fModificationMessage);
-
- BMessage *msg;
- parent->Window()->PostMessage(msg = new
BMessage(kTextInputModifyMessage),
- parent);
- delete msg;
- }
-}
-
-
-// #pragma mark -
-
-
-BComboBox::ComboBoxWindow::ComboBoxWindow(BComboBox *box)
- : BWindow(BRect(0, 0, 10, 10), NULL, B_BORDERED_WINDOW_LOOK,
- B_FLOATING_SUBSET_WINDOW_FEEL, B_NOT_MOVABLE | B_NOT_RESIZABLE
- | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
- | B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS)
-{
- fParent = box;
- DoPosition();
- BWindow *parentWin = fParent->Window();
- if (parentWin)
- AddToSubset(parentWin);
-
- BRect rect(Bounds());
- rect.right -= B_V_SCROLL_BAR_WIDTH;
- fListView = new ChoiceListView(rect, fParent);
- AddChild(fListView);
- rect.left = rect.right;
- rect.right += B_V_SCROLL_BAR_WIDTH;
- fScrollBar = new BScrollBar(rect, "_popup_scroll_bar_", fListView, 0,
1000,
- B_VERTICAL);
- AddChild(fScrollBar);
- fListView->AdjustScrollBar();
-}
-
-
-BComboBox::ComboBoxWindow::~ComboBoxWindow()
-{
- fListView->RemoveSelf();
- delete fListView;
-}
-
-
-void BComboBox::ComboBoxWindow::WindowActivated(bool /*active*/)
-{
-// if (active)
-// fListView->AdjustScrollBar();
-}
-
-
-void BComboBox::ComboBoxWindow::FrameResized(float /*width*/, float /*height*/)
-{
- fListView->AdjustScrollBar();
-}
-
-
-void BComboBox::ComboBoxWindow::DoPosition()
-{
- BRect winRect(fParent->fText->Frame());
- winRect = fParent->ConvertToScreen(winRect);
-// winRect.left += fParent->Divider() + 5;
- winRect.right -= 2;
- winRect.OffsetTo(winRect.left, winRect.bottom + kTextInputMargin);
- winRect.bottom = winRect.top + 100;
- MoveTo(winRect.LeftTop());
- ResizeTo(winRect.IntegerWidth(), winRect.IntegerHeight());
-}
-
-
-BComboBox::ChoiceListView *BComboBox::ComboBoxWindow::ListView()
-{
- return fListView;
-}
-
-
-BScrollBar *BComboBox::ComboBoxWindow::ScrollBar()
-{
- return fScrollBar;
-}
-
-
-// ----------------------------------------------------------------------------
-// #pragma mark -
-
-
-BComboBox::BComboBox(BRect frame, const char *name, const char *label,
- BMessage *message, uint32 resizeMask, uint32 flags)
- : BControl(frame, name, label, message, resizeMask,
- flags | B_WILL_DRAW | B_FRAME_EVENTS),
- fPopupWindow(NULL),
- fModificationMessage(NULL),
- fChoiceList(0),
- fLabelAlign(B_ALIGN_LEFT),
- fAutoComplete(false),
- fButtonDepressed(false),
- fDepressedWhenClicked(false),
- fTrackingButtonDown(false),
- fFrameCache(frame)
-{
- // If the user wants this control to be keyboard navigable, then we
really
- // want the underlying text view to be navigable, not this view.
- bool navigate = ((Flags() & B_NAVIGABLE) != 0);
- if (navigate)
- {
- fSkipSetFlags = true;
- SetFlags(Flags() & ~B_NAVIGABLE); // disable navigation
for this
- fSkipSetFlags = false;
- }
-
- fDivider = StringWidth(label);
-
- BRect rect(frame);
- rect.OffsetTo(0, 0);
- rect.left += fDivider + kLabelRightMargin;
-// rect.right -= kButtonWidth + 1;
-// rect.right;
- rect.InsetBy(kTextInputMargin, kTextInputMargin);
- BRect textRect(rect);
- textRect.OffsetTo(0, 0);
- textRect.left += 2;
- textRect.right -= 2;
-
- fText = new TextInput(rect, textRect, B_FOLLOW_TOP |
B_FOLLOW_LEFT_RIGHT,
- B_WILL_DRAW | B_FRAME_EVENTS | (navigate ? B_NAVIGABLE : 0));
- float height = fText->LineHeight();
- rect.bottom = rect.top + height;
-// fText->ResizeTo(rect.IntegerWidth(), height);
- AddChild(fText);
-
- font_height fontInfo;
- GetFontHeight(&fontInfo);
- float h1 = ceil(fontInfo.ascent + fontInfo.descent + fontInfo.leading);
- float h2 = fText->LineHeight();
-
- // Height of main view must be the larger of h1 and h2+(TV_MARGIN*2)
- float h = (h1 > h2 + (TV_MARGIN*2)) ? h1 : h2 + (TV_MARGIN*2);
- BRect b = Bounds();
- ResizeTo(b.Width(), h);
- b.bottom = h;
-
- // set height and position of text entry view
- fText->ResizeTo(fText->Bounds().Width(), h2);
- // vertically center this view
- fText->MoveBy(0, (b.Height() - (h2+(TV_MARGIN*2))) / 2);
-
- rect.left = rect.right + 1;
- rect.right = rect.left + kButtonWidth;
-
- fButtonRect = rect;
- fTextEnd = 0;
- fSelected = -1;
- fCompletionIndex = -1;
- fWinMovedFilter = new MovedMessageFilter(this);
-}
-
-
-BComboBox::~BComboBox()
-{
- if (fPopupWindow && fPopupWindow->Lock())
- fPopupWindow->Quit();
-
- RemoveChild(fText);
- delete fText;
-
- if (fWinMovedFilter->Looper())
- fWinMovedFilter->Looper()->RemoveFilter(fWinMovedFilter);
-
- delete fWinMovedFilter;
-
-}
-
-
-void BComboBox::SetChoiceList(BChoiceList *list)
-{
-// delete fChoiceList;
- fChoiceList = list;
- ChoiceListUpdated();
-}
-
-
-BChoiceList *BComboBox::ChoiceList()
-{
- return fChoiceList;
-}
-
-
-void BComboBox::ChoiceListUpdated()
-{
- if (fPopupWindow && fPopupWindow->Lock())
- {
- if (!fPopupWindow->IsHidden())
- {
- // do an invalidate on the choice list
- fPopupWindow->ListView()->Invalidate();
- fPopupWindow->ListView()->AdjustScrollBar();
- // XXX: change the selection and select the proper
item, if possible
- }
- fPopupWindow->Unlock();
- }
-}
-
-
-//void BComboBox::AddChoice(const char *text)
-//{
-// fChoiceList.AddItem((char *)text);
-// if (fPopupWindow && fPopupWindow->Lock()) {
-// if (!fPopupWindow->IsHidden()) {
-// // do an invalidate on the new item's location
-// int32 index = CountChoices() - 1;
-// fPopupWindow->ListView()->InvalidateItem(index);
-// fPopupWindow->ListView()->AdjustScrollBar();
-// }
-// fPopupWindow->Unlock();
-// }
-//}
-
-
-//const char *BComboBox::ChoiceAt(int32 index)
-//{
-// return (const char *)fChoiceList.ItemAt(index);
-//}
-
-
-//int32 BComboBox::CountChoices()
-//{
-// return fChoiceList.CountItems();
-//}
-
-
-void
-BComboBox::Select(int32 index, bool changeTextSelection)
-{
- int32 oldIndex = fSelected;
- if (index < fChoiceList->CountChoices() && index >= 0) {
- BWindow *win = Window();
- bool gotLock = (win && win->Lock());
- if (!win || gotLock) {
- fSelected = index;
- if (fPopupWindow && fPopupWindow->Lock()) {
- ChoiceListView *lv = fPopupWindow->ListView();
- lv->InvalidateItem(oldIndex);
- lv->InvalidateItem(fSelected);
- lv->ScrollToSelection();
- fPopupWindow->Unlock();
- }
-
- if (changeTextSelection) {
- // Find last coma
- const char *ptr = fText->Text();
- const char *end;
- int32 tlength = fText->TextLength();
-
- for (end = ptr+tlength-1; end>ptr; end--) {
- if (*end == ',') {
- // Find end of whitespace
- for (end++; isspace(*end);
end++) {}
- break;
- }
- }
- int32 soffset = end-ptr;
- int32 eoffset = tlength;
- if (end != 0)
- fText->Delete(soffset, eoffset);
-
- tlength =
strlen(fChoiceList->ChoiceAt(fSelected));
- fText->Insert(soffset,
fChoiceList->ChoiceAt(fSelected), tlength);
- eoffset = fText->TextLength();
- fText->Select(soffset, eoffset);
-//
fText->SetText(fChoiceList->ChoiceAt(fSelected));
-// fText->SelectAll();
- }
-
- if (gotLock)
- win->Unlock();
- }
- } else {
- Deselect();
- return;
- }
-}
-
-
-void
-BComboBox::Deselect()
-{
- BWindow *win = Window();
- bool gotLock = (win && win->Lock());
- if (!win || gotLock) {
- int32 oldIndex = fSelected;
- fSelected = -1;
- // invalidate the old selected item, if needed
- if (oldIndex >= 0 && fPopupWindow && fPopupWindow->Lock()) {
- fPopupWindow->ListView()->InvalidateItem(oldIndex);
- fPopupWindow->Unlock();
- }
-
- if (gotLock)
- win->Unlock();
- }
-}
-
-
-int32
-BComboBox::CurrentSelection()
-{
- return fSelected;
-}
-
-
-void
-BComboBox::SetAutoComplete(bool on)
-{
- fAutoComplete = on;
-}
-
-
-bool
-BComboBox::GetAutoComplete()
-{
- return fAutoComplete;
-}
-
-
-void
-BComboBox::SetLabel(const char *text)
-{
- BControl::SetLabel(text);
- BRect invalRect = Bounds();
- invalRect.right = fDivider;
- Invalidate(invalRect);
-}
-
-
-void
-BComboBox::SetValue(int32 value)
-{
- BControl::SetValue(value);
-}
-
-
-void
-BComboBox::SetText(const char *text)
-{
- fText->SetText(text);
- if (fText->IsFocus())
- fText->SetInitialText();
-
- fText->Invalidate();
-}
-
-
-const char *
-BComboBox::Text() const
-{
- return fText->Text();
-}
-
-
-int32
-BComboBox::TextLength() const
-{
- return fText->TextLength();
-}
-
-
-BTextView *
-BComboBox::TextView()
-{
- return fText;
-}
-
-
-void
-BComboBox::SetDivider(float divide)
-{
- float diff = fDivider - divide;
- fDivider = divide;
-
- fText->MoveBy(-diff, 0);
- fText->ResizeBy(diff, 0);
-
- if (Window()) {
- fText->Invalidate();
- Invalidate();
- }
-}
-
-
-float
-BComboBox::Divider() const
-{
- return fDivider;
-}
-
-
-void
-BComboBox::SetAlignment(alignment label, alignment text)
-{
- fText->SetAlignment(text);
- fText->AlignTextRect();
-
- if (fLabelAlign != label) {
- fLabelAlign = label;
- Invalidate();
- }
-}
-
-
-void
-BComboBox::GetAlignment(alignment *label, alignment *text) const
-{
- *text = fText->Alignment();
- *label = fLabelAlign;
-}
-
-
-void
-BComboBox::SetModificationMessage(BMessage *message)
-{
- delete fModificationMessage;
- fModificationMessage = message;
-}
-
-
-BMessage *
-BComboBox::ModificationMessage() const
-{
- return fModificationMessage;
-}
-
-
-void
-BComboBox::SetFilter(text_input_filter_hook hook)
-{
- fText->SetFilter(hook);
-}
-
-
-void
-BComboBox::GetPreferredSize(float */*width*/, float */*height*/)
-{
-// BFont font;
-// GetFont(&font);
-//

[ *** diff truncated: 4714 lines dropped *** ]


############################################################################

Commit: d8919236503108a2db13c454109d7c7696677514
URL: http://cgit.haiku-os.org/haiku/commit/?id=d89192365031
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Sun Aug 30 19:15:16 2015 UTC

BMenuField: use layout rect for the label.

* Instead of just laying it out as without the layout API.

----------------------------------------------------------------------------

############################################################################

Commit: 8b1aaf348c30289eab0adc9799c1ce3e50473fd9
URL: http://cgit.haiku-os.org/haiku/commit/?id=8b1aaf348c30
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 06:10:39 2015 UTC

Mail: properly disable prev/next buttons without Tracker.

* The prev/next buttons will only work when invoked via an actual
mail file from Tracker.

----------------------------------------------------------------------------

############################################################################

Commit: cc7e5aac407f89e8eae8aaf6c19a80cb32c6d912
URL: http://cgit.haiku-os.org/haiku/commit/?id=cc7e5aac407f
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 07:13:36 2015 UTC

Mail: fAccount text control is no longer used.

----------------------------------------------------------------------------

############################################################################

Commit: 19d8cb703c30602e188891a9a82bfabe55f690e7
URL: http://cgit.haiku-os.org/haiku/commit/?id=19d8cb703c30
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 16:01:33 2015 UTC

BDate: added time_t constructor.

* This class is pretty much useless as it is.

----------------------------------------------------------------------------

############################################################################

Commit: 66078c7911354d2d37e4afe500b8a27be6a6b146
URL: http://cgit.haiku-os.org/haiku/commit/?id=66078c791135
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 16:04:03 2015 UTC

BMailComponent: made a few methods const.

----------------------------------------------------------------------------

############################################################################

Commit: 7bdee8beab1ad3214daaf55b42c56cc3e698065f
URL: http://cgit.haiku-os.org/haiku/commit/?id=7bdee8beab1a
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 16:14:17 2015 UTC

BEmailMessage: added missing const, Date() returns time_t.

* Added missing const to some getter methods.
* Date() now tries to parse the date of the mail, and return it as
a time_t; you can still retrieve the actual string via
HeaderField("Date") if you have to.
* Mail now shows the time in the local time zone, and with the
current locale.

----------------------------------------------------------------------------

############################################################################

Commit: 4182c53bc4cf0e2e8e801c14f8da5cddf534a376
URL: http://cgit.haiku-os.org/haiku/commit/?id=4182c53bc4cf
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 17:03:20 2015 UTC

Mail: change look of disabled text controls.

* Added HeaderTextControl that draws the text in black, and uses the
panel background without a frame when it's disabled. Only the label
is still drawn as disabled.
* Changed AddressTextControl to behave in the same way.
* The date view is now a HeaderTextControl, too.
* Unfortunately, the label is not vertically aligned with the contents.

----------------------------------------------------------------------------

############################################################################

Commit: 62c1b01661ebd296b1404ccd4e9f18e0ed61f731
URL: http://cgit.haiku-os.org/haiku/commit/?id=62c1b01661eb
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Mon Aug 31 17:30:32 2015 UTC

Mail: temporary workaround for the label placing issue.

* Does not work for all font sizes.

----------------------------------------------------------------------------

############################################################################

Commit: 15c1056242587294ef01a30fdb32518c842af881
URL: http://cgit.haiku-os.org/haiku/commit/?id=15c105624258
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Wed Sep 2 18:40:32 2015 UTC

BMailSettings: removed debug message dump.

----------------------------------------------------------------------------

############################################################################

Commit: 31c65be109011d26204e5924cd197b3ff121057c
URL: http://cgit.haiku-os.org/haiku/commit/?id=31c65be10901
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Wed Sep 2 18:54:59 2015 UTC

Mail: fixed crash on resend.

* Seems to have been there for quite some time. Probably a good
reason to remove that feature altogether.

----------------------------------------------------------------------------

############################################################################

Commit: 50d381e8620a847a3cc736e4983eddbfb7d9e421
URL: http://cgit.haiku-os.org/haiku/commit/?id=50d381e8620a
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Wed Sep 2 18:56:08 2015 UTC

Mail: use layout version of BMenuBar.

* Fixes layout issue: the minimal size was incorrect.
* Moved variable declaration to where it is actually used.

----------------------------------------------------------------------------

############################################################################

Commit: 6b8712663acc699606054363a509f6e6cbed3fd1
URL: http://cgit.haiku-os.org/haiku/commit/?id=6b8712663acc
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Wed Sep 2 19:31:09 2015 UTC

BToolBar: made FindButton() public.

----------------------------------------------------------------------------

############################################################################

Revision: hrev49614
Commit: 9ed8f484983a77a3b88adfa41e4136501b6df4b3
URL: http://cgit.haiku-os.org/haiku/commit/?id=9ed8f484983a
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Wed Sep 2 19:31:33 2015 UTC

Mail: show icons only setting works again.

* It will show the label as tool tip when the labels are hidden.

----------------------------------------------------------------------------


Other related posts: