void
JXTreeListWidget::HandleMouseDown
	(
	const JPoint&			pt,
	const JXMouseButton		button,
	const JSize				clickCount,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	itsToggleDragIndex = 0;

	JPoint cell;
	const JBoolean inCell = GetCell(pt, &cell);

	if (button == kJXLeftButton &&
		inCell && JIndex(cell.x) == itsToggleOpenColIndex &&
		(itsTreeList->GetNode(cell.y))->IsOpenable())
		{
		itsMouseInToggleFlag = kJTrue;
		itsToggleDragIndex   = cell.y;
		TableRefreshCell(cell);
		}
	else if (button == kJXLeftButton && clickCount == 2 &&
			 inCell && JIndex(cell.x) != itsToggleOpenColIndex)
		{
		Broadcast(NodeDblClicked(itsTreeList->GetNode(cell.y), cell));
		}
	else
		{
		ScrollForWheel(button, modifiers);
		}
}
void
JXTreeListWidget::HandleMouseDrag
	(
	const JPoint&			pt,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	JPoint cell;
	if (itsToggleDragIndex > 0 &&
		GetCell(pt, &cell) &&
		JIndex(cell.x) == itsToggleOpenColIndex &&
		cell.y == itsToggleDragIndex)
		{
		if (!itsMouseInToggleFlag)
			{
			itsMouseInToggleFlag = kJTrue;
			TableRefreshCell(itsToggleDragIndex, itsToggleOpenColIndex);
			}
		}
	else if (itsToggleDragIndex > 0 && itsMouseInToggleFlag)
		{
		itsMouseInToggleFlag = kJFalse;
		TableRefreshCell(itsToggleDragIndex, itsToggleOpenColIndex);
		}
}
void
CMLineIndexTable::TableDrawCell
	(
	JPainter&		p,
	const JPoint&	cell,
	const JRect&	rect
	)
{
	HilightIfSelected(p, cell, rect);

	if (JIndex(cell.x) == kBreakpointColumn)
		{
		DrawBreakpoints(p, cell, rect);
		}

	else if (JIndex(cell.x) == kExecPointColumn && cell.y == itsCurrentLineIndex)
		{
		// We can't use a static polygon because line heights can vary,
		// e.g. due to underlines.

		const JCoordinate delta = rect.height()/2;

		JPolygon poly;
		poly.AppendElement(JPoint(rect.left+kMarginWidth,       rect.top));
		poly.AppendElement(JPoint(rect.left+kMarginWidth+delta, rect.top + delta));
		poly.AppendElement(JPoint(rect.left+kMarginWidth,       rect.top + 2*delta));

		p.SetPenColor(GetCurrentLineMarkerColor());
		p.SetFilling(kJTrue);
		p.Polygon(poly);

		p.SetPenColor(GetColormap()->GetBlackColor());
		p.SetFilling(kJFalse);
		p.Polygon(poly);
		}

	else if (JIndex(cell.x) == kLineNumberColumn)
		{
		p.SetFont(itsText->GetDefaultFont());

		JRect r  = rect;
		r.right -= kMarginWidth;

		const JString str = GetLineText(cell.y);
		p.String(r, str, JPainter::kHAlignRight);
		}
}
JBoolean
JXTreeListWidget::IsEditable
	(
	const JPoint& cell
	)
	const
{
	return JI2B( JIndex(cell.x) != itsToggleOpenColIndex );
}
JBoolean
JXTreeListWidget::IsSelectable
	(
	const JPoint&	cell,
	const JBoolean	forExtend
	)
	const
{
	return JI2B( JIndex(cell.x) == itsNodeColIndex );
}
JBoolean
JXTextMenuTable::CellToItemIndex
	(
	const JPoint&	pt,
	const JPoint&	cell,
	JIndex*			itemIndex
	)
	const
{
	if (JIndex(cell.y) < GetRowCount() && itsTextMenuData->HasSeparator(cell.y))
		{
		const JRect r = GetCellRect(cell);
		if (r.bottom - kSeparatorHeight <= pt.y && pt.y <= r.bottom)
			{
			*itemIndex = 0;
			return kJFalse;
			}
		}

	*itemIndex = cell.y;
	return kJTrue;
}
void
CBCommandTable::HandleDNDDrop
	(
	const JPoint&		pt,
	const JArray<Atom>&	typeList,
	const Atom			action,
	const Time			time,
	const JXWidget*		source
	)
{
	JXSelectionManager* selMgr = GetSelectionManager();
	JXDNDManager* dndMgr       = GetDNDManager();
	const Atom selName         = dndMgr->GetDNDSelectionName();

	if (source == this && action == dndMgr->GetDNDActionMoveXAtom())
		{
		JPoint cell;
		if ((GetTableSelection()).GetSingleSelectedCell(&cell) &&
			itsDNDRowIndex != JIndex(cell.y) && itsDNDRowIndex != JIndex(cell.y)+1)
			{
			JIndex newIndex = itsDNDRowIndex;
			if (newIndex > JIndex(cell.y))
				{
				newIndex--;
				}
			newIndex = JMin(newIndex, GetRowCount());

			itsCmdList->MoveElementToIndex(cell.y, newIndex);
			MoveRow(cell.y, newIndex);
			SelectSingleCell(JPoint(1, newIndex));
			}
		}
	else if (source == this)
		{
		JPoint cell;
		if ((GetTableSelection()).GetSingleSelectedCell(&cell))
			{
			itsCmdList->InsertElementAtIndex(
				itsDNDRowIndex, (itsCmdList->GetElement(cell.y)).Copy());
			InsertRows(itsDNDRowIndex, 1);
			SelectSingleCell(JPoint(1, itsDNDRowIndex));
			}
		}
	else
		{
		Atom returnType;
		unsigned char* data;
		JSize dataLength;
		JXSelectionManager::DeleteMethod delMethod;
		if (selMgr->GetData(selName, time, itsCommandXAtom,
							&returnType, &data, &dataLength, &delMethod))
			{
			if (returnType == itsCommandXAtom)
				{
				const std::string s((char*) data, dataLength);
				std::istringstream input(s);

				CBCommandManager::CmdInfo cmdInfo =
					CBCommandManager::ReadCmdInfo(input, CBCommandManager::GetCurrentCmdInfoFileVersion());
				if (!input.fail())
					{
					const JIndex newIndex = JMax(JIndex(1), itsDNDRowIndex);
					itsCmdList->InsertElementAtIndex(newIndex, cmdInfo);
					InsertRows(newIndex, 1);
					SelectSingleCell(JPoint(1, newIndex));

					if (action == dndMgr->GetDNDActionMoveXAtom())
						{
						selMgr->SendDeleteRequest(selName, time);
						}
					}
				}

			selMgr->DeleteData(&data, delMethod);
			}
		}

	HandleDNDLeave();
}
void
JXTreeListWidget::TableDrawCell
	(
	JPainter&		p,
	const JPoint&	cell,
	const JRect&	rect
	)
{
	if (JIndex(cell.x) == itsNodeColIndex && itsDrawSelectionFlag)
		{
		HilightIfSelected(p, cell, rect);
		}

	const JTreeNode* node = itsTreeList->GetNode(cell.y);
	if (JIndex(cell.x) == itsToggleOpenColIndex && node->IsOpenable())
		{
		p.ShiftOrigin(rect.topLeft());

		const JPolygon* triangle = (itsTreeList->IsOpen(cell.y) ?
									&kOpenTriangle : &kClosedTriangle);
		if (kOpenTriangle.IsEmpty())
			{
			kOpenTriangle.AppendElement(JPoint(5,  6));
			kOpenTriangle.AppendElement(JPoint(15, 6));
			kOpenTriangle.AppendElement(JPoint(10, 11));

			kClosedTriangle.AppendElement(JPoint(10, 3));
			kClosedTriangle.AppendElement(JPoint(15, 8));
			kClosedTriangle.AppendElement(JPoint(10, 13));
			}

		const JColormap* colormap = p.GetColormap();

		if ((itsToggleDragIndex == cell.y && itsMouseInToggleFlag) ||
			itsDNDTargetIndex == JIndex(cell.y))
			{
			p.SetFilling(kJTrue);
			p.SetPenColor(colormap->GetBlackColor());
			p.Polygon(*triangle);
			}
		else
			{
			p.SetFilling(kJTrue);
			p.SetPenColor(colormap->GetGrayColor(90));
			p.Polygon(*triangle);

			p.SetFilling(kJFalse);
			p.SetPenColor(colormap->GetBlackColor());
			p.Polygon(*triangle);
			}

		p.ShiftOrigin(-(rect.topLeft()));
		}

	else if (JIndex(cell.x) == itsNodeColIndex)
		{
		JRect r = rect;
		r.left += GetNodeIndent(cell.y);
		p.SetClipRect(r);
		TLWDrawNode(p, cell, r);
		// Table controls clip rect, so we don't have to reset it.
		}
}