私は (C++ で) GUI のコードを書いていますが、今は行単位でのテキストの構成に関心があります。私が抱えている問題の 1 つは、コードが非常に長くなり、混乱を招くことです。テキスト プレゼンテーションに追加するすべてのオプションに対して、必要な関数の数が ^2 のシナリオに陥り始めています。 write はその 2 乗です。これに対処しようとして、特定の設計上の選択肢が出てきましたが、より良い方法、またはそれらの間の長所または短所の程度はわかりません。
フローが非常に似ている 2 つのメソッドがあります。つまり、同じ制約を考慮して同じオブジェクトを反復しますが、最終的にはこのフロー間で異なる操作を実行します。誰にとっても興味深いことに、メソッドはテキストをレンダリングし、テキストが他のオブジェクトの周りにラップされているか、単に行の終わりにあるためにテキストが行からオーバーフローしているかどうかをそれぞれ判断します。
これらの関数は、フローが異なる左、右、または中央のテキスト用にコピーして書き直す必要があるため、私が行うデザインの選択は 3 回繰り返されます。
基本的には、これらの異なるアクションを処理するための 2 つの別々の方法である、現在持っているものを継続することも、それらを 1 つの関数にマージすることもできます。テキストオーバーフロー。
これについて一般的に受け入れられている正しい方法はありますか?それ以外の場合、関係するトレードオフは何ですか?ある方法を他の方法よりも使用する必要があることを示す可能性のある兆候は何ですか? 私が見逃したことを行う他の方法はありますか?
私はこれを数回編集して理解しやすくしましたが、そうでない場合は、編集して説明できるようにいくつか質問してください. 2 つの異なるメソッドのソース コードを投稿することもできますが、それらは説明に時間がかかりすぎる多くの関数とオブジェクトを使用しています。
// 編集: ソースコード //
機能 1:
void GUITextLine::renderLeftShifted(const GUIRenderInfo& renderInfo) { if(m_renderLines.empty()) return;
Uint iL = 0; Array2t<float> renderCoords; renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[0].s_x; renderCoords.s_y = renderInfo.s_offset.s_y + m_y; float remainingPixelsInLine = m_renderLines[0].s_y; for (Uint iTO= 0;iTO != m_text.size();++iTO) { if(m_text[iTO].s_pixelWidth <= remainingPixelsInLine) { string preview = m_text[iTO].s_string; m_text[iTO].render(&renderCoords); remainingPixelsInLine -= m_text[iTO].s_pixelWidth; } else { FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData(); float characterWidth = 0; Uint iFirstCharacterOfRenderLine = 0; for(Uint iC = 0;;++iC) { if(iC == m_text[iTO].s_string.size()) { // wrap up string renderPart = m_text[iTO].s_string; renderPart.erase(iC, renderPart.size()); renderPart.erase(0, iFirstCharacterOfRenderLine); m_text[iTO].s_font->renderString(renderPart.c_str(), intData, &renderCoords); break; } characterWidth += m_text[iTO].s_font->getWidthOfGlyph(intData, m_text[iTO].s_string[iC]); if(characterWidth > remainingPixelsInLine) { // Can't push in the last character // No more space in this line // First though, render what we already have: string renderPart = m_text[iTO].s_string; renderPart.erase(iC, renderPart.size()); renderPart.erase(0, iFirstCharacterOfRenderLine); m_text[iTO].s_font->renderString(renderPart.c_str(), intData, &renderCoords); if(++iL != m_renderLines.size()) { remainingPixelsInLine = m_renderLines[iL].s_y; renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[iL].s_x; // Cool, so now try rendering this character again --iC; iFirstCharacterOfRenderLine = iC; characterWidth = 0; } else { // Quit break; } } } } } // Done! }
機能 2:
ベクトル GUITextLine::recalculateWrappingContraints_LeftShift() { m_pixelsOfCharacters = 0;
float pixelsRemaining = m_renderLines[0].s_y; Uint iRL = 0; // Go through every text object, fiting them into render lines for(Uint iTO = 0;iTO != m_text.size();++iTO) { // If an entire text object fits in a single line if(pixelsRemaining >= m_text[iTO].s_pixelWidth) { pixelsRemaining -= m_text[iTO].s_pixelWidth; m_pixelsOfCharacters += m_text[iTO].s_pixelWidth; } // Otherwise, character by character else { // Get some data now we don't get it every function call FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData(); for(Uint iC = 0; iC != m_text[iTO].s_string.size();++iC) { float characterWidth = m_text[iTO].s_font->getWidthOfGlyph(intData, '-'); if(characterWidth < pixelsRemaining) { pixelsRemaining -= characterWidth; m_pixelsOfCharacters += characterWidth; } else // End of render line! { m_pixelsOfWrapperCharacters += pixelsRemaining; // we might track how much wrapping px we use // If this is true, then we ran out of render lines before we ran out of text. Means we have some overflow to return if(++iRL == m_renderLines.size()) { return harvestOverflowFrom(iTO, iC); } else { pixelsRemaining = m_renderLines[iRL].s_y; } } } } } vector<GUIText> emptyOverflow; return emptyOverflow; }
したがって、基本的に render() は renderCoordinates をパラメーターとして取り、そこからレンダリングする必要がある場所のグローバル位置を取得します。calcWrappingConstraints は、割り当てられたスペースを超えるオブジェクト内のテキストの量を計算し、そのテキストを関数として返します。
m_renderLines は 2 つの float 構造の std::vector です。ここで、.s_x = レンダリングを開始できる場所、.s_y = レンダリングのためのスペースの大きさ - ではなく、'renderLine' の本質的な幅であり、終了場所ではありません。
m_text は、テキストの文字列と、スタイル、色、サイズなどのデータを含む GUIText オブジェクトの std::vector です。また、レンダリングを実行したり、グリフの幅を計算したりするフォント オブジェクトへの参照である s_font の下にも含まれています。
うまくいけば、これで問題が解決します。