Text position in the cell

Post Reply
Natter
Posts: 1279
Joined: Mon May 14, 2007 9:49 am

Text position in the cell

Post by Natter »

Hi,

By default, the xBrowse cell is set to be vertically centered. Can this be changed (:nDataStrAlign does not help) ?
User avatar
Antonio Linares
Site Admin
Posts: 42831
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 155 times
Been thanked: 119 times
Contact:

Re: Text position in the cell

Post by Antonio Linares »

You're right, the default vertical alignment in TXBrowse cells is centered, and nDataStrAlign primarily controls horizontal alignment and only influences vertical alignment for single-line text using the DT_VCENTER, DT_TOP, or DT_BOTTOM flags passed to the underlying DrawTextEx WinAPI function.

When text wraps (DT_WORDBREAK is used, which happens implicitly if nDataLines > 1 or if the text is too long for a single line), DT_VCENTER, DT_TOP, and DT_BOTTOM often don't control the vertical positioning of the entire text block within the cell's height as you might expect. The text block itself usually starts drawing from the top of the provided rectangle.

The perceived centering comes from the ROW_EXTRAHEIGHT padding added to the calculated text height when determining the nRowHeight. DrawTextEx then draws the text (often top-aligned within this padded rectangle), making it appear centered overall.

How to Change Vertical Alignment (Top or Bottom):

The most flexible way to precisely control vertical alignment, especially for multi-line text or to override the single-line default, is to use the bPaintText codeblock for the specific column (TXBrwColumn).

This codeblock gives you full control over how the text is drawn within the cell's data area.

Example: Forcing Top Alignment
// Assuming oBrw is your TXBrowse object and oCol is the specific TXBrwColumn

// --- Define the Column ---
@ R,C XBROWSE oBrw ...
ADD COLUMN oCol OF oBrw ... // Other column definitions

// --- Set the bPaintText codeblock for Top Alignment ---
oCol:bPaintText := {| oCol, hDC, cData, aRect, aColors, lHighLite, lSelected | ;
local nStyle, oFont, nTextColor, nVAlign ;
( lHighLite, lSelected ) ; // Parameters might be needed depending on your logic

oFont := oCol:DataFont() // Get the correct font for the cell
oFont:Activate( hDC ) // Activate font on the Device Context

// Determine text color (handle highlighting etc. if needed)
nTextColor := aColors[1] // Use the foreground color passed in aColors

// --- Core Logic for Alignment ---
// Get the base style, removing default vertical centering if present
nStyle := oCol:nDataStyle
nStyle := nOr( nStyle, DT_TOP ) // *** Explicitly add DT_TOP ***
nStyle := nOr( nStyle, DT_WORDBREAK ) // Ensure word break if needed
nStyle := nAnd( nStyle, NOT DT_VCENTER, NOT DT_BOTTOM ) // Remove other vertical flags

// Draw the text using the adjusted style within the provided rectangle
// FW_SayText is a FiveWin wrapper around DrawTextEx
FW_SayText( hDC, cData, aRect, nil, oFont, nTextColor, nil, nil, nStyle )

oFont:Deactivate( hDC ) // Deactivate the font
|}

oBrw:CreateFromCode()

Explanation:

bPaintText: We assign a codeblock to the column's bPaintText data member. This block will be executed instead of the default text painting logic.

Parameters: The block receives several parameters, including the column object (oCol), the device context (hDC), the text data (cData), the rectangle to draw in (aRect), and calculated colors (aColors).

Get Font: We retrieve the appropriate font using oCol:DataFont() and activate it.

Get Text Color: We typically use the foreground color provided in aColors[1]. You might add logic here to change the color based on lHighLite or lSelected if needed.

Modify Style (nStyle):
We start with the column's default nDataStyle.
We explicitly add DT_TOP using nOr().
We ensure DT_WORDBREAK is set if multi-line text is possible.
We explicitly remove DT_VCENTER and DT_BOTTOM using nAnd(..., NOT flag, NOT flag) to prevent conflicts.

FW_SayText: We call the FiveWin drawing function (or you could use DrawTextEx directly) with the modified nStyle. This forces the text rendering to start at the top of the aRect.
Deactivate Font: Clean up by deactivating the font.

For Bottom Alignment:

You would modify the nStyle calculation similarly, but use DT_BOTTOM instead of DT_TOP:

nStyle := oCol:nDataStyle
nStyle := nOr( nStyle, DT_BOTTOM ) // *** Explicitly add DT_BOTTOM ***
nStyle := nOr( nStyle, DT_WORDBREAK )
nStyle := nAnd( nStyle, NOT DT_VCENTER, NOT DT_TOP ) // Remove other vertical flags

Alternative (Less Flexible - Affects All Columns):

If you want all cells to be effectively top-aligned and don't need the extra vertical padding, you could try setting ROW_EXTRAHEIGHT to 0 before creating the browse. This makes the row height fit the calculated text height more closely.

#include "xbrowse.ch" // Make sure ROW_EXTRAHEIGHT is accessible

// BEFORE creating the browse object or columns:
ROW_EXTRAHEIGHT := 0 // Or maybe 1 or 2 for minimal padding

// ... create your browse ...
@ R,C XBROWSE oBrw ...

This is less flexible as it affects all columns and removes the visual padding. Using bPaintText offers column-specific control.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Natter
Posts: 1279
Joined: Mon May 14, 2007 9:49 am

Re: Text position in the cell

Post by Natter »

Thank you, Antonio ! I'm impressed. I'll try to make :shock:
Post Reply