News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Character Attributes

Started by raleeper, April 25, 2007, 09:48:50 AM

Previous topic - Next topic

raleeper

So far I haven't found anything in the SDK about assigning attributes [bold, italic, red, font face=Arial, etc.] to single characters or substrings within a string to be drawn by DrawText or another text output function.  Something like HTML tags would be OK.

Can anyone suggest a pointer for further research?

ramguru

You won't find  :bg .. The fastest text drawing procedure is ExtTextOut the only possible solution is drawing a range of characters in one pass with appropriate attributes (then do another pass...another..until everything is done ), or simpler one char in one pass (but it isn't very fast)

raleeper

Quote from: ramguru on April 25, 2007, 09:55:54 AM
You won't find  :bg .. The fastest text drawing procedure is ExtTextOut the only possible solution is drawing a range of characters in one pass with appropriate attributes (then do another pass...another..until everything is done ), or simpler one char in one pass (but it isn't very fast)

OK.  I was afraid the answer might be something like that [but thanks for the tip about ExtTextOut.  I haven't explored ExtTextOut much yet, but I don't want to lose the tab and crlf [0A0Dh] processing that DrawTextEx allows].

If an API function that does what I want doesn't exist, then I'll have to write a procedure that does - something like:

LFtextout   proc   hdc,....,ADDR string,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
LFtextout   endp

But this seems like such an obvious and useful routine that someone must already have written something like it, in MASM or C or whatever.

Can you [or anyone] suggest tips that might speed my search for such?

Tedd

The font face and effects used come from whichever font is currently selected into the device context, so whenever you want to change any of these you'll have to create another font, select that in, and then draw text with it. This doesn't include colour though, which comes from the current text colour attribute (held by the graphics context.)
But you're right, it is something that would be useful, yet I don't know of any available function to do it. Most people simply opt for a RichEdit control (though there is still some setup associated with it.)
I suppose the nicest way of doing it would be to be able to insert 'markers' into the string which indicate a change in face/effect/colour, which is passed to the magic function who handles the necessary font creation, drawing parts, etc; that said, re-creating numerous fonts every refresh isn't going to be too efficient, so some method of caching them would probably be a good idea.
No snowflake in an avalanche feels responsible.

ramguru

Quote from: raleeper on April 25, 2007, 10:42:33 AM

LFtextout   proc   hdc,....,ADDR string,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
   invoke ExtTextOut ...,nextsubstring,...
...
LFtextout   endp


ExtTextOut is good not only that it's fast, but one can change background color using it, so THE procedure could look like this:

LFtextout proc hdc,....,ADDR string,...

... parse string looking for markers as Ted said
...
invoke SetBkColor, ps.hdc, color1a
invoke SetTextColor, ps.hdc, color2a
invoke ExtTextOut ...,nextsubstring,...
...
invoke SetBkColor, ps.hdc, color1b
invoke SetTextColor, ps.hdc, color2b
invoke ExtTextOut ...,nextsubstring,...
...
invoke SetBkColor, ps.hdc, color1c
invoke SetTextColor, ps.hdc, color2c
invoke ExtTextOut ...,nextsubstring,...
...
LFtextout endp


Actually it was done many times by many people (mostly for text editors that support syntax highlighting), but no one bothered to write a unique procedure.

hutch--

Another factor you learn from syntax highliting is if its only display you need, you only need to write to the visible display area. If its document you need, RTF is probably the easiest way to handle te text characteristics and you display it with a rich edit control set to read and write RTF.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Timbo

Raleeper,

Scintilla is an open source editing component.  You can find the source here.

I've never viewed the source but I can imagine it is c++.  Should be helpful regardless.

Hope this helps,

Tim

raleeper

Quote from: hutch-- on April 25, 2007, 11:17:59 AM
Another factor you learn from syntax highliting is if its only display you need, you only need to write to the visible display area. If its document you need, RTF is probably the easiest way to handle te text characteristics and you display it with a rich edit control set to read and write RTF.

"rich edit control"? - [bzzzzz - working]

Thanks.


raleeper

"rich edit control"? - [bzzzzz - working]

SDK section on Rich Edit Controls almost unintelligible.  All that computes is "A rich edit control is a window [for text]".

[bzzzzz - still working].

Thanks.


Quote

raleeper

The SDK says:

To create a rich edit control, call the CreateWindowEx function, specifying the rich edit window class. If  you are using Rich Edit 1.0 (Riched32.dll), specify RichEdit for the window class parameter. If you are  using Rich Edit 2.0 or later (Riched20.dll), specify RICHEDIT_CLASS for the window class parameter.

So, instead of Eczelion's

   ClassName   db   "SimpleWinClass",0

   for
   
      mov   wc.lpszClassName,OFFSET ClassName   for
   
         invoke   RegisterClassEx, addr wc
   
   and
   
      invoke   CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ ....

I should use:

   ClassName   db   "RICHEDIT_CLASS"?

And after I've made that simple change, DrawTextEx or ExtextOut will understand and properly handle all the richtext controls??

[bzzzzz - still working - looks like I may need help, but not yet].


Tedd

#10
...not exactly :bdg

Okay, well it IS a window (that displays text)... just as a 'normal' edit control does. And in the same way that you 'tell' an edit control to display text, so you do with a rich-edit control -- you do this by sending it messages (usually ones that start EM_.... ) which indicate what text you want to insert, and others for the display options, etc..

See the attachment to start you off (removed - see below.)
No snowflake in an avalanche feels responsible.

raleeper

Quote from: Tedd on April 27, 2007, 09:45:28 AM
...not exactly :bdg

See the attachment to start you off :wink


Thanks Tedd.  When I try to open richy.zip I get "The compressed ... folder is invalid or corrupt".  Do I need some other zip utility?


Tedd

Nope, just an ordinary zip file. Maybe the windows unzip dll (or whatever you're using) has some problem with it ::)
I've attached it again just to be sure.

But the code's not that long, so..

.586
.model flat, stdcall
option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
include gdi32.inc
includelib gdi32.lib

;***************************************************************************************************

WinMain proto
WndProc proto hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

RichAppend proto pBuff:DWORD,col:DWORD

;***************************************************************************************************

WIN_WIDTH       equ 320
WIN_HEIGHT      equ 240

IDRICH1         equ 10001

;***************************************************************************************************

.data
ClassName   db "richtest",0
AppName     db "Richy",0

RichDLL     db "Riched20.dll",0
RichClass   db "RichEdit20A",0

;;some test strings
nl      db 13,10,0
strS    db "Server: ",0
strC    db "Client: ",0
msg1    db "Hello",13,10,0
msg2    db "May I help you?",13,10,0
msg3    db "Give me root access",13,10,0
msg4    db "I don't think so",0
msg5    db " -- GO AWAY!!",13,10,0
msg6    db "<Disconnected>",0

.data?
hInstance   HINSTANCE   ?
hWnd        HWND        ?
hRichDLL    HMODULE     ?
hRWnd       HWND        ?

.code
start:
    invoke GetModuleHandle, NULL
    mov hInstance,eax
    invoke WinMain
    invoke ExitProcess, eax

;***************************************************************************************************

WinMain proc
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    mov [wc].cbSize,SIZEOF wc
    mov [wc].style,CS_HREDRAW or CS_VREDRAW
    mov [wc].lpfnWndProc,OFFSET WndProc
    mov eax,hInstance
    mov [wc].hInstance,eax
    invoke LoadIcon, NULL,IDI_APPLICATION
    mov [wc].hIcon,eax
    invoke LoadCursor, NULL,IDC_ARROW
    mov [wc].hCursor,eax
    mov [wc].hbrBackground,COLOR_WINDOW+1
    mov [wc].lpszClassName,OFFSET ClassName
    xor eax,eax
    mov [wc].cbClsExtra,eax
    mov [wc].cbWndExtra,eax
    mov [wc].lpszMenuName,eax
    mov [wc].hIconSm,eax
    invoke RegisterClassEx, ADDR wc
    invoke CreateWindowEx, NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,WIN_WIDTH,WIN_HEIGHT,NULL,NULL,hInstance,NULL
    .IF (eax)
        push ebx
        mov hWnd,eax
        invoke ShowWindow, hWnd,SW_SHOWDEFAULT
        invoke UpdateWindow, hWnd
        lea ebx,[msg]
        assume ebx:ptr MSG
        .WHILE TRUE
            xor eax,eax
            invoke GetMessage, ebx,eax,eax,eax
            .BREAK .IF(!eax)
            invoke TranslateMessage, ebx
            invoke DispatchMessage, ebx
        .ENDW
        mov eax,[ebx].wParam
        assume ebx:nothing
        pop ebx
    .ENDIF
    ret
WinMain endp

WndProc proc hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    mov eax,uMsg
;-- WM_SIZE -----------------------------------------------------------------------------------------
    .IF (eax==WM_SIZE)
        mov eax,lParam
        mov edx,eax
        and eax,0ffffh  ;width
        shr edx,16      ;height
        invoke MoveWindow, hRWnd,0,0,eax,edx,TRUE
;-- WM_CREATE ---------------------------------------------------------------------------------------
    .ELSEIF (eax==WM_CREATE)
        ;need to make sure the dll is loaded - so we can access the richedit control
        ;(this only needs to be done once)
        invoke LoadLibrary, ADDR RichDLL
        mov hRichDLL,eax

        ;** create a richedit window
        invoke CreateWindowEx, WS_EX_CLIENTEDGE,ADDR RichClass,NULL,WS_VISIBLE or WS_CHILD or WS_VSCROLL or ES_MULTILINE or ES_READONLY,0,0,0,0,hwnd,IDRICH1,hInstance,NULL
        mov hRWnd,eax

        ;** limit text to 4MB
        invoke SendMessage, hRWnd,EM_EXLIMITTEXT,NULL,0400000h

        ;** set a nicer font
        invoke GetStockObject, DEFAULT_GUI_FONT     ;could also use: SYSTEM_FIXED_FONT, OEM_FIXED_FONT
        invoke SendMessage, hRWnd,WM_SETFONT,eax,TRUE

        ;** print some stuff
        invoke RichAppend, ADDR strC,07f7f7fh   ;grey
        invoke RichAppend, ADDR msg1,0ff0000h   ;blue

        invoke RichAppend, ADDR strS,07f7f7fh   ;grey
        invoke RichAppend, ADDR msg2,07f007fh   ;magenta

        invoke RichAppend, ADDR strC,07f7f7fh   ;grey
        invoke RichAppend, ADDR msg3,0ff0000h   ;blue

        invoke RichAppend, ADDR strS,07f7f7fh   ;grey
        invoke RichAppend, ADDR msg4,07f007fh   ;magenta
        invoke RichAppend, ADDR msg5,00000ffh   ;bright red

        invoke RichAppend, ADDR msg6,0007fffh   ;orange
;-- WM_DESTROY -------------------------------------------------------------------------------------
    .ELSEIF (eax==WM_DESTROY)
        invoke PostQuitMessage, NULL
;-- default ----------------------------------------------------------------------------------------
    .ELSE
        invoke DefWindowProc, hwnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor eax,eax
    ret
WndProc endp

RichAppend proc pBuff:DWORD,col:DWORD
    LOCAL charrng:CHARRANGE
    LOCAL charfmt:CHARFORMAT
    mov eax,-1
    mov charrng.cpMax,eax
    mov charrng.cpMin,eax
    mov charfmt.cbSize,SIZEOF CHARFORMAT
    mov charfmt.dwMask,CFM_COLOR
    mov eax,col
    mov charfmt.crTextColor,eax
    invoke SendMessage, hRWnd,EM_EXSETSEL,NULL,ADDR charrng
    invoke SendMessage, hRWnd,EM_SETCHARFORMAT,SCF_SELECTION,ADDR charfmt
    invoke SendMessage, hRWnd,EM_REPLACESEL,FALSE,pBuff
    invoke SendMessage, hRWnd,EM_SCROLLCARET,NULL,NULL      ;scroll the text into view
    ret
RichAppend endp

end start

[attachment deleted by admin]
No snowflake in an avalanche feels responsible.

Tedd

And once you've got the hang of that..

Here's the proper reference for Rich-Edit Controls :bg
http://msdn2.microsoft.com/en-us/library/ms651298.aspx
No snowflake in an avalanche feels responsible.

raleeper

Quote from: Tedd on May 03, 2007, 12:11:53 PM
And once you've got the hang of that..

Here's the proper reference for Rich-Edit Controls :bg
http://msdn2.microsoft.com/en-us/library/ms651298.aspx


Thanks Tedd.

I'm working thru richy [actually rich2] now.  [I have a day job & can only spend an hour - maybe steal another - on this.

The assembler didn't recognize HMODULE - tho it's in the SDK docs - but hey, handles are just dwords, and the program assembles & works fine w/ that change.

I don't really know enough at this point to have an opinion, but it seems to me that instead of

    hRichDLL   HMODULE   ?

it would be better from several points of view to use:

    hRichDLL   DD   ?   ;handle to module - ret'd by !LoadLibrary

And of course, to save a few bytes, your 'save as type: asm' routine (optionally) skips "tab,;" and anything after on/in that (line).


Best Wishes,

RAL

   A slave is yet a slave if his master
   Allows him to make any decision
   About which he, the master,
   Is utterly indifferent.

[rel: snowflake..., causation,aggregation,responsibility,...]