#include "DiagramItemGroup.h"
#include "DiagramItem.h"
#include <Region.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x)
DiagramItemGroup::DiagramItemGroup(uint32 acceptedTypes, bool multiSelection)
:fBoxes(0),
fWires(0),
fEndPoints(0),
fSelection(0),
fTypes(acceptedTypes),
fItemAlignment(1.0, 1.0),
fMultiSelection(multiSelection),
fLastItemUnder(0)
{
D_METHOD(("DiagramItemGroup::DiagramItemGroup()\n"));
fSelection = new BList(1);
}
DiagramItemGroup::~DiagramItemGroup()
{
D_METHOD(("DiagramItemGroup::~DiagramItemGroup()\n"));
int32 count = 0;
if (fWires && (fTypes & DiagramItem::M_WIRE)) {
count = fWires->CountItems();
for (int32 i = 0; i < count; ++i)
delete static_cast<DiagramItem*>(fWires->ItemAt(i));
delete fWires;
}
if (fBoxes && (fTypes & DiagramItem::M_BOX)) {
count = fBoxes->CountItems();
for (int32 i = 0; i < count; ++i)
delete static_cast<DiagramItem*>(fBoxes->ItemAt(i));
delete fBoxes;
}
if (fEndPoints && (fTypes & DiagramItem::M_ENDPOINT)) {
count = fEndPoints->CountItems();
for (int32 i = 0; i < count; ++i)
delete static_cast<DiagramItem*>(fEndPoints->ItemAt(i));
delete fEndPoints;
}
if (fSelection)
delete fSelection;
}
uint32
DiagramItemGroup::CountItems(uint32 whichType) const
{
D_METHOD(("DiagramItemGroup::CountItems()\n"));
uint32 count = 0;
if (whichType & fTypes) {
if (whichType & DiagramItem::M_BOX) {
if (fBoxes)
count += fBoxes->CountItems();
}
if (whichType & DiagramItem::M_WIRE) {
if (fWires)
count += fWires->CountItems();
}
if (whichType & DiagramItem::M_ENDPOINT) {
if (fEndPoints)
count += fEndPoints->CountItems();
}
}
return count;
}
DiagramItem*
DiagramItemGroup::ItemAt(uint32 index, uint32 whichType) const
{
D_METHOD(("DiagramItemGroup::ItemAt()\n"));
if (fTypes & whichType) {
if (whichType & DiagramItem::M_BOX) {
if (fBoxes && (index < CountItems(DiagramItem::M_BOX)))
return static_cast<DiagramItem *>(fBoxes->ItemAt(index));
else
index -= CountItems(DiagramItem::M_BOX);
}
if (whichType & DiagramItem::M_WIRE) {
if (fWires && (index < CountItems(DiagramItem::M_WIRE)))
return static_cast<DiagramItem *>(fWires->ItemAt(index));
else
index -= CountItems(DiagramItem::M_WIRE);
}
if (whichType & DiagramItem::M_ENDPOINT) {
if (fEndPoints && (index < CountItems(DiagramItem::M_ENDPOINT)))
return static_cast<DiagramItem *>(fEndPoints->ItemAt(index));
}
}
return 0;
}
DiagramItem*
DiagramItemGroup::ItemUnder(BPoint point)
{
D_METHOD(("DiagramItemGroup::ItemUnder()\n"));
if (fTypes & DiagramItem::M_BOX) {
for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0)) {
return (fLastItemUnder = item);
}
}
}
if (fTypes & DiagramItem::M_WIRE) {
float closest = 0.0;
DiagramItem *closestItem = 0;
for (uint32 i = 0; i < CountItems(DiagramItem::M_WIRE); i++) {
DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
if (item->Frame().Contains(point)) {
float howClose = item->howCloseTo(point);
if (howClose > closest) {
closestItem = item;
if (howClose == 1.0)
return (fLastItemUnder = item);
closest = howClose;
}
}
}
if (closest > 0.5)
return (fLastItemUnder = closestItem);
}
if (fTypes & DiagramItem::M_ENDPOINT) {
for (uint32 i = 0; i < CountItems(DiagramItem::M_ENDPOINT); i++) {
DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
if (item->Frame().Contains(point) && (item->howCloseTo(point) == 1.0))
return (fLastItemUnder = item);
}
}
return (fLastItemUnder = 0);
}
bool
DiagramItemGroup::AddItem(DiagramItem *item)
{
D_METHOD(("DiagramItemGroup::AddItem()\n"));
if (item && (fTypes & item->type())) {
if (item->m_group)
item->m_group->RemoveItem(item);
switch (item->type()) {
case DiagramItem::M_BOX:
if (!fBoxes)
fBoxes = new BList();
item->m_group = this;
return fBoxes->AddItem(static_cast<void *>(item));
case DiagramItem::M_WIRE:
if (!fWires)
fWires = new BList();
item->m_group = this;
return fWires->AddItem(static_cast<void *>(item));
case DiagramItem::M_ENDPOINT:
if (!fEndPoints)
fEndPoints = new BList();
item->m_group = this;
return fEndPoints->AddItem(static_cast<void *>(item));
}
}
return false;
}
bool
DiagramItemGroup::RemoveItem(DiagramItem* item)
{
D_METHOD(("DiagramItemGroup::RemoveItem()\n"));
if (item && (fTypes & item->type())) {
if (fLastItemUnder == item)
fLastItemUnder = 0;
if (item->isSelected())
fSelection->RemoveItem(static_cast<void *>(item));
switch (item->type()) {
case DiagramItem::M_BOX:
if (fBoxes) {
item->m_group = 0;
return fBoxes->RemoveItem(static_cast<void *>(item));
}
break;
case DiagramItem::M_WIRE:
if (fWires) {
item->m_group = 0;
return fWires->RemoveItem(static_cast<void *>(item));
}
break;
case DiagramItem::M_ENDPOINT:
if (fEndPoints) {
item->m_group = 0;
return fEndPoints->RemoveItem(static_cast<void *>(item));
}
}
}
return false;
}
void
DiagramItemGroup::SortItems(uint32 whichType,
int (*compareFunc)(const void *, const void *))
{
D_METHOD(("DiagramItemGroup::SortItems()\n"));
if ((whichType != DiagramItem::M_ANY) && (fTypes & whichType)) {
switch (whichType) {
case DiagramItem::M_BOX:
if (fBoxes)
fBoxes->SortItems(compareFunc);
break;
case DiagramItem::M_WIRE:
if (fWires)
fWires->SortItems(compareFunc);
break;
case DiagramItem::M_ENDPOINT:
if (fEndPoints)
fEndPoints->SortItems(compareFunc);
break;
}
}
}
void
DiagramItemGroup::DrawItems(BRect updateRect, uint32 whichType, BRegion* updateRegion)
{
D_METHOD(("DiagramItemGroup::DrawItems()\n"));
if (whichType & DiagramItem::M_WIRE) {
for (int32 i = CountItems(DiagramItem::M_WIRE) - 1; i >= 0; i--) {
DiagramItem *item = ItemAt(i, DiagramItem::M_WIRE);
if (item->Frame().Intersects(updateRect))
item->Draw(updateRect);
}
}
if (whichType & DiagramItem::M_BOX) {
for (int32 i = CountItems(DiagramItem::M_BOX) - 1; i >= 0; i--) {
DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
if (item && item->Frame().Intersects(updateRect)) {
item->Draw(updateRect);
if (updateRegion)
updateRegion->Exclude(item->Frame());
}
}
}
if (whichType & DiagramItem::M_ENDPOINT) {
for (int32 i = CountItems(DiagramItem::M_ENDPOINT) - 1; i >= 0; i--) {
DiagramItem *item = ItemAt(i, DiagramItem::M_ENDPOINT);
if (item && item->Frame().Intersects(updateRect))
item->Draw(updateRect);
}
}
}
bool
DiagramItemGroup::GetClippingAbove(DiagramItem *which, BRegion *region)
{
D_METHOD(("DiagramItemGroup::GetClippingAbove()\n"));
bool found = false;
if (which && region) {
switch (which->type()) {
case DiagramItem::M_BOX:
{
int32 index = fBoxes->IndexOf(which);
if (index >= 0) {
BRect r = which->Frame();
for (int32 i = 0; i < index; i++) {
DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
if (item && item->Frame().Intersects(r)) {
region->Include(item->Frame() & r);
found = true;
}
}
}
break;
}
case DiagramItem::M_WIRE:
{
BRect r = which->Frame();
for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
DiagramItem *item = ItemAt(i, DiagramItem::M_BOX);
if (item && item->Frame().Intersects(r)) {
region->Include(item->Frame() & r);
found = true;
}
}
break;
}
}
}
return found;
}
uint32
DiagramItemGroup::SelectedType() const
{
D_METHOD(("DiagramItemGroup::SelectedType()\n"));
if (CountSelectedItems() > 0)
return SelectedItemAt(0)->type();
return 0;
}
uint32
DiagramItemGroup::CountSelectedItems() const
{
D_METHOD(("DiagramItemGroup::CountSelectedItems()\n"));
if (fSelection)
return fSelection->CountItems();
return 0;
}
DiagramItem*
DiagramItemGroup::SelectedItemAt(uint32 index) const
{
D_METHOD(("DiagramItemGroup::SelectedItemAt()\n"));
if (fSelection)
return static_cast<DiagramItem *>(fSelection->ItemAt(index));
return 0;
}
bool
DiagramItemGroup::SelectItem(DiagramItem* which, bool deselectOthers)
{
D_METHOD(("DiagramItemGroup::SelectItem()\n"));
bool selectionChanged = false;
if (which && !which->isSelected() && which->isSelectable()) {
if (fMultiSelection) {
if (which->type() != SelectedType())
deselectOthers = true;
}
if (deselectOthers || !fMultiSelection) {
while (CountSelectedItems() > 0)
DeselectItem(SelectedItemAt(0));
}
if (deselectOthers || CountSelectedItems() == 0)
which->select();
else
which->selectAdding();
fSelection->AddItem(which);
selectionChanged = true;
}
if (selectionChanged) {
SortItems(which->type(), compareSelectionTime);
SortSelectedItems(compareSelectionTime);
return true;
}
return false;
}
bool
DiagramItemGroup::DeselectItem(DiagramItem* which)
{
D_METHOD(("DiagramItemGroup::DeselectItem()\n"));
if (which && which->isSelected()) {
fSelection->RemoveItem(which);
which->deselect();
SortItems(which->type(), compareSelectionTime);
SortSelectedItems(compareSelectionTime);
return true;
}
return false;
}
bool
DiagramItemGroup::SelectAll(uint32 itemType)
{
D_METHOD(("DiagramItemGroup::SelectAll()\n"));
bool selectionChanged = false;
if (fTypes & itemType) {
for (uint32 i = 0; i < CountItems(itemType); i++) {
if (SelectItem(ItemAt(i, itemType), false))
selectionChanged = true;
}
}
return selectionChanged;
}
bool
DiagramItemGroup::DeselectAll(uint32 itemType)
{
D_METHOD(("DiagramItemGroup::DeselectAll()\n"));
bool selectionChanged = false;
if (fTypes & itemType) {
for (uint32 i = 0; i < CountItems(itemType); i++) {
if (DeselectItem(ItemAt(i, itemType)))
selectionChanged = true;
}
}
return selectionChanged;
}
void
DiagramItemGroup::SortSelectedItems(int (*compareFunc)(const void *, const void *))
{
D_METHOD(("DiagramItemGroup::SortSelectedItems()\n"));
fSelection->SortItems(compareFunc);
}
void
DiagramItemGroup::DragSelectionBy(float x, float y, BRegion* updateRegion)
{
D_METHOD(("DiagramItemGroup::DragSelectionBy()\n"));
if (SelectedType() == DiagramItem::M_BOX) {
Align(&x, &y);
if ((x != 0) || (y != 0)) {
for (int32 i = CountSelectedItems() - 1; i >= 0; i--) {
DiagramItem *item = dynamic_cast<DiagramItem *>(SelectedItemAt(i));
if (item->isDraggable())
item->MoveBy(x, y, updateRegion);
}
}
}
}
void
DiagramItemGroup::RemoveSelection()
{
D_METHOD(("DiagramItemGroup::RemoveSelection()\n"));
for (uint32 i = 0; i < CountSelectedItems(); i++)
RemoveItem(SelectedItemAt(i));
}
void
DiagramItemGroup::GetItemAlignment(float *horizontal, float *vertical)
{
D_METHOD(("DiagramItemGroup::GetItemAlignment()\n"));
if (horizontal)
*horizontal = fItemAlignment.x;
if (vertical)
*vertical = fItemAlignment.y;
}
void
DiagramItemGroup::Align(float *x, float *y) const
{
D_METHOD(("DiagramItemGroup::Align()\n"));
*x = ((int)*x / (int)fItemAlignment.x) * fItemAlignment.x;
*y = ((int)*y / (int)fItemAlignment.y) * fItemAlignment.y;
}
BPoint
DiagramItemGroup::Align(BPoint point) const
{
D_METHOD(("DiagramItemGroup::Align()\n"));
float x = point.x, y = point.y;
Align(&x, &y);
return BPoint(x, y);
}