* 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:
parent
6d93874469
commit
029353b44c
520
src/apps/webpositive/tabview/TabContainerView.cpp
Normal file
520
src/apps/webpositive/tabview/TabContainerView.cpp
Normal 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);
|
||||
}
|
||||
|
102
src/apps/webpositive/tabview/TabContainerView.h
Normal file
102
src/apps/webpositive/tabview/TabContainerView.h
Normal 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
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
366
src/apps/webpositive/tabview/TabView.cpp
Normal file
366
src/apps/webpositive/tabview/TabView.cpp
Normal 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);
|
||||
}
|
122
src/apps/webpositive/tabview/TabView.h
Normal file
122
src/apps/webpositive/tabview/TabView.h
Normal 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
|
Loading…
Reference in New Issue
Block a user