#include "pch.h"
#include "RegDumpDocPaneDlgViewHelper.h"
#include "Screen_Sizes.h"


IMPLEMENT_DYNAMIC(CRegDumpDocPaneDlgViewHelper, CDocPaneDlgViewBase)

static const std::array<CRegDumpDocPaneDlgViewHelper::ColParam_t, COLNUM_STD> arLSTCols =
{
	{
		{COL_WIDTH | COL_COLOR, COLUMN_WIDTH, BG_COLOR},
		{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH, 0}
	}
};


void CRegDumpDocPaneDlgViewHelper::CreateList(ListParam_t &p)
{
	p.pList->SetFont(&m_hFont, FALSE);
	p.pList->SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER | LVS_EX_SNAPTOGRID);
	// создаём колонки
	int n = 0;

	for (auto &col : p.pCP)
	{
		if (col.dwState & COL_WIDTH)
		{
			p.pList->InsertColumn(n, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, ::MulDiv(col.nWidth, m_nPixelW, DEFAULT_DPIX));
		}
		else
		{
			p.pList->InsertColumn(n, LPSTR_TEXTCALLBACK, LVCFMT_LEFT);
		}

		n++;
	}

	// добавляем строки и значения в ячейки
	for (int row = 0; row < p.nRows; ++row)
	{
		const auto pRow = std::span{ &p.pRP[row * p.nCols], p.nCols };
		n = 0;

		for (auto &col : pRow)
		{
			const bool b = ((col.dwState & COL_VALUE) && col.nIDStrValue);
			const CString str = (b ? CString(MAKEINTRESOURCE(col.nIDStrValue)) : CString());

			if (n == 0)
			{
				p.pList->InsertItem(row, (b ? str.GetString() : LPSTR_TEXTCALLBACK));
			}
			else
			{
				p.pList->SetItem(row, n, LVIF_TEXT, (b ? str.GetString() : LPSTR_TEXTCALLBACK), 0, 0, 0, 0);
			}

			n++;
		}
	}

	// задаём свойства колонок, их можно применять только к уже созданным элементам,
	// поэтому повторный цикл уже после создания строк
	n = 0;

	for (auto &col : p.pCP)
	{
		if (col.dwState & COL_COLOR)
		{
			p.pList->SetColumnBkColor(col.color, n);
		}

		p.pList->EnableColumnEdit(!!(col.dwState & COL_EDITABLE), n);
		n++;
	}
}

void CRegDumpDocPaneDlgViewHelper::ReArrangeList(ListParam_t &p) const
{
	if (!p.bVisible)
	{
		p.pList->EnableWindow(FALSE);
		p.pList->ShowWindow(SW_HIDE);
		CWnd *grp = p.nGrpId ? GetDlgItem(p.nGrpId) : nullptr;

		if (grp)
		{
			grp->EnableWindow(FALSE);
			grp->ShowWindow(SW_HIDE);
		}

		return;
	}

	p.pList->EnableWindow(TRUE);
	p.pList->ShowWindow(SW_SHOW);
	CWnd *grp = p.nGrpId ? GetDlgItem(p.nGrpId) : nullptr;

	if (grp)
	{
		grp->EnableWindow(TRUE);
		grp->ShowWindow(SW_SHOW);
	}
}

void CRegDumpDocPaneDlgViewHelper::ResizeList(ListParam_t &p, CPoint &ptLT, int &maxGW) const
{
	CRect listRect, grpRect, itemRect;
	p.pList->GetWindowRect(&listRect);      // текущие размеры списка
	ScreenToClient(&listRect);

	if (!p.bVisible)
	{
		// если этот элемент невидимый, то координаты его нужно передать для следующего списка
		if (ptLT.x == 0)
		{
			ptLT.x = listRect.left;
		}

		if (ptLT.y == 0)
		{
			ptLT.y = listRect.top;
		}

		return;
	}

	if (ptLT.x)
	{
		listRect.left = ptLT.x;
	}

	if (ptLT.y)
	{
		listRect.top = ptLT.y;
	}

	CWnd *grp = p.nGrpId ? GetDlgItem(p.nGrpId) : nullptr;

	if (grp)
	{
		grp->GetWindowRect(&grpRect);   // текущие размеры группы
		ScreenToClient(&grpRect);
	}

	p.pList->GetItemRect(0, itemRect, LVIR_BOUNDS); // получим размеры элемента строки списка
	// и на их основе расчитаем новые размеры списка, чтобы был точно по размерам элементов
	const int cx = itemRect.Width() + ::GetSystemMetrics(SM_CXDLGFRAME);
	const int cy = itemRect.Height() * p.nRows + ::GetSystemMetrics(SM_CYDLGFRAME);
	p.pList->SetWindowPos(nullptr, listRect.left, listRect.top, cx, cy, SWP_NOREDRAW); // изменяем размеры списка

	if (grp)
	{
		grpRect.left = listRect.left - m_padX;
		grpRect.top = listRect.top - ::GetSystemMetrics(SM_CYCAPTION) / 2 - m_padY;
		grpRect.right = listRect.left + cx + m_padX;
		grpRect.bottom = listRect.top + cy + m_padY;
		grp->SetWindowPos(nullptr, grpRect.left, grpRect.top, grpRect.Width(), grpRect.Height(), SWP_SHOWWINDOW | SWP_NOSENDCHANGING); // изменяем размеры группы

		if (maxGW < grpRect.Width())
		{
			maxGW = grpRect.Width();
		}

		ptLT.x = listRect.left;
		ptLT.y = grpRect.bottom + ::GetSystemMetrics(SM_CYCAPTION) / 2 + m_padY;
	}
}

void CRegDumpDocPaneDlgViewHelper::SetGrpWidth(CWnd *grp, const int width) const
{
	CRect grpRect;
	grp->GetWindowRect(&grpRect);   // текущие размеры группы
	ScreenToClient(&grpRect);
	grp->SetWindowPos(nullptr, grpRect.left, grpRect.top, width, grpRect.Height(), SWP_SHOWWINDOW); // изменяем размеры группы
}

LRESULT CRegDumpDocPaneDlgViewHelper::HandleInitDialog(WPARAM wp, LPARAM lp)
{
	CDocPaneDlgViewBase::HandleInitDialog(wp, lp);
	m_nPixelW = ::GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSX);
	m_nPixelH = ::GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSY);
	m_padX = ::MulDiv(4, m_nPixelW, DEFAULT_DPIX); // отступ группы от списка слева и справа
	m_padY = ::MulDiv(5, m_nPixelH, DEFAULT_DPIY); // отступ группы от списка сверху и снизу
	return TRUE;
}

