Witam.
Szukam api które mi policzy ilość znaków które się zmieszczą w podanej ilości pixeli (szerokość), uwzględniając własny rozmiar tabulatora.
Piszę "edytor" tekstu z kolorowaniem składni. Wyświetlanie działa już ok, przyszedł czas na obsługę caretu.
W OnLButtonDown chcę policzyć przed/za którym znakiem powinienem ustawić caret. Nie mogę znaleźć takiego api które by mi pasowało, bo:
- funkcja ta musi akceptować rozmiar tabulatora, który może się zawsze zmienić.
Do rysowania tekstu użyłem TabbedTextOut - jedyna z ogólnie dostępnych api która poprawnie tab'uje.
DrawText/Ex tab'uje po 500 pixeli i dodatkowo deformatuje pojedyncze '&'.
Znalazłem sposób na mój problem - jest kiepski czasowo jako algorytm, ale działa:
- wykonuj x razy GetTabbedTextExtent zmieniając ilość znaków aż zwrócona wartość będzie w odpowiednim zakresie błędu.
To działa, ostatni "algorytm liczący" potrzebuje max 6 wywołań tej funkcji (krótkie linie) aby policzyć index znaku przed kursorem, Ten sposób jest wolny, choć user tego nie zauważy. Liczę że jest jakaś funkcja która to policzy szybciej.
Mam to tak:
CColorEdit::OnLButtonDown(int x,int y, int flags)
{
RECT rcDraw;
SetDrawRect(&rcDraw);
POINT *lppt = &x;
// clicked inside margins?
if PtInRect(&rcDraw, *lppt)
{
m_CaretLine = m_TopLineIndex + ((y-m_rcMargin.top)/m_LineSpacing);
HideCaret(m_hwnd);
UpdateCaretPos();
ShowCaret(m_hwnd);
if (m_CaretVisible)
{
POINT ptCaretPos;
::GetCaretPos(&ptCaretPos);
CLineToken *pLine = GetLine(m_CaretLine);
// obliczamy w którym pixelu od pocz?tku linii jest kursor
int TextPixelOffset = x - m_rcMargin.left + m_hScrollPos; // ok
OnBeforeDraw(); // setup HDC m_memDC
// liczymy od ko?ca linii - m_CaretCharIndex b?dzie wynikiem
m_CaretCharIndex = pLine->m_TextLen - 2; // bez \n
int width1 = ::GetTabbedTextExtent(m_memDC, pLine->m_lpText, m_CaretCharIndex, 1, &m_TabSizeInPixels) & 0xFFFF;
if (TextPixelOffset > width1)
{
// m_CaretCharIndex jest ok, klikni?to na prawo od ostatniego znaku
}
else
{
// przesuwamy si? w ?rodek b??du + troszk? w prawo
int AverageCharWidth = width1 / m_CaretCharIndex;
m_CaretCharIndex = (TextPixelOffset / AverageCharWidth) + 5;
// jeszcze kilka porówna? znak po znaku...
while (width1 > TextPixelOffset)
{
m_CaretCharIndex--;
width1 = ::GetTabbedTextExtent(m_memDC, pLine->m_lpText, m_CaretCharIndex, 1, &m_TabSizeInPixels) & 0xFFFF;
}
// place the caret before or after character?
int width2 = ::GetTabbedTextExtent(m_memDC, pLine->m_lpText, m_CaretCharIndex+1, 1, &m_TabSizeInPixels) & 0xFFFF;
if (width2 - TextPixelOffset) < (TextPixelOffset - width1)
{
width1 = width2;
m_CaretCharIndex++;
}
}
ptCaretPos.x = m_rcMargin.left - m_hScrollPos + width1;
OnAfterDraw();
::SetCaretPos(ptCaretPos.x, ptCaretPos.y);
}
}
}