Beginning of a framework for drawing charts. Works a bit already, but there are
lots of loose ends. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30501 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,12 +12,14 @@ MergeObject DebugAnalyzer_gui.o
|
|||||||
SubWindow.cpp
|
SubWindow.cpp
|
||||||
SubWindowManager.cpp
|
SubWindowManager.cpp
|
||||||
:
|
:
|
||||||
|
DebugAnalyzer_gui_chart.o
|
||||||
DebugAnalyzer_gui_main_window.o
|
DebugAnalyzer_gui_main_window.o
|
||||||
DebugAnalyzer_gui_table.o
|
DebugAnalyzer_gui_table.o
|
||||||
DebugAnalyzer_gui_thread_window.o
|
DebugAnalyzer_gui_thread_window.o
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
HaikuSubInclude chart ;
|
||||||
HaikuSubInclude main_window ;
|
HaikuSubInclude main_window ;
|
||||||
HaikuSubInclude table ;
|
HaikuSubInclude table ;
|
||||||
HaikuSubInclude thread_window ;
|
HaikuSubInclude thread_window ;
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/BigtimeChartAxisLegendSource.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDataRange.h"
|
||||||
|
#include "chart/StringChartLegend.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct decomposed_time {
|
||||||
|
bigtime_t hours;
|
||||||
|
int minutes;
|
||||||
|
int seconds;
|
||||||
|
int micros;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
decompose_time(bigtime_t time, decomposed_time& decomposed)
|
||||||
|
{
|
||||||
|
// microsecs
|
||||||
|
decomposed.micros = time % 1000000;
|
||||||
|
time /= 1000000;
|
||||||
|
// secs
|
||||||
|
decomposed.seconds = time % 60;
|
||||||
|
time /= 60;
|
||||||
|
// mins
|
||||||
|
decomposed.minutes = time % 60;
|
||||||
|
time /= 60;
|
||||||
|
// hours
|
||||||
|
decomposed.hours = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BigtimeChartAxisLegendSource::GetAxisLegends(const ChartDataRange& range,
|
||||||
|
ChartLegend** legends, double* values, int32 maxLegends)
|
||||||
|
{
|
||||||
|
// interpret range as time range
|
||||||
|
bigtime_t startTime = (bigtime_t)range.min;
|
||||||
|
bigtime_t endTime = (bigtime_t)range.max;
|
||||||
|
printf("BigtimeChartAxisLegendSource::GetAxisLegends(): range: %lld - %lld\n", startTime, endTime);
|
||||||
|
// TODO: Handle sub-microsecs ranges!
|
||||||
|
if (startTime >= endTime)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bigtime_t positionFactors[4];
|
||||||
|
positionFactors[3] = 1;
|
||||||
|
positionFactors[2] = 1000000;
|
||||||
|
positionFactors[1] = positionFactors[2] * 60;
|
||||||
|
positionFactors[0] = positionFactors[1] * 60;
|
||||||
|
|
||||||
|
// find the main position (h, m, s, us) we want to play with
|
||||||
|
int32 position = 0;
|
||||||
|
bigtime_t rangeTime = endTime - startTime;
|
||||||
|
while (rangeTime / positionFactors[position] + 1 < maxLegends / 2
|
||||||
|
&& position < 3) {
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust the factor so that we get maxLegends / 2 to maxLegends legends
|
||||||
|
bigtime_t baseInterval = positionFactors[position];
|
||||||
|
bigtime_t relativeFactor = 1;
|
||||||
|
while (rangeTime / (baseInterval * relativeFactor) >= maxLegends) {
|
||||||
|
if (relativeFactor == 1) {
|
||||||
|
relativeFactor = 2;
|
||||||
|
} else if (relativeFactor == 2) {
|
||||||
|
relativeFactor = 5;
|
||||||
|
} else if (relativeFactor == 5) {
|
||||||
|
baseInterval *= 10;
|
||||||
|
relativeFactor = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the legends
|
||||||
|
int32 count = 0;
|
||||||
|
bigtime_t interval = baseInterval * relativeFactor;
|
||||||
|
bigtime_t time = (startTime + interval - 1) / interval * interval;
|
||||||
|
for (; time <= endTime; time += interval) {
|
||||||
|
decomposed_time decomposed;
|
||||||
|
decompose_time(time, decomposed);
|
||||||
|
char buffer[128];
|
||||||
|
snprintf(buffer, sizeof(buffer), "%02lld:%02d:%02d.%06d",
|
||||||
|
decomposed.hours, decomposed.minutes, decomposed.seconds,
|
||||||
|
decomposed.micros);
|
||||||
|
// TODO: Drop superfluous micro seconds digits, or even microseconds and seconds
|
||||||
|
// completely.
|
||||||
|
|
||||||
|
StringChartLegend* legend = new(std::nothrow) StringChartLegend(buffer,
|
||||||
|
1);
|
||||||
|
if (legend == 0)
|
||||||
|
return count;
|
||||||
|
|
||||||
|
legends[count] = legend;
|
||||||
|
values[count++] = (double)time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef BIGTIME_CHART_AXIS_LEGEND_SOURCE_H
|
||||||
|
#define BIGTIME_CHART_AXIS_LEGEND_SOURCE_H
|
||||||
|
|
||||||
|
#include "chart/ChartAxisLegendSource.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BigtimeChartAxisLegendSource : public ChartAxisLegendSource {
|
||||||
|
public:
|
||||||
|
virtual int32 GetAxisLegends(const ChartDataRange& range,
|
||||||
|
ChartLegend** legends, double* values,
|
||||||
|
int32 maxLegends);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BIGTIME_CHART_AXIS_LEGEND_SOURCE_H
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/Chart.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <Region.h>
|
||||||
|
|
||||||
|
#include "chart/ChartAxis.h"
|
||||||
|
#include "chart/ChartDataSource.h"
|
||||||
|
#include "chart/ChartRenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Chart::AxisInfo
|
||||||
|
|
||||||
|
|
||||||
|
Chart::AxisInfo::AxisInfo()
|
||||||
|
:
|
||||||
|
axis(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::AxisInfo::SetFrame(float left, float top, float right, float bottom)
|
||||||
|
{
|
||||||
|
frame.Set(left, top, right, bottom);
|
||||||
|
if (axis != NULL)
|
||||||
|
axis->SetFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::AxisInfo::SetRange(const ChartDataRange& range)
|
||||||
|
{
|
||||||
|
if (axis != NULL)
|
||||||
|
axis->SetRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::AxisInfo::Render(BView* view, const BRect& updateRect)
|
||||||
|
{
|
||||||
|
if (axis != NULL)
|
||||||
|
axis->Render(view, updateRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Chart
|
||||||
|
|
||||||
|
|
||||||
|
Chart::Chart(ChartRenderer* renderer, const char* name)
|
||||||
|
:
|
||||||
|
BView(name, B_FRAME_EVENTS | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
||||||
|
fRenderer(renderer)
|
||||||
|
{
|
||||||
|
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||||
|
|
||||||
|
// fRenderer->SetFrame(Bounds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Chart::~Chart()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Chart::AddDataSource(ChartDataSource* dataSource, int32 index,
|
||||||
|
ChartRendererDataSourceConfig* config)
|
||||||
|
{
|
||||||
|
printf("Chart::AddDataSource(%p)\n", dataSource);
|
||||||
|
if (dataSource == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (index < 0 || index > fDataSources.CountItems())
|
||||||
|
index = fDataSources.CountItems();
|
||||||
|
|
||||||
|
if (!fDataSources.AddItem(dataSource, index))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!fRenderer->AddDataSource(dataSource, index, config)) {
|
||||||
|
fDataSources.RemoveItemAt(index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_UpdateDomainAndRange();
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
Invalidate();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Chart::AddDataSource(ChartDataSource* dataSource,
|
||||||
|
ChartRendererDataSourceConfig* config)
|
||||||
|
{
|
||||||
|
return AddDataSource(dataSource, -1, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Chart::RemoveDataSource(ChartDataSource* dataSource)
|
||||||
|
{
|
||||||
|
if (dataSource == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return RemoveDataSource(fDataSources.IndexOf(dataSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChartDataSource*
|
||||||
|
Chart::RemoveDataSource(int32 index)
|
||||||
|
{
|
||||||
|
printf("Chart::RemoveDataSource(%ld)\n", index);
|
||||||
|
if (index < 0 || index >= fDataSources.CountItems())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ChartDataSource* dataSource = fDataSources.RemoveItemAt(index);
|
||||||
|
|
||||||
|
fRenderer->RemoveDataSource(dataSource);
|
||||||
|
|
||||||
|
_UpdateDomainAndRange();
|
||||||
|
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::RemoveAllDataSources()
|
||||||
|
{
|
||||||
|
printf("Chart::RemoveAllDataSources()\n");
|
||||||
|
int32 count = fDataSources.CountItems();
|
||||||
|
for (int32 i = count - 1; i >= 0; i--)
|
||||||
|
fRenderer->RemoveDataSource(fDataSources.ItemAt(i));
|
||||||
|
|
||||||
|
fDataSources.MakeEmpty();
|
||||||
|
|
||||||
|
_UpdateDomainAndRange();
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::SetAxis(ChartAxisLocation location, ChartAxis* axis)
|
||||||
|
{
|
||||||
|
switch (location) {
|
||||||
|
case CHART_AXIS_LEFT:
|
||||||
|
fLeftAxis.axis = axis;
|
||||||
|
break;
|
||||||
|
case CHART_AXIS_TOP:
|
||||||
|
fTopAxis.axis = axis;
|
||||||
|
break;
|
||||||
|
case CHART_AXIS_RIGHT:
|
||||||
|
fRightAxis.axis = axis;
|
||||||
|
break;
|
||||||
|
case CHART_AXIS_BOTTOM:
|
||||||
|
fBottomAxis.axis = axis;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axis->SetLocation(location);
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ChartDataRange
|
||||||
|
Chart::Domain() const
|
||||||
|
{
|
||||||
|
return fDataSource != NULL ? fDataSource->Domain() : ChartDataRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::SetDisplayDomain(const ChartDataRange& domain)
|
||||||
|
{
|
||||||
|
fRenderer->SetDomain(domain);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::SetDisplayDomain(const ChartDataRange& range)
|
||||||
|
{
|
||||||
|
fRenderer->SetRange(range);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::FrameResized(float newWidth, float newHeight)
|
||||||
|
{
|
||||||
|
//printf("Chart::FrameResized(%f, %f)\n", newWidth, newHeight);
|
||||||
|
// fRenderer->SetFrame(Bounds());
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
printf("Chart::Draw((%f, %f) - (%f, %f))\n", updateRect.left, updateRect.top, updateRect.right, updateRect.bottom);
|
||||||
|
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
rgb_color color;
|
||||||
|
|
||||||
|
// clear the axes background
|
||||||
|
if (fLeftAxis.axis != NULL || fTopAxis.axis != NULL
|
||||||
|
|| fRightAxis.axis != NULL || fBottomAxis.axis != NULL) {
|
||||||
|
SetHighColor(background);
|
||||||
|
BRegion clippingRegion(Bounds());
|
||||||
|
clippingRegion.Exclude(fChartFrame);
|
||||||
|
ConstrainClippingRegion(&clippingRegion);
|
||||||
|
FillRect(Bounds());
|
||||||
|
ConstrainClippingRegion(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render the axes
|
||||||
|
fLeftAxis.Render(this, updateRect);
|
||||||
|
fTopAxis.Render(this, updateRect);
|
||||||
|
fRightAxis.Render(this, updateRect);
|
||||||
|
fBottomAxis.Render(this, updateRect);
|
||||||
|
|
||||||
|
// draw the frame around the chart area and clear the background
|
||||||
|
BRect chartFrame(fChartFrame);
|
||||||
|
be_control_look->DrawBorder(this, chartFrame, updateRect, background,
|
||||||
|
B_PLAIN_BORDER);
|
||||||
|
// DrawBorder() insets the supplied rect
|
||||||
|
SetHighColor(color.set_to(255, 255, 255, 255));
|
||||||
|
FillRect(chartFrame);
|
||||||
|
|
||||||
|
// render the chart
|
||||||
|
BRegion clippingRegion(chartFrame);
|
||||||
|
ConstrainClippingRegion(&clippingRegion);
|
||||||
|
fRenderer->Render(this, updateRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
BSize
|
||||||
|
Chart::MinSize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
Chart::MaxSize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
Chart::PreferredSize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::DoLayout()
|
||||||
|
{
|
||||||
|
// get size in pixels
|
||||||
|
BSize size = Bounds().Size();
|
||||||
|
printf("Chart::DoLayout(%f, %f)\n", size.width, size.height);
|
||||||
|
int32 width = size.IntegerWidth() + 1;
|
||||||
|
int32 height = size.IntegerHeight() + 1;
|
||||||
|
|
||||||
|
// compute the axis insets
|
||||||
|
int32 left = 0;
|
||||||
|
int32 right = 0;
|
||||||
|
int32 top = 0;
|
||||||
|
int32 bottom = 0;
|
||||||
|
|
||||||
|
if (fLeftAxis.axis != NULL)
|
||||||
|
left = fLeftAxis.axis->PreferredSize(this).IntegerWidth() + 1;
|
||||||
|
if (fRightAxis.axis != NULL)
|
||||||
|
right = fRightAxis.axis->PreferredSize(this).IntegerWidth() + 1;
|
||||||
|
if (fTopAxis.axis != NULL)
|
||||||
|
top = fTopAxis.axis->PreferredSize(this).IntegerHeight() + 1;
|
||||||
|
if (fBottomAxis.axis != NULL)
|
||||||
|
bottom = fBottomAxis.axis->PreferredSize(this).IntegerHeight() + 1;
|
||||||
|
|
||||||
|
fChartFrame = BRect(left, top, width - right - 1, height - bottom - 1);
|
||||||
|
fRenderer->SetFrame(fChartFrame.InsetByCopy(1, 1));
|
||||||
|
printf(" fChartFrame: (%f, %f) - (%f, %f)\n", fChartFrame.left, fChartFrame.top, fChartFrame.right, fChartFrame.bottom);
|
||||||
|
|
||||||
|
fLeftAxis.SetFrame(0, fChartFrame.top, fChartFrame.left - 1,
|
||||||
|
fChartFrame.bottom);
|
||||||
|
fRightAxis.SetFrame(fChartFrame.right + 1, fChartFrame.top, width - 1,
|
||||||
|
fChartFrame.bottom);
|
||||||
|
fTopAxis.SetFrame(fChartFrame.left, 0, fChartFrame.right,
|
||||||
|
fChartFrame.top - 1);
|
||||||
|
fBottomAxis.SetFrame(fChartFrame.left, fChartFrame.bottom + 1,
|
||||||
|
fChartFrame.right, height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Chart::_UpdateDomainAndRange()
|
||||||
|
{
|
||||||
|
if (fDataSources.IsEmpty()) {
|
||||||
|
fDomain = ChartDataRange();
|
||||||
|
fRange = ChartDataRange();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
ChartDataSource* firstSource = fDataSources.ItemAt(0);
|
||||||
|
fDomain = firstSource->Domain();
|
||||||
|
fRange = firstSource->Range();
|
||||||
|
|
||||||
|
for (int32 i = 1; ChartDataSource* source = fDataSources.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
fDomain.Extend(source->Domain());
|
||||||
|
fRange.Extend(source->Range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fRenderer->SetDomain(fDomain);
|
||||||
|
fRenderer->SetRange(fRange);
|
||||||
|
|
||||||
|
fLeftAxis.SetRange(fRange);
|
||||||
|
fTopAxis.SetRange(fDomain);
|
||||||
|
fRightAxis.SetRange(fRange);
|
||||||
|
fBottomAxis.SetRange(fDomain);
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_H
|
||||||
|
#define CHART_H
|
||||||
|
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDataRange.h"
|
||||||
|
#include "chart/ChartDefs.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ChartAxis;
|
||||||
|
class ChartDataSource;
|
||||||
|
class ChartRenderer;
|
||||||
|
class ChartRendererDataSourceConfig;
|
||||||
|
|
||||||
|
|
||||||
|
class Chart : public BView {
|
||||||
|
public:
|
||||||
|
Chart(ChartRenderer* renderer,
|
||||||
|
const char* name = NULL);
|
||||||
|
virtual ~Chart();
|
||||||
|
|
||||||
|
bool AddDataSource(ChartDataSource* dataSource,
|
||||||
|
int32 index,
|
||||||
|
ChartRendererDataSourceConfig* config
|
||||||
|
= NULL);
|
||||||
|
bool AddDataSource(ChartDataSource* dataSource,
|
||||||
|
ChartRendererDataSourceConfig* config
|
||||||
|
= NULL);
|
||||||
|
bool RemoveDataSource(
|
||||||
|
ChartDataSource* dataSource);
|
||||||
|
ChartDataSource* RemoveDataSource(int32 index);
|
||||||
|
void RemoveAllDataSources();
|
||||||
|
|
||||||
|
void SetAxis(ChartAxisLocation location,
|
||||||
|
ChartAxis* axis);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ChartDataRange Domain() const;
|
||||||
|
|
||||||
|
void SetDisplayDomain(const ChartDataRange& domain);
|
||||||
|
void SetDisplayRange(const ChartDataRange& range);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual void FrameResized(float newWidth, float newHeight);
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
virtual BSize PreferredSize();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual void DoLayout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef BObjectList<ChartDataSource> DataSourceList;
|
||||||
|
|
||||||
|
struct AxisInfo {
|
||||||
|
ChartAxis* axis;
|
||||||
|
BRect frame;
|
||||||
|
|
||||||
|
AxisInfo();
|
||||||
|
void SetFrame(float left, float top, float right,
|
||||||
|
float bottom);
|
||||||
|
void SetRange(const ChartDataRange& range);
|
||||||
|
void Render(BView* view, const BRect& updateRect);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _UpdateDomainAndRange();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChartRenderer* fRenderer;
|
||||||
|
DataSourceList fDataSources;
|
||||||
|
AxisInfo fLeftAxis;
|
||||||
|
AxisInfo fTopAxis;
|
||||||
|
AxisInfo fRightAxis;
|
||||||
|
AxisInfo fBottomAxis;
|
||||||
|
ChartDataRange fDomain;
|
||||||
|
ChartDataRange fRange;
|
||||||
|
#if 0
|
||||||
|
ChartDataRange fDisplayDomain;
|
||||||
|
ChartDataRange fDisplayRange;
|
||||||
|
#endif
|
||||||
|
BRect fChartFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_H
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/ChartAxis.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ChartAxis
|
||||||
|
|
||||||
|
|
||||||
|
ChartAxis::~ChartAxis()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_AXIS_H
|
||||||
|
#define CHART_AXIS_H
|
||||||
|
|
||||||
|
#include <Rect.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDefs.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
class ChartDataRange;
|
||||||
|
|
||||||
|
|
||||||
|
class ChartAxis {
|
||||||
|
public:
|
||||||
|
virtual ~ChartAxis();
|
||||||
|
|
||||||
|
virtual void SetLocation(ChartAxisLocation location) = 0;
|
||||||
|
virtual void SetRange(const ChartDataRange& range) = 0;
|
||||||
|
virtual void SetFrame(BRect frame) = 0;
|
||||||
|
virtual BSize PreferredSize(BView* view) = 0;
|
||||||
|
virtual void Render(BView* view, BRect updateRect) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_AXIS_H
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/ChartAxisLegendSource.h"
|
||||||
|
|
||||||
|
|
||||||
|
ChartAxisLegendSource::~ChartAxisLegendSource()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_AXIS_LEGEND_SOURCE_H
|
||||||
|
#define CHART_AXIS_LEGEND_SOURCE_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
class ChartDataRange;
|
||||||
|
class ChartLegend;
|
||||||
|
|
||||||
|
|
||||||
|
class ChartAxisLegendSource {
|
||||||
|
public:
|
||||||
|
virtual ~ChartAxisLegendSource();
|
||||||
|
|
||||||
|
virtual int32 GetAxisLegends(const ChartDataRange& range,
|
||||||
|
ChartLegend** legends, double* values,
|
||||||
|
int32 maxLegends) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_AXIS_LEGEND_SOURCE_H
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_DATA_RANGE_H
|
||||||
|
#define CHART_DATA_RANGE_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
class ChartDataRange {
|
||||||
|
public:
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
|
||||||
|
ChartDataRange()
|
||||||
|
:
|
||||||
|
min(0),
|
||||||
|
max(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartDataRange(double min, double max)
|
||||||
|
:
|
||||||
|
min(min),
|
||||||
|
max(max)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartDataRange(const ChartDataRange& other)
|
||||||
|
:
|
||||||
|
min(other.min),
|
||||||
|
max(other.max)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartDataRange& Extend(const ChartDataRange& other)
|
||||||
|
{
|
||||||
|
min = std::min(min, other.min);
|
||||||
|
max = std::max(max, other.max);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartDataRange& operator=(const ChartDataRange& other)
|
||||||
|
{
|
||||||
|
min = other.min;
|
||||||
|
max = other.max;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ChartDataRange& other) const
|
||||||
|
{
|
||||||
|
return min == other.min && max == other.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ChartDataRange& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_DATA_RANGE_H
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/ChartDataSource.h"
|
||||||
|
|
||||||
|
|
||||||
|
ChartDataSource::~ChartDataSource()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_DATA_SOURCE_H
|
||||||
|
#define CHART_DATA_SOURCE_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDataRange.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ChartDataSource {
|
||||||
|
public:
|
||||||
|
virtual ~ChartDataSource();
|
||||||
|
|
||||||
|
virtual ChartDataRange Domain() const = 0;
|
||||||
|
virtual ChartDataRange Range() const = 0;
|
||||||
|
|
||||||
|
virtual void GetSamples(double start, double end,
|
||||||
|
double* samples, int32 count) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHART_DATA_SOURCE_H
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_DEFS_H
|
||||||
|
#define CHART_DEFS_H
|
||||||
|
|
||||||
|
|
||||||
|
enum ChartAxisLocation {
|
||||||
|
CHART_AXIS_LEFT,
|
||||||
|
CHART_AXIS_TOP,
|
||||||
|
CHART_AXIS_RIGHT,
|
||||||
|
CHART_AXIS_BOTTOM
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_DEFS_H
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/ChartLegend.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ChartLegend
|
||||||
|
|
||||||
|
|
||||||
|
ChartLegend::ChartLegend(int32 level)
|
||||||
|
:
|
||||||
|
fLevel(level)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChartLegend::~ChartLegend()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ChartLegendRenderer
|
||||||
|
|
||||||
|
|
||||||
|
ChartLegendRenderer::~ChartLegendRenderer()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_LEGEND_H
|
||||||
|
#define CHART_LEGEND_H
|
||||||
|
|
||||||
|
#include <Point.h>
|
||||||
|
#include <Size.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
class ChartDataRange;
|
||||||
|
|
||||||
|
|
||||||
|
class ChartLegend {
|
||||||
|
public:
|
||||||
|
ChartLegend(int32 level = 0);
|
||||||
|
// A lower level means more likely to be
|
||||||
|
// shown. <= 0 is mandatory.
|
||||||
|
virtual ~ChartLegend();
|
||||||
|
|
||||||
|
int32 Level() { return fLevel; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 fLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ChartLegendRenderer {
|
||||||
|
public:
|
||||||
|
virtual ~ChartLegendRenderer();
|
||||||
|
|
||||||
|
virtual void GetMinimumLegendSpacing(BView* view,
|
||||||
|
float* horizontal, float* vertical) = 0;
|
||||||
|
virtual BSize MaximumLegendSize(BView* view) = 0;
|
||||||
|
|
||||||
|
virtual BSize LegendSize(ChartLegend* legend,
|
||||||
|
BView* view) = 0;
|
||||||
|
virtual void RenderLegend(ChartLegend* legend, BView* view,
|
||||||
|
BPoint point) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_LEGEND_H
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/ChartRenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ChartRenderer
|
||||||
|
|
||||||
|
|
||||||
|
ChartRenderer::~ChartRenderer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ChartRendererDataSourceConfig
|
||||||
|
|
||||||
|
|
||||||
|
ChartRendererDataSourceConfig::~ChartRendererDataSourceConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CHART_RENDERER_H
|
||||||
|
#define CHART_RENDERER_H
|
||||||
|
|
||||||
|
#include <Rect.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
class ChartDataRange;
|
||||||
|
class ChartDataSource;
|
||||||
|
|
||||||
|
|
||||||
|
class ChartRendererDataSourceConfig {
|
||||||
|
public:
|
||||||
|
virtual ~ChartRendererDataSourceConfig();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ChartRenderer {
|
||||||
|
public:
|
||||||
|
virtual ~ChartRenderer();
|
||||||
|
|
||||||
|
virtual bool AddDataSource(
|
||||||
|
ChartDataSource* dataSource,
|
||||||
|
int32 index,
|
||||||
|
ChartRendererDataSourceConfig* config) = 0;
|
||||||
|
virtual void RemoveDataSource(
|
||||||
|
ChartDataSource* dataSource) = 0;
|
||||||
|
|
||||||
|
virtual void SetFrame(const BRect& frame) = 0;
|
||||||
|
virtual void SetDomain(const ChartDataRange& domain) = 0;
|
||||||
|
virtual void SetRange(const ChartDataRange& range) = 0;
|
||||||
|
|
||||||
|
virtual void Render(BView* view, BRect updateRect) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CHART_RENDERER_H
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
SubDir HAIKU_TOP src apps debuganalyzer gui chart ;
|
||||||
|
|
||||||
|
UsePrivateHeaders shared ;
|
||||||
|
|
||||||
|
UseHeaders $(HAIKU_DEBUG_ANALYZER_HEADERS) ;
|
||||||
|
|
||||||
|
|
||||||
|
MergeObject DebugAnalyzer_gui_chart.o
|
||||||
|
:
|
||||||
|
BigtimeChartAxisLegendSource.cpp
|
||||||
|
Chart.cpp
|
||||||
|
ChartAxis.cpp
|
||||||
|
ChartAxisLegendSource.cpp
|
||||||
|
ChartDataSource.cpp
|
||||||
|
ChartLegend.cpp
|
||||||
|
ChartRenderer.cpp
|
||||||
|
LegendChartAxis.cpp
|
||||||
|
LineChartRenderer.cpp
|
||||||
|
StringChartLegend.cpp
|
||||||
|
;
|
||||||
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/LegendChartAxis.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <Font.h>
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
#include "chart/ChartLegend.h"
|
||||||
|
#include "chart/ChartAxisLegendSource.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const int32 kChartRulerDistance = 2;
|
||||||
|
static const int32 kRulerSize = 3;
|
||||||
|
static const int32 kRulerMarkSize = 3;
|
||||||
|
static const int32 kRulerLegendDistance = 2;
|
||||||
|
static const int32 kChartLegendDistance
|
||||||
|
= kChartRulerDistance + kRulerSize + kRulerMarkSize + kRulerLegendDistance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct LegendChartAxis::LegendInfo {
|
||||||
|
ChartLegend* legend;
|
||||||
|
double value;
|
||||||
|
BSize size;
|
||||||
|
|
||||||
|
LegendInfo(ChartLegend* legend, double value, BSize size)
|
||||||
|
:
|
||||||
|
legend(legend),
|
||||||
|
value(value),
|
||||||
|
size(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~LegendInfo()
|
||||||
|
{
|
||||||
|
delete legend;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
LegendChartAxis::_LegendPosition(double value, float legendSize,
|
||||||
|
float totalSize, double scale)
|
||||||
|
{
|
||||||
|
float position = (value - fRange.min) * scale - legendSize / 2;
|
||||||
|
if (position + legendSize > totalSize)
|
||||||
|
position = totalSize - legendSize;
|
||||||
|
if (position < 0)
|
||||||
|
position = 0;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::_FilterLegends(int32 totalSize, int32 spacing,
|
||||||
|
float BSize::* sizeField)
|
||||||
|
{
|
||||||
|
printf("LegendChartAxis::_FilterLegends(%ld, %ld)\n", totalSize, spacing);
|
||||||
|
// compute the min/max legend levels
|
||||||
|
int32 legendCount = fLegends.CountItems();
|
||||||
|
int32 minLevel = INT_MAX;
|
||||||
|
int32 maxLevel = 0;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < legendCount; i++) {
|
||||||
|
LegendInfo* info = fLegends.ItemAt(i);
|
||||||
|
int32 level = info->legend->Level();
|
||||||
|
if (level < minLevel)
|
||||||
|
minLevel = level;
|
||||||
|
if (level > maxLevel)
|
||||||
|
maxLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxLevel <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double rangeSize = fRange.max - fRange.min;
|
||||||
|
if (rangeSize == 0)
|
||||||
|
rangeSize = 1.0;
|
||||||
|
double scale = (double)totalSize / rangeSize;
|
||||||
|
|
||||||
|
// Filter out all higher level legends colliding with lower level or
|
||||||
|
// preceeding same-level legends. We iterate backwards from the lower to
|
||||||
|
// the higher levels
|
||||||
|
for (int32 level = std::max(minLevel, 0L); level <= maxLevel;) {
|
||||||
|
printf(" level: %ld\n", level);
|
||||||
|
legendCount = fLegends.CountItems();
|
||||||
|
|
||||||
|
// get the first legend position/end
|
||||||
|
LegendInfo* info = fLegends.ItemAt(0);
|
||||||
|
float position = _LegendPosition(info->value, info->size.*sizeField,
|
||||||
|
(float)totalSize, scale);;
|
||||||
|
|
||||||
|
int32 previousEnd = (int32)ceilf(position + info->size.*sizeField);
|
||||||
|
int32 previousLevel = info->legend->Level();
|
||||||
|
printf(" first legend: pos: %f, size: %f\n", position, info->size.*sizeField);
|
||||||
|
|
||||||
|
for (int32 i = 1; (info = fLegends.ItemAt(i)) != NULL; i++) {
|
||||||
|
float position = _LegendPosition(info->value, info->size.*sizeField,
|
||||||
|
(float)totalSize, scale);;
|
||||||
|
printf(" legend %ld: pos: %f, size: %f\n", i, position, info->size.*sizeField);
|
||||||
|
|
||||||
|
if (position - spacing < previousEnd
|
||||||
|
&& (previousLevel <= level
|
||||||
|
|| info->legend->Level() <= level)
|
||||||
|
&& std::max(previousLevel, info->legend->Level()) > 0) {
|
||||||
|
// The item intersects with the previous one -- remove the
|
||||||
|
// one at the higher level.
|
||||||
|
if (info->legend->Level() >= previousLevel) {
|
||||||
|
// This item is at the higher level -- remove it.
|
||||||
|
delete fLegends.RemoveItemAt(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The previous item is at the higher level -- remove it.
|
||||||
|
delete fLegends.RemoveItemAt(i - 1);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0 && position < 0)
|
||||||
|
position = 0;
|
||||||
|
previousEnd = (int32)ceilf(position + info->size.*sizeField);
|
||||||
|
previousLevel = info->legend->Level();
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat with the level as long as we've removed something
|
||||||
|
if (legendCount == fLegends.CountItems())
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LegendChartAxis::LegendChartAxis(ChartAxisLegendSource* legendSource,
|
||||||
|
ChartLegendRenderer* legendRenderer)
|
||||||
|
:
|
||||||
|
fLegendSource(legendSource),
|
||||||
|
fLegendRenderer(legendRenderer),
|
||||||
|
fLocation(CHART_AXIS_BOTTOM),
|
||||||
|
fRange(),
|
||||||
|
fFrame(),
|
||||||
|
fLegends(20, true),
|
||||||
|
fHorizontalSpacing(20),
|
||||||
|
fVerticalSpacing(10),
|
||||||
|
fLayoutValid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LegendChartAxis::~LegendChartAxis()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::SetLocation(ChartAxisLocation location)
|
||||||
|
{
|
||||||
|
if (location != fLocation) {
|
||||||
|
fLocation = location;
|
||||||
|
_InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::SetRange(const ChartDataRange& range)
|
||||||
|
{
|
||||||
|
if (range != fRange) {
|
||||||
|
fRange = range;
|
||||||
|
_InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::SetFrame(BRect frame)
|
||||||
|
{
|
||||||
|
printf("LegendChartAxis::SetFrame((%f, %f) - (%f, %f))\n", frame.left, frame.top, frame.right, frame.bottom);
|
||||||
|
if (frame != fFrame) {
|
||||||
|
fFrame = frame;
|
||||||
|
_InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
LegendChartAxis::PreferredSize(BView* view)
|
||||||
|
{
|
||||||
|
// TODO: Implement for real!
|
||||||
|
BSize size = fLegendRenderer->MaximumLegendSize(view);
|
||||||
|
if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT) {
|
||||||
|
size.width += kChartLegendDistance;
|
||||||
|
size.height = std::max(size.height * 4, 100.0f);
|
||||||
|
} else {
|
||||||
|
size.width = std::max(size.width * 4, 100.0f);
|
||||||
|
size.height += kChartLegendDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::Render(BView* view, BRect updateRect)
|
||||||
|
{
|
||||||
|
printf("LegendChartAxis::Render()\n");
|
||||||
|
if (!_ValidateLayout(view))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fLocation == CHART_AXIS_BOTTOM) {
|
||||||
|
printf(" rendering...\n");
|
||||||
|
float totalSize = floorf(fFrame.Width()) + 1;
|
||||||
|
double rangeSize = fRange.max - fRange.min;
|
||||||
|
if (rangeSize == 0)
|
||||||
|
rangeSize = 1.0;
|
||||||
|
double scale = (double)totalSize / rangeSize;
|
||||||
|
float BSize::* sizeField = &BSize::width;
|
||||||
|
|
||||||
|
// draw the ruler
|
||||||
|
float rulerLeft = fFrame.left;
|
||||||
|
float rulerTop = fFrame.top + kChartRulerDistance;
|
||||||
|
float rulerRight = fFrame.right;
|
||||||
|
float rulerBottom = rulerTop + kRulerSize;
|
||||||
|
printf(" ruler: (%f, %f) - (%f, %f)\n", rulerLeft, rulerTop, rulerRight, rulerBottom);
|
||||||
|
|
||||||
|
rgb_color black = { 0, 0, 0, 255 };
|
||||||
|
view->BeginLineArray(3 + fLegends.CountItems());
|
||||||
|
view->AddLine(BPoint(rulerLeft, rulerTop),
|
||||||
|
BPoint(rulerLeft, rulerBottom), black);
|
||||||
|
view->AddLine(BPoint(rulerLeft, rulerBottom),
|
||||||
|
BPoint(rulerRight, rulerBottom), black);
|
||||||
|
view->AddLine(BPoint(rulerRight, rulerBottom),
|
||||||
|
BPoint(rulerRight, rulerTop), black);
|
||||||
|
|
||||||
|
// marks
|
||||||
|
for (int32 i = 0; LegendInfo* info = fLegends.ItemAt(i); i++) {
|
||||||
|
float position = (info->value - fRange.min) * scale;
|
||||||
|
position += rulerLeft;
|
||||||
|
printf(" drawing mark at (%f, %f)\n", position, rulerBottom);
|
||||||
|
view->AddLine(BPoint(position, rulerBottom),
|
||||||
|
BPoint(position, rulerBottom + kRulerMarkSize), black);
|
||||||
|
}
|
||||||
|
view->EndLineArray();
|
||||||
|
|
||||||
|
// draw the legends
|
||||||
|
float legendTop = rulerBottom + kRulerMarkSize + kRulerLegendDistance;
|
||||||
|
|
||||||
|
for (int32 i = 0; LegendInfo* info = fLegends.ItemAt(i); i++) {
|
||||||
|
float position = _LegendPosition(info->value, info->size.*sizeField,
|
||||||
|
(float)totalSize, scale);;
|
||||||
|
printf(" legend %ld: position: (%f, %f), size: (%f, %f)\n", i, position, legendTop, info->size.width, info->size.height);
|
||||||
|
|
||||||
|
fLegendRenderer->RenderLegend(info->legend, view,
|
||||||
|
BPoint(rulerLeft + position, legendTop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LegendChartAxis::_InvalidateLayout()
|
||||||
|
{
|
||||||
|
fLayoutValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LegendChartAxis::_ValidateLayout(BView* view)
|
||||||
|
{
|
||||||
|
if (fLayoutValid)
|
||||||
|
return true;
|
||||||
|
printf("LegendChartAxis::_ValidateLayout()\n");
|
||||||
|
|
||||||
|
fLegends.MakeEmpty();
|
||||||
|
|
||||||
|
int32 width = fFrame.IntegerWidth() + 1;
|
||||||
|
int32 height = fFrame.IntegerHeight() + 1;
|
||||||
|
printf(" width: %ld, height: %ld\n", width, height);
|
||||||
|
|
||||||
|
fLegendRenderer->GetMinimumLegendSpacing(view, &fHorizontalSpacing,
|
||||||
|
&fVerticalSpacing);
|
||||||
|
|
||||||
|
// estimate the maximum legend count we might need
|
||||||
|
int32 maxLegends;
|
||||||
|
if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT)
|
||||||
|
maxLegends = height / (10 + fVerticalSpacing);
|
||||||
|
else
|
||||||
|
maxLegends = width / (20 + fHorizontalSpacing);
|
||||||
|
|
||||||
|
printf(" max %ld legends\n", maxLegends);
|
||||||
|
if (maxLegends == 0)
|
||||||
|
{
|
||||||
|
printf(" too small for any legends!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the legends
|
||||||
|
ChartLegend* legends[maxLegends];
|
||||||
|
double values[maxLegends];
|
||||||
|
|
||||||
|
int32 legendCount = fLegendSource->GetAxisLegends(fRange, legends, values,
|
||||||
|
maxLegends);
|
||||||
|
printf(" got %ld legends\n", legendCount);
|
||||||
|
if (legendCount == 0)
|
||||||
|
{
|
||||||
|
printf(" got no legends from source!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" range: %f - %f\n", fRange.min, fRange.max);
|
||||||
|
// create legend infos
|
||||||
|
for (int32 i = 0; i < legendCount; i++) {
|
||||||
|
ChartLegend* legend = legends[i];
|
||||||
|
BSize size = fLegendRenderer->LegendSize(legend, view);
|
||||||
|
LegendInfo* info = new(std::nothrow) LegendInfo(legend, values[i],
|
||||||
|
size);
|
||||||
|
printf(" legend %ld: size: (%f, %f), value: %f\n", i, size.width, size.height, info->value);
|
||||||
|
if (info == NULL || !fLegends.AddItem(info)) {
|
||||||
|
// TODO: Report error!
|
||||||
|
delete info;
|
||||||
|
for (int32 k = i; k < legendCount; k++)
|
||||||
|
delete legends[k];
|
||||||
|
printf(" failed to create legend info!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fLocation == CHART_AXIS_LEFT || fLocation == CHART_AXIS_RIGHT)
|
||||||
|
_FilterLegends(height, fVerticalSpacing, &BSize::height);
|
||||||
|
else
|
||||||
|
_FilterLegends(width, fHorizontalSpacing, &BSize::width);
|
||||||
|
|
||||||
|
fLayoutValid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef LEGEND_CHART_AXIS_H
|
||||||
|
#define LEGEND_CHART_AXIS_H
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "chart/ChartAxis.h"
|
||||||
|
#include "chart/ChartDataRange.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ChartAxisLegendSource;
|
||||||
|
class ChartLegendRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
class LegendChartAxis : public ChartAxis {
|
||||||
|
public:
|
||||||
|
LegendChartAxis(
|
||||||
|
ChartAxisLegendSource* legendSource,
|
||||||
|
ChartLegendRenderer* legendRenderer);
|
||||||
|
virtual ~LegendChartAxis();
|
||||||
|
|
||||||
|
virtual void SetLocation(ChartAxisLocation location);
|
||||||
|
virtual void SetRange(const ChartDataRange& range);
|
||||||
|
virtual void SetFrame(BRect frame);
|
||||||
|
virtual BSize PreferredSize(BView* view);
|
||||||
|
virtual void Render(BView* view, BRect updateRect);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LegendInfo;
|
||||||
|
typedef BObjectList<LegendInfo> LegendList;
|
||||||
|
private:
|
||||||
|
void _InvalidateLayout();
|
||||||
|
bool _ValidateLayout(BView* view);
|
||||||
|
inline float _LegendPosition(double value, float legendSize,
|
||||||
|
float totalSize, double scale);
|
||||||
|
inline void _FilterLegends(int32 totalSize, int32 spacing,
|
||||||
|
float BSize::* sizeField);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChartAxisLegendSource* fLegendSource;
|
||||||
|
ChartLegendRenderer* fLegendRenderer;
|
||||||
|
ChartAxisLocation fLocation;
|
||||||
|
ChartDataRange fRange;
|
||||||
|
BRect fFrame;
|
||||||
|
LegendList fLegends;
|
||||||
|
float fHorizontalSpacing;
|
||||||
|
float fVerticalSpacing;
|
||||||
|
bool fLayoutValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LEGEND_CHART_AXIS_H
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/LineChartRenderer.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDataSource.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DataSourceInfo
|
||||||
|
|
||||||
|
|
||||||
|
struct LineChartRenderer::DataSourceInfo {
|
||||||
|
public:
|
||||||
|
ChartDataSource* source;
|
||||||
|
double* samples;
|
||||||
|
int32 sampleCount;
|
||||||
|
bool samplesValid;
|
||||||
|
LineChartRendererDataSourceConfig config;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataSourceInfo(ChartDataSource* source,
|
||||||
|
LineChartRendererDataSourceConfig* config);
|
||||||
|
~DataSourceInfo();
|
||||||
|
|
||||||
|
bool UpdateSamples(const ChartDataRange& domain,
|
||||||
|
int32 sampleCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRenderer::DataSourceInfo::DataSourceInfo(ChartDataSource* source,
|
||||||
|
LineChartRendererDataSourceConfig* config)
|
||||||
|
:
|
||||||
|
source(source),
|
||||||
|
samples(NULL),
|
||||||
|
sampleCount(0),
|
||||||
|
samplesValid(false)
|
||||||
|
{
|
||||||
|
if (config != NULL)
|
||||||
|
this->config = *config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRenderer::DataSourceInfo::~DataSourceInfo()
|
||||||
|
{
|
||||||
|
delete[] samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LineChartRenderer::DataSourceInfo::UpdateSamples(const ChartDataRange& domain,
|
||||||
|
int32 sampleCount)
|
||||||
|
{
|
||||||
|
if (samplesValid)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// check the sample count -- we might need to realloc the sample array
|
||||||
|
if (sampleCount != this->sampleCount) {
|
||||||
|
delete[] samples;
|
||||||
|
this->sampleCount = 0;
|
||||||
|
|
||||||
|
samples = new(std::nothrow) double[sampleCount];
|
||||||
|
if (samples == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->sampleCount = sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the new samples
|
||||||
|
source->GetSamples(domain.min, domain.max, samples, sampleCount);
|
||||||
|
|
||||||
|
samplesValid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - LineChartRenderer
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRenderer::LineChartRenderer()
|
||||||
|
:
|
||||||
|
fFrame(),
|
||||||
|
fDomain(),
|
||||||
|
fRange()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRenderer::~LineChartRenderer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LineChartRenderer::AddDataSource(ChartDataSource* dataSource, int32 index,
|
||||||
|
ChartRendererDataSourceConfig* config)
|
||||||
|
{
|
||||||
|
DataSourceInfo* info = new(std::nothrow) DataSourceInfo(dataSource,
|
||||||
|
dynamic_cast<LineChartRendererDataSourceConfig*>(config));
|
||||||
|
if (info == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!fDataSources.AddItem(info, index)) {
|
||||||
|
delete info;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::RemoveDataSource(ChartDataSource* dataSource)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
|
||||||
|
info->samplesValid = false;
|
||||||
|
if (info->source == dataSource) {
|
||||||
|
delete fDataSources.RemoveItemAt(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::SetFrame(const BRect& frame)
|
||||||
|
{
|
||||||
|
fFrame = frame;
|
||||||
|
_InvalidateSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::SetDomain(const ChartDataRange& domain)
|
||||||
|
{
|
||||||
|
if (domain != fDomain) {
|
||||||
|
fDomain = domain;
|
||||||
|
_InvalidateSamples();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::SetRange(const ChartDataRange& range)
|
||||||
|
{
|
||||||
|
if (range != fRange) {
|
||||||
|
fRange = range;
|
||||||
|
_InvalidateSamples();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::Render(BView* view, BRect updateRect)
|
||||||
|
{
|
||||||
|
if (!updateRect.IsValid() || updateRect.left > fFrame.right
|
||||||
|
|| fFrame.left > updateRect.right) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fDomain.min >= fDomain.max || fRange.min >= fRange.max)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_UpdateSamples())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get the range to draw (draw one more sample on each side)
|
||||||
|
int32 left = (int32)fFrame.left;
|
||||||
|
int32 first = (int32)updateRect.left - left - 1;
|
||||||
|
int32 last = (int32)updateRect.right - left + 1;
|
||||||
|
if (first < 0)
|
||||||
|
first = 0;
|
||||||
|
if (last > fFrame.IntegerWidth())
|
||||||
|
last = fFrame.IntegerWidth();
|
||||||
|
if (first > last)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double minRange = fRange.min;
|
||||||
|
double sampleRange = fRange.max - minRange;
|
||||||
|
if (sampleRange == 0) {
|
||||||
|
minRange = fRange.min - 0.5;
|
||||||
|
sampleRange = 1;
|
||||||
|
}
|
||||||
|
double scale = (double)fFrame.IntegerHeight() / sampleRange;
|
||||||
|
|
||||||
|
// draw
|
||||||
|
for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
|
||||||
|
printf("LineChartRenderer::Render(): %p\n", info);
|
||||||
|
view->SetHighColor(info->config.Color());
|
||||||
|
|
||||||
|
float bottom = fFrame.bottom;
|
||||||
|
view->MovePenTo(left + first,
|
||||||
|
bottom - ((info->samples[first] - minRange) * scale));
|
||||||
|
|
||||||
|
for (int32 i = first; i <= last; i++) {
|
||||||
|
view->StrokeLine(BPoint(float(left + i),
|
||||||
|
float(bottom - ((info->samples[i] - minRange) * scale))));
|
||||||
|
//printf(" %f: %f (%f)\n", info->samples[i] - minRange, float(bottom - ((info->samples[i] - minRange) * scale)), bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRenderer::_InvalidateSamples()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++)
|
||||||
|
info->samplesValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LineChartRenderer::_UpdateSamples()
|
||||||
|
{
|
||||||
|
int32 width = fFrame.IntegerWidth() + 1;
|
||||||
|
if (width <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int32 i = 0; DataSourceInfo* info = fDataSources.ItemAt(i); i++) {
|
||||||
|
if (!info->UpdateSamples(fDomain, width))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - LineChartRendererDataSourceConfig
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRendererDataSourceConfig::LineChartRendererDataSourceConfig()
|
||||||
|
{
|
||||||
|
fColor.red = 0;
|
||||||
|
fColor.green = 0;
|
||||||
|
fColor.blue = 0;
|
||||||
|
fColor.alpha = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRendererDataSourceConfig::LineChartRendererDataSourceConfig(
|
||||||
|
const rgb_color& color)
|
||||||
|
{
|
||||||
|
fColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineChartRendererDataSourceConfig::~LineChartRendererDataSourceConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rgb_color&
|
||||||
|
LineChartRendererDataSourceConfig::Color() const
|
||||||
|
{
|
||||||
|
return fColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineChartRendererDataSourceConfig::SetColor(const rgb_color& color)
|
||||||
|
{
|
||||||
|
fColor = color;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef LINE_CHART_RENDERER_H
|
||||||
|
#define LINE_CHART_RENDERER_H
|
||||||
|
|
||||||
|
#include <InterfaceDefs.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "chart/ChartDataRange.h"
|
||||||
|
#include "chart/ChartRenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
|
||||||
|
|
||||||
|
class LineChartRenderer : public ChartRenderer {
|
||||||
|
public:
|
||||||
|
class DataSourceConfig;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LineChartRenderer();
|
||||||
|
virtual ~LineChartRenderer();
|
||||||
|
|
||||||
|
virtual bool AddDataSource(ChartDataSource* dataSource,
|
||||||
|
int32 index,
|
||||||
|
ChartRendererDataSourceConfig* config);
|
||||||
|
virtual void RemoveDataSource(ChartDataSource* dataSource);
|
||||||
|
|
||||||
|
virtual void SetFrame(const BRect& frame);
|
||||||
|
virtual void SetDomain(const ChartDataRange& domain);
|
||||||
|
virtual void SetRange(const ChartDataRange& range);
|
||||||
|
|
||||||
|
virtual void Render(BView* view, BRect updateRect);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DataSourceInfo;
|
||||||
|
|
||||||
|
typedef BObjectList<DataSourceInfo> DataSourceList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _InvalidateSamples();
|
||||||
|
bool _UpdateSamples();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataSourceList fDataSources;
|
||||||
|
BRect fFrame;
|
||||||
|
ChartDataRange fDomain;
|
||||||
|
ChartDataRange fRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LineChartRendererDataSourceConfig : public ChartRendererDataSourceConfig {
|
||||||
|
public:
|
||||||
|
LineChartRendererDataSourceConfig();
|
||||||
|
LineChartRendererDataSourceConfig(
|
||||||
|
const rgb_color& color);
|
||||||
|
virtual ~LineChartRendererDataSourceConfig();
|
||||||
|
|
||||||
|
const rgb_color& Color() const;
|
||||||
|
void SetColor(const rgb_color& color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
rgb_color fColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LINE_CHART_RENDERER_H
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chart/StringChartLegend.h"
|
||||||
|
|
||||||
|
#include <Font.h>
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - StringChartLegend
|
||||||
|
|
||||||
|
|
||||||
|
StringChartLegend::StringChartLegend(const char* string, int32 level)
|
||||||
|
:
|
||||||
|
ChartLegend(level),
|
||||||
|
fString(string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - StringChartLegendRenderer
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StringChartLegendRenderer::GetMinimumLegendSpacing(BView* view,
|
||||||
|
float* horizontal, float* vertical)
|
||||||
|
{
|
||||||
|
// TODO: Implement for real!
|
||||||
|
*horizontal = 40;
|
||||||
|
*vertical = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
StringChartLegendRenderer::MaximumLegendSize(BView* view)
|
||||||
|
{
|
||||||
|
// TODO: Implement for real!
|
||||||
|
return BSize(100, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
StringChartLegendRenderer::LegendSize(ChartLegend* _legend, BView* view)
|
||||||
|
{
|
||||||
|
StringChartLegend* legend = dynamic_cast<StringChartLegend*>(_legend);
|
||||||
|
if (legend == NULL)
|
||||||
|
return BSize();
|
||||||
|
|
||||||
|
// TODO: It's a bit expensive to do that for each legend!
|
||||||
|
// TODO: Have a font per renderer?
|
||||||
|
BFont font;
|
||||||
|
view->GetFont(&font);
|
||||||
|
font_height fh;
|
||||||
|
font.GetHeight(&fh);
|
||||||
|
float fontHeight = ceilf(fh.ascent) + ceilf(fh.descent);
|
||||||
|
float width = ceilf(font.StringWidth(legend->String()));
|
||||||
|
|
||||||
|
return BSize(width, fontHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StringChartLegendRenderer::RenderLegend(ChartLegend* _legend, BView* view,
|
||||||
|
BPoint point)
|
||||||
|
{
|
||||||
|
StringChartLegend* legend = dynamic_cast<StringChartLegend*>(_legend);
|
||||||
|
if (legend == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BFont font;
|
||||||
|
view->GetFont(&font);
|
||||||
|
font_height fh;
|
||||||
|
font.GetHeight(&fh);
|
||||||
|
point.y += fh.ascent;
|
||||||
|
|
||||||
|
view->SetHighColor(rgb_color().set_to(0, 0, 0, 255));
|
||||||
|
view->DrawString(legend->String(), point);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef STRING_CHART_LEGEND_H
|
||||||
|
#define STRING_CHART_LEGEND_H
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "chart/ChartLegend.h"
|
||||||
|
|
||||||
|
|
||||||
|
class StringChartLegend : public ChartLegend {
|
||||||
|
public:
|
||||||
|
StringChartLegend(const char* string,
|
||||||
|
int32 level = 0);
|
||||||
|
|
||||||
|
const char* String() const { return fString.String(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fString;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StringChartLegendRenderer : public ChartLegendRenderer {
|
||||||
|
public:
|
||||||
|
virtual void GetMinimumLegendSpacing(BView* view,
|
||||||
|
float* horizontal, float* vertical);
|
||||||
|
virtual BSize MaximumLegendSize(BView* view);
|
||||||
|
|
||||||
|
virtual BSize LegendSize(ChartLegend* legend,
|
||||||
|
BView* view);
|
||||||
|
virtual void RenderLegend(ChartLegend* legend, BView* view,
|
||||||
|
BPoint point);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // STRING_CHART_LEGEND_H
|
||||||
Reference in New Issue
Block a user