* Reworded defines in Jamfiles to make them more readable.

* Split WebTabView into several files in a new sub-folder "tabview".
* Implemented scrolling the tab view left/right when there are more tabs than
  fit into the view.
* Fixed graphic glitches in the TabContainerView when the window is resized,
  the space behind the last tab was not managed properly.

git-svn-id: http://svn.haiku-os.org/webpositive/webkit/trunk@416 94f232f2-1747-11df-bad5-a5bfde151594
This commit is contained in:
stippi 2010-04-15 12:19:16 +00:00 committed by Alexandre Deckner
parent 6d93874469
commit 029353b44c
6 changed files with 1330 additions and 835 deletions

View File

@ -0,0 +1,520 @@
/*
* Copyright (C) 2010 Rene Gollent <rene@gollent.com>
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "TabContainerView.h"
#include <stdio.h>
#include <Application.h>
#include <AbstractLayoutItem.h>
#include <Bitmap.h>
#include <Button.h>
#include <CardLayout.h>
#include <ControlLook.h>
#include <GroupView.h>
#include <MenuBar.h>
#include <SpaceLayoutItem.h>
#include <Window.h>
#include "TabView.h"
static const float kLeftTabInset = 4;
TabContainerView::TabContainerView(Controller* controller)
:
BGroupView(B_HORIZONTAL),
fLastMouseEventTab(NULL),
fMouseDown(false),
fClickCount(0),
fSelectedTab(NULL),
fController(controller),
fFirstVisibleTabIndex(0)
{
SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
SetViewColor(B_TRANSPARENT_COLOR);
GroupLayout()->SetInsets(kLeftTabInset, 0, 0, 1);
GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue(), 0.0f);
}
TabContainerView::~TabContainerView()
{
}
BSize
TabContainerView::MinSize()
{
// Eventually, we want to be scrolling if the tabs don't fit.
BSize size(BGroupView::MinSize());
size.width = 300;
return size;
}
void
TabContainerView::MessageReceived(BMessage* message)
{
switch (message->what) {
default:
BGroupView::MessageReceived(message);
}
}
void
TabContainerView::Draw(BRect updateRect)
{
// Stroke separator line at bottom.
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
BRect frame(Bounds());
SetHighColor(tint_color(base, B_DARKEN_2_TINT));
StrokeLine(frame.LeftBottom(), frame.RightBottom());
frame.bottom--;
// Draw empty area before first tab.
uint32 borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
BRect leftFrame(frame.left, frame.top, kLeftTabInset, frame.bottom);
be_control_look->DrawInactiveTab(this, leftFrame, updateRect, base, 0,
borders);
// Draw all tabs, keeping track of where they end.
BGroupLayout* layout = GroupLayout();
int32 count = layout->CountItems() - 1;
for (int32 i = 0; i < count; i++) {
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
layout->ItemAt(i));
if (!item || !item->IsVisible())
continue;
item->Parent()->Draw(updateRect);
frame.left = item->Frame().right + 1;
}
// Draw empty area after last tab.
be_control_look->DrawInactiveTab(this, frame, updateRect, base, 0, borders);
}
void
TabContainerView::MouseDown(BPoint where)
{
uint32 buttons;
if (Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons) != B_OK)
buttons = B_PRIMARY_MOUSE_BUTTON;
uint32 clicks;
if (Window()->CurrentMessage()->FindInt32("clicks", (int32*)&clicks) != B_OK)
clicks = 1;
fMouseDown = true;
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
if (fLastMouseEventTab)
fLastMouseEventTab->MouseDown(where, buttons);
else {
if (clicks > 1)
fClickCount++;
else
fClickCount = 1;
}
}
void
TabContainerView::MouseUp(BPoint where)
{
fMouseDown = false;
if (fLastMouseEventTab)
fLastMouseEventTab->MouseUp(where);
else if (fClickCount > 1) {
fClickCount = 0;
fController->DoubleClickOutsideTabs();
}
}
void
TabContainerView::MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
_MouseMoved(where, transit, dragMessage);
}
void
TabContainerView::DoLayout()
{
BGroupView::DoLayout();
_ValidateTabVisibility();
_SendFakeMouseMoved();
}
void
TabContainerView::AddTab(const char* label, int32 index)
{
TabView* tab;
if (fController)
tab = fController->CreateTabView();
else
tab = new TabView();
tab->SetLabel(label);
AddTab(tab, index);
}
void
TabContainerView::AddTab(TabView* tab, int32 index)
{
tab->SetContainerView(this);
if (index == -1)
index = GroupLayout()->CountItems() - 1;
bool hasFrames = fController != NULL && fController->HasFrames();
bool isFirst = index == 0 && hasFrames;
bool isLast = index == GroupLayout()->CountItems() - 1 && hasFrames;
bool isFront = fSelectedTab == NULL;
tab->Update(isFirst, isLast, isFront);
GroupLayout()->AddItem(index, tab->LayoutItem());
if (isFront)
SelectTab(tab);
if (isLast) {
TabLayoutItem* item
= dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index - 1));
if (item)
item->Parent()->SetIsLast(false);
}
SetFirstVisibleTabIndex(MaxFirstVisibleTabIndex());
_ValidateTabVisibility();
}
TabView*
TabContainerView::RemoveTab(int32 index)
{
TabLayoutItem* item
= dynamic_cast<TabLayoutItem*>(GroupLayout()->RemoveItem(index));
if (!item)
return NULL;
BRect dirty(Bounds());
dirty.left = item->Frame().left;
TabView* removedTab = item->Parent();
removedTab->SetContainerView(NULL);
if (removedTab == fLastMouseEventTab)
fLastMouseEventTab = NULL;
// Update tabs after or before the removed tab.
bool hasFrames = fController != NULL && fController->HasFrames();
item = dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index));
if (item) {
// This tab is behind the removed tab.
TabView* tab = item->Parent();
tab->Update(index == 0 && hasFrames,
index == GroupLayout()->CountItems() - 2 && hasFrames,
tab == fSelectedTab);
if (removedTab == fSelectedTab) {
fSelectedTab = NULL;
SelectTab(tab);
} else if (fController && tab == fSelectedTab)
fController->TabSelected(index);
} else {
// The removed tab was the last tab.
item = dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index - 1));
if (item) {
TabView* tab = item->Parent();
tab->Update(index == 0 && hasFrames,
index == GroupLayout()->CountItems() - 2 && hasFrames,
tab == fSelectedTab);
if (removedTab == fSelectedTab) {
fSelectedTab = NULL;
SelectTab(tab);
}
}
}
Invalidate(dirty);
_ValidateTabVisibility();
return removedTab;
}
TabView*
TabContainerView::TabAt(int32 index) const
{
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
GroupLayout()->ItemAt(index));
if (item)
return item->Parent();
return NULL;
}
int32
TabContainerView::IndexOf(TabView* tab) const
{
return GroupLayout()->IndexOfItem(tab->LayoutItem());
}
void
TabContainerView::SelectTab(int32 index)
{
TabView* tab = NULL;
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
GroupLayout()->ItemAt(index));
if (item)
tab = item->Parent();
SelectTab(tab);
}
void
TabContainerView::SelectTab(TabView* tab)
{
if (tab == fSelectedTab)
return;
if (fSelectedTab)
fSelectedTab->SetIsFront(false);
fSelectedTab = tab;
if (fSelectedTab)
fSelectedTab->SetIsFront(true);
if (fController != NULL) {
int32 index = -1;
if (fSelectedTab != NULL)
index = GroupLayout()->IndexOfItem(tab->LayoutItem());
fController->TabSelected(index);
}
}
void
TabContainerView::SetTabLabel(int32 tabIndex, const char* label)
{
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
GroupLayout()->ItemAt(tabIndex));
if (item == NULL)
return;
item->Parent()->SetLabel(label);
}
void
TabContainerView::SetFirstVisibleTabIndex(int32 index)
{
if (index < 0)
index = 0;
if (index > MaxFirstVisibleTabIndex())
index = MaxFirstVisibleTabIndex();
if (fFirstVisibleTabIndex == index)
return;
fFirstVisibleTabIndex = index;
_UpdateTabVisibility();
}
int32
TabContainerView::FirstVisibleTabIndex() const
{
return fFirstVisibleTabIndex;
}
int32
TabContainerView::MaxFirstVisibleTabIndex() const
{
float availableWidth = _AvailableWidthForTabs();
if (availableWidth < 0)
return 0;
float visibleTabsWidth = 0;
BGroupLayout* layout = GroupLayout();
int32 i = layout->CountItems() - 2;
for (; i >= 0; i--) {
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
layout->ItemAt(i));
if (item == NULL)
continue;
float itemWidth = item->MinSize().width;
if (availableWidth >= visibleTabsWidth + itemWidth)
visibleTabsWidth += itemWidth;
else {
// The tab before this tab is the last one that can be visible.
return i + 1;
}
}
return 0;
}
bool
TabContainerView::CanScrollLeft() const
{
return fFirstVisibleTabIndex < MaxFirstVisibleTabIndex();
}
bool
TabContainerView::CanScrollRight() const
{
BGroupLayout* layout = GroupLayout();
int32 count = layout->CountItems() - 1;
if (count > 0) {
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
layout->ItemAt(count - 1));
return !item->IsVisible();
}
return false;
}
// #pragma mark -
TabView*
TabContainerView::_TabAt(const BPoint& where) const
{
BGroupLayout* layout = GroupLayout();
int32 count = layout->CountItems() - 1;
for (int32 i = 0; i < count; i++) {
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
layout->ItemAt(i));
if (item && item->IsVisible() && item->Frame().Contains(where))
return item->Parent();
}
return NULL;
}
void
TabContainerView::_MouseMoved(BPoint where, uint32 _transit,
const BMessage* dragMessage)
{
TabView* tab = _TabAt(where);
if (fMouseDown) {
uint32 transit = tab == fLastMouseEventTab
? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
if (fLastMouseEventTab)
fLastMouseEventTab->MouseMoved(where, transit, dragMessage);
return;
}
if (fLastMouseEventTab && fLastMouseEventTab == tab)
fLastMouseEventTab->MouseMoved(where, B_INSIDE_VIEW, dragMessage);
else {
if (fLastMouseEventTab)
fLastMouseEventTab->MouseMoved(where, B_EXITED_VIEW, dragMessage);
fLastMouseEventTab = tab;
if (fLastMouseEventTab)
fLastMouseEventTab->MouseMoved(where, B_ENTERED_VIEW, dragMessage);
}
}
void
TabContainerView::_ValidateTabVisibility()
{
if (fFirstVisibleTabIndex > MaxFirstVisibleTabIndex())
SetFirstVisibleTabIndex(MaxFirstVisibleTabIndex());
else
_UpdateTabVisibility();
}
void
TabContainerView::_UpdateTabVisibility()
{
float availableWidth = _AvailableWidthForTabs();
if (availableWidth < 0)
return;
float visibleTabsWidth = 0;
bool canScrollTabsLeft = fFirstVisibleTabIndex > 0;
bool canScrollTabsRight = false;
BGroupLayout* layout = GroupLayout();
int32 count = layout->CountItems() - 1;
for (int32 i = 0; i < count; i++) {
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
layout->ItemAt(i));
if (i < fFirstVisibleTabIndex)
item->SetVisible(false);
else {
float itemWidth = item->MinSize().width;
bool visible = availableWidth >= visibleTabsWidth + itemWidth;
item->SetVisible(visible && !canScrollTabsRight);
visibleTabsWidth += itemWidth;
if (!visible)
canScrollTabsRight = true;
}
}
fController->UpdateTabScrollability(canScrollTabsLeft, canScrollTabsRight);
}
float
TabContainerView::_AvailableWidthForTabs() const
{
float width = Bounds().Width() - 10;
// TODO: Don't really know why -10 is needed above.
float left;
float right;
GroupLayout()->GetInsets(&left, NULL, &right, NULL);
width -= left + right;
return width;
}
void
TabContainerView::_SendFakeMouseMoved()
{
BPoint where;
uint32 buttons;
GetMouse(&where, &buttons, false);
if (Bounds().Contains(where))
_MouseMoved(where, B_INSIDE_VIEW, NULL);
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TAB_CONTAINER_VIEW_H
#define TAB_CONTAINER_VIEW_H
#include <GroupView.h>
class TabView;
class TabContainerView : public BGroupView {
public:
class Controller {
public:
virtual void TabSelected(int32 tabIndex) = 0;
virtual bool HasFrames() = 0;
virtual TabView* CreateTabView() = 0;
virtual void DoubleClickOutsideTabs() = 0;
virtual void UpdateTabScrollability(bool canScrollLeft,
bool canScrollRight) = 0;
};
public:
TabContainerView(Controller* controller);
virtual ~TabContainerView();
virtual BSize MinSize();
virtual void MessageReceived(BMessage*);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void DoLayout();
void AddTab(const char* label, int32 index = -1);
void AddTab(TabView* tab, int32 index = -1);
TabView* RemoveTab(int32 index);
TabView* TabAt(int32 index) const;
int32 IndexOf(TabView* tab) const;
void SelectTab(int32 tabIndex);
void SelectTab(TabView* tab);
void SetTabLabel(int32 tabIndex, const char* label);
void SetFirstVisibleTabIndex(int32 index);
int32 FirstVisibleTabIndex() const;
int32 MaxFirstVisibleTabIndex() const;
bool CanScrollLeft() const;
bool CanScrollRight() const;
private:
TabView* _TabAt(const BPoint& where) const;
void _MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
void _ValidateTabVisibility();
void _UpdateTabVisibility();
float _AvailableWidthForTabs() const;
void _SendFakeMouseMoved();
private:
TabView* fLastMouseEventTab;
bool fMouseDown;
uint32 fClickCount;
TabView* fSelectedTab;
Controller* fController;
int32 fFirstVisibleTabIndex;
};
#endif // TAB_CONTAINER_VIEW_H

View File

@ -40,6 +40,7 @@ class BBitmap;
class BCardLayout;
class BGroupView;
class BMenu;
class TabContainerGroup;
class TabContainerView;
class TabManagerController;
@ -81,7 +82,7 @@ private:
#if INTEGRATE_MENU_INTO_TAB_BAR
BMenu* fMenu;
#endif
BGroupView* fTabContainerGroup;
TabContainerGroup* fTabContainerGroup;
TabContainerView* fTabContainerView;
BView* fContainerView;
BCardLayout* fCardLayout;

View File

@ -0,0 +1,366 @@
/*
* Copyright (C) 2010 Rene Gollent <rene@gollent.com>
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "TabView.h"
#include <stdio.h>
#include <Application.h>
#include <Bitmap.h>
#include <Button.h>
#include <CardLayout.h>
#include <ControlLook.h>
#include <GroupView.h>
#include <MenuBar.h>
#include <SpaceLayoutItem.h>
#include <Window.h>
#include "TabContainerView.h"
// #pragma mark - TabView
TabView::TabView()
:
fContainerView(NULL),
fLayoutItem(new TabLayoutItem(this)),
fLabel()
{
}
TabView::~TabView()
{
// The layout item is deleted for us by the layout which contains it.
if (!fContainerView)
delete fLayoutItem;
}
BSize
TabView::MinSize()
{
BSize size(MaxSize());
size.width = 100.0f;
return size;
}
BSize
TabView::PreferredSize()
{
return MaxSize();
}
BSize
TabView::MaxSize()
{
float extra = be_control_look->DefaultLabelSpacing();
float labelWidth = fContainerView->StringWidth(fLabel.String()) + 2 * extra;
labelWidth = min_c(300.0f, labelWidth);
return BSize(labelWidth, _LabelHeight() + extra);
}
void
TabView::Draw(BRect updateRect)
{
BRect frame(fLayoutItem->Frame());
if (fIsFront) {
// Extend the front tab outward left/right in order to merge
// the frames of adjacent tabs.
if (!fIsFirst)
frame.left--;
if (!fIsLast)
frame.right++;
frame.bottom++;
}
DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast,
fIsFront);
if (fIsFront) {
frame.top += 3.0f;
if (!fIsFirst)
frame.left++;
if (!fIsLast)
frame.right--;
} else
frame.top += 6.0f;
float spacing = be_control_look->DefaultLabelSpacing();
frame.InsetBy(spacing, spacing / 2);
DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast,
fIsFront);
}
void
TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect,
bool isFirst, bool isLast, bool isFront)
{
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
uint32 borders = BControlLook::B_TOP_BORDER
| BControlLook::B_BOTTOM_BORDER;
if (isFirst)
borders |= BControlLook::B_LEFT_BORDER;
if (isLast)
borders |= BControlLook::B_RIGHT_BORDER;
if (isFront) {
be_control_look->DrawActiveTab(owner, frame, updateRect, base,
0, borders);
} else {
be_control_look->DrawInactiveTab(owner, frame, updateRect, base,
0, borders);
}
}
void
TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect,
bool isFirst, bool isLast, bool isFront)
{
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect,
base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
}
void
TabView::MouseDown(BPoint where, uint32 buttons)
{
fContainerView->SelectTab(this);
}
void
TabView::MouseUp(BPoint where)
{
}
void
TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
{
}
void
TabView::SetIsFront(bool isFront)
{
Update(fIsFirst, fIsLast, isFront);
}
bool
TabView::IsFront() const
{
return fIsFront;
}
void
TabView::SetIsLast(bool isLast)
{
Update(fIsFirst, isLast, fIsFront);
}
void
TabView::Update(bool isFirst, bool isLast, bool isFront)
{
if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront)
return;
fIsFirst = isFirst;
fIsLast = isLast;
fIsFront = isFront;
fLayoutItem->InvalidateContainer();
}
void
TabView::SetContainerView(TabContainerView* containerView)
{
fContainerView = containerView;
}
TabContainerView*
TabView::ContainerView() const
{
return fContainerView;
}
BLayoutItem*
TabView::LayoutItem() const
{
return fLayoutItem;
}
void
TabView::SetLabel(const char* label)
{
if (fLabel == label)
return;
fLabel = label;
fLayoutItem->InvalidateLayout();
}
const BString&
TabView::Label() const
{
return fLabel;
}
BRect
TabView::Frame() const
{
return fLayoutItem->Frame();
}
float
TabView::_LabelHeight() const
{
font_height fontHeight;
fContainerView->GetFontHeight(&fontHeight);
return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
}
// #pragma mark - TabLayoutItem
TabLayoutItem::TabLayoutItem(TabView* parent)
:
fParent(parent),
fVisible(true)
{
}
bool
TabLayoutItem::IsVisible()
{
return fVisible;
}
void
TabLayoutItem::SetVisible(bool visible)
{
if (fVisible == visible)
return;
fVisible = visible;
InvalidateContainer();
fParent->ContainerView()->InvalidateLayout();
}
BRect
TabLayoutItem::Frame()
{
return fFrame;
}
void
TabLayoutItem::SetFrame(BRect frame)
{
BRect dirty = fFrame;
fFrame = frame;
dirty = dirty | fFrame;
InvalidateContainer(dirty);
}
BView*
TabLayoutItem::View()
{
return NULL;
}
BSize
TabLayoutItem::BaseMinSize()
{
return fParent->MinSize();
}
BSize
TabLayoutItem::BaseMaxSize()
{
return fParent->MaxSize();
}
BSize
TabLayoutItem::BasePreferredSize()
{
return fParent->PreferredSize();
}
BAlignment
TabLayoutItem::BaseAlignment()
{
return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
}
TabView*
TabLayoutItem::Parent() const
{
return fParent;
}
void
TabLayoutItem::InvalidateContainer()
{
InvalidateContainer(Frame());
}
void
TabLayoutItem::InvalidateContainer(BRect frame)
{
// Invalidate more than necessary, to help the TabContainerView
// redraw the parts outside any tabs...
frame.bottom++;
frame.right++;
fParent->ContainerView()->Invalidate(frame);
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TAB_VIEW_H
#define TAB_VIEW_H
#include <AbstractLayoutItem.h>
#include <Rect.h>
#include <String.h>
class BMessage;
class BView;
class TabContainerView;
class TabLayoutItem;
class TabView {
public:
TabView();
virtual ~TabView();
virtual BSize MinSize();
virtual BSize PreferredSize();
virtual BSize MaxSize();
void Draw(BRect updateRect);
virtual void DrawBackground(BView* owner, BRect frame,
const BRect& updateRect, bool isFirst,
bool isLast, bool isFront);
virtual void DrawContents(BView* owner, BRect frame,
const BRect& updateRect, bool isFirst,
bool isLast, bool isFront);
virtual void MouseDown(BPoint where, uint32 buttons);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
void SetIsFront(bool isFront);
bool IsFront() const;
void SetIsLast(bool isLast);
virtual void Update(bool isFirst, bool isLast,
bool isFront);
BLayoutItem* LayoutItem() const;
void SetContainerView(
TabContainerView* containerView);
TabContainerView* ContainerView() const;
void SetLabel(const char* label);
const BString& Label() const;
BRect Frame() const;
private:
float _LabelHeight() const;
private:
TabContainerView* fContainerView;
TabLayoutItem* fLayoutItem;
BString fLabel;
bool fIsFirst;
bool fIsLast;
bool fIsFront;
};
class TabLayoutItem : public BAbstractLayoutItem {
public:
TabLayoutItem(TabView* parent);
virtual bool IsVisible();
virtual void SetVisible(bool visible);
virtual BRect Frame();
virtual void SetFrame(BRect frame);
virtual BView* View();
virtual BSize BaseMinSize();
virtual BSize BaseMaxSize();
virtual BSize BasePreferredSize();
virtual BAlignment BaseAlignment();
TabView* Parent() const;
void InvalidateContainer();
void InvalidateContainer(BRect frame);
private:
TabView* fParent;
BRect fFrame;
bool fVisible;
};
#endif // TAB_VIEW_H