jak zmienić nPixels na nCharIndex

0

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);
      }
   }
}
0
sapero napisał(a)

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.

skorzystaj z WinAPI,
GetTextMetrics
TEXTMETRIC

0

Użyłem tej funkcji do 'obliczenia' odstępów pomiędzy liniami, ale ona nie ma ani grama styczności z tabulatorem.
Funkcja której szukam powinna skanować podany text litera po literze, dodawać ich szerokości i dodawać zmienną szerokość każdego napotkanego \t, gdzie największa "szerokość" znaku \t jest jednym z argumentów funkcji.
Kod który widać powyżej robi to w hamski sposób bo zaczyna skanowanie od połowy i robi to ciut inaczej i dużo wolniej niż powinien.

Dostałem wczoraj snippet w MFC od twórcy kompletnego IDE+parser+linker, tam koleś faktycznie skanował litera po literze. On do dzisiaj nie wie czy w systemie jest taka cudowna funkcja, więc temat uważam za zamknięty.
Może kiedyś, ktoś przypadkowo znajdzie ;)

0

wiesz co wydaje mi się że w "programming windows" był taki przykład z liczeniem długości tekstów i malowaniem ich w odpowiednich miejscach na oknie
dzisiaj już jestem zaspany postaram się jutro to sprawdzić i odpisać

1 użytkowników online, w tym zalogowanych: 0, gości: 1