• Welcome to Valhalla Legends Archive.
 

RichEdit control transparency

Started by brew, June 29, 2009, 11:14 PM

Previous topic - Next topic

brew

It's quite desirable to have a RichEdit control with a background image - however not so easy to accomplish this.
A -very- long time ago, I learned how to do this with Visual Basic 6. It was as simple as setting the WS_EX_TRANSPARENT bit of the extended window style of the richedit contol in question, and slapping an image control with the picture you'd like in back of it. It's unfortunate this isn't so easy for any other language. VB6 does a lot of custom window drawing voodoo with all of its controls, which helps much in this matter.
Working with nothing more than the Win32 API is considerably more difficult, however, because of a god awful blur created when the richedit repaints when scrolling (WM_ERASEBKGND isn't sent to the richedit then).
According to MSDN, with WS_EX_TRANSPARENT enabled, it "should not be painted until siblings beneath the window (that were created by the same thread) have been painted. "

Ok, the first logical thing to try is to send a WM_ERASEBKGND where it didn't...
Subclass the richedit, and on WM_VSCROLL call RedrawWindow with RDW_ERASE | RDW_INTERNALPAINT.
Doesn't work. Has no effect.
It seems like the blur is being painted onto the parent window's background (which is the richedit's background too, since it's transparent), so the next logical thing to do is try to redraw the parent window yourself.
In the richedit's proc, handle WM_PAINT before returning CallWindowProc, where you will FillRect the target area of the RichEdit right before painting. No effect, still blurs.
Then, you notice, every time the richedit is painted to, the parent window receives a neat WM_ERASEBKGND message too! Maybe it'd work if you tried to manually erase the background here? No.
So on, and so forth....
Then, I had asked myself if making it a transparent window was even necessary.
Long story short, it is. For some reason it seems the background clearing/painting is done in the richedit's internal painting routine (what were they thinking?). Any paints made in a WM_PAINT handler before calling the original window proc would result in a neat painting over your picasso.

So there must be some way to do this, right?
There are, theoretically. I don't know how to do either of these, which might be potential solutions:
1). Make a brush with CreatePatternBrush using the image you'd like to paint the background of the richedit with, then you'd somehow be able to have it paint the background on its own with the brush you indicate.
2). Have it output what it would paint into a memory DC, so you're able to TransparentBlt it onto the final window, effectively getting rid of the background it painted on by itself.

I couldn't solve this problem two years ago when I threw this feature into my bot, so I kind of cheated by using microsoft's implementation of #2: WS_EX_COMPOSITED.
This is basically a bit that enables double buffering for a window and all of its child windows, only problem is that it can't be used on a control (only top-level windows or MDI children), so you'll see its undesirable effects on all child windows of that parent window, which include an ungodly amount of CPU usage, and the inability to have column headers in a listview. It took me a while to figure out the exact cause of the latter, as it had caused a constant stream of NM_CUSTOMDRAW WM_NOTIFY messages to be sent to the parent from an unidentified hWnd which turned out to be the column component.
Back then, I looked at it as a temporary fix, but over time I'd forgotten about it. Now that I go back to implement a neat feature I just thought up which utilizes richedit background drawing, I'd remembered, and attempted to make a more permanent solution with my 2 years more experience. I failed again.

P.S.
You might take 5 minutes of your time and search for "transparent richedit" on google, and you'll find a wealth of CodeProject and related sites with articles on exactly this, but before you post links to those here, do download the demo applications and try them out yourself. None of them are able to overcome the unfortunate blur effect.

EDIT*
if anyone needs to see for themselves, this is the blur effect happening to the codeproject article's demo application.  apparently, this doesn't happen to cuphead. i suspect if this is true and i wasn't being bullshitted to, there is a newer version of riched32.dll out there with this problem fixed.
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

brew

bump

For anyone wondering, I haven't checked into it much yet but two days ago I stumbled upon WM_PRINT, which I believe might be the solution. I would be able to do solution #2 as described in my first post.
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

MyndFyre

If that works out, it'll be an interesting and creative solution.  I think you might probably still run into the problem of the background being drawn.

Ultimately, though, I think that the most difficult part of this problem for you to solve will be font blending and smoothing.  The API is going to draw the fonts against a black (or any other color background), and then the fonts will be composited according to that color background.  If you then strip out the background and blit the contents of the window onto another surface, your fonts will still look as if they're composted according to another background.

What about, instead of trying to hook or subclass WM_PAINT, you look into hooking the function that the rich edit uses to fill the background, likely something such as FillRect?  Since you're doing something incredibly specialized, you should be able to determine if the system is calling that function to fill one of your specialized rich edits (you'll probably need to track them in some kind of extension manager) and, if so, instead of calling FillRect, you substitute the call with a function that will draw your background image?
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.