static void DrawProperties(HWND hwnd, HDC hdc) { PropertiesLayout *layoutData = FindPropertyWindowByHwnd(hwnd); ScopedFont fontLeftTxt(GetSimpleFont(hdc, LEFT_TXT_FONT, LEFT_TXT_FONT_SIZE)); ScopedFont fontRightTxt(GetSimpleFont(hdc, RIGHT_TXT_FONT, RIGHT_TXT_FONT_SIZE)); HGDIOBJ origFont = SelectObject(hdc, fontLeftTxt); /* Just to remember the orig font */ SetBkMode(hdc, TRANSPARENT); ClientRect rcClient(hwnd); FillRect(hdc, &rcClient.ToRECT(), gBrushAboutBg); SetTextColor(hdc, WIN_COL_BLACK); /* render text on the left*/ SelectObject(hdc, fontLeftTxt); for (size_t i = 0; i < layoutData->Count(); i++) { PropertyEl *el = layoutData->At(i); DrawText(hdc, el->leftTxt, -1, &el->leftPos.ToRECT(), DT_RIGHT | DT_NOPREFIX); } /* render text on the right */ SelectObject(hdc, fontRightTxt); for (size_t i = 0; i < layoutData->Count(); i++) { PropertyEl *el = layoutData->At(i); RectI rc = el->rightPos; if (rc.x + rc.dx > rcClient.x + rcClient.dx - PROPERTIES_RECT_PADDING) rc.dx = rcClient.x + rcClient.dx - PROPERTIES_RECT_PADDING - rc.x; DrawText(hdc, el->rightTxt, -1, &rc.ToRECT(), DT_LEFT | DT_PATH_ELLIPSIS | DT_NOPREFIX); } SelectObject(hdc, origFont); }
static void DrawSumatraVersion(HDC hdc, RectI rect) { ScopedFont fontSumatraTxt(GetSimpleFont(hdc, SUMATRA_TXT_FONT, SUMATRA_TXT_FONT_SIZE)); ScopedFont fontVersionTxt(GetSimpleFont(hdc, VERSION_TXT_FONT, VERSION_TXT_FONT_SIZE)); HGDIOBJ oldFont = SelectObject(hdc, fontSumatraTxt); SetBkMode(hdc, TRANSPARENT); SIZE txtSize; const WCHAR *txt = APP_NAME_STR; GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI mainRect(rect.x + (rect.dx - txtSize.cx) / 2, rect.y + (rect.dy - txtSize.cy) / 2, txtSize.cx, txtSize.cy); DrawSumatraPDF(hdc, mainRect.TL()); SetTextColor(hdc, WIN_COL_BLACK); SelectObject(hdc, fontVersionTxt); PointI pt(mainRect.x + mainRect.dx + ABOUT_INNER_PADDING, mainRect.y); txt = VERSION_TXT; TextOut(hdc, pt.x, pt.y, txt, (int)str::Len(txt)); txt = VERSION_SUB_TXT; TextOut(hdc, pt.x, pt.y + 16, txt, (int)str::Len(txt)); SelectObject(hdc, oldFont); }
static void UpdatePropertiesLayout(PropertiesLayout *layoutData, HDC hdc, RectI *rect) { ScopedFont fontLeftTxt(GetSimpleFont(hdc, LEFT_TXT_FONT, LEFT_TXT_FONT_SIZE)); ScopedFont fontRightTxt(GetSimpleFont(hdc, RIGHT_TXT_FONT, RIGHT_TXT_FONT_SIZE)); HGDIOBJ origFont = SelectObject(hdc, fontLeftTxt); /* calculate text dimensions for the left side */ SelectObject(hdc, fontLeftTxt); int leftMaxDx = 0; for (size_t i = 0; i < layoutData->Count(); i++) { PropertyEl *el = layoutData->At(i); RECT rc = { 0 }; DrawText(hdc, el->leftTxt, -1, &rc, DT_NOPREFIX | DT_CALCRECT); el->leftPos.dx = rc.right - rc.left; // el->leftPos.dy is set below to be equal to el->rightPos.dy if (el->leftPos.dx > leftMaxDx) leftMaxDx = el->leftPos.dx; } /* calculate text dimensions for the right side */ SelectObject(hdc, fontRightTxt); int rightMaxDx = 0; int lineCount = 0; int textDy = 0; for (size_t i = 0; i < layoutData->Count(); i++) { PropertyEl *el = layoutData->At(i); RECT rc = { 0 }; DrawText(hdc, el->rightTxt, -1, &rc, DT_NOPREFIX | DT_CALCRECT); el->rightPos.dx = rc.right - rc.left; el->leftPos.dy = el->rightPos.dy = rc.bottom - rc.top; textDy += el->rightPos.dy; if (el->rightPos.dx > rightMaxDx) rightMaxDx = el->rightPos.dx; lineCount++; } assert(lineCount > 0 && textDy > 0); int totalDx = leftMaxDx + PROPERTIES_LEFT_RIGHT_SPACE_DX + rightMaxDx; int totalDy = 4; totalDy += textDy + (lineCount - 1) * PROPERTIES_TXT_DY_PADDING; totalDy += 4; int offset = PROPERTIES_RECT_PADDING; if (rect) *rect = RectI(0, 0, totalDx + 2 * offset, totalDy + offset); int currY = 0; for (size_t i = 0; i < layoutData->Count(); i++) { PropertyEl *el = layoutData->At(i); el->leftPos = RectI(offset, offset + currY, leftMaxDx, el->leftPos.dy); el->rightPos.x = offset + leftMaxDx + PROPERTIES_LEFT_RIGHT_SPACE_DX; el->rightPos.y = offset + currY; currY += el->rightPos.dy + PROPERTIES_TXT_DY_PADDING; } SelectObject(hdc, origFont); }
static SizeI CalcSumatraVersionSize(HDC hdc) { SizeI result; ScopedFont fontSumatraTxt(GetSimpleFont(hdc, SUMATRA_TXT_FONT, SUMATRA_TXT_FONT_SIZE)); ScopedFont fontVersionTxt(GetSimpleFont(hdc, VERSION_TXT_FONT, VERSION_TXT_FONT_SIZE)); HGDIOBJ oldFont = SelectObject(hdc, fontSumatraTxt); SIZE txtSize; /* calculate minimal top box size */ const WCHAR *txt = APP_NAME_STR; GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); result.dy = txtSize.cy + ABOUT_BOX_MARGIN_DY * 2; result.dx = txtSize.cx; /* consider version and version-sub strings */ SelectObject(hdc, fontVersionTxt); txt = VERSION_TXT; GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); int minWidth = txtSize.cx; txt = VERSION_SUB_TXT; GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); txtSize.cx = max(txtSize.cx, minWidth); result.dx += 2 * (txtSize.cx + ABOUT_INNER_PADDING); SelectObject(hdc, oldFont); return result; }
static RectI DrawBottomRightLink(HWND hwnd, HDC hdc, const WCHAR *txt) { ScopedFont fontLeftTxt(GetSimpleFont(hdc, L"MS Shell Dlg", 14)); HPEN penLinkLine = CreatePen(PS_SOLID, 1, COL_BLUE_LINK); HGDIOBJ origFont = SelectObject(hdc, fontLeftTxt); /* Just to remember the orig font */ SetTextColor(hdc, COL_BLUE_LINK); SetBkMode(hdc, TRANSPARENT); ClientRect rc(hwnd); SIZE txtSize; GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI rect(rc.dx - txtSize.cx - ABOUT_INNER_PADDING, rc.y + rc.dy - txtSize.cy - ABOUT_INNER_PADDING, txtSize.cx, txtSize.cy); if (IsUIRightToLeft()) rect.x = ABOUT_INNER_PADDING; DrawText(hdc, txt, -1, &rect.ToRECT(), IsUIRightToLeft() ? DT_RTLREADING : DT_LEFT); SelectObject(hdc, penLinkLine); PaintLine(hdc, RectI(rect.x, rect.y + rect.dy, rect.dx, 0)); SelectObject(hdc, origFont); DeleteObject(penLinkLine); // make the click target larger rect.Inflate(ABOUT_INNER_PADDING, ABOUT_INNER_PADDING); return rect; }
LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { NPP instance = (NPP)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (uiMsg == WM_PAINT) { InstanceData *data = (InstanceData *)instance->pdata; PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); HBRUSH brushBg = CreateSolidBrush(COL_WINDOW_BG); HFONT hFont = GetSimpleFont(hDC, L"MS Shell Dlg", 14); bool isRtL = IsLanguageRtL(gTranslationIdx); // set up double buffering RectI rcClient = ClientRect(hWnd); DoubleBuffer buffer(hWnd, rcClient); HDC hDCBuffer = buffer.GetDC(); // display message centered in the window RECT rectClient = rcClient.ToRECT(); FillRect(hDCBuffer, &rectClient, brushBg); hFont = (HFONT)SelectObject(hDCBuffer, hFont); SetTextColor(hDCBuffer, RGB(0, 0, 0)); SetBkMode(hDCBuffer, TRANSPARENT); DrawCenteredText(hDCBuffer, rcClient, data->message, isRtL); // draw a progress bar, if a download is in progress if (0 < data->progress && data->progress <= 1) { SIZE msgSize; RectI rcProgress = rcClient; HBRUSH brushProgress = CreateSolidBrush(RGB(0x80, 0x80, 0xff)); GetTextExtentPoint32(hDCBuffer, data->message, (int)str::Len(data->message), &msgSize); rcProgress.Inflate(-(rcProgress.dx - msgSize.cx) / 2, -(rcProgress.dy - msgSize.cy) / 2 + 2); rcProgress.Offset(0, msgSize.cy + 4 + 2); RECT rectProgress = rcProgress.ToRECT(); FillRect(hDCBuffer, &rectProgress, GetStockBrush(WHITE_BRUSH)); RectI rcProgressAll = rcProgress; rcProgress.dx = (int)(data->progress * rcProgress.dx); rectProgress = rcProgress.ToRECT(); FillRect(hDCBuffer, &rectProgress, brushProgress); DeleteObject(brushProgress); ScopedMem<WCHAR> currSize(FormatSizeSuccint(data->currSize)); if (0 == data->totalSize || data->currSize > data->totalSize) { // total size unknown or bogus => show just the current size DrawCenteredText(hDCBuffer, rcProgressAll, currSize, isRtL); } else { ScopedMem<WCHAR> totalSize(FormatSizeSuccint(data->totalSize)); ScopedMem<WCHAR> s(str::Format(_TR("%s of %s"), currSize, totalSize)); DrawCenteredText(hDCBuffer, rcProgressAll, s, isRtL); } } // draw the buffer on screen buffer.Flush(hDC); DeleteObject(SelectObject(hDCBuffer, hFont)); DeleteObject(brushBg); EndPaint(hWnd, &ps); HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) InvalidateRect(hChild, NULL, FALSE); } else if (uiMsg == WM_SIZE) { HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) { ClientRect rcClient(hWnd); MoveWindow(hChild, rcClient.x, rcClient.y, rcClient.dx, rcClient.dy, FALSE); } } else if (uiMsg == WM_COPYDATA) { COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam; if (cds && 0x4C5255 /* URL */ == cds->dwData) { plogf("sp: NPN_GetURL %s", cds->dwData, (const char *)cds->lpData); gNPNFuncs.geturl(instance, (const char *)cds->lpData, "_blank"); return TRUE; } } return DefWindowProc(hWnd, uiMsg, wParam, lParam); }
LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { InstanceData *data = (InstanceData *)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (uiMsg == WM_PAINT) { PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); HBRUSH brushBg = CreateSolidBrush(COL_WINDOW_BG); HFONT hFont = GetSimpleFont(hDC, _T("MS Shell Dlg"), 14); // set up double buffering RectI rcClient = ClientRect(hWnd); DoubleBuffer buffer(hWnd, rcClient); HDC hDCBuffer = buffer.GetDC(); // display message centered in the window FillRect(hDCBuffer, &rcClient.ToRECT(), brushBg); hFont = (HFONT)SelectObject(hDCBuffer, hFont); SetTextColor(hDCBuffer, RGB(0, 0, 0)); SetBkMode(hDCBuffer, TRANSPARENT); DrawCenteredText(hDCBuffer, rcClient, data->message); // draw a progress bar, if a download is in progress if (0 < data->progress && data->progress <= 1) { SIZE msgSize; RectI rcProgress = rcClient; HBRUSH brushProgress = CreateSolidBrush(RGB(0x80, 0x80, 0xff)); GetTextExtentPoint32(hDCBuffer, data->message, (int)str::Len(data->message), &msgSize); rcProgress.Inflate(-(rcProgress.dx - msgSize.cx) / 2, -(rcProgress.dy - msgSize.cy) / 2 + 2); rcProgress.Offset(0, msgSize.cy + 4 + 2); FillRect(hDCBuffer, &rcProgress.ToRECT(), GetStockBrush(WHITE_BRUSH)); RectI rcProgressAll = rcProgress; rcProgress.dx = (int)(data->progress * rcProgress.dx); FillRect(hDCBuffer, &rcProgress.ToRECT(), brushProgress); DeleteObject(brushProgress); ScopedMem<TCHAR> currSize(FormatSizeSuccint(data->currSize)); if (0 == data->totalSize || data->currSize > data->totalSize) { // total size unknown or bogus => show just the current size DrawCenteredText(hDCBuffer, rcProgressAll, currSize); } else { ScopedMem<TCHAR> totalSize(FormatSizeSuccint(data->totalSize)); ScopedMem<TCHAR> s(str::Format(_T("%s of %s"), currSize, totalSize)); DrawCenteredText(hDCBuffer, rcProgressAll, s); } } // draw the buffer on screen buffer.Flush(hDC); DeleteObject(SelectObject(hDCBuffer, hFont)); DeleteObject(brushBg); EndPaint(hWnd, &ps); HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) InvalidateRect(hChild, NULL, FALSE); } else if (uiMsg == WM_SIZE) { HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) { ClientRect rcClient(hWnd); MoveWindow(hChild, rcClient.x, rcClient.y, rcClient.dx, rcClient.dy, FALSE); } } return DefWindowProc(hWnd, uiMsg, wParam, lParam); }
void DrawStartPage(WindowInfo& win, HDC hdc, FileHistory& fileHistory, COLORREF colorRange[2]) { HPEN penBorder = CreatePen(PS_SOLID, DOCLIST_SEPARATOR_DY, WIN_COL_BLACK); HPEN penThumbBorder = CreatePen(PS_SOLID, DOCLIST_THUMBNAIL_BORDER_W, WIN_COL_BLACK); HPEN penLinkLine = CreatePen(PS_SOLID, 1, COL_BLUE_LINK); ScopedFont fontSumatraTxt(GetSimpleFont(hdc, L"MS Shell Dlg", 24)); ScopedFont fontLeftTxt(GetSimpleFont(hdc, L"MS Shell Dlg", 14)); HGDIOBJ origFont = SelectObject(hdc, fontSumatraTxt); /* Just to remember the orig font */ ClientRect rc(win.hwndCanvas); FillRect(hdc, &rc.ToRECT(), gBrushLogoBg); SelectObject(hdc, gBrushLogoBg); SelectObject(hdc, penBorder); bool isRtl = IsUIRightToLeft(); /* render title */ RectI titleBox = RectI(PointI(0, 0), CalcSumatraVersionSize(hdc)); titleBox.x = rc.dx - titleBox.dx - 3; DrawSumatraVersion(hdc, titleBox); PaintLine(hdc, RectI(0, titleBox.dy, rc.dx, 0)); /* render recent files list */ SelectObject(hdc, penThumbBorder); SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, WIN_COL_BLACK); rc.y += titleBox.dy; rc.dy -= titleBox.dy; FillRect(hdc, &rc.ToRECT(), gBrushAboutBg); rc.dy -= DOCLIST_BOTTOM_BOX_DY; Vec<DisplayState *> list; fileHistory.GetFrequencyOrder(list); int width = limitValue((rc.dx - DOCLIST_MARGIN_LEFT - DOCLIST_MARGIN_RIGHT + DOCLIST_MARGIN_BETWEEN_X) / (THUMBNAIL_DX + DOCLIST_MARGIN_BETWEEN_X), 1, DOCLIST_MAX_THUMBNAILS_X); int height = min((rc.dy - DOCLIST_MARGIN_TOP - DOCLIST_MARGIN_BOTTOM + DOCLIST_MARGIN_BETWEEN_Y) / (THUMBNAIL_DY + DOCLIST_MARGIN_BETWEEN_Y), FILE_HISTORY_MAX_FREQUENT / width); PointI offset(rc.x + DOCLIST_MARGIN_LEFT + (rc.dx - width * THUMBNAIL_DX - (width - 1) * DOCLIST_MARGIN_BETWEEN_X - DOCLIST_MARGIN_LEFT - DOCLIST_MARGIN_RIGHT) / 2, rc.y + DOCLIST_MARGIN_TOP); if (offset.x < ABOUT_INNER_PADDING) offset.x = ABOUT_INNER_PADDING; else if (list.Count() == 0) offset.x = DOCLIST_MARGIN_LEFT; SelectObject(hdc, fontSumatraTxt); SIZE txtSize; const WCHAR *txt = _TR("Frequently Read"); GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI headerRect(offset.x, rc.y + (DOCLIST_MARGIN_TOP - txtSize.cy) / 2, txtSize.cx, txtSize.cy); if (isRtl) headerRect.x = rc.dx - offset.x - headerRect.dx; DrawText(hdc, txt, -1, &headerRect.ToRECT(), (isRtl ? DT_RTLREADING : DT_LEFT) | DT_NOPREFIX); SelectObject(hdc, fontLeftTxt); SelectObject(hdc, GetStockBrush(NULL_BRUSH)); win.staticLinks.Reset(); for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { if (h * width + w >= (int)list.Count()) { // display the "Open a document" link right below the last row height = w > 0 ? h + 1 : h; break; } DisplayState *state = list.At(h * width + w); RectI page(offset.x + w * (int)(THUMBNAIL_DX + DOCLIST_MARGIN_BETWEEN_X * win.uiDPIFactor), offset.y + h * (int)(THUMBNAIL_DY + DOCLIST_MARGIN_BETWEEN_Y * win.uiDPIFactor), THUMBNAIL_DX, THUMBNAIL_DY); if (isRtl) page.x = rc.dx - page.x - page.dx; bool loadOk = true; if (!state->thumbnail) loadOk = LoadThumbnail(*state); if (loadOk && state->thumbnail) { SizeI thumbSize = state->thumbnail->Size(); if (thumbSize.dx != THUMBNAIL_DX || thumbSize.dy != THUMBNAIL_DY) { page.dy = thumbSize.dy * THUMBNAIL_DX / thumbSize.dx; page.y += THUMBNAIL_DY - page.dy; } HRGN clip = CreateRoundRectRgn(page.x, page.y, page.x + page.dx, page.y + page.dy, 10, 10); SelectClipRgn(hdc, clip); RenderedBitmap *clone = state->thumbnail->Clone(); UpdateBitmapColorRange(clone->GetBitmap(), colorRange); clone->StretchDIBits(hdc, page); SelectClipRgn(hdc, NULL); DeleteObject(clip); delete clone; } RoundRect(hdc, page.x, page.y, page.x + page.dx, page.y + page.dy, 10, 10); int iconSpace = (int)(20 * win.uiDPIFactor); RectI rect(page.x + iconSpace, page.y + page.dy + 3, page.dx - iconSpace, iconSpace); if (isRtl) rect.x -= iconSpace; DrawText(hdc, path::GetBaseName(state->filePath), -1, &rect.ToRECT(), DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (isRtl ? DT_RIGHT : DT_LEFT)); SHFILEINFO sfi; HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo(state->filePath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES); ImageList_Draw(himl, sfi.iIcon, hdc, isRtl ? page.x + page.dx - (int)(16 * win.uiDPIFactor) : page.x, rect.y, ILD_TRANSPARENT); win.staticLinks.Append(StaticLinkInfo(rect.Union(page), state->filePath, state->filePath)); } } /* render bottom links */ rc.y += DOCLIST_MARGIN_TOP + height * THUMBNAIL_DY + (height - 1) * DOCLIST_MARGIN_BETWEEN_Y + DOCLIST_MARGIN_BOTTOM; rc.dy = DOCLIST_BOTTOM_BOX_DY; SetTextColor(hdc, COL_BLUE_LINK); SelectObject(hdc, penLinkLine); HIMAGELIST himl = (HIMAGELIST)SendMessage(win.hwndToolbar, TB_GETIMAGELIST, 0, 0); RectI rectIcon(offset.x, rc.y, 0, 0); ImageList_GetIconSize(himl, &rectIcon.dx, &rectIcon.dy); rectIcon.y += (rc.dy - rectIcon.dy) / 2; if (isRtl) rectIcon.x = rc.dx - offset.x - rectIcon.dx; ImageList_Draw(himl, 0 /* index of Open icon */, hdc, rectIcon.x, rectIcon.y, ILD_NORMAL); txt = _TR("Open a document..."); GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI rect(offset.x + rectIcon.dx + 3, rc.y + (rc.dy - txtSize.cy) / 2, txtSize.cx, txtSize.cy); if (isRtl) rect.x = rectIcon.x - rect.dx - 3; DrawText(hdc, txt, -1, &rect.ToRECT(), isRtl ? DT_RTLREADING : DT_LEFT); PaintLine(hdc, RectI(rect.x, rect.y + rect.dy, rect.dx, 0)); // make the click target larger rect = rect.Union(rectIcon); rect.Inflate(10, 10); win.staticLinks.Append(StaticLinkInfo(rect, SLINK_OPEN_FILE)); rect = DrawBottomRightLink(win.hwndCanvas, hdc, _TR("Hide frequently read")); win.staticLinks.Append(StaticLinkInfo(rect, SLINK_LIST_HIDE)); SelectObject(hdc, origFont); DeleteObject(penBorder); DeleteObject(penThumbBorder); DeleteObject(penLinkLine); }
static void UpdateAboutLayoutInfo(HWND hwnd, HDC hdc, RectI *rect) { ScopedFont fontLeftTxt(GetSimpleFont(hdc, LEFT_TXT_FONT, LEFT_TXT_FONT_SIZE)); ScopedFont fontRightTxt(GetSimpleFont(hdc, RIGHT_TXT_FONT, RIGHT_TXT_FONT_SIZE)); HGDIOBJ origFont = SelectObject(hdc, fontLeftTxt); /* calculate minimal top box size */ SizeI headerSize = CalcSumatraVersionSize(hdc); /* calculate left text dimensions */ SelectObject(hdc, fontLeftTxt); int leftLargestDx = 0; int leftDy = 0; for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) { SIZE txtSize; GetTextExtentPoint32(hdc, el->leftTxt, (int)str::Len(el->leftTxt), &txtSize); el->leftPos.dx = txtSize.cx; el->leftPos.dy = txtSize.cy; if (el == &gAboutLayoutInfo[0]) leftDy = el->leftPos.dy; else assert(leftDy == el->leftPos.dy); if (leftLargestDx < el->leftPos.dx) leftLargestDx = el->leftPos.dx; } /* calculate right text dimensions */ SelectObject(hdc, fontRightTxt); int rightLargestDx = 0; int rightDy = 0; for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) { SIZE txtSize; GetTextExtentPoint32(hdc, el->rightTxt, (int)str::Len(el->rightTxt), &txtSize); el->rightPos.dx = txtSize.cx; el->rightPos.dy = txtSize.cy; if (el == &gAboutLayoutInfo[0]) rightDy = el->rightPos.dy; else assert(rightDy == el->rightPos.dy); if (rightLargestDx < el->rightPos.dx) rightLargestDx = el->rightPos.dx; } /* calculate total dimension and position */ RectI minRect; minRect.dx = ABOUT_LEFT_RIGHT_SPACE_DX + leftLargestDx + ABOUT_LINE_SEP_SIZE + rightLargestDx + ABOUT_LEFT_RIGHT_SPACE_DX; if (minRect.dx < headerSize.dx) minRect.dx = headerSize.dx; minRect.dx += 2 * ABOUT_LINE_OUTER_SIZE + 2 * ABOUT_MARGIN_DX; minRect.dy = headerSize.dy; for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) minRect.dy += rightDy + ABOUT_TXT_DY; minRect.dy += 2 * ABOUT_LINE_OUTER_SIZE + 4; ClientRect rc(hwnd); minRect.x = (rc.dx - minRect.dx) / 2; minRect.y = (rc.dy - minRect.dy) / 2; if (rect) *rect = minRect; /* calculate text positions */ int linePosX = ABOUT_LINE_OUTER_SIZE + ABOUT_MARGIN_DX + leftLargestDx + ABOUT_LEFT_RIGHT_SPACE_DX; int currY = minRect.y + headerSize.dy + 4; for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) { el->leftPos.x = minRect.x + linePosX - ABOUT_LEFT_RIGHT_SPACE_DX - el->leftPos.dx; el->leftPos.y = currY + (rightDy - leftDy) / 2; el->rightPos.x = minRect.x + linePosX + ABOUT_LEFT_RIGHT_SPACE_DX; el->rightPos.y = currY; currY += rightDy + ABOUT_TXT_DY; } SelectObject(hdc, origFont); }
/* Draws the about screen and remembers some state for hyperlinking. It transcribes the design I did in graphics software - hopeless to understand without seeing the design. */ static void DrawAbout(HWND hwnd, HDC hdc, RectI rect, Vec<StaticLinkInfo>& linkInfo) { HPEN penBorder = CreatePen(PS_SOLID, ABOUT_LINE_OUTER_SIZE, WIN_COL_BLACK); HPEN penDivideLine = CreatePen(PS_SOLID, ABOUT_LINE_SEP_SIZE, WIN_COL_BLACK); HPEN penLinkLine = CreatePen(PS_SOLID, ABOUT_LINE_SEP_SIZE, COL_BLUE_LINK); ScopedFont fontLeftTxt(GetSimpleFont(hdc, LEFT_TXT_FONT, LEFT_TXT_FONT_SIZE)); ScopedFont fontRightTxt(GetSimpleFont(hdc, RIGHT_TXT_FONT, RIGHT_TXT_FONT_SIZE)); HGDIOBJ origFont = SelectObject(hdc, fontLeftTxt); /* Just to remember the orig font */ ClientRect rc(hwnd); FillRect(hdc, &rc.ToRECT(), gBrushAboutBg); /* render title */ RectI titleRect(rect.TL(), CalcSumatraVersionSize(hdc)); SelectObject(hdc, gBrushLogoBg); SelectObject(hdc, penBorder); #ifndef ABOUT_USE_LESS_COLORS Rectangle(hdc, rect.x, rect.y + ABOUT_LINE_OUTER_SIZE, rect.x + rect.dx, rect.y + titleRect.dy + ABOUT_LINE_OUTER_SIZE); #else RectI titleBgBand(0, rect.y, rc.dx, titleRect.dy); FillRect(hdc, &titleBgBand.ToRECT(), gBrushLogoBg); PaintLine(hdc, RectI(0, rect.y, rc.dx, 0)); PaintLine(hdc, RectI(0, rect.y + titleRect.dy, rc.dx, 0)); #endif titleRect.Offset((rect.dx - titleRect.dx) / 2, 0); DrawSumatraVersion(hdc, titleRect); /* render attribution box */ SetTextColor(hdc, ABOUT_BORDER_COL); SetBkMode(hdc, TRANSPARENT); #ifndef ABOUT_USE_LESS_COLORS Rectangle(hdc, rect.x, rect.y + titleRect.dy, rect.x + rect.dx, rect.y + rect.dy); #endif /* render text on the left*/ SelectObject(hdc, fontLeftTxt); for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) { TextOut(hdc, el->leftPos.x, el->leftPos.y, el->leftTxt, (int)str::Len(el->leftTxt)); } /* render text on the right */ SelectObject(hdc, fontRightTxt); SelectObject(hdc, penLinkLine); linkInfo.Reset(); for (AboutLayoutInfoEl *el = gAboutLayoutInfo; el->leftTxt; el++) { bool hasUrl = HasPermission(Perm_DiskAccess) && el->url; SetTextColor(hdc, hasUrl ? COL_BLUE_LINK : ABOUT_BORDER_COL); TextOut(hdc, el->rightPos.x, el->rightPos.y, el->rightTxt, (int)str::Len(el->rightTxt)); if (hasUrl) { int underlineY = el->rightPos.y + el->rightPos.dy - 3; PaintLine(hdc, RectI(el->rightPos.x, underlineY, el->rightPos.dx, 0)); linkInfo.Append(StaticLinkInfo(el->rightPos, el->url, el->url)); } } SelectObject(hdc, penDivideLine); RectI divideLine(gAboutLayoutInfo[0].rightPos.x - ABOUT_LEFT_RIGHT_SPACE_DX, rect.y + titleRect.dy + 4, 0, rect.y + rect.dy - 4 - gAboutLayoutInfo[0].rightPos.y); PaintLine(hdc, divideLine); SelectObject(hdc, origFont); DeleteObject(penBorder); DeleteObject(penDivideLine); DeleteObject(penLinkLine); }