Added beginnings of a generic header view.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31878 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-07-29 00:12:42 +00:00
parent aaa7c62f4d
commit c97796c267
3 changed files with 917 additions and 0 deletions
+707
View File
@@ -0,0 +1,707 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2009, Stephan Aßmus, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "HeaderView.h"
#include <stdio.h>
#include <algorithm>
#include <new>
#include <ControlLook.h>
#include <LayoutUtils.h>
// #pragma mark - HeaderRenderer
HeaderRenderer::~HeaderRenderer()
{
}
// #pragma mark - DefaultHeaderRenderer
DefaultHeaderRenderer::DefaultHeaderRenderer()
{
}
DefaultHeaderRenderer::~DefaultHeaderRenderer()
{
}
float
DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header)
{
BVariant value;
if (!header->GetValue(value))
return 0;
if (value.Type() == B_STRING_TYPE) {
return 15;
// TODO:...
} else
return 0;
}
void
DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect,
const Header* header, uint32 flags)
{
printf("DefaultHeaderRenderer::DrawHeader(): frame: (%f, %f) - (%f, %f), header: %p\n",
frame.left, frame.top, frame.right, frame.bottom, header);
BVariant value;
if (!header->GetValue(value))
return;
if (value.Type() == B_STRING_TYPE) {
be_control_look->DrawLabel(view, value.ToString(), frame, updateRect,
view->LowColor(), 0);
}
}
// #pragma mark - HeaderListener
HeaderListener::~HeaderListener()
{
}
// #pragma mark - Header
Header::Header(int32 modelIndex)
:
fWidth(100),
fMinWidth(0),
fMaxWidth(10000),
fPreferredWidth(100),
fValue(),
fRenderer(NULL),
fModelIndex(modelIndex),
fResizable(true)
{
}
Header::Header(float width, float minWidth, float maxWidth,
float preferredWidth, int32 modelIndex)
:
fWidth(width),
fMinWidth(minWidth),
fMaxWidth(maxWidth),
fPreferredWidth(preferredWidth),
fValue(),
fRenderer(NULL),
fModelIndex(modelIndex),
fResizable(true)
{
}
float
Header::Width() const
{
return fWidth;
}
float
Header::MinWidth() const
{
return fMinWidth;
}
float
Header::MaxWidth() const
{
return fMaxWidth;
}
float
Header::PreferredWidth() const
{
return fPreferredWidth;
}
void
Header::SetWidth(float width)
{
if (width != fWidth) {
fWidth = width;
NotifyPropertiesChanged(true, true);
}
}
void
Header::SetMinWidth(float width)
{
if (width != fMinWidth) {
fMinWidth = width;
NotifyPropertiesChanged(false, false);
}
}
void
Header::SetMaxWidth(float width)
{
if (width != fMaxWidth) {
fMaxWidth = width;
NotifyPropertiesChanged(false, false);
}
}
void
Header::SetPreferredWidth(float width)
{
if (width != fPreferredWidth) {
fPreferredWidth = width;
NotifyPropertiesChanged(false, false);
}
}
bool
Header::IsResizable() const
{
return fResizable;
}
void
Header::SetResizable(bool resizable)
{
if (resizable != fResizable) {
fResizable = resizable;
NotifyPropertiesChanged(false, false);
}
}
bool
Header::GetValue(BVariant& _value) const
{
_value = fValue;
return true;
}
void
Header::SetValue(const BVariant& value)
{
fValue = value;
NotifyPropertiesChanged(true, false);
}
int32
Header::ModelIndex() const
{
return fModelIndex;
}
void
Header::SetModelIndex(int32 index)
{
if (index != fModelIndex) {
fModelIndex = index;
NotifyPropertiesChanged(true, false);
}
}
HeaderRenderer*
Header::GetHeaderRenderer() const
{
return fRenderer;
}
void
Header::SetHeaderRenderer(HeaderRenderer* renderer)
{
if (renderer != fRenderer) {
fRenderer = renderer;
NotifyPropertiesChanged(true, false);
}
}
void
Header::AddListener(HeaderListener* listener)
{
fListeners.AddItem(listener);
}
void
Header::RemoveListener(HeaderListener* listener)
{
fListeners.RemoveItem(listener);
}
void
Header::NotifyPropertiesChanged(bool redrawNeeded, bool relayoutNeeded)
{
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
HeaderListener* listener = fListeners.ItemAt(i);
listener->HeaderPropertiesChanged(this, redrawNeeded, relayoutNeeded);
}
}
// #pragma mark - HeaderModelListener
HeaderModelListener::~HeaderModelListener()
{
}
void
HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index)
{
}
void
HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index)
{
}
void
HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex,
int32 toIndex)
{
}
// #pragma mark - HeaderModel
HeaderModel::HeaderModel()
{
}
HeaderModel::~HeaderModel()
{
}
int32
HeaderModel::CountHeaders() const
{
return fHeaders.CountItems();
}
Header*
HeaderModel::HeaderAt(int32 index) const
{
return fHeaders.ItemAt(index);
}
int32
HeaderModel::IndexOfHeader(Header* header) const
{
return fHeaders.IndexOf(header);
}
bool
HeaderModel::AddHeader(Header* header)
{
if (!fHeaders.AddItem(header))
return false;
NotifyHeaderAdded(fHeaders.CountItems() - 1);
return true;
}
Header*
HeaderModel::RemoveHeader(int32 index)
{
Header* header = fHeaders.RemoveItemAt(index);
if (header != NULL)
return NULL;
NotifyHeaderRemoved(index);
return header;
}
void
HeaderModel::RemoveHeader(Header* header)
{
RemoveHeader(fHeaders.IndexOf(header));
}
bool
HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex)
{
int32 headerCount = fHeaders.CountItems();
if (fromIndex < 0 || fromIndex >= headerCount
|| toIndex < 0 || toIndex >= headerCount) {
return false;
}
if (fromIndex == toIndex)
return true;
Header* header = fHeaders.RemoveItemAt(fromIndex);
fHeaders.AddItem(header, toIndex);
// TODO: Might fail.
NotifyHeaderMoved(fromIndex, toIndex);
return true;
}
void
HeaderModel::AddListener(HeaderModelListener* listener)
{
fListeners.AddItem(listener);
}
void
HeaderModel::RemoveListener(HeaderModelListener* listener)
{
fListeners.RemoveItem(listener);
}
void
HeaderModel::NotifyHeaderAdded(int32 index)
{
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
HeaderModelListener* listener = fListeners.ItemAt(i);
listener->HeaderAdded(this, index);
}
}
void
HeaderModel::NotifyHeaderRemoved(int32 index)
{
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
HeaderModelListener* listener = fListeners.ItemAt(i);
listener->HeaderRemoved(this, index);
}
}
void
HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex)
{
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
HeaderModelListener* listener = fListeners.ItemAt(i);
listener->HeaderMoved(this, fromIndex, toIndex);
}
}
// #pragma mark - HeaderEntry
struct HeaderView::HeaderEntry {
Header* header;
float position;
float width;
HeaderEntry(Header* header)
:
header(header)
{
}
};
// #pragma mark - HeaderView
HeaderView::HeaderView()
:
BView("header view", B_WILL_DRAW),
fModel(NULL),
fHeaderEntries(10, true),
fLayoutValid(false)
{
HeaderModel* model = new(std::nothrow) HeaderModel;
Reference<HeaderModel> modelReference(model, true);
SetModel(model);
}
HeaderView::~HeaderView()
{
SetModel(NULL);
}
void
HeaderView::Draw(BRect updateRect)
{
if (fModel == NULL)
return;
_ValidateHeadersLayout();
DefaultHeaderRenderer defaultRenderer;
float bottom = Bounds().Height();
for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) {
if (Header* header = fModel->HeaderAt(i)) {
HeaderRenderer* renderer = header->GetHeaderRenderer();
if (renderer == NULL)
renderer = &defaultRenderer;
BRect frame(entry->position, 0, entry->position + entry->width - 1,
bottom);
renderer->DrawHeader(this, frame, updateRect, header, 0);
// TODO: flags!
}
}
}
BSize
HeaderView::MinSize()
{
_ValidateHeadersLayout();
return BLayoutUtils::ComposeSize(ExplicitMinSize(),
BSize(100, fPreferredHeight - 1));
}
BSize
HeaderView::MaxSize()
{
_ValidateHeadersLayout();
return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1));
}
BSize
HeaderView::PreferredSize()
{
_ValidateHeadersLayout();
return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
BSize(fPreferredWidth - 1, fPreferredHeight - 1));
}
HeaderModel*
HeaderView::Model() const
{
return fModel;
}
status_t
HeaderView::SetModel(HeaderModel* model)
{
if (model == fModel)
return B_OK;
printf("HeaderView::SetModel(%p)\n", model);
if (fModel != NULL) {
// remove all headers
for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++)
{
printf(" unsetting entry %p, header: %p\n", entry, entry->header);
entry->header->RemoveListener(this);
}
fHeaderEntries.MakeEmpty();
fModel->RemoveListener(this);
fModel->ReleaseReference();
}
fModel = model;
if (fModel != NULL) {
fModel->AcquireReference();
fModel->AddListener(this);
// create header entries
int32 headerCount = fModel->CountHeaders();
for (int32 i = 0; i < headerCount; i++) {
HeaderEntry* entry = new(std::nothrow) HeaderEntry(
fModel->HeaderAt(i));
if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
delete entry;
return B_NO_MEMORY;
}
entry->header->AddListener(this);
}
}
_InvalidateHeadersLayout(0);
Invalidate();
return B_OK;
}
void
HeaderView::AddListener(HeaderViewListener* listener)
{
fListeners.AddItem(listener);
}
void
HeaderView::RemoveListener(HeaderViewListener* listener)
{
fListeners.RemoveItem(listener);
}
void
HeaderView::HeaderAdded(HeaderModel* model, int32 index)
{
if (Header* header = fModel->HeaderAt(index)) {
HeaderEntry* entry = new(std::nothrow) HeaderEntry(
fModel->HeaderAt(index));
printf("HeaderView::HeaderAdded(%p, %ld): header: %p, entry: %p\n", model, index, entry->header, entry);
if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
delete entry;
return;
}
header->AddListener(this);
_InvalidateHeadersLayout(index);
}
}
void
HeaderView::HeaderRemoved(HeaderModel* model, int32 index)
{
if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) {
entry->header->RemoveListener(this);
_InvalidateHeadersLayout(index);
}
}
void
HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex)
{
_InvalidateHeadersLayout(std::min(fromIndex, toIndex));
}
void
HeaderView::HeaderPropertiesChanged(Header* header, bool redrawNeeded,
bool relayoutNeeded)
{
if (!redrawNeeded && !relayoutNeeded)
return;
int32 index = fModel->IndexOfHeader(header);
if (relayoutNeeded)
_InvalidateHeadersLayout(index);
else if (redrawNeeded)
_InvalidateHeaders(index, index + 1);
}
void
HeaderView::_InvalidateHeadersLayout(int32 firstIndex)
{
if (!fLayoutValid)
return;
fLayoutValid = false;
InvalidateLayout();
Invalidate();
}
void
HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex)
{
Invalidate();
// TODO: Be less lazy!
}
void
HeaderView::_ValidateHeadersLayout()
{
if (fLayoutValid)
return;
DefaultHeaderRenderer defaultRenderer;
int32 headerCount = fHeaderEntries.CountItems();
float position = 0;
fPreferredWidth = 0;
fPreferredHeight = 0;
for (int32 i = 0; i < headerCount; i++) {
HeaderEntry* entry = fHeaderEntries.ItemAt(i);
entry->position = position;
if (Header* header = fModel->HeaderAt(i)) {
entry->width = header->Width();
fPreferredWidth += header->PreferredWidth();
} else
entry->width = 0;
position = entry->position + entry->width;
if (Header* header = fModel->HeaderAt(i)) {
HeaderRenderer* renderer = header->GetHeaderRenderer();
if (renderer == NULL)
renderer = &defaultRenderer;
float height = renderer->HeaderHeight(this, header);
if (height > fPreferredHeight)
fPreferredHeight = height;
}
}
fLayoutValid = true;
}
// #pragma mark - HeaderViewListener
HeaderViewListener::~HeaderViewListener()
{
}
+207
View File
@@ -0,0 +1,207 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2009, Stephan Aßmus, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef HEADER_VIEW_H
#define HEADER_VIEW_H
#include <View.h>
#include <ObjectList.h>
#include <Referenceable.h>
#include <Variant.h>
class Header;
class HeaderModel;
class HeaderViewListener;
class HeaderRenderer {
public:
virtual ~HeaderRenderer();
virtual float HeaderHeight(BView* view, const Header* header)
= 0;
virtual void DrawHeader(BView* view, BRect frame,
BRect updateRect, const Header* header,
uint32 flags) = 0;
};
class DefaultHeaderRenderer : public HeaderRenderer {
public:
DefaultHeaderRenderer();
virtual ~DefaultHeaderRenderer();
virtual float HeaderHeight(BView* view, const Header* header);
virtual void DrawHeader(BView* view, BRect frame,
BRect updateRect, const Header* header,
uint32 flags);
};
class HeaderListener {
public:
virtual ~HeaderListener();
virtual void HeaderPropertiesChanged(Header* header,
bool redrawNeeded, bool relayoutNeeded) = 0;
};
class Header {
public:
Header(int32 modelIndex = 0);
Header(float width, float minWidth,
float maxWidth, float preferredWidth,
int32 modelIndex = 0);
float Width() const;
float MinWidth() const;
float MaxWidth() const;
float PreferredWidth() const;
void SetWidth(float width);
void SetMinWidth(float width);
void SetMaxWidth(float width);
void SetPreferredWidth(float width);
bool IsResizable() const;
void SetResizable(bool resizable);
bool GetValue(BVariant& _value) const;
void SetValue(const BVariant& value);
int32 ModelIndex() const;
void SetModelIndex(int32 index);
HeaderRenderer* GetHeaderRenderer() const;
void SetHeaderRenderer(HeaderRenderer* renderer);
void AddListener(HeaderListener* listener);
void RemoveListener(HeaderListener* listener);
protected:
void NotifyPropertiesChanged(bool redrawNeeded,
bool relayoutNeeded);
private:
typedef BObjectList<HeaderListener> ListenerList;
private:
float fWidth;
float fMinWidth;
float fMaxWidth;
float fPreferredWidth;
BVariant fValue;
HeaderRenderer* fRenderer;
int32 fModelIndex;
bool fResizable;
ListenerList fListeners;
};
class HeaderModelListener {
public:
virtual ~HeaderModelListener();
virtual void HeaderAdded(HeaderModel* model, int32 index);
virtual void HeaderRemoved(HeaderModel* model, int32 index);
virtual void HeaderMoved(HeaderModel* model,
int32 fromIndex, int32 toIndex);
};
class HeaderModel : public BReferenceable {
public:
HeaderModel();
virtual ~HeaderModel();
virtual int32 CountHeaders() const;
virtual Header* HeaderAt(int32 index) const;
virtual int32 IndexOfHeader(Header* header) const;
virtual bool AddHeader(Header* header);
virtual Header* RemoveHeader(int32 index);
virtual void RemoveHeader(Header* header);
virtual bool MoveHeader(int32 fromIndex, int32 toIndex);
virtual void AddListener(HeaderModelListener* listener);
virtual void RemoveListener(HeaderModelListener* listener);
protected:
void NotifyHeaderAdded(int32 index);
void NotifyHeaderRemoved(int32 index);
void NotifyHeaderMoved(int32 fromIndex,
int32 toIndex);
private:
typedef BObjectList<Header> HeaderList;
typedef BObjectList<HeaderModelListener> ListenerList;
private:
HeaderList fHeaders;
ListenerList fListeners;
};
class HeaderView : public BView, private HeaderModelListener,
private HeaderListener {
public:
HeaderView();
virtual ~HeaderView();
virtual void Draw(BRect updateRect);
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
HeaderModel* Model() const;
status_t SetModel(HeaderModel* model);
void AddListener(HeaderViewListener* listener);
void RemoveListener(HeaderViewListener* listener);
private:
struct HeaderEntry;
typedef BObjectList<HeaderEntry> HeaderEntryList;
typedef BObjectList<HeaderViewListener> ListenerList;
private:
// HeaderModelListener
virtual void HeaderAdded(HeaderModel* model, int32 index);
virtual void HeaderRemoved(HeaderModel* model, int32 index);
virtual void HeaderMoved(HeaderModel* model,
int32 fromIndex, int32 toIndex);
// HeaderListener
virtual void HeaderPropertiesChanged(Header* header,
bool redrawNeeded, bool relayoutNeeded);
void _InvalidateHeadersLayout(int32 firstIndex);
void _InvalidateHeaders(int32 firstIndex,
int32 endIndex);
void _ValidateHeadersLayout();
private:
HeaderModel* fModel;
HeaderEntryList fHeaderEntries;
float fPreferredWidth;
float fPreferredHeight;
bool fLayoutValid;
ListenerList fListeners;
};
class HeaderViewListener {
public:
virtual ~HeaderViewListener();
};
#endif // HEADER_VIEW_H
+3
View File
@@ -5,11 +5,14 @@ UsePrivateSystemHeaders ;
UseHeaders $(HAIKU_DEBUG_ANALYZER_HEADERS) ;
CCFLAGS += -Werror ;
C++FLAGS += -Werror ;
MergeObject DebugAnalyzer_gui.o
:
AbstractGeneralPage.cpp
ColorCheckBox.cpp
HeaderView.cpp
SubWindow.cpp
SubWindowManager.cpp
: