コード例 #1
0
ファイル: RConData.cpp プロジェクト: davgit/ConEmu
// returns count of *lines* were copied to pChar/pAttr
// nWidth & nHeight - dimension which VCon want to display
UINT CRConData::GetConsoleData(wchar_t* rpChar, CharAttr* rpAttr, UINT anWidth, UINT anHeight,
	wchar_t wSetChar, CharAttr lcaDef, CharAttr *lcaTable, CharAttr *lcaTableExt,
	bool bFade, bool bExtendFonts)
{
	TODO("Во время ресайза консоль может подглючивать - отдает не то что нужно...");
	//_ASSERTE(*con.pConChar!=ucBoxDblVert);
	UINT nYMax = std::min(anHeight,nHeight);

	MFileMapping<AnnotationHeader>& TrueMap = mp_RCon->m_TrueColorerMap;
	const AnnotationInfo *pTrueData = mp_RCon->mp_TrueColorerData;

	wchar_t  *pszDst = rpChar;
	CharAttr *pcaDst = rpAttr;

	wchar_t  *pszSrc = pConChar;
	WORD     *pnSrc = pConAttr;

	bool lbIsFar = mp_RCon->isFar();

	// Т.к. есть блокировка (csData), то con.pConChar и con.pConAttr
	// не должны меняться во время выполнения этой функции
	const wchar_t* const pszSrcStart = pConChar;
	WORD* const pnSrcStart = pConAttr;
	size_t nSrcCells = (nWidth * nHeight);

	Assert(pszSrcStart==pszSrc && pnSrcStart==pnSrc);

	const AnnotationInfo *pcolSrc = NULL;
	const AnnotationInfo *pcolEnd = NULL;
	BOOL bUseColorData = FALSE, bStartUseColorData = FALSE;

	if (gpSet->isTrueColorer && TrueMap.IsValid() && pTrueData)
	{
		pcolSrc = pTrueData;
		pcolEnd = pTrueData + TrueMap.Ptr()->bufferSize;
		bUseColorData = TRUE;
		WARNING("Если far/w - pcolSrc нужно поднять вверх, bStartUseColorData=TRUE, bUseColorData=FALSE");
		if (m_sbi.dwSize.Y > (int)nHeight) // con.bBufferHeight
		{
			int lnShiftRows = (m_sbi.dwSize.Y - anHeight) - m_sbi.srWindow.Top;

			if (lnShiftRows > 0)
			{
				#ifdef _DEBUG
				if (nWidth != (m_sbi.srWindow.Right - m_sbi.srWindow.Left + 1))
				{
					_ASSERTE(nWidth == (m_sbi.srWindow.Right - m_sbi.srWindow.Left + 1));
				}
				#endif

				pcolSrc -= (lnShiftRows * nWidth);
				DEBUGSTRTRUEMOD(L"TrueMod skipped due to nShiftRows, bStartUseColorData was set");
				bUseColorData = FALSE;
				bStartUseColorData = TRUE;
			}
			#ifdef _DEBUG
			else if (lnShiftRows < 0)
			{
				//_ASSERTE(nShiftRows>=0);
				wchar_t szLog[200];
				swprintf_c(szLog, L"!!! CRealBuffer::GetConsoleData !!! "
					L"nShiftRows=%i nWidth=%i nHeight=%i Rect={%i,%i}-{%i,%i} Buf={%i,%i}",
					lnShiftRows, anWidth, anHeight,
					m_sbi.srWindow.Left, m_sbi.srWindow.Top, m_sbi.srWindow.Right, m_sbi.srWindow.Bottom,
					m_sbi.dwSize.X, m_sbi.dwSize.Y);
				mp_RCon->LogString(szLog);
			}
			#endif
		}
	}
	else
	{
		DEBUGSTRTRUEMOD(L"TrueMod is not allowed here");
	}

	DWORD cbDstLineSize = anWidth * 2;
	DWORD cnSrcLineLen = nWidth;
	DWORD cbSrcLineSize = cnSrcLineLen * 2;

	#ifdef _DEBUG
	if (nWidth != m_sbi.dwSize.X)
	{
		_ASSERTE(nWidth == m_sbi.dwSize.X); // Scrolling?
	}
	#endif

	DWORD cbLineSize = std::min(cbDstLineSize,cbSrcLineSize);
	int nCharsLeft = (anWidth > nWidth) ? (anWidth - nWidth) : 0;
	//int nY, nX;
	UINT nExtendStartsY = 0;
	//int nPrevDlgBorder = -1;

	// Собственно данные
	for (UINT nY = 0; nY < nYMax; nY++)
	{
		if (nY == nExtendStartsY)
			lcaTable = lcaTableExt;

		// Текст
		memmove(pszDst, pszSrc, cbLineSize);

		if (nCharsLeft > 0)
			wmemset(pszDst+cnSrcLineLen, wSetChar, nCharsLeft);

		// Console text colors (Fg,Bg)
		BYTE PalIndex = MAKECONCOLOR(7,0);

		// While console is in recreate (shutdown console, startup new root)
		// it's shown using monochrome (gray on black)
		bool bForceMono = (mp_RCon->mn_InRecreate != 0);

		bool has_rowid = (cnSrcLineLen >= ROWID_USED_CELLS) && (GetRowIdFromAttrs(pnSrc) != 0);
		if (!has_rowid && cnSrcLineLen >= ROWID_USED_CELLS) {
			_ASSERTE(!(pnSrc[0]&COMMON_LVB_REVERSE_VIDEO));
			_ASSERTE(!(pnSrc[1]&COMMON_LVB_REVERSE_VIDEO));
			_ASSERTE(!(pnSrc[2]&COMMON_LVB_REVERSE_VIDEO));
			_ASSERTE(!(pnSrc[3]&COMMON_LVB_REVERSE_VIDEO));
		}

		int iTail = cnSrcLineLen;
		wchar_t* pch = pszDst;
		for (UINT nX = 0;
			// Don't forget to advance same pointers at the and if bPair
			iTail-- > 0; nX++, pnSrc++, pcolSrc++, pch++)
		{
			CharAttr& lca = pcaDst[nX];
			bool hasTrueColor = false;
			bool hasFont = false;
			bool inversed = false;
			bool is_rowid = has_rowid && (nX < ROWID_USED_CELLS);

			// If not "mono" we need only lower byte with color indexes
			if (!bForceMono)
			{
				inversed = !is_rowid && ((*pnSrc) & COMMON_LVB_REVERSE_VIDEO);
				if (inversed)
					PalIndex = MAKECONCOLOR(CONBACKCOLOR(*pnSrc), CONFORECOLOR(*pnSrc)); // Inverse
				else
					PalIndex = ((*pnSrc) & 0xFF);
			}
			TODO("OPTIMIZE: lca = lcaTable[PalIndex];");
			lca = lcaTable[PalIndex];
			TODO("OPTIMIZE: вынести проверку bExtendColors за циклы");

			lca.ConAttr = *pnSrc;

			bool bPair = (iTail > 0);
			ucs32 wwch = ucs32_from_wchar(pch, bPair);
			_ASSERTE(wwch >= 0);

			// Colorer & Far - TrueMod
			TODO("OPTIMIZE: вынести проверку bUseColorData за циклы");

			if (bStartUseColorData && !bUseColorData)
			{
				// В случае "far /w" буфер цвета может начаться НИЖЕ верхней видимой границы,
				// если буфер немного прокручен вверх
				if (pcolSrc >= mp_RCon->mp_TrueColorerData)
				{
					DEBUGSTRTRUEMOD(L"TrueMod forced back due bStartUseColorData");
					bUseColorData = TRUE;
				}
			}

			if (bUseColorData)
			{
				if (pcolSrc >= pcolEnd)
				{
					DEBUGSTRTRUEMOD(L"TrueMod stopped - out of buffer");
					bUseColorData = FALSE;
				}
				else
				{
					if (pcolSrc->style & AI_STYLE_REVERSE)
						inversed = true;

					if (pcolSrc->fg_valid)
					{
						hasTrueColor = true;
						hasFont = true;
						lca.nFontIndex = fnt_Normal; //bold/italic/underline will be set below

						unsigned fore = bFade ? gpSet->GetFadeColor(pcolSrc->fg_color) : pcolSrc->fg_color;
						unsigned back = pcolSrc->bk_valid
							? (bFade ? gpSet->GetFadeColor(pcolSrc->bk_color) : pcolSrc->bk_color)
							: (lca.crBackColor);
						lca.crForeColor = inversed ? back : fore;
						lca.crBackColor = inversed ? fore : back;
					}
					else if (pcolSrc->bk_valid)
					{
						hasTrueColor = true;
						hasFont = true;
						lca.nFontIndex = fnt_Normal; //bold/italic/underline will be set below
						unsigned back = bFade ? gpSet->GetFadeColor(pcolSrc->bk_color) : pcolSrc->bk_color;;
						if (inversed)
							lca.crForeColor = back;
						else
							lca.crBackColor = back;
					}

					// nFontIndex: 0 - normal, 1 - bold, 2 - italic, 3 - bold&italic,..., 4 - underline, ...
					if (pcolSrc->style)
					{
						hasFont = true;
						lca.nFontIndex = pcolSrc->style & fnt_StdFontMask;
					}
				}
			}

			if (!hasFont && !is_rowid && ((*pnSrc) & COMMON_LVB_UNDERSCORE))
			{
				lca.nFontIndex = fnt_Underline;
			}

			switch (get_wcwidth(wwch))
			{
			case 0:
				lca.Flags2 |= CharAttr2_Combining;
				break;
			case 2:
				lca.Flags2 |= CharAttr2_DoubleSpaced;
				break;
			}

			if (bPair)
			{
				lca.Flags2 |= CharAttr2_Surrogate;
				CharAttr& lca2 = pcaDst[nX+1];
				lca2 = lca;
				lca2.Flags2 = (lca.Flags2 & ~(CharAttr2_Combining)) | CharAttr2_NonSpacing;
				// advance +1 character
				nX++; pnSrc++; pcolSrc++; pch++; iTail--;
			}
		}

		// Залить остаток (если запрошен больший участок, чем есть консоль
		for (UINT nX = cnSrcLineLen; nX < anWidth; nX++)
		{
			pcaDst[nX] = lcaDef;
		}

		// Far2 показывает красный 'A' в правом нижнем углу консоли
		// Этот ярко красный цвет фона может попасть в Extend Font Colors
		if (bExtendFonts && ((nY+1) == nYMax) && lbIsFar
			&& (pszDst[anWidth-1] == L'A') && (PalIndex == 0xCF))
		{
			// Вернуть "родной" цвет и шрифт
			pcaDst[anWidth-1] = lcaTable[PalIndex];
		}

		// Next line
		pszDst += anWidth;
		pcaDst += anWidth;
		pszSrc += cnSrcLineLen;
	}

	#ifndef __GNUC__
	UNREFERENCED_PARAMETER(pszSrcStart);
	UNREFERENCED_PARAMETER(pnSrcStart);
	#endif
	UNREFERENCED_PARAMETER(nSrcCells);

	return nYMax;
}
コード例 #2
0
ファイル: RConData.cpp プロジェクト: 2asoft/ConEmu
// returns count of *lines* were copied to pChar/pAttr
// nWidth & nHeight - dimension which VCon want to display
UINT CRConData::GetConsoleData(wchar_t* rpChar, CharAttr* rpAttr, UINT anWidth, UINT anHeight,
	wchar_t wSetChar, CharAttr lcaDef, CharAttr *lcaTable, CharAttr *lcaTableExt,
	bool bFade, bool bExtendColors, BYTE nExtendColorIdx, bool bExtendFonts)
{
	TODO("Во время ресайза консоль может подглючивать - отдает не то что нужно...");
	//_ASSERTE(*con.pConChar!=ucBoxDblVert);
	UINT nYMax = klMin(anHeight,nHeight);

	MFileMapping<AnnotationHeader>& TrueMap = mp_RCon->m_TrueColorerMap;
	const AnnotationInfo *pTrueData = mp_RCon->mp_TrueColorerData;

	wchar_t  *pszDst = rpChar;
	CharAttr *pcaDst = rpAttr;

	wchar_t  *pszSrc = pConChar;
	WORD     *pnSrc = pConAttr;

	bool lbIsFar = mp_RCon->isFar();

	// Т.к. есть блокировка (csData), то con.pConChar и con.pConAttr
	// не должны меняться во время выполнения этой функции
	const wchar_t* const pszSrcStart = pConChar;
	WORD* const pnSrcStart = pConAttr;
	size_t nSrcCells = (nWidth * nHeight);

	Assert(pszSrcStart==pszSrc && pnSrcStart==pnSrc);

	const AnnotationInfo *pcolSrc = NULL;
	const AnnotationInfo *pcolEnd = NULL;
	BOOL bUseColorData = FALSE, bStartUseColorData = FALSE;

	if (gpSet->isTrueColorer && TrueMap.IsValid() && pTrueData)
	{
		pcolSrc = pTrueData;
		pcolEnd = pTrueData + TrueMap.Ptr()->bufferSize;
		bUseColorData = TRUE;
		WARNING("Если far/w - pcolSrc нужно поднять вверх, bStartUseColorData=TRUE, bUseColorData=FALSE");
		if (m_sbi.dwSize.Y > (int)nHeight) // con.bBufferHeight
		{
			int lnShiftRows = (m_sbi.dwSize.Y - anHeight) - m_sbi.srWindow.Top;

			if (lnShiftRows > 0)
			{
				#ifdef _DEBUG
				if (nWidth != (m_sbi.srWindow.Right - m_sbi.srWindow.Left + 1))
				{
					_ASSERTE(nWidth == (m_sbi.srWindow.Right - m_sbi.srWindow.Left + 1));
				}
				#endif

				pcolSrc -= (lnShiftRows * nWidth);
				DEBUGSTRTRUEMOD(L"TrueMod skipped due to nShiftRows, bStartUseColorData was set");
				bUseColorData = FALSE;
				bStartUseColorData = TRUE;
			}
			#ifdef _DEBUG
			else if (lnShiftRows < 0)
			{
				//_ASSERTE(nShiftRows>=0);
				wchar_t szLog[200];
				_wsprintf(szLog, SKIPCOUNT(szLog) L"!!! CRealBuffer::GetConsoleData !!! "
					L"nShiftRows=%i nWidth=%i nHeight=%i Rect={%i,%i}-{%i,%i} Buf={%i,%i}",
					lnShiftRows, anWidth, anHeight,
					m_sbi.srWindow.Left, m_sbi.srWindow.Top, m_sbi.srWindow.Right, m_sbi.srWindow.Bottom,
					m_sbi.dwSize.X, m_sbi.dwSize.Y);
				mp_RCon->LogString(szLog);
			}
			#endif
		}
	}
	else
	{
		DEBUGSTRTRUEMOD(L"TrueMod is not allowed here");
	}

	DWORD cbDstLineSize = anWidth * 2;
	DWORD cnSrcLineLen = nWidth;
	DWORD cbSrcLineSize = cnSrcLineLen * 2;

	#ifdef _DEBUG
	if (nWidth != m_sbi.dwSize.X)
	{
		_ASSERTE(nWidth == m_sbi.dwSize.X); // Scrolling?
	}
	#endif

	DWORD cbLineSize = min(cbDstLineSize,cbSrcLineSize);
	int nCharsLeft = (anWidth > nWidth) ? (anWidth - nWidth) : 0;
	//int nY, nX;
	//120331 - Нехорошо заменять на "черный" с самого начала
	BYTE attrBackLast = 0;
	UINT nExtendStartsY = 0;
	//int nPrevDlgBorder = -1;

	bool lbStoreBackLast = false;
	if (bExtendColors)
	{
		BYTE FirstBackAttr = lcaTable[(*pnSrc) & 0xFF].nBackIdx;
		if (FirstBackAttr != nExtendColorIdx)
			attrBackLast = FirstBackAttr;

		const CEFAR_INFO_MAPPING* pFarInfo = lbIsFar ? mp_RCon->GetFarInfo() : NULL;
		if (pFarInfo)
		{
			// Если в качестве цвета "расширения" выбран цвет панелей - значит
			// пользователь просто настроил "другую" палитру для панелей фара.
			// К сожалению, таким образом нельзя заменить только цвета для элемента под курсором.
			if (CONBACKCOLOR(pFarInfo->nFarColors[col_PanelText]) != nExtendColorIdx)
				lbStoreBackLast = true;
			else
				attrBackLast = FirstBackAttr;

			if (pFarInfo->FarInterfaceSettings.AlwaysShowMenuBar || mp_RCon->isEditor() || mp_RCon->isViewer())
				nExtendStartsY = 1; // пропустить обработку строки меню
		}
		else
		{
			lbStoreBackLast = true;
		}
	}

	// Собственно данные
	for (UINT nY = 0; nY < nYMax; nY++)
	{
		if (nY == nExtendStartsY)
			lcaTable = lcaTableExt;

		// Текст
		memmove(pszDst, pszSrc, cbLineSize);

		if (nCharsLeft > 0)
			wmemset(pszDst+cnSrcLineLen, wSetChar, nCharsLeft);

		// Console text colors (Fg,Bg)
		BYTE PalIndex = MAKECONCOLOR(7,0);

		// While console is in recreate (shutdown console, startup new root)
		// it's shown using monochrome (gray on black)
		bool bForceMono = (mp_RCon->mn_InRecreate != 0);

		int iTail = cnSrcLineLen;
		wchar_t* pch = pszDst;
		for (UINT nX = 0;
			// Don't forget to advance same pointers at the and if bPair
			iTail-- > 0; nX++, pnSrc++, pcolSrc++, pch++)
		{
			CharAttr& lca = pcaDst[nX];
			bool hasTrueColor = false;
			bool hasFont = false;

			// If not "mono" we need only lower byte with color indexes
			if (!bForceMono)
			{
				if (((*pnSrc) & COMMON_LVB_REVERSE_VIDEO) && (((*pnSrc) & CHANGED_CONATTR) == COMMON_LVB_REVERSE_VIDEO))
					PalIndex = MAKECONCOLOR(CONBACKCOLOR(*pnSrc), CONFORECOLOR(*pnSrc)); // Inverse
				else
					PalIndex = ((*pnSrc) & 0xFF);
			}
			TODO("OPTIMIZE: lca = lcaTable[PalIndex];");
			lca = lcaTable[PalIndex];
			TODO("OPTIMIZE: вынести проверку bExtendColors за циклы");

			bool bPair = (iTail > 0);
			ucs32 wwch = ucs32_from_wchar(pch, bPair);
			_ASSERTE(wwch >= 0);

			// Colorer & Far - TrueMod
			TODO("OPTIMIZE: вынести проверку bUseColorData за циклы");

			if (bStartUseColorData && !bUseColorData)
			{
				// В случае "far /w" буфер цвета может начаться НИЖЕ верхней видимой границы,
				// если буфер немного прокручен вверх
				if (pcolSrc >= mp_RCon->mp_TrueColorerData)
				{
					DEBUGSTRTRUEMOD(L"TrueMod forced back due bStartUseColorData");
					bUseColorData = TRUE;
				}
			}

			if (bUseColorData)
			{
				if (pcolSrc >= pcolEnd)
				{
					DEBUGSTRTRUEMOD(L"TrueMod stopped - out of buffer");
					bUseColorData = FALSE;
				}
				else
				{
					TODO("OPTIMIZE: доступ к битовым полям тяжело идет...");

					if (pcolSrc->fg_valid)
					{
						hasTrueColor = true;
						hasFont = true;
						lca.nFontIndex = fnt_Normal; //bold/italic/underline will be set below
						lca.crForeColor = bFade ? gpSet->GetFadeColor(pcolSrc->fg_color) : pcolSrc->fg_color;

						if (pcolSrc->bk_valid)
							lca.crBackColor = bFade ? gpSet->GetFadeColor(pcolSrc->bk_color) : pcolSrc->bk_color;
					}
					else if (pcolSrc->bk_valid)
					{
						hasTrueColor = true;
						hasFont = true;
						lca.nFontIndex = fnt_Normal; //bold/italic/underline will be set below
						lca.crBackColor = bFade ? gpSet->GetFadeColor(pcolSrc->bk_color) : pcolSrc->bk_color;
					}

					// nFontIndex: 0 - normal, 1 - bold, 2 - italic, 3 - bold&italic,..., 4 - underline, ...
					if (pcolSrc->style)
					{
						hasFont = true;
						lca.nFontIndex = pcolSrc->style & fnt_StdFontMask;
					}
				}
			}

			if (!hasFont
				&& ((*pnSrc) & COMMON_LVB_UNDERSCORE)
				&& ((nX >= ROWID_USED_CELLS) || !((*pnSrc) & (CHANGED_CONATTR & ~COMMON_LVB_UNDERSCORE)))
				)
			{
				lca.nFontIndex = fnt_Underline;
			}

			if (!hasTrueColor && bExtendColors && (nY >= nExtendStartsY))
			{
				if (lca.nBackIdx == nExtendColorIdx)
				{
					// Have to change the color to adjacent(?) cell
					lca.nBackIdx = attrBackLast;
					// For the background nExtendColorIdx we use upper
					// palette range for text: 16..31 instead of 0..15
					lca.nForeIdx += 0x10;
					lca.crForeColor = lca.crOrigForeColor = mp_RCon->mp_Palette->m_Colors[lca.nForeIdx];
					lca.crBackColor = lca.crOrigBackColor = mp_RCon->mp_Palette->m_Colors[lca.nBackIdx];
				}
				else if (lbStoreBackLast)
				{
					// Remember last "normal" background
					attrBackLast = lca.nBackIdx;
				}
			}

			switch (get_wcwidth(wwch))
			{
			case 0:
				lca.Flags2 |= CharAttr2_Combining;
				break;
			case 2:
				lca.Flags2 |= CharAttr2_DoubleSpaced;
				break;
			}

			if (bPair)
			{
				lca.Flags2 |= CharAttr2_Surrogate;
				CharAttr& lca2 = pcaDst[nX+1];
				lca2 = lca;
				lca2.Flags2 = (lca.Flags2 & ~(CharAttr2_Combining)) | CharAttr2_NonSpacing;
				// advance +1 character
				nX++; pnSrc++; pcolSrc++; pch++; iTail--;
			}
		}

		// Залить остаток (если запрошен больший участок, чем есть консоль
		for (UINT nX = cnSrcLineLen; nX < anWidth; nX++)
		{
			pcaDst[nX] = lcaDef;
		}

		// Far2 показывает красный 'A' в правом нижнем углу консоли
		// Этот ярко красный цвет фона может попасть в Extend Font Colors
		if (bExtendFonts && ((nY+1) == nYMax) && lbIsFar
			&& (pszDst[anWidth-1] == L'A') && (PalIndex == 0xCF))
		{
			// Вернуть "родной" цвет и шрифт
			pcaDst[anWidth-1] = lcaTable[PalIndex];
		}

		// Next line
		pszDst += anWidth;
		pcaDst += anWidth;
		pszSrc += cnSrcLineLen;
	}

	#ifndef __GNUC__
	UNREFERENCED_PARAMETER(pszSrcStart);
	UNREFERENCED_PARAMETER(pnSrcStart);
	#endif
	UNREFERENCED_PARAMETER(nSrcCells);

	return nYMax;
}
コード例 #3
0
ファイル: VConText.cpp プロジェクト: Maximus5/ConEmu
bool CVConLine::ParseLine(bool abForce, unsigned anTextWidth, unsigned anFontWidth, unsigned anRow, wchar_t* apConCharLine, CharAttr* apConAttrLine, const wchar_t* const ConCharLine2, const CharAttr* const ConAttrLine2)
{
	const bool bNeedAlloc = (MaxBufferSize < anTextWidth);
	TextWidth = anTextWidth;
	FontWidth = anFontWidth;
	row = anRow;
	ConCharLine = apConCharLine;
	ConAttrLine = apConAttrLine;
	PartsCount = 0;

	NextDialog = true;
	NextDialogX = 0;
	CurDialogX1 = CurDialogX2 = CurDialogI = 0;
	CurDialogFlags = 0;

	isFilePanel = (mn_DialogAllFlags & (FR_LEFTPANEL|FR_RIGHTPANEL|FR_FULLPANEL)) != 0;

	//TODO: Extend to other old-scool managers?
	isFixFrameCoord = mp_RCon->isFar();

	if (bNeedAlloc && !AllocateMemory())
		return false;

	const bool bEnhanceGraphics = gpSet->isEnhanceGraphics;
	const bool bUseAlternativeFont = _bool(gpSet->isFixFarBorders);

	for (unsigned j = 0; j < TextWidth;)
	{
		bool bPair = ((j+1) < TextWidth);
		ucs32 wc = ucs32_from_wchar(ConCharLine+j, bPair);
		unsigned j2 = j + (bPair ? 2 : 1);

		const CharAttr attr = ConAttrLine[j];

		VConTextPart* p = TextParts+(PartsCount++);

		//TODO: DBCS cell number, it may differ from j
		p->Init(j, j, this);

		// Process Far Dialogs to justify rectangles and frames
		TextPartFlags dlgBorder = j ? isDialogBorderCoord(j) : TRF_None;

		/* *** Now we split our text line into parts with characters one "family" *** */

		_ASSERTE(p->Flags == TRF_None);

		if (dlgBorder)
		{
			p->Flags = dlgBorder | TRF_SizeFixed
				| (isCharBorderVertical(wc) ? TRF_TextPseudograph : TRF_None)
				//| (isCharSpaceSingle(wc) ? TRF_TextSpacing : TRF_None)
				| ((bUseAlternativeFont && isCharAltFont(wc)) ? TRF_TextAlternative : TRF_None)
				| ((bEnhanceGraphics && isCharProgress(wc)) ? TRF_TextProgress : TRF_None)
				;
		}
		else if (isCharSpaceSingle(wc))
		{
			// CJK Double-width space will be processed under isCharCJK
			p->Flags = TRF_TextSpacing;
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharSpaceSingle(ConCharLine[j2]))
				j2++;
		}
		else if (isCharSeparate(wc))
		{
			p->Flags = TRF_TextSeparate;
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharSeparate(ConCharLine[j2]))
				j2++;
		}
		// isCharProgress must be checked before isCharScroll!
		else if (bEnhanceGraphics && isCharProgress(wc))
		{
			p->Flags = TRF_TextProgress
				| ((bUseAlternativeFont && isCharAltFont(wc)) ? TRF_TextAlternative : TRF_None)
				;
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharProgress(ConCharLine[j2]))
				j2++;
		}
		// isCharScroll has wider range than isCharProgress, and comes after it
		else if (bEnhanceGraphics && isCharScroll(wc))
		{
			p->Flags = TRF_TextScroll
				| ((bUseAlternativeFont && isCharAltFont(wc)) ? TRF_TextAlternative : TRF_None)
				;
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharScroll(ConCharLine[j2]))
				j2++;
		}
		else if (bEnhanceGraphics && isCharTriangles(wc))
		{
			p->Flags = TRF_TextTriangles;
		}
		// Miscellaneous borders
		else if (isCharPseudographics(wc))
		{
			// Processed separately from isCharAltFont, because last may cover larger range
			p->Flags = TRF_TextPseudograph;
			if (bUseAlternativeFont && isCharAltFont(wc))
			{
				p->Flags |= TRF_TextAlternative;
				wchar_t wc2;
				if (!bPair)
				while ((j2 < TextWidth) && (ConAttrLine[j2] == attr)
					&& isCharPseudographics((wc2=ConCharLine[j2]))
					&& (!bEnhanceGraphics || !isCharScroll(wc2))
					&& !isCharBorderVertical(wc2)
					&& isCharAltFont(wc2))
					j2++;
			}
			else
			{
				wchar_t wc2;
				if (!bPair)
				while ((j2 < TextWidth) && (ConAttrLine[j2] == attr)
					&& isCharPseudographics((wc2=ConCharLine[j2]))
					&& (!bEnhanceGraphics || !isCharScroll(wc2))
					&& !isCharBorderVertical(wc2)
					)
					j2++;
			}
		}
		else if (isCharCJK(wc)) // Double-width characters (CJK, etc.)
		{
			// Processed separately from isCharAltFont, because last may cover larger range
			p->Flags = TRF_TextCJK;
			if (bUseAlternativeFont && isCharAltFont(wc))
			{
				p->Flags |= TRF_TextAlternative;
				wchar_t wc2;
				if (!bPair)
				while ((j2 < TextWidth) && (ConAttrLine[j2] == attr)
					&& isCharCJK((wc2=ConCharLine[j2]))
					&& isCharAltFont(wc2))
					j2++;
			}
			else
			{
				if (!bPair)
				while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharCJK(ConCharLine[j2]))
					j2++;
			}
		}
		else if (bUseAlternativeFont && isCharAltFont(wc))
		{
			p->Flags = TRF_TextAlternative;
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr) && isCharScroll(ConCharLine[j2]))
				j2++;
		}
		else
		{
			p->Flags = TRF_TextNormal;
			wchar_t wc2;
			// That's more complicated as previous branches,
			// we must break on all chars mentioned above
			if (!bPair)
			while ((j2 < TextWidth) && (ConAttrLine[j2] == attr)
				&& !isCharSpaceSingle((wc2=ConCharLine[j2]))
				&& !isCharSeparate(wc2)
				&& !isCharProgress(wc2)
				&& !isCharScroll(wc2)
				&& !isCharPseudographics(wc2)
				&& (wc2 != L'}') // Far Manager Panels mark "file name is trimmed"
				&& !(bUseAlternativeFont && isCharAltFont(wc2))
				//TODO: RTL/LTR
				)
				j2++;
		}

		/* *** We shall prepare this token (default/initial widths must be set) *** */
		_ASSERTE(j2>j);
		p->SetLen(j2-j, FontWidth);

		#if 0
		TotalLineWidth += p->TotalWidth;
		MinLineWidth += p->MinWidth;
		#endif

		/* Next part */
		j = j2;
	}

	return true;
}