void CFilePreviewCtrl::DrawTextLine(HDC hdc, DWORD nLineNo) { CRect rcClient; GetClientRect(&rcClient); DWORD dwOffset = 0; DWORD dwLength = 0; { CAutoLock lock(&m_csLock); dwOffset = m_aTextLines[nLineNo]; if(nLineNo==m_uNumLines-1) dwLength = (DWORD)m_fm.GetSize() - dwOffset; else dwLength = m_aTextLines[nLineNo+1]-dwOffset-1; } if(dwLength==0) return; //get data from our file mapping LPBYTE ptr = m_fm.CreateView(dwOffset, dwLength); //draw this line to the screen CRect rcText; rcText.left = -(int)(m_nHScrollPos * m_xChar); rcText.top = (nLineNo - m_nVScrollPos) * m_yChar; rcText.right = rcClient.right; rcText.bottom = rcText.top + m_yChar; DRAWTEXTPARAMS params; memset(¶ms, 0, sizeof(DRAWTEXTPARAMS)); params.cbSize = sizeof(DRAWTEXTPARAMS); params.iTabLength = m_xChar*m_cchTabLength; DWORD dwFlags = DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS; if(m_TextEncoding==ENC_UTF8) { // Decode line strconv_t strconv; LPCWSTR szLine = strconv.utf82w((char*)ptr, dwLength-1); DrawTextExW(hdc, (LPWSTR)szLine, -1, &rcText, dwFlags, ¶ms); } else if(m_TextEncoding==ENC_UTF16_LE) { DrawTextExW(hdc, (WCHAR*)ptr, dwLength/2-1, &rcText, dwFlags, ¶ms); } else if(m_TextEncoding==ENC_UTF16_BE) { // Decode line strconv_t strconv; LPCWSTR szLine = strconv.w2w_be((WCHAR*)ptr, dwLength/2-1); DrawTextExW(hdc, (LPWSTR)szLine, -1, &rcText, dwFlags, ¶ms); } else // ASCII { DrawTextExA(hdc, (char*)ptr, dwLength-1, &rcText, dwFlags, ¶ms); } }
/*********************************************************************** * DrawTextExA (USER32.@) * * If DT_MODIFYSTRING is specified then there must be room for up to * 4 extra characters. We take great care about just how much modified * string we return. */ INT WINAPI DrawTextExA( HDC hdc, LPSTR str, INT count, LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp ) { WCHAR *wstr; WCHAR *p; INT ret = 0; int i; DWORD wcount; DWORD wmax; DWORD amax; UINT cp; if (!count) return 0; if( !str || ((count == -1) && !(count = strlen(str)))) { if( flags & DT_CALCRECT) { rect->right = rect->left; rect->bottom = rect->top; } return 0; } cp = GdiGetCodePage( hdc ); wcount = MultiByteToWideChar( cp, 0, str, count, NULL, 0 ); wmax = wcount; amax = count; if (flags & DT_MODIFYSTRING) { wmax += 4; amax += 4; } wstr = HeapAlloc(GetProcessHeap(), 0, wmax * sizeof(WCHAR)); if (wstr) { MultiByteToWideChar( cp, 0, str, count, wstr, wcount ); if (flags & DT_MODIFYSTRING) for (i=4, p=wstr+wcount; i--; p++) *p=0xFFFE; /* Initialise the extra characters so that we can see which ones * change. U+FFFE is guaranteed to be not a unicode character and * so will not be generated by DrawTextEx itself. */ ret = DrawTextExW( hdc, wstr, wcount, rect, flags, dtp ); if (flags & DT_MODIFYSTRING) { /* Unfortunately the returned string may contain multiple \0s * and so we need to measure it ourselves. */ for (i=4, p=wstr+wcount; i-- && *p != 0xFFFE; p++) wcount++; WideCharToMultiByte( cp, 0, wstr, wcount, str, amax, NULL, NULL ); } HeapFree(GetProcessHeap(), 0, wstr); } return ret; }
// TODO alter this so that only the visible columns are redrawn // TODO this means rename controlSize to clientRect static void drawItem(struct table *t, HDC dc, intptr_t i, LONG y, LONG height, RECT controlSize) { RECT rsel; HBRUSH background; int textColor; WCHAR msg[100]; RECT headeritem; intptr_t j; LRESULT xoff; IMAGELISTDRAWPARAMS ip; // TODO verify these two background = (HBRUSH) (COLOR_WINDOW + 1); textColor = COLOR_WINDOWTEXT; if (t->selected == i) { // these are the colors wine uses (http://source.winehq.org/source/dlls/comctl32/listview.c) // the two for unfocused are also suggested by http://stackoverflow.com/questions/10428710/windows-forms-inactive-highlight-color background = (HBRUSH) (COLOR_HIGHLIGHT + 1); textColor = COLOR_HIGHLIGHTTEXT; if (GetFocus() != t->hwnd) { background = (HBRUSH) (COLOR_BTNFACE + 1); textColor = COLOR_BTNTEXT; } } // first fill the selection rect // note that this already only draws the visible area rsel.left = controlSize.left; rsel.top = y; rsel.right = controlSize.right - controlSize.left; rsel.bottom = y + height; if (FillRect(dc, &rsel, background) == 0) abort(); xoff = SendMessageW(t->header, HDM_GETBITMAPMARGIN, 0, 0); // now adjust for horizontal scrolling xoff -= t->hpos; // now draw the cells if (SetTextColor(dc, GetSysColor(textColor)) == CLR_INVALID) abort(); if (SetBkMode(dc, TRANSPARENT) == 0) abort(); for (j = 0; j < t->nColumns; j++) { if (SendMessageW(t->header, HDM_GETITEMRECT, (WPARAM) j, (LPARAM) (&headeritem)) == 0) abort(); switch (t->columnTypes[j]) { case tableColumnText: rsel.left = headeritem.left + xoff; rsel.top = y; rsel.right = headeritem.right; rsel.bottom = y + height; // TODO vertical center in case the height is less than the icon height? if (DrawTextExW(dc, msg, wsprintf(msg, L"Item %d", i), &rsel, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0) abort(); break; case tableColumnImage: // TODO vertically center if image is smaller than text height // TODO same for checkboxes ZeroMemory(&ip, sizeof (IMAGELISTDRAWPARAMS)); ip.cbSize = sizeof (IMAGELISTDRAWPARAMS); ip.himl = t->checkboxes;//t->imagelist; ip.i = (i%8);//0; ip.hdcDst = dc; ip.x = headeritem.left + xoff; ip.y = y; ip.cx = 0; // draw whole image ip.cy = 0; ip.xBitmap = 0; ip.yBitmap = 0; ip.rgbBk = CLR_NONE; ip.fStyle = ILD_NORMAL | ILD_SCALE; // TODO alpha-blend; ILD_DPISCALE? // TODO ILS_ALPHA? if (ImageList_DrawIndirect(&ip) == 0) abort(); break; case tableColumnCheckbox: // TODO replace all this rsel.left = headeritem.left + xoff; rsel.top = y; rsel.right = rsel.left + t->checkboxWidth; rsel.bottom = rsel.top + t->checkboxHeight; if (SetDCBrushColor(dc, RGB(255, 0, 0)) == CLR_INVALID) abort(); if (FillRect(dc, &rsel, GetStockObject(DC_BRUSH)) == 0) abort(); break; } if (t->selected == i && t->focusedColumn == j) { rsel.left = headeritem.left; rsel.top = y; rsel.right = headeritem.right; rsel.bottom = y + height; if (DrawFocusRect(dc, &rsel) == 0) abort(); } } }