diff --git a/GUI.cpp b/GUI.cpp index cc583dd..f4e3f5f 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -926,6 +926,7 @@ bool __fastcall XgLoadSettings(void) xg_nRules = XG_DEFAULT_RULES; xg_nViewMode = XG_VIEW_NORMAL; xg_nFileType = XG_FILETYPE_XD; + xg_nLineWidthInPt = XG_LINE_WIDTH_DEFAULT; xg_nMarkingX = xg_nMarkingY = CW_USEDEFAULT; @@ -1144,6 +1145,14 @@ bool __fastcall XgLoadSettings(void) xg_nViewMode = XG_VIEW_NORMAL; } } + if (!app_key.QueryDword(L"LineWidth", dwValue)) { + float value = dwValue * 0.01; + if (value < XG_MIN_LINEWIDTH) + value = XG_MIN_LINEWIDTH; + if (value > XG_MAX_LINEWIDTH) + value = XG_MAX_LINEWIDTH; + xg_nLineWidthInPt = value; + } if (!app_key.QuerySz(L"Recent", sz, ARRAYSIZE(sz))) { xg_dict_name = sz; @@ -1256,6 +1265,7 @@ bool __fastcall XgSaveSettings(void) app_key.SetDword(L"ShowDoubleFrameLetters", xg_bShowDoubleFrameLetters); app_key.SetDword(L"ViewMode", xg_nViewMode); + app_key.SetDword(L"LineWidth", INT(xg_nLineWidthInPt * 100)); app_key.SetSz(L"Recent", xg_dict_name.c_str()); @@ -1792,16 +1802,19 @@ static void XgPrintIt(HDC hdc, PRINTDLGW* ppd, bool bPrintAnswer) ::DeleteFont(hFont); } + // サイズを取得する。 + SIZE siz; + XgGetXWordExtent(&siz); + // EMFオブジェクトを作成する。 HDC hdcEMF = ::CreateEnhMetaFileW(hdc, nullptr, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdcEMF != nullptr) { // EMFオブジェクトにクロスワードを描画する。 - SIZE siz; - XgGetXWordExtent(&siz); + XgSetSizeOfEMF(hdcEMF, &siz); if (bPrintAnswer) - XgDrawXWord(xg_solution, hdcEMF, &siz, false); + XgDrawXWord(xg_solution, hdcEMF, &siz, DRAW_MODE_EMF); else - XgDrawXWord(xg_xword, hdcEMF, &siz, false); + XgDrawXWord(xg_xword, hdcEMF, &siz, DRAW_MODE_EMF); // EMFオブジェクトを閉じる。 HENHMETAFILE hEMF = ::CloseEnhMetaFile(hdcEMF); @@ -3564,7 +3577,8 @@ void XgCopyBoard(HWND hwnd) HDC hdc = ::CreateEnhMetaFileW(hdcRef, nullptr, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdc) { // EMFに描画する。 - XgDrawXWord(*pxw, hdc, &siz, false); + XgSetSizeOfEMF(hdc, &siz); + XgDrawXWord(*pxw, hdc, &siz, DRAW_MODE_PRINT); // EMFを設定。 HENHMETAFILE hEMF = ::CloseEnhMetaFile(hdc); @@ -3578,7 +3592,7 @@ void XgCopyBoard(HWND hwnd) RECT rc; SetRect(&rc, 0, 0, siz.cx, siz.cy); FillRect(hDC, &rc, GetStockBrush(WHITE_BRUSH)); - XgDrawXWord(*pxw, hDC, &siz, false); + XgDrawXWord(*pxw, hDC, &siz, DRAW_MODE_PRINT); SelectObject(hDC, hbmOld); ::DeleteDC(hDC); @@ -3621,7 +3635,8 @@ void XgCopyBoardAsImage(HWND hwnd) HDC hdc = ::CreateEnhMetaFileW(hdcRef, nullptr, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdc) { // EMFに描画する。 - XgDrawXWord(*pxw, hdc, &siz, false); + XgSetSizeOfEMF(hdc, &siz); + XgDrawXWord(*pxw, hdc, &siz, DRAW_MODE_PRINT); hEMF = ::CloseEnhMetaFile(hdc); } @@ -3704,6 +3719,7 @@ void __fastcall XgCopyMarkWord(HWND hwnd) HDC hdc = ::CreateEnhMetaFileW(hdcRef, nullptr, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdc) { // EMFに描画する。 + XgSetSizeOfEMF(hdc, &siz); XgDrawMarkWord(hdc, &siz); hEMF = ::CloseEnhMetaFile(hdc); } diff --git a/HISTORY.txt b/HISTORY.txt index c0bf19a..1fffcb7 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -210,6 +210,11 @@ - Improved block patterns (PAT.txt). - Global optimization that focuses on the fact that there are fewer candidates for longer words. - Improved block patterns dialog. +- 2023-05-23 ver.5.0.4 + - Allowed line widths to be specified. Default line width to 1.0. + - Properly calculating the width of the line. + - Improved drawing of the board. + - Avoided EMF drawing defects for external softwares with incomplete EMF support. # 開発履歴 (Japanese) @@ -735,3 +740,8 @@ - 黒マスパターン(PAT.txt)を改良。 - 長い単語には候補が少ないことに着目した大局的な最適化。 - 黒マスパターンダイアログの改良。 +- 2023年05月23日 ver.5.0.4 + - 線の幅を指定できるようにする。線の幅のデフォルトを1.0に。 + - 線の幅をちゃんと計算。 + - 盤面の描画を改良。 + - 不完全なEMFサポートの外部ソフトウェアに対してEMF描画の不具合を回避。 diff --git a/XG_PatternDialog.hpp b/XG_PatternDialog.hpp index 94e8d9d..c66742c 100644 --- a/XG_PatternDialog.hpp +++ b/XG_PatternDialog.hpp @@ -289,6 +289,7 @@ class XG_PatternDialog : public XG_Dialog ShellExecuteW(hwnd, NULL, L"https://katahiromz.web.fc2.com/xword/patterns", NULL, NULL, SW_SHOWNORMAL); } + XG_NOINLINE INT GetType0() { if (IsDlgButtonChecked(m_hWnd, rad1) == BST_CHECKED) @@ -300,6 +301,7 @@ class XG_PatternDialog : public XG_Dialog return -1; } + XG_NOINLINE INT GetType1() { if (IsDlgButtonChecked(m_hWnd, rad4) == BST_CHECKED) diff --git a/XG_SettingsDialog.cpp b/XG_SettingsDialog.cpp index 302f600..2d49f83 100644 --- a/XG_SettingsDialog.cpp +++ b/XG_SettingsDialog.cpp @@ -83,6 +83,11 @@ BOOL XG_SettingsDialog::OnInitDialog(HWND hwnd) SendMessageW(hwnd, WM_COMMAND, IDOK, 0); } + // 線の太さ。 + WCHAR szText[MAX_PATH]; + StringCchPrintfW(szText, _countof(szText), XG_LINE_WIDTH_FORMAT, xg_nLineWidthInPt); + SetDlgItemTextW(hwnd, edt6, szText); + return TRUE; } @@ -193,6 +198,17 @@ void XG_SettingsDialog::OnOK(HWND hwnd) ComboBox_RealGetText(hCmb2, szText, _countof(szText)); xg_strDoubleFrameLetters = szText; + // 線の太さ。 + GetDlgItemTextW(hwnd, edt6, szText, _countof(szText)); + std::wstring str = szText; + xg_str_trim(str); + float value = wcstof(str.c_str(), NULL); + if (value > XG_MAX_LINEWIDTH) + value = XG_MAX_LINEWIDTH; + if (value < XG_MIN_LINEWIDTH) + value = XG_MIN_LINEWIDTH; + xg_nLineWidthInPt = value; + // イメージを更新する。 XgUpdateImage(xg_hMainWnd); @@ -646,6 +662,31 @@ XG_SettingsDialog::DialogProcDx(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar OnDropFiles(hwnd, (HDROP)wParam); break; + case WM_NOTIFY: + { + NM_UPDOWN *pUpDown = (NM_UPDOWN *)lParam; + if (pUpDown->hdr.code == UDN_DELTAPOS) + { + WCHAR szText[MAX_PATH]; + GetDlgItemTextW(hwnd, edt6, szText, _countof(szText)); + std::wstring str = szText; + xg_str_trim(str); + float value = wcstof(str.c_str(), NULL); + if (pUpDown->iDelta < 0) + value += XG_LINE_WIDTH_DELTA; + if (pUpDown->iDelta > 0) + value -= XG_LINE_WIDTH_DELTA; + if (value > XG_MAX_LINEWIDTH) + value = XG_MAX_LINEWIDTH; + if (value < XG_MIN_LINEWIDTH) + value = XG_MIN_LINEWIDTH; + StringCchPrintfW(szText, _countof(szText), XG_LINE_WIDTH_FORMAT, value); + SetDlgItemTextW(hwnd, edt6, szText); + return TRUE; + } + } + break; + case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: diff --git a/XWordGiver.cpp b/XWordGiver.cpp index 5d9e78f..1f0a98b 100644 --- a/XWordGiver.cpp +++ b/XWordGiver.cpp @@ -114,6 +114,9 @@ std::wstring xg_strBlackCellImage; // ビューモード。 XG_VIEW_MODE xg_nViewMode = XG_VIEW_NORMAL; +// 線の太さ(pt)。 +float xg_nLineWidthInPt = XG_LINE_WIDTH_DEFAULT; + ////////////////////////////////////////////////////////////////////////////// // static variables @@ -4443,6 +4446,18 @@ void __fastcall XgEndSolve(void) noexcept } } +// ポイント単位をピクセル単位に変換する(X座標)。 +INT XPixelsFromPoints(HDC hDC, INT points) +{ + return MulDiv(points, GetDeviceCaps(hDC, LOGPIXELSX), 72); +} + +// ポイント単位をピクセル単位に変換する(Y座標)。 +INT YPixelsFromPoints(HDC hDC, INT points) +{ + return MulDiv(points, GetDeviceCaps(hDC, LOGPIXELSY), 72); +} + // 二重マス単語を描画する。 void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) { @@ -4457,16 +4472,28 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) HBRUSH hbrWhite = ::CreateSolidBrush(xg_rgbWhiteCellColor); HBRUSH hbrMarked = ::CreateSolidBrush(xg_rgbMarkedCellColor); - // 細いペンを作成し、選択する。 - HPEN hThinPen = ::CreatePen(PS_SOLID, 1, xg_rgbBlackCellColor); + // 線の太さ。 + INT c_nThin = YPixelsFromPoints(hdc, xg_nLineWidthInPt); + INT c_nWide = YPixelsFromPoints(hdc, xg_nLineWidthInPt * 4); + if (c_nThin < 2) + c_nThin = 2; + if (c_nWide < 2) + c_nWide = 2; + if (c_nWide > xg_nNarrowMargin) + c_nWide = xg_nNarrowMargin; + + // セルの幅。 + INT nCellSize = xg_nCellSize; - // 太い線と黒いブラシを作成する。 + // 黒いブラシ。 LOGBRUSH lbBlack; - ::GetObject(hbrBlack, sizeof(lbBlack), &lbBlack); - int c_nWide = 4; - HPEN hWidePen = ::ExtCreatePen( + lbBlack.lbStyle = BS_SOLID; + lbBlack.lbColor = xg_rgbBlackCellColor; + + // 細いペンを作成し、選択する。 + HPEN hThinPen = ::ExtCreatePen( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, - c_nWide, &lbBlack, 0, NULL); + c_nThin, &lbBlack, 0, NULL); LOGFONTW lf; @@ -4511,7 +4538,6 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) WCHAR sz[32]; SIZE siz; HGDIOBJ hFontOld = ::SelectObject(hdc, hFontSmall); - HGDIOBJ hPenOld = ::SelectObject(hdc, hThinPen); for (int i = 0; i < nCount; i++) { ::SetRect(&rc, static_cast(xg_nNarrowMargin + i * xg_nCellSize), @@ -4519,15 +4545,17 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) static_cast(xg_nNarrowMargin + (i + 1) * xg_nCellSize - 1), static_cast(xg_nNarrowMargin + 1 * xg_nCellSize)); ::FillRect(hdc, &rc, hbrMarked); - ::InflateRect(&rc, -4, -4); + ::InflateRect(&rc, -nCellSize / 9, -nCellSize / 9); if (!xg_bNumCroMode && xg_bDrawFrameForMarkedCell) { + HGDIOBJ hPenOld = ::SelectObject(hdc, hThinPen); ::MoveToEx(hdc, rc.left, rc.top, NULL); ::LineTo(hdc, rc.right + 1, rc.top); ::LineTo(hdc, rc.right + 1, rc.bottom + 1); ::LineTo(hdc, rc.left, rc.bottom + 1); ::LineTo(hdc, rc.left, rc.top); + ::SelectObject(hdc, hPenOld); } - ::InflateRect(&rc, 4, 4); + ::InflateRect(&rc, nCellSize / 9, nCellSize / 9); WCHAR ch; if (xg_bNumCroMode && xg_bSolved) { @@ -4544,27 +4572,28 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) ::GetTextExtentPoint32W(hdc, sz, int(wcslen(sz)), &siz); RECT rcText = rc; - INT x, y; if (xg_bNumCroMode && xg_bSolved) { rcText.left += 2; - rcText.right = rcText.left + std::max(siz.cx, siz.cy); - rcText.bottom = rcText.top + std::max(siz.cx, siz.cy); - x = rcText.left; + rcText.right = rcText.left + (siz.cx + siz.cy) / 2; + rcText.bottom = rcText.top + siz.cy; } else { - rcText.left = rcText.right - std::max(siz.cx, siz.cy); - rcText.top = rcText.bottom - std::max(siz.cx, siz.cy); - x = (rcText.left + rcText.right - siz.cx) / 2; + rcText.left = rcText.right - (siz.cx + siz.cy) / 2; + rcText.top = rcText.bottom - siz.cy; + } + + // EMFで枠線が余分に描画されてしまう不具合の回避のため、FillRectの前にNULL_PENを選択する。 + HGDIOBJ hPen2Old = ::SelectObject(hdc, ::GetStockObject(NULL_PEN)); + { + ::FillRect(hdc, &rcText, hbrMarked); } - y = rcText.top; - ::FillRect(hdc, &rcText, hbrMarked); + ::SelectObject(hdc, hPen2Old); // 二重マスの文字を描く。 ::SetTextColor(hdc, xg_rgbBlackCellColor); ::SetBkMode(hdc, TRANSPARENT); - ::TextOutW(hdc, x, y, sz, lstrlenW(sz)); + ::TextOutW(hdc, rcText.left, rcText.top - 1, sz, lstrlenW(sz)); } ::SelectObject(hdc, hFontOld); - ::SelectObject(hdc, hPenOld); // マスの文字を描画する。 hFontOld = ::SelectObject(hdc, hFont); @@ -4632,7 +4661,7 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) // 線を引く。塗りつぶさない。 ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH)); - hPenOld = ::SelectObject(hdc, hThinPen); + HGDIOBJ hPenOld = ::SelectObject(hdc, hThinPen); for (int i = 0; i < nCount; i++) { ::Rectangle(hdc, static_cast(xg_nNarrowMargin + i * xg_nCellSize), @@ -4643,7 +4672,6 @@ void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz) ::SelectObject(hdc, hPenOld); // 破棄する。 - ::DeleteObject(hWidePen); ::DeleteObject(hThinPen); ::DeleteObject(hFont); ::DeleteObject(hFontSmall); @@ -4702,8 +4730,59 @@ std::unordered_set XgGetSlot(INT number, BOOL vertical) const COLORREF c_rgbHighlight = RGB(255, 255, 140); const COLORREF c_rgbHighlightAndDblFrame = RGB(255, 155, 100); +// マスの数字を描画する。 +void __fastcall +XgDrawCellNumber(HDC hdc, const RECT& rcCell, INT i, INT j, INT number, std::unordered_set& slot) +{ + WCHAR sz[8]; + StringCbPrintf(sz, sizeof(sz), L"%u", number); + + RECT rcText; + SIZE siz; + GetTextExtentPoint32(hdc, sz, lstrlen(sz), &siz); + rcText = rcCell; + rcText.right = rcCell.left + siz.cx; + rcText.bottom = rcCell.top + siz.cy; + + ::SetBkMode(hdc, TRANSPARENT); + + // 文字の背景を塗りつぶす。 + INT nMarked = XgGetMarked(i, j); + COLORREF rgbBack; + if (xg_bSolved && xg_bNumCroMode) { + // 文字の背景を塗りつぶす。 + if (slot.count(XG_Pos(i, j)) > 0) { + rgbBack = c_rgbHighlight; + } else { + rgbBack = xg_rgbWhiteCellColor; + } + } else { + if (slot.count(XG_Pos(i, j)) > 0) { + rgbBack = c_rgbHighlight; + } else if (nMarked != -1 && !xg_bNumCroMode) { + rgbBack = xg_rgbMarkedCellColor; + } else { + rgbBack = xg_rgbWhiteCellColor; + } + } + // EMFにおいてFillRectが余分な枠線を描画する不具合の回避のため、NULL_PENを選択する。 + HGDIOBJ hPen2Old = ::SelectObject(hdc, ::GetStockObject(NULL_PEN)); + { + HBRUSH hbr = ::CreateSolidBrush(rgbBack); + ::FillRect(hdc, &rcText, hbr); + ::DeleteObject(hbr); + } + ::SelectObject(hdc, hPen2Old); + + if (xg_bShowNumbering) { + // 数字を描く。 + ::SetTextColor(hdc, xg_rgbBlackCellColor); + ::TextOutW(hdc, rcText.left, rcText.top, sz, lstrlenW(sz)); + } +} + // クロスワードを描画する(通常ビュー)。 -void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool bScreen) +void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, DRAW_MODE mode) { INT nCellSize; if (xg_nForDisplay > 0) { @@ -4715,6 +4794,7 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool // 全体を白で塗りつぶす。 RECT rc; ::SetRect(&rc, 0, 0, psiz->cx, psiz->cy); + ::SelectObject(hdc, ::GetStockObject(NULL_PEN)); ::FillRect(hdc, &rc, reinterpret_cast(::GetStockObject(WHITE_BRUSH))); LOGFONTW lf; @@ -4752,8 +4832,34 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool if (xg_nForDisplay <= 0) slot.clear(); + // 線の太さ。 + INT c_nThin = 1; + INT c_nWide = 4; + switch (mode) + { + case DRAW_MODE_SCREEN: + case DRAW_MODE_PRINT: + c_nThin = YPixelsFromPoints(hdc, xg_nLineWidthInPt); + c_nWide = YPixelsFromPoints(hdc, xg_nLineWidthInPt * 4); + break; + case DRAW_MODE_EMF: + break; + } + if (c_nThin < 2) + c_nThin = 2; + if (c_nWide < 2) + c_nWide = 2; + if (c_nWide > xg_nMargin) + c_nWide = xg_nMargin; + + LOGBRUSH lbBlack; + lbBlack.lbStyle = BS_SOLID; + lbBlack.lbColor = xg_rgbBlackCellColor; + // 黒の細いペンを作成する。 - HPEN hThinPen = ::CreatePen(PS_SOLID, 1, xg_rgbBlackCellColor); + HPEN hThinPen = ::ExtCreatePen( + PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, + c_nThin, &lbBlack, 0, NULL); // 赤いキャレットペンを作成する。 LOGBRUSH lbRed; @@ -4763,14 +4869,6 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_BEVEL, 1, &lbRed, 0, NULL); - // 黒い太いペンを作成する。 - LOGBRUSH lbBlack; - ::GetObject(hbrBlack, sizeof(lbBlack), &lbBlack); - int c_nWide = 4; - HPEN hWidePen = ::ExtCreatePen( - PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, - c_nWide, &lbBlack, 0, NULL); - WCHAR sz[32]; SIZE siz; HGDIOBJ hFontOld, hPenOld; @@ -4852,12 +4950,12 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool // 二重マスの内側の枠を描く。 if (xg_bDrawFrameForMarkedCell) { - ::InflateRect(&rc, -4, -4); + ::InflateRect(&rc, -nCellSize / 9, -nCellSize / 9); ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH)); hPenOld = ::SelectObject(hdc, hThinPen); ::Rectangle(hdc, rc.left, rc.top, rc.right + 1, rc.bottom + 1); ::SelectObject(hdc, hPenOld); - ::InflateRect(&rc, 4, 4); + ::InflateRect(&rc, nCellSize / 9, nCellSize / 9); } if (xg_bShowDoubleFrameLetters) { @@ -4870,17 +4968,22 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool RECT rcText; GetTextExtentPoint32(hdc, sz, lstrlen(sz), &siz); rcText = rc; - rcText.left = rc.right - std::max(siz.cx, siz.cy); - rcText.top = rc.bottom - std::max(siz.cx, siz.cy); + rcText.left = rc.right - (siz.cx + siz.cy) / 2; + rcText.top = rc.bottom - siz.cy; - HBRUSH hbr = CreateSolidBrush(xg_rgbMarkedCellColor); - FillRect(hdc, &rcText, hbr); - DeleteObject(hbr); + // EMFで枠線が余分に描画されてしまう不具合の回避のため、FillRectの前にNULL_PENを選択する。 + HGDIOBJ hPen2Old = ::SelectObject(hdc, ::GetStockObject(NULL_PEN)); + { + HBRUSH hbr = ::CreateSolidBrush(xg_rgbMarkedCellColor); + ::FillRect(hdc, &rcText, hbr); + ::DeleteObject(hbr); + } + ::SelectObject(hdc, hPen2Old); // 二重マスの右下端の文字を描く。 ::SetBkMode(hdc, TRANSPARENT); ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rcText, DT_CENTER | DT_SINGLELINE | DT_BOTTOM); + ::TextOutW(hdc, rcText.left, rcText.top - 1, sz, lstrlenW(sz)); } } } @@ -4892,30 +4995,15 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool for (int k = 0; k < size; k++) { const int i = xg_vTateInfo[k].m_iRow; const int j = xg_vTateInfo[k].m_jCol; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_vTateInfo[k].m_number); - // 文字の背景を塗りつぶす。 - ::SetBkMode(hdc, OPAQUE); - int nMarked = XgGetMarked(i, j); - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else if (nMarked != -1 && !xg_bNumCroMode) { - ::SetBkColor(hdc, xg_rgbMarkedCellColor); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_vTateInfo[k].m_number, slot); } } @@ -4925,29 +5013,15 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool for (int k = 0; k < size; k++) { const int i = xg_vYokoInfo[k].m_iRow; const int j = xg_vYokoInfo[k].m_jCol; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_vYokoInfo[k].m_number); - // 文字の背景を塗りつぶす。 - int nMarked = XgGetMarked(i, j); - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else if (nMarked != -1 && !xg_bNumCroMode) { - ::SetBkColor(hdc, xg_rgbMarkedCellColor); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_vYokoInfo[k].m_number, slot); } } @@ -4959,26 +5033,14 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool if (ch == ZEN_BLACK || ch == ZEN_SPACE) continue; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_mapNumCro1[ch]); - - // 文字の背景を塗りつぶす。 - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_mapNumCro1[ch], slot); } } } @@ -5045,7 +5107,7 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool } // キャレットを描画する。 - if (bScreen && xg_bShowCaret) { + if (mode == DRAW_MODE_SCREEN && xg_bShowCaret) { const int i = xg_caret_pos.m_i; const int j = xg_caret_pos.m_j; ::SetRect(&rc, @@ -5095,15 +5157,29 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool } ::SelectObject(hdc, hPenOld); - // 周りに太い線を描く。 - hPenOld = ::SelectObject(hdc, hWidePen); + // 周りに太い線を描く。線を引こうと思ったが、コーナーがうまく描画できないので、 + // 塗りつぶしで対処する。 + hPenOld = ::SelectObject(hdc, GetStockBrush(NULL_PEN)); if (xg_bAddThickFrame) { - c_nWide /= 2; - ::MoveToEx(hdc, xg_nMargin - c_nWide, xg_nMargin - c_nWide, nullptr); - ::LineTo(hdc, psiz->cx - xg_nMargin + c_nWide, xg_nMargin - c_nWide); - ::LineTo(hdc, psiz->cx - xg_nMargin + c_nWide, psiz->cy - xg_nMargin + c_nWide); - ::LineTo(hdc, xg_nMargin - c_nWide, psiz->cy - xg_nMargin + c_nWide); - ::LineTo(hdc, xg_nMargin - c_nWide, xg_nMargin - c_nWide); + RECT rc = { xg_nMargin, xg_nMargin, psiz->cx - xg_nMargin, psiz->cy - xg_nMargin }; + ::InflateRect(&rc, c_nWide, c_nWide); + RECT rc2; + + rc2 = rc; + rc2.right = rc.left + c_nWide; + ::FillRect(hdc, &rc2, hbrBlack); + + rc2 = rc; + rc2.left = rc.right - c_nWide; + ::FillRect(hdc, &rc2, hbrBlack); + + rc2 = rc; + rc2.bottom = rc.top + c_nWide; + ::FillRect(hdc, &rc2, hbrBlack); + + rc2 = rc; + rc2.top = rc.bottom - c_nWide; + ::FillRect(hdc, &rc2, hbrBlack); } ::SelectObject(hdc, hPenOld); @@ -5111,7 +5187,6 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool ::DeleteObject(hFont); ::DeleteObject(hFontSmall); ::DeleteObject(hThinPen); - ::DeleteObject(hWidePen); ::DeleteObject(hCaretPen); ::DeleteObject(hbrBlack); ::DeleteObject(hbrWhite); @@ -5121,7 +5196,7 @@ void __fastcall XgDrawXWord_NormalView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool } // クロスワードを描画する(スケルトンビュー)。 -void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, bool bScreen) +void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, DRAW_MODE mode) { INT nCellSize; if (xg_nForDisplay > 0) { @@ -5134,7 +5209,7 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo // それ以外は、四隅に白い点を描く(EMFで余白が省略されないように)。 RECT rc; ::SetRect(&rc, 0, 0, psiz->cx, psiz->cy); - if (bScreen) { + if (mode == DRAW_MODE_SCREEN) { ::FillRect(hdc, &rc, reinterpret_cast(::GetStockObject(WHITE_BRUSH))); } else { COLORREF rgbWhite = RGB(255, 255, 255); @@ -5179,8 +5254,23 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo if (xg_nForDisplay <= 0) slot.clear(); + // 線の太さ。 + INT c_nThin = YPixelsFromPoints(hdc, xg_nLineWidthInPt); + INT c_nWide = 4; + if (c_nThin < 2) + c_nThin = 2; + if (c_nWide < 2) + c_nWide = 2; + + // 黒いブラシ。 + LOGBRUSH lbBlack; + lbBlack.lbStyle = BS_SOLID; + lbBlack.lbColor = xg_rgbBlackCellColor; + // 黒の細いペンを作成する。 - HPEN hThinPen = ::CreatePen(PS_SOLID, 1, xg_rgbBlackCellColor); + HPEN hThinPen = ::ExtCreatePen( + PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, + c_nThin, &lbBlack, 0, NULL); // 赤いキャレットペンを作成する。 LOGBRUSH lbRed; @@ -5190,14 +5280,6 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_BEVEL, 1, &lbRed, 0, NULL); - // 黒い太いペンを作成する。 - LOGBRUSH lbBlack; - ::GetObject(hbrBlack, sizeof(lbBlack), &lbBlack); - int c_nWide = 4; - HPEN hWidePen = ::ExtCreatePen( - PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, - c_nWide, &lbBlack, 0, NULL); - WCHAR sz[32]; SIZE siz; HGDIOBJ hFontOld, hPenOld; @@ -5254,23 +5336,6 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo // その他のマス。 ::FillRect(hdc, &rc, hbrWhite); } - - if (ch != ZEN_BLACK) { - // 線を引く。 - hPenOld = ::SelectObject(hdc, hThinPen); - { - ::MoveToEx(hdc, static_cast(xg_nMargin + j * nCellSize), static_cast(xg_nMargin + i * nCellSize), nullptr); - ++i; - ::LineTo(hdc, static_cast(xg_nMargin + j * nCellSize), static_cast(xg_nMargin + i * nCellSize)); - --i; - - ::MoveToEx(hdc, static_cast(xg_nMargin + j * nCellSize), static_cast(xg_nMargin + i * nCellSize), nullptr); - ++j; - ::LineTo(hdc, static_cast(xg_nMargin + j * nCellSize), static_cast(xg_nMargin + i * nCellSize)); - --j; - } - ::SelectObject(hdc, hPenOld); - } } } @@ -5296,12 +5361,12 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo // 二重マスの内側の枠を描く。 if (xg_bDrawFrameForMarkedCell) { - ::InflateRect(&rc, -4, -4); + ::InflateRect(&rc, -nCellSize / 9, -nCellSize / 9); ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH)); hPenOld = ::SelectObject(hdc, hThinPen); ::Rectangle(hdc, rc.left, rc.top, rc.right + 1, rc.bottom + 1); ::SelectObject(hdc, hPenOld); - ::InflateRect(&rc, 4, 4); + ::InflateRect(&rc, nCellSize / 9, nCellSize / 9); } if (xg_bShowDoubleFrameLetters) { @@ -5314,17 +5379,22 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo RECT rcText; GetTextExtentPoint32(hdc, sz, lstrlen(sz), &siz); rcText = rc; - rcText.left = rc.right - std::max(siz.cx, siz.cy); - rcText.top = rc.bottom - std::max(siz.cx, siz.cy); + rcText.left = rc.right - (siz.cx + siz.cy) / 2; + rcText.top = rc.bottom - siz.cy; - HBRUSH hbr = CreateSolidBrush(xg_rgbMarkedCellColor); - FillRect(hdc, &rcText, hbr); - DeleteObject(hbr); + // EMFで枠線が余分に描画されてしまう不具合の回避のため、FillRectの前にNULL_PENを選択する。 + HGDIOBJ hPen2Old = ::SelectObject(hdc, GetStockObject(NULL_PEN)); + { + HBRUSH hbr = ::CreateSolidBrush(xg_rgbMarkedCellColor); + ::FillRect(hdc, &rcText, hbr); + ::DeleteObject(hbr); + } + ::SelectObject(hdc, hPen2Old); // 二重マスの右下端の文字を描く。 ::SetBkMode(hdc, TRANSPARENT); ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rcText, DT_CENTER | DT_SINGLELINE | DT_BOTTOM); + ::TextOutW(hdc, rcText.left, rcText.top - 1, sz, lstrlenW(sz)); } } } @@ -5336,30 +5406,15 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo for (int k = 0; k < size; k++) { const int i = xg_vTateInfo[k].m_iRow; const int j = xg_vTateInfo[k].m_jCol; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_vTateInfo[k].m_number); - // 文字の背景を塗りつぶす。 - ::SetBkMode(hdc, OPAQUE); - int nMarked = XgGetMarked(i, j); - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else if (nMarked != -1) { - ::SetBkColor(hdc, xg_rgbMarkedCellColor); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_vTateInfo[k].m_number, slot); } } @@ -5369,29 +5424,15 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo for (int k = 0; k < size; k++) { const int i = xg_vYokoInfo[k].m_iRow; const int j = xg_vYokoInfo[k].m_jCol; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_vYokoInfo[k].m_number); - // 文字の背景を塗りつぶす。 - int nMarked = XgGetMarked(i, j); - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else if (nMarked != -1) { - ::SetBkColor(hdc, xg_rgbMarkedCellColor); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_vYokoInfo[k].m_number, slot); } } @@ -5403,26 +5444,14 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo if (ch == ZEN_BLACK || ch == ZEN_SPACE) continue; - StringCbPrintf(sz, sizeof(sz), L"%u", xg_mapNumCro1[ch]); - - // 文字の背景を塗りつぶす。 - if (slot.count(XG_Pos(i, j)) > 0) { - ::SetBkColor(hdc, c_rgbHighlight); - } else { - ::SetBkColor(hdc, xg_rgbWhiteCellColor); - } + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + ::OffsetRect(&rc, c_nThin, c_nThin * 2 / 3); - if (xg_bShowNumbering) { - // 数字を描く。 - ::SetRect(&rc, - static_cast(xg_nMargin + j * nCellSize), - static_cast(xg_nMargin + i * nCellSize), - static_cast(xg_nMargin + (j + 1) * nCellSize), - static_cast(xg_nMargin + (i + 1) * nCellSize)); - ::OffsetRect(&rc, 2, 1); - ::SetTextColor(hdc, xg_rgbBlackCellColor); - ::DrawTextW(hdc, sz, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_TOP); - } + XgDrawCellNumber(hdc, rc, i, j, xg_mapNumCro1[ch], slot); } } } @@ -5490,8 +5519,29 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo } } + // セルの枠を描画する。 + for (int i = 0; i < xg_nRows; i++) { + for (int j = 0; j < xg_nCols; j++) { + // セルの座標をセットする。 + ::SetRect(&rc, + static_cast(xg_nMargin + j * nCellSize), + static_cast(xg_nMargin + i * nCellSize), + static_cast(xg_nMargin + (j + 1) * nCellSize), + static_cast(xg_nMargin + (i + 1) * nCellSize)); + WCHAR ch = xw.GetAt(i, j); + if (ch == ZEN_BLACK) + continue; + + ::SelectObject(hdc, GetStockObject(NULL_BRUSH)); + + HGDIOBJ hPen2Old = ::SelectObject(hdc, hThinPen); + Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); + ::SelectObject(hdc, hPen2Old); + } + } + // キャレットを描画する。 - if (bScreen && xg_bShowCaret) { + if (mode == DRAW_MODE_SCREEN && xg_bShowCaret) { const int i = xg_caret_pos.m_i; const int j = xg_caret_pos.m_j; ::SetRect(&rc, @@ -5533,7 +5583,6 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo ::DeleteObject(hFont); ::DeleteObject(hFontSmall); ::DeleteObject(hThinPen); - ::DeleteObject(hWidePen); ::DeleteObject(hCaretPen); ::DeleteObject(hbrBlack); ::DeleteObject(hbrWhite); @@ -5543,20 +5592,20 @@ void __fastcall XgDrawXWord_SkeletonView(XG_Board& xw, HDC hdc, LPSIZE psiz, boo } // クロスワードを描画する。 -void __fastcall XgDrawXWord(XG_Board& xw, HDC hdc, LPSIZE psiz, bool bScreen) +void __fastcall XgDrawXWord(XG_Board& xw, HDC hdc, LPSIZE psiz, DRAW_MODE mode) { switch (xg_nViewMode) { case XG_VIEW_NORMAL: default: - XgDrawXWord_NormalView(xw, hdc, psiz, bScreen); + XgDrawXWord_NormalView(xw, hdc, psiz, mode); break; case XG_VIEW_SKELETON: - XgDrawXWord_SkeletonView(xw, hdc, psiz, bScreen); + XgDrawXWord_SkeletonView(xw, hdc, psiz, mode); break; } // ボックスを描画する。 - if (!bScreen) + if (mode != DRAW_MODE_SCREEN) XgDrawBoxes(xw, hdc, psiz); } @@ -5587,7 +5636,7 @@ HBITMAP __fastcall XgCreateXWordImage(XG_Board& xw, LPSIZE psiz, bool bScreen) // 描画する。 HGDIOBJ hbmOld = ::SelectObject(hdc, hbm); - XgDrawXWord(xw, hdc, psiz, bScreen); + XgDrawXWord(xw, hdc, psiz, bScreen ? DRAW_MODE_SCREEN : DRAW_MODE_PRINT); ::SelectObject(hdc, hbmOld); // 互換DCを破棄する。 @@ -6510,7 +6559,8 @@ void __fastcall XgSaveProbAsImage(HWND hwnd) HDC hdcRef = ::GetDC(hwnd); HDC hdc = ::CreateEnhMetaFileW(hdcRef, szFileName, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdc) { - XgDrawXWord(xg_xword, hdc, &siz, false); + XgSetSizeOfEMF(hdc, &siz); + XgDrawXWord(xg_xword, hdc, &siz, DRAW_MODE_EMF); ::CloseEnhMetaFile(hdc); } else { XgCenterMessageBoxW(hwnd, XgLoadStringDx1(IDS_CANTSAVE2), nullptr, MB_ICONERROR); @@ -6562,7 +6612,8 @@ void __fastcall XgSaveAnsAsImage(HWND hwnd) HDC hdcRef = ::GetDC(hwnd); HDC hdc = ::CreateEnhMetaFileW(hdcRef, szFileName, nullptr, XgLoadStringDx1(IDS_APPNAME)); if (hdc) { - XgDrawXWord(xg_solution, hdc, &siz, false); + XgSetSizeOfEMF(hdc, &siz); + XgDrawXWord(xg_solution, hdc, &siz, DRAW_MODE_EMF); ::CloseEnhMetaFile(hdc); } else { XgCenterMessageBoxW(hwnd, XgLoadStringDx1(IDS_CANTSAVE2), nullptr, MB_ICONERROR); @@ -6572,6 +6623,14 @@ void __fastcall XgSaveAnsAsImage(HWND hwnd) } } +// EMFの寸法をセットする。 +void XgSetSizeOfEMF(HDC hdcEMF, const SIZE *psiz) +{ + //SetMapMode(hdcEMF, MM_ANISOTROPIC); + //SetWindowExtEx(hdcEMF, psiz->cx, psiz->cy, NULL); + //SetViewportExtEx(hdcEMF, psiz->cx, psiz->cy, NULL); +} + // クロスワードの文字列を取得する。 void __fastcall XG_Board::GetString(std::wstring& str) const { diff --git a/XWordGiver.hpp b/XWordGiver.hpp index 543d46f..902e4a2 100644 --- a/XWordGiver.hpp +++ b/XWordGiver.hpp @@ -648,8 +648,16 @@ HBITMAP __fastcall XgCreateXWordImage(XG_Board& xw, LPSIZE psiz, bool bCaret); // 二重マス単語を描画する。 void __fastcall XgDrawMarkWord(HDC hdc, LPSIZE psiz); +// 描画モード。 +enum DRAW_MODE +{ + DRAW_MODE_SCREEN, + DRAW_MODE_PRINT, + DRAW_MODE_EMF, +}; + // クロスワードを描画する。 -void __fastcall XgDrawXWord(XG_Board& xw, HDC hdc, LPSIZE psiz, bool bCaret); +void __fastcall XgDrawXWord(XG_Board& xw, HDC hdc, LPSIZE psiz, DRAW_MODE mode); // 解を求めるのを開始。 void __fastcall XgStartSolve_AddBlack(void) noexcept; @@ -701,6 +709,9 @@ typedef enum XG_VIEW_MODE } XG_VIEW_MODE; extern XG_VIEW_MODE xg_nViewMode; +// EMFの寸法をセットする。 +void XgSetSizeOfEMF(HDC hdcEMF, const SIZE *psiz); + ////////////////////////////////////////////////////////////////////////////// // inline functions @@ -1326,6 +1337,14 @@ extern INT xg_nPatWndY; extern INT xg_nPatWndCX; extern INT xg_nPatWndCY; +// 線の太さ(pt)。 +extern float xg_nLineWidthInPt; +#define XG_MIN_LINEWIDTH 0.05f +#define XG_MAX_LINEWIDTH 5.0f +#define XG_LINE_WIDTH_DEFAULT 1.0f +#define XG_LINE_WIDTH_DELTA 0.5f +#define XG_LINE_WIDTH_FORMAT L"%.1f" + ////////////////////////////////////////////////////////////////////////////// // 再計算するか? diff --git a/XWordGiver_res.rc b/XWordGiver_res.rc index c3ada08..214abce 100644 --- a/XWordGiver_res.rc +++ b/XWordGiver_res.rc @@ -1,5 +1,5 @@ // XWordGiver_res.rc -// This file is automatically generated by RisohEditor. +// This file is automatically generated by RisohEditor 5.7.5. // † <-- This dagger helps UTF-8 detection. #include "resource.h" diff --git a/installer32.iss b/installer32.iss index 6fbc0da..edd0a9f 100644 --- a/installer32.iss +++ b/installer32.iss @@ -7,8 +7,8 @@ ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{07AF81F8-4484-4672-90B4-6262A94E8E1B} AppName={cm:AppNameBits} -AppVersion=5.0.3 -AppVerName={cm:AppNameBits} ver.5.0.3 +AppVersion=5.0.4 +AppVerName={cm:AppNameBits} ver.5.0.4 AppPublisher={cm:Author} AppPublisherURL=http://katahiromz.web.fc2.com/ AppSupportURL=http://katahiromz.web.fc2.com/ @@ -16,7 +16,7 @@ AppUpdatesURL=http://katahiromz.web.fc2.com/ DefaultDirName={pf}\XWordGiver32 DefaultGroupName={cm:AppNameBits} OutputDir=. -OutputBaseFilename=XWordGiver-x86-5.0.3-setup +OutputBaseFilename=XWordGiver-x86-5.0.4-setup Compression=lzma SolidCompression=yes UninstallDisplayIcon={app}\XWordGiver32.exe diff --git a/installer64.iss b/installer64.iss index 3467fe2..8f2f2c5 100644 --- a/installer64.iss +++ b/installer64.iss @@ -7,8 +7,8 @@ ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{CDECA641-CFBB-43E0-A075-13802703E7EC} AppName={cm:AppNameBits} -AppVersion=5.0.3 -AppVerName={cm:AppNameBits} ver.5.0.3 +AppVersion=5.0.4 +AppVerName={cm:AppNameBits} ver.5.0.4 AppPublisher={cm:Author} AppPublisherURL=http://katahiromz.web.fc2.com/ AppSupportURL=http://katahiromz.web.fc2.com/ @@ -16,7 +16,7 @@ AppUpdatesURL=http://katahiromz.web.fc2.com/ DefaultDirName={pf}\XWordGiver64 DefaultGroupName={cm:AppNameBits} OutputDir=. -OutputBaseFilename=XWordGiver-x64-5.0.3-setup +OutputBaseFilename=XWordGiver-x64-5.0.4-setup Compression=lzma SolidCompression=yes UninstallDisplayIcon={app}\XWordGiver64.exe diff --git a/lang/en_US.rc b/lang/en_US.rc index 0b71962..524377f 100644 --- a/lang/en_US.rc +++ b/lang/en_US.rc @@ -1,4 +1,4 @@ -// This file is automatically generated by RisohEditor. +// This file is automatically generated by RisohEditor 5.7.5. // † <-- This dagger helps UTF-8 detection. #pragma code_page(65001) // UTF-8 @@ -677,16 +677,20 @@ FONT 9, "Tahoma" PUSHBUTTON "", psh8, 140, 94, 15, 15, BS_OWNERDRAW RTEXT "Dbl-frame color:", -1, 172, 96, 55, 12 PUSHBUTTON "", psh9, 232, 94, 15, 15, BS_OWNERDRAW - LTEXT "Cell font size:", -1, 5, 124, 65, 12 - EDITTEXT edt4, 72, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL - CONTROL "", scr1, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 94, 122, 12, 20 - LTEXT "%", -1, 112, 124, 14, 12 - PUSHBUTTON "Reset", psh10, 70, 140, 35, 14 - LTEXT "Sma&ll font size:", -1, 137, 124, 70, 12 - EDITTEXT edt5, 209, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL - CONTROL "", scr2, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 232, 122, 12, 20 - LTEXT "%", -1, 248, 124, 14, 12 - PUSHBUTTON "Reset", psh11, 209, 140, 35, 14 + RTEXT "Cell font size:", -1, 5, 124, 67, 12 + EDITTEXT edt4, 75, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL + CONTROL "", scr1, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 98, 122, 12, 20 + LTEXT "%", -1, 114, 124, 10, 12 + PUSHBUTTON "リセット", psh10, 129, 123, 35, 14 + RTEXT "Sma&ll font size:", -1, 5, 145, 67, 12 + EDITTEXT edt5, 75, 143, 33, 14, ES_NUMBER | ES_AUTOHSCROLL + CONTROL "", scr2, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 98, 143, 12, 20 + LTEXT "%", -1, 114, 145, 10, 12 + PUSHBUTTON "リセット", psh11, 129, 145, 35, 14 + RTEXT "Line width:", -1, 170, 127, 44, 12 + EDITTEXT edt6, 218, 125, 36, 14, ES_AUTOHSCROLL + CONTROL "", scr3, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT, 246, 127, 12, 20 + LTEXT "pt", -1, 259, 127, 11, 12 LTEXT "Block i&mage:", -1, 5, 166, 52, 11 COMBOBOX cmb1, 60, 165, 102, 300, CBS_HASSTRINGS | CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP LTEXT "Please drop your favorite image into the BLOCK folder.", -1, 5, 182, 150, 21 @@ -1306,10 +1310,10 @@ STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION | WS_THICKFRAME | FONT 9, "Tahoma" { LTEXT "Please select a pattern from the list below.", stc1, 5, 2, 220, 12 - AUTORADIOBUTTON "&Large", rad1, 5, 15, 45, 16, WS_TABSTOP | WS_GROUP + AUTORADIOBUTTON "&Large", rad1, 5, 15, 45, 16, WS_GROUP | WS_TABSTOP AUTORADIOBUTTON "&Medium", rad2, 55, 15, 50, 16, WS_TABSTOP AUTORADIOBUTTON "&Small", rad3, 110, 15, 50, 16, WS_TABSTOP - AUTORADIOBUTTON "L&andscape", rad4, 175, 15, 48, 16, WS_TABSTOP | WS_GROUP + AUTORADIOBUTTON "L&andscape", rad4, 175, 15, 48, 16, WS_GROUP | WS_TABSTOP AUTORADIOBUTTON "&Portrait", rad5, 227, 15, 43, 16, WS_TABSTOP AUTORADIOBUTTON "S&quare", rad6, 275, 15, 55, 16, WS_TABSTOP LTEXT "Lis&t:", stc2, 8, 37, 47, 12 @@ -1484,7 +1488,7 @@ FONT 9, "Tahoma" LTEXT "The double-frame &word:", -1, 5, 5, 128, 12 EDITTEXT edt1, 5, 20, 205, 14 LTEXT "Enter a word or choose from the suggestions below:", stc1, 5, 40, 205, 14 - LISTBOX lst1, 5, 60, 205, 100, LBS_MULTICOLUMN | LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS | WS_HSCROLL | WS_VSCROLL | WS_TABSTOP + LISTBOX lst1, 5, 60, 205, 100, LBS_MULTICOLUMN | LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP PUSHBUTTON "< &previous word", psh1, 5, 165, 100, 17 PUSHBUTTON "&next word >", psh2, 110, 165, 100, 17 PUSHBUTTON "&another layout", psh3, 110, 185, 100, 17 @@ -1495,10 +1499,11 @@ FONT 9, "Tahoma" // RT_VERSION 1 VERSIONINFO -FILEVERSION 5, 0, 3, 0 -PRODUCTVERSION 5, 0, 3, 0 +FILEVERSION 5, 0, 4, 0 +PRODUCTVERSION 5, 0, 4, 0 FILEOS 0x40004 FILETYPE 0x1 +FILESUBTYPE 0x0 { BLOCK "StringFileInfo" { @@ -1506,10 +1511,10 @@ FILETYPE 0x1 { VALUE "CompanyName", "Katayama Hirofumi MZ\0" VALUE "FileDescription", "XWordGiver\0" - VALUE "FileVersion", "5.0.3\0" + VALUE "FileVersion", "5.0.4\0" VALUE "LegalCopyright", "Copyright (C) 2012-2020 katahiromz. All rights reserved.\0" VALUE "ProductName", "XWordGiver\0" - VALUE "ProductVersion", "5.0.3\0" + VALUE "ProductVersion", "5.0.4\0" } } BLOCK "VarFileInfo" @@ -1523,7 +1528,7 @@ FILETYPE 0x1 STRINGTABLE { - IDS_VERSION, "XWordGiver ver.5.0.3\nby katahiromz" + IDS_VERSION, "XWordGiver ver.5.0.4\nby katahiromz" IDS_APPNAME, "XWordGiver" IDS_CANTLOAD, "I couldn't load the file." IDS_WRONGFORMAT, "This format is wrong." @@ -1536,7 +1541,7 @@ STRINGTABLE IDS_CANTACCEL, "I couldn't load the accelerators." IDS_CANTREGWND, "I couldn't register the window classes." IDS_CANTMAKEWND, "I couldn't create the window." - IDS_APPTITLE, "XWordGiver ver.5.0.3 - %s" + IDS_APPTITLE, "XWordGiver ver.5.0.4 - %s" IDS_MADEPROBLEM, "I have generated a crossword.\n\nCalculation time: %u.%u[sec]" IDS_CANTMAKEPROBLEM, "I couldn't create the puzzle.\n\nPlease confirm the dictionary, the block pattern, and the policy.\n\nCalculation time: %u.%u[sec]" IDS_ENTERINT, "Please enter an integer between 2 and 256." @@ -1555,7 +1560,7 @@ STRINGTABLE IDS_NOWSOLVING, "Calculating...(%u.%u sec) - %u Retrial(s)" IDS_HLINE, "----------------------------" IDS_MONOFONT, "MS ゴシック" - IDS_APPTITLE2, "XWordGiver ver.5.0.3 (%s) - %s" + IDS_APPTITLE2, "XWordGiver ver.5.0.4 (%s) - %s" IDS_CROSSWORD, "Crossword" IDS_ANSWER, "Answer: " IDS_SETPORTRAIT, "Please use the portrait paper to print." @@ -1619,8 +1624,8 @@ STRINGTABLE IDS_VINPUT, "Vert" IDS_ABC, "ABC" IDS_DICTIONARY, "Dict" - IDS_APPINFO, "XWordGiver ver.5.0.3" - IDS_APPINFO2, "XWordGiver ver.5.0.3 (%s)" + IDS_APPINFO, "XWordGiver ver.5.0.4" + IDS_APPINFO2, "XWordGiver ver.5.0.4 (%s)" IDS_HINPUT2, "H\no\nr\nz" IDS_VINPUT2, "V\ne\nr\nt" IDS_KANA, "Kana" diff --git a/lang/ja_JP.rc b/lang/ja_JP.rc index 58d4366..626e247 100644 --- a/lang/ja_JP.rc +++ b/lang/ja_JP.rc @@ -1,4 +1,4 @@ -// This file is automatically generated by RisohEditor. +// This file is automatically generated by RisohEditor 5.7.5. // † <-- This dagger helps UTF-8 detection. #pragma code_page(65001) // UTF-8 @@ -680,16 +680,20 @@ FONT 9, "MS UI Gothic" PUSHBUTTON "", psh8, 140, 94, 15, 15, BS_OWNERDRAW RTEXT "二重マスの色(&3):", -1, 172, 96, 55, 12 PUSHBUTTON "", psh9, 232, 94, 15, 15, BS_OWNERDRAW - LTEXT "セル文字の大きさ(&P):", -1, 5, 124, 65, 12 - EDITTEXT edt4, 72, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL - CONTROL "", scr1, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 94, 122, 12, 20 - LTEXT "%", -1, 112, 124, 14, 12 - PUSHBUTTON "リセット", psh10, 70, 140, 35, 14 - LTEXT "小さい文字の大きさ(&L):", -1, 137, 124, 70, 12 - EDITTEXT edt5, 209, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL - CONTROL "", scr2, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 232, 122, 12, 20 - LTEXT "%", -1, 248, 124, 14, 12 - PUSHBUTTON "リセット", psh11, 209, 140, 35, 14 + RTEXT "セル文字の大きさ(&P):", -1, 5, 124, 67, 12 + EDITTEXT edt4, 75, 122, 33, 14, ES_NUMBER | ES_AUTOHSCROLL + CONTROL "", scr1, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 98, 122, 12, 20 + LTEXT "%", -1, 114, 124, 10, 12 + PUSHBUTTON "リセット", psh10, 129, 123, 35, 14 + RTEXT "小さい文字の大きさ(&L):", -1, 5, 145, 67, 12 + EDITTEXT edt5, 75, 143, 33, 14, ES_NUMBER | ES_AUTOHSCROLL + CONTROL "", scr2, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 98, 143, 12, 20 + LTEXT "%", -1, 114, 145, 10, 12 + PUSHBUTTON "リセット", psh11, 129, 145, 35, 14 + RTEXT "線の幅(&Z):", -1, 170, 127, 44, 12 + EDITTEXT edt6, 218, 125, 36, 14, ES_AUTOHSCROLL + CONTROL "", scr3, "msctls_updown32", UDS_ARROWKEYS | UDS_AUTOBUDDY | UDS_ALIGNRIGHT, 246, 127, 12, 20 + LTEXT "pt", -1, 259, 127, 11, 12 LTEXT "黒マス画像(&M):", -1, 5, 166, 52, 11 COMBOBOX cmb1, 60, 165, 102, 300, CBS_HASSTRINGS | CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP LTEXT "BLOCKフォルダに好きな画像を放り込んで下さい。", -1, 10, 182, 150, 21 @@ -1309,10 +1313,10 @@ STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION | WS_THICKFRAME | FONT 9, "MS UI Gothic" { LTEXT "下のリストから黒マスパターンをお選び下さい。", stc1, 5, 2, 220, 12 - AUTORADIOBUTTON "大(&Large)", rad1, 5, 15, 45, 16, WS_TABSTOP | WS_GROUP + AUTORADIOBUTTON "大(&Large)", rad1, 5, 15, 45, 16, WS_GROUP | WS_TABSTOP AUTORADIOBUTTON "中(&Medium)", rad2, 55, 15, 50, 16, WS_TABSTOP AUTORADIOBUTTON "小(&Small)", rad3, 110, 15, 50, 16, WS_TABSTOP - AUTORADIOBUTTON "横長(&H)", rad4, 175, 15, 40, 16, WS_TABSTOP | WS_GROUP + AUTORADIOBUTTON "横長(&H)", rad4, 175, 15, 40, 16, WS_GROUP | WS_TABSTOP AUTORADIOBUTTON "縦長(&V)", rad5, 220, 15, 40, 16, WS_TABSTOP AUTORADIOBUTTON "正方形(&Q)", rad6, 275, 15, 55, 16, WS_TABSTOP LTEXT "リスト(&T):", stc2, 8, 37, 47, 12 @@ -1487,7 +1491,7 @@ FONT 9, "MS UI Gothic" LTEXT "二重マス単語(&W):", -1, 5, 5, 128, 12 EDITTEXT edt1, 5, 20, 205, 14 LTEXT "単語を入力、または下の候補から選択して下さい:", stc1, 5, 40, 205, 14 - LISTBOX lst1, 5, 60, 205, 100, LBS_MULTICOLUMN | LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS | WS_HSCROLL | WS_VSCROLL | WS_TABSTOP + LISTBOX lst1, 5, 60, 205, 100, LBS_MULTICOLUMN | LBS_NOINTEGRALHEIGHT | LBS_HASSTRINGS | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP PUSHBUTTON "←前の単語(&P)", psh1, 5, 165, 100, 17 PUSHBUTTON "次の単語(&N)→", psh2, 110, 165, 100, 17 PUSHBUTTON "別の配置(&A)", psh3, 110, 185, 100, 17 @@ -1498,10 +1502,11 @@ FONT 9, "MS UI Gothic" // RT_VERSION 1 VERSIONINFO -FILEVERSION 5, 0, 3, 0 -PRODUCTVERSION 5, 0, 3, 0 +FILEVERSION 5, 0, 4, 0 +PRODUCTVERSION 5, 0, 4, 0 FILEOS 0x40004 FILETYPE 0x1 +FILESUBTYPE 0x0 { BLOCK "StringFileInfo" { @@ -1509,10 +1514,10 @@ FILETYPE 0x1 { VALUE "CompanyName", "片山博文MZ\0" VALUE "FileDescription", "クロスワード ギバー\0" - VALUE "FileVersion", "5.0.3\0" + VALUE "FileVersion", "5.0.4\0" VALUE "LegalCopyright", "Copyright (C) 2012-2020 片山博文MZ. All rights reserved.\0" VALUE "ProductName", "XWordGiver\0" - VALUE "ProductVersion", "5.0.3\0" + VALUE "ProductVersion", "5.0.4\0" } } BLOCK "VarFileInfo" @@ -1526,7 +1531,7 @@ FILETYPE 0x1 STRINGTABLE { - IDS_VERSION, "クロスワード ギバー ver.5.0.3\nby 片山博文MZ" + IDS_VERSION, "クロスワード ギバー ver.5.0.4\nby 片山博文MZ" IDS_APPNAME, "クロスワード ギバー" IDS_CANTLOAD, "ファイルが読み込めません。" IDS_WRONGFORMAT, "形式が間違っています。" @@ -1539,7 +1544,7 @@ STRINGTABLE IDS_CANTACCEL, "アクセラレータの読み込みに失敗しました。" IDS_CANTREGWND, "ウィンドウクラスの登録に失敗しました。" IDS_CANTMAKEWND, "ウィンドウ作成に失敗しました。" - IDS_APPTITLE, "クロスワード ギバー ver.5.0.3 - %s" + IDS_APPTITLE, "クロスワード ギバー ver.5.0.4 - %s" IDS_MADEPROBLEM, "問題を作成しました。\n\n計算時間: %u.%u[秒]" IDS_CANTMAKEPROBLEM, "問題を作成できませんでした。\n\n辞書の設定や黒マスの配置やルールを確認して下さい。\n\n計算時間: %u.%u[秒]" IDS_ENTERINT, "2以上256以下の整数を入力して下さい。" @@ -1558,7 +1563,7 @@ STRINGTABLE IDS_NOWSOLVING, "計算しています...(%u.%u秒経過)- %u 回目の再試行" IDS_HLINE, "――――――――――――――" IDS_MONOFONT, "MS ゴシック" - IDS_APPTITLE2, "クロスワード ギバー ver.5.0.3 (%s) - %s" + IDS_APPTITLE2, "クロスワード ギバー ver.5.0.4 (%s) - %s" IDS_CROSSWORD, "クロスワード" IDS_ANSWER, "答え:" IDS_SETPORTRAIT, "縦長の用紙設定で印刷して下さい。" @@ -1622,8 +1627,8 @@ STRINGTABLE IDS_VINPUT, "タテ入力" IDS_ABC, "英字" IDS_DICTIONARY, "辞書" - IDS_APPINFO, "クロスワード ギバー ver.5.0.3" - IDS_APPINFO2, "クロスワード ギバー ver.5.0.3 (%s)" + IDS_APPINFO, "クロスワード ギバー ver.5.0.4" + IDS_APPINFO2, "クロスワード ギバー ver.5.0.4 (%s)" IDS_HINPUT2, "ヨコ\n入\n力" IDS_VINPUT2, "タテ\n入\n力" IDS_KANA, "カナ" diff --git a/resource.h b/resource.h index cbaa7c8..d80b51c 100644 --- a/resource.h +++ b/resource.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ Compatible -// This file is automatically generated by RisohEditor. +// This file is automatically generated by RisohEditor 5.7.5. // XWordGiver_res.rc #define IDB_FROMWORDS 100