Click to See Complete Forum and Search --> : Format text in richedit without using EM_SETSEL


Ali Imran
June 15th, 2005, 03:38 AM
As in other help topics it is stated that if we need to format a specific text then we must select it first and then format it, as

SendMessage(richctrl, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);

where
richctrl is handle (HWND) of richedit control
cf is CHARFORMAT

BUT, I want to know if we can pass value other than SCF_SELECTION to message EM_SETCHARFORMAT, then what is it, so that we can prevent prior selection for formating a specific piece of text ? And we dont move the caret.

Extending this topic I also need another small function
I want zero-based index of left most visible character.
Get the left most character index in the text line where caret is, where horizontal scrollbar may have been scrolled to right. (not the first character of line, but the first visible left most character index)
somethign like

LONG getLeftCharPos(HWND hwnd) {
return left most visible character of line where caret is
}


Waiting for the kind reply, especially from Superkoko.


best regards

SuperKoko
June 15th, 2005, 05:52 AM
You can choose another value for wParam of EM_SETCHARFORMAT message

SCF_ALL
Applies the formatting to all text in the control. Not valid with SCF_SELECTION or SCF_WORD.
SCF_SELECTION
Applies the formatting to the current selection. If the selection is empty, the character formatting is applied to the insertion point, and the new character format is in effect only until the insertion point changes.
SCF_WORD
Applies the formatting to the selected word or words. If the selection is empty but the insertion point is inside a word, the formatting is applied to the word. The SCF_WORD value must be used in conjunction with the SCF_SELECTION value.
SCF_ASSOCIATEFONT
RichEdit 4.1: Associates a font to a given script, thus changing the default font for that script. To specify the font, use the following members of CHARFORMAT2: yHeight, bCharSet, bPitchAndFamily, szFaceName, and lcid.
SCF_ASSOCIATEFONT2
RichEdit 4.1: Associates a surrogate (plane-2) font to a given script, thus changing the default font for that script. To specify the font, use the following members of CHARFORMAT2: yHeight, bCharSet, bPitchAndFamily, szFaceName, and lcid.
SCF_DEFAULT
RichEdit 4.1: Sets the default font for the control.
SCF_NOKBUPDATE
RichEdit 4.1: Prevents keyboard switching to match the font. For example, if an Arabic font is set, normally the autokeyboard feature for Bidi languages changes the keyboard to an Arabic keyboard.
SCF_USEUIRULES
RichEdit 4.1: Used with SCF_SELECTION. Indicates that format came from a toolbar or other UI tool, so UI formatting rules should be used instead of literal formatting.

The SCF_DEFAULT, SCF_ALL, SCF_SELECTION and SCF_WORD determine the text range formatted.
You probably want to be able to explicit a range.

In that case, you should save the currently selected text, select a new range, set the format, and restore the old selection.

There is a problem with the scroll position, i don't know how to restore exactly the scroll position. The best i can do is to ensure that the caret be in the visible range with the EM_SCROLLCARET message.
Here is a function that may help you:

void setTextFormat(HWND hWnd,const CHARRANGE &Range,const CHARFORMAT &Format)
{
CHARRANGE OldRange;
SendMessage(hWnd,EM_EXGETSEL,0,LPARAM(&OldRange));

SendMessage(hWnd,EM_EXSETSEL,0,LPARAM(&Range));
SendMessage(hWnd,EM_SETCHARFORMAT,SCF_SELECTION,LPARAM(&Format));

SendMessage(hWnd,EM_EXSETSEL,0,LPARAM(&OldRange)); // restores old selection
SendMessage(hWnd,EM_SCROLLCARET,0,0);
}

SuperKoko
June 15th, 2005, 06:40 AM
int getLeftCharPos(HWND hWnd)
{
POINTL p;
SendMessage(hWnd,EM_POSFROMCHAR,WPARAM(&p),getLineFirstCharPos(hWnd));
if (p.x<0) p.x=0;
return SendMessage(hWnd,EM_CHARFROMPOS,0,LPARAM(&p));
}

I have tested it.
It seems to work.
If no character are visible on the line, it returns the index of the character following the last character of the line.
But it returns the first visible character of the client area of the rich edit box, if the line is upper that the client area.

SuperKoko
June 15th, 2005, 07:02 AM
Here is a better version:
It returns -1 if no char of the line containing the caret is visible.

int getLastVisibleChar(HWND hWnd) // (get the last visible char in the client area)+1
{
RECT r;
GetClientRect(hWnd,&r);
POINTL ptLastVisible={r.right,r.bottom};
return SendMessage(hWnd,EM_CHARFROMPOS,0,WPARAM(&ptLastVisible));
}
int getLeftCharPos(HWND hWnd)
{
POINTL pt;
SendMessage(hWnd,EM_POSFROMCHAR,WPARAM(&pt),getLineFirstCharPos(hWnd));
if (pt.x<0) pt.x=0;
if (pt.y<0) return -1;
int r=SendMessage(hWnd,EM_CHARFROMPOS,0,LPARAM(&pt));
if (r>=getLastVisibleChar(hWnd) || r>=getLineLastCharPos(hWnd)) return -1;
return r;
}

There is an imperfection it does not returns -1 if the line is the (max visible line)+1, but instead returns the index first char of this invisible line.

Ali Imran
June 15th, 2005, 08:13 PM
Thanks for reply, it worked perfect. you are the man.

regards

SuperKoko
June 17th, 2005, 04:58 AM
Here is an improved version of setTextFormat, which saves correctly the scroll position:

void setTextFormat(HWND hWnd,const CHARRANGE &Range,const CHARFORMAT &Format)
{
CHARRANGE OldRange;
DWORD Line0=SendMessage(hWnd,EM_GETFIRSTVISIBLELINE,0,0);
SendMessage(hWnd,EM_EXGETSEL,0,LPARAM(&OldRange));

SendMessage(hWnd,EM_EXSETSEL,0,LPARAM(&Range));
SendMessage(hWnd,EM_SETCHARFORMAT,SCF_SELECTION,LPARAM(&Format));

SendMessage(hWnd,EM_EXSETSEL,0,LPARAM(&OldRange)); // restores old selection
DWORD Line1=SendMessage(hWnd,EM_GETFIRSTVISIBLELINE,0,0);
SendMessage(hWnd,EM_LINESCROLL,0,Line0-Line1);
}