How do I draw an image with an alpha channel to a TSpeedButton? - delphi

I've got a TSpeedButton, and a TImageList that holds various glyphs. One of them has an alpha channel, and it looks very nice when drawn to certain parts of the UI... but when that glyph is drawn on a TSpeedButton, it doesn't take the alpha channel into effect.
Looking at the relevant code in TButtonGlyph.DrawButtonGlyph, it's getting passed true for the Transparent parameter, but Transparent isn't taken into account at all in the if FThemesEnabled code path; it only gets referenced in the else section. Since this program has themes enabled, does that mean it's impossible to draw an alpha-blended image to a TSpeedButton?
Is there any way to work around this?
EDIT: Looking at this a bit more closely, it appears that it takes transparency into account... sort of. Pixels that are fully transparent don't get drawn at all, which is correct behavior. But the antialiasing (partial transparency) around the edges gets drawn as fully opaque.

From what I can see, TSpeedButton takes your bitmap and adds it to an image list. That's FGlyphList in the private section of TButtonGlyph. That image list has ColorDepth of cdDeviceDependent. You'd need that image list to have ColorDepth of cd32Bit if you wanted alpha transparency to be respected. So that right there explains the artifacts.
I'm not sure how you go about working around this. I think that I'd personally subclass TButtonGlyph and connect it directly to an image list of your selection. Then replace TButtonGlyph.DrawButtonGlyph with code that draws from your image list. I'm sure you'll be able to work out the coding.
But there'll be no simple workaround. Without major modifications to the VCL, that image list is going to use cdDeviceDependent and there's no simple way for you to change that. There's no obvious quick fix that I can see.
Actually, what I would do would be to use TButton, but that's just me.
Regarding the Transparent property of the speed button the documentation says:
Specifies whether the background of the button is transparent.
Use Transparent to specify whether the background of the button is transparent.
This property works only if the Flat property of the TSpeedButton is set to True.
When Windows themes are enabled, the Transparent property cannot make the button background transparent.
That is, the property influences the button background, for flat buttons, when unthemed, and has no relevance to glyph drawing.

In the interest of full disclosure: I ran into a similar problem and used this Q&A to base my initial solution on. Since I needed a quick fix for my app and compiler (I use C++ Builder 2009) I decided to 'hack' the VCL's private members and set Glyphlist's ColorDepth to cd32Bit, until I had time to work on something more permanent. This hack worked, with a few more changes, but was far from ideal, for all the obvious reasons, but also functionality wise, there were issues to consider.
However, while doing so I experimented further and finally arrived at below, working solution, without any dirty tricks needed. Not being that familiar with the internal workings of VCL and the rather 'it's not possible as is' feedback from people who are far more in depth in VCL I'm a bit unsure on what I'm missing right now !? Because below solution works for me. Confirmed on XP, XP-High-contrast, W7 and W10. The Glyphs don't look good on W2K but then that is true for Main Menu and Popup icons as well, so that is that.
I code in C++ but use the same underlying VCL, so I will post my C++ solution here, as answer to a Delphi question. I hope that is OK, in the interest of offering a path to a solution rather than keeping it to myself. A Delphi guru can convert and post as answer as well then, unless I'm missing something and my solution isn't what was needed all along.
Since I started with the 'hack' approach first I subclassed TSpeedButton and put the code in a MyTSpeedButton function, but that is not needed to make this work. However, it is the code that I'm posting:
header
class MyVCLTSpeedButton : public TSpeedButton
{
public:
__fastcall MyVCLTSpeedButton(Classes::TComponent* AOwner) ;
void __fastcall AddGlyphWithAlphaChannel(Imglist::TCustomImageList* ImageList, int UpIndex, int DisabledIndex = -1, int ClickedIndex = -1, int DownIndex = -1) ;
};
cpp
void __fastcall MyVCLTSpeedButton::AddGlyphWithAlphaChannel(Imglist::TCustomImageList* ImageList, int UpIndex, int DisabledIndex, int ClickedIndex, int DownIndex)
{
Glyph->Assign(NULL) ; // Clear the current bitmap
NumGlyphs = (DisabledIndex > -1)?((ClickedIndex > -1)?((DownIndex > -1)?(4):(3)):(2)):(1) ;
Graphics::TBitmap *BitMap = new Graphics::TBitmap ;
//BitMap->AlphaFormat = afDefined ; // Don't Change AlphaFormat, it will negatively affect rendering !
BitMap->PixelFormat = pf32bit ; // Doesn't seem to be that important
BitMap->Height = ImageList->Height ;
BitMap->Width = (ImageList->Width * NumGlyphs) ;
BitMap->Canvas->Brush->Color = Parent->Brush->Color ;
BitMap->Canvas->Brush->Style = bsSolid ;
BitMap->Canvas->FillRect(BitMap->Canvas->ClipRect) ;
TIcon *Icon = new TIcon() ;
for (int x = 0 ; x < NumGlyphs ; x++)
{
ImageList->GetIcon((x == 0)?(UpIndex):((x == 1)?(DisabledIndex):((x == 2)?(ClickedIndex):(DownIndex))), Icon) ;
BitMap->Canvas->Draw((ImageList->Width * x), 0, Icon) ;
}
Glyph->Assign(BitMap) ;
delete Icon ;
delete BitMap ;
}

Related

How to get window decorations pixel size in LUA

I am using rdesktop with seamlessrdp. This way I can open Windows apps on my Linux machines. Also I added devilspie2 to the mix so I could control the window decorations. devilspie2 uses lua as its config management. I made everything work. The only issue left is to move the opening (dialog) windows a couple of pixels because the VNC windows will appear as if they had decorations (but without them). I got the code working by hard coding the amount of pixels needed to move. The issue is we have more than one distros here and they have different pixel sizes for their window decorations.
What I want is to GET the decoration size in pixels instead of hard coding them so it will work perfectly for all my distros.
Here is the piece of code that does it atm:
if get_window_class()=="SeamlessRDP" then
undecorate_window();
--x-1 and y-28 works for one distro but for the other I need to use x-6 and y-27
if get_window_type()=="WINDOW_TYPE_DIALOG" then
x, y = xy();
xy(x-1, y-28);
end
end
As you can see from the script. It would be much better if I could somehow call the size of the window decorations and then use them rather than hard coded pixels.
EDIT (ANSWER):
Even though I found the answer before the following post, I wanted to accept it anyways because it did show the right path to follow. I am only further commenting here to show the full answer:
--get x and y's for decorated and non-decorated windows
x1, y1, width1, height1 = get_window_geometry();
x2, y2, width2, height2 = get_window_client_geometry();
--calculate pixels to slide window
xpixel = x2-x1;
ypixel = y2-y1;
--check if class is seamlessrdp
if get_window_class()=="SeamlessRDP" then
undecorate_window();
--if window is a dialog then move it
if get_window_type()=="WINDOW_TYPE_DIALOG" then
xy(x1-xpixel, y1-ypixel);
end
end
devilspie2 provides only two ways to get the window size, get_window_geometry and get_window_client_geometry.
Whereby the last one excludes the window borders. If this does not work for you, you can create a file with a table for all values to make them easily editable. You could also use the window class names as table keys if possible to make the use easier.

TImageList - True color + alpha channel vs. 8-bit (256 colors)

I use c++ Builder 2009 but I tagged this for Delphi as well since I expect the exact same issue to exist there as well.
I use TImageList (16x16) and associate it to TListView (SmallImages) and TTreeView.
I was adding new icons via the IDE (design time) and imported some 16x16 True color + alpha channel icons. In the IDE they looked fine:
During run time, they do not look fine at all:
Notice the edges especially. The top icon is icon 5 and the bottom icon is icon 7. See how they are supposed to look in above picture.
When I convert the icons to 8 bit (256 colors) icons and import them via the IDE, they look fine during run time ! So that is certainly a solution for me. But the icons obviously lose information and though probably hardly noticeable in 16x16 icons, it sort of bugs me that I cannot find why this happens ?
The ImageList is created at design time and has its default properties.
I also tried: DrawingStyle = dsTransparent and ColorDepth = cd32Bit after which I had to import the icons again via the IDE.
The result is the same. I wonder if I need to set a particular BlendColor ?
Do I need to do something special for it to support true color icons ?
Or is the issue with TTreeView and TListView ?
Is this a VCL limitation or Windows or ..
Thoughts, suggestions ?
- Additional information - after having read David's comment.
I added a new TImageList to my project and added the 32bit icons with alpha channel. Next I 'hacked' my code to always use that ImageList and it worked beautifully.
What I do in the code is, because I have a set of icons that I use for all OS (very application related) and because I also use icons that are OS specific, such as folder icons, CD icons etc. I have an ImageList that contains all icons (OS and app specific) and on program start and OS check, I copy the OS icons that I need from one list to the list that I use.
Like so:
TIcon *Icon = new TIcon() ;
for (int x = 0 ; x < OS_Specific_count ; x++)
{
OS_xx_ImageList->GetIcon(x, Icon) ;
Use_ImageList->ReplaceIcon(x, Icon) ;
}
delete Icon ;
I fear the issue is in this part of the code !
- Additional information - after having done more testing
If I rewrite the code to something like:
TBitmap *Bitmap= new TBitmap () ;
for (int x = 0 ; x < OS_Specific_count ; x++)
{
OS_xx_ImageList->GetBitmap(x, Bitmap) ;
Use_ImageList->Replace(x, Bitmap, NULL) ;
}
delete Bitmap;
I have similar problems, yet not exactly the same. The transparency seems to get lost !
I have also noticed that:
Use_ImageList->AddImage(OS_xx_ImageList, x) ;
starting from an empty Use_ImageList seems to preserve all alpha channel data properly !
Maybe I should rewrite the code to always copy the lot this way ...

JUNG Visualisation

Does anyone know if you are able to set the colour of the text for a vertex label in JUNG.
I'm using the Visualisation Viewer and can seem to be able to set the colour for everything else.
vv = new VisualizationViewer<String,Integer>(treeLayout, new Dimension(410,557));
Transformer<String,Paint> vertexPaint = new Transformer<String,Paint>() {
public Paint transform(String b) {
return Color.orange;
}
};
vv.setBackground(Color.white);
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
//vv.getRenderContext().setVertexFontTransformer(vertexFont);
// add a listener for ToolTips
vv.setVertexToolTipTransformer(new ToStringLabeller());
vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.WHITE));
The DefaultVertexLabelRenderer and the DefaultEdgeLabelRenderer extend JLabel (it is similar to the way cell renderers work in JTable and JTree).
By default, it uses the foreground color of the VisualizationViewer to draw the label text.
vv.setForegroundColor(Color.red);
will make all of your labels red.
This approach is less expensive than making all of the labels parse HTML.
Sorry that the solution is so obscure.
Additionally, since the default renderers extend JLabel, the use of html is the same as it is for JLabel. There are good online resources to show examples of using html with javax.swing. What's missing is documentation to make the connection between using html in JUNG and using html in javax.swing.
You can use HTML in the label to specify the color; an example is here: https://stackoverflow.com/a/2017576/664856
In your case,
vv.getRenderContext().setVertexLabelRenderer(new DefaultVertexLabelRenderer(Color.RED));
should work (if you wanted selected vertex to be Red). I tested it myself. This applies to the selected vertex.
Upon inspection of code, I would have to believe that the link I provided does correctly work for those vertices which are not selected, but I did not actually try implementing that link.

locating a change between two images

I have two images that are similar, but one has a additional change on it. What I need to be able to do is locate the change between the two images. Both images have white backgrounds and the change is a line being draw. I don't need anything as complex as openCV I'm looking for a "simple" solution in c or c++.
If you just want to show the differences, so you can use the code below.
FastBitmap original = new FastBitmap(bitmap);
FastBitmap overlay = new FastBitmap(processedBitmap);
//Subtract the original with overlay and just see the differences.
Subtract sub = new Subtract(overlay);
sub.applyInPlace(original);
// Show the results
JOptionPane.showMessageDialog(null, original.toIcon());
For compare two images, you can use ObjectiveFideliy class in Catalano Framework.
Catalano Framework is in Java, so you can port this class in another LGPL project.
https://code.google.com/p/catalano-framework/
FastBitmap original = new FastBitmap(bitmap);
FastBitmap reconstructed = new FastBitmap(processedBitmap);
ObjectiveFidelity of = new ObjectiveFidelity(original, reconstructed);
int error = of.getTotalError();
double errorRMS = of.getErrorRMS();
double snr = of.getSignalToNoiseRatioRMS();
//Show the results
Disclaimer: I am the author of this framework, but I thought this would help.
Your description leaves me with a few unanswered questions. It would be good to see some example before/after images.
However at the face of it, assuming you just want to find the parameters of the added line, it may be enough to convert the frames to grey-scale, subtract them from one another, segment the result to black & white and then perform line segment detection.
If the resulting image only contains one straight line segment, then it might be enough to find the bounding box around the remaining pixels, with a simple check to determine which of the two possible line segments you have.
However it would probably be simpler to use one of the Hough Transform methods provided by OpenCV.
You can use memcmp() (Ansi C function to compare 2 memory blocks, much like strcmp()). Just activate it on the Arrays of pixels and it returns whether they are identical or not.
You can add a little tweak that you get as result the pointer to the memory block where the first change occurred. This will give you a pointer to the first pixel. You can than just go along its neighbors to find all the non white pixels (representing your line).
bool AreImagesDifferent(const char*Im1, const char* Im2, const int size){
return memcmp(Im1,Im2,size);
}
const char* getFirstDifferentPixel(const char*Im1, const char* Im2, const int size){
const char* Im1end = Im1+size;
for (;Im1<Im1end; Im1++, Im2++){
if ((*Im1)!=(*Im2))
return Im1;
}
}

BCB: how to get the (approximate) width of a character in a given TFont?

It's a TMemo, not that that should make any difference.
Googling suggests that I can use Canvas->TextWidth() but those are Delphi examples and BCB doesn't seem to offer this property.
I really want something analogous to memo->Font->Height for width.
I realize that not all fonts are fixed width, so a good estimate will do.
All that I need is to take the width of a TMemo in pixels and make a reasonable guess at how many characters of the current font it will hold.
Of course, if I really want to be lazy, I can just google for the average height/width ratio, since height is known. Remember, an approximation is good enough for me if it is tricky to get exact.
http://www.plainlanguagenetwork.org/type/utbo211.htm says, " A width to height ratio of 3:5 (0.6) is recommended for most applications"
Actually your google search is not entirely off. You do need access to a canvas object, or at least a handle to a DC object. In general when searching for help concerning VCL classes it often pays to search for delphi examples since these are more common.
Anyway to calculate the size of a string you could have a look at the TextExtent function, it is a function for the TCanvas class. Simply pass the character which width you want to test, and the return value will be a TSize construct. However there is also a TextWidth function, as well as a TextHeight function. You can use these as well. Actually these call the TextExtent internally.
You have to note one thing though, the functions use the current font of the TCanvas object, more specifically the font bound to the DC the canvas uses. So assign the font you wish to test with first, and then pass the character.
I have some old code that calculates the width of a string like this:
// This canvas could be the form canvas: canvas = Form1->Canvas or the
// memo canvas which will probably be what you want.
canvas->Font->Assign(fontToTest);
int textwidth = TextWidth(textToTest);
If you want more control of what to do, you can also do this using the Windows API, this is essentially what the VCL does for you, in that case the following example would look like this:
// This canvas could be the form canvas: canvas = Form1->Canvas
canvas->Font->Assign(fontToTest);
// The initial size, this is really important if we use wordwrapping. This is
// the text area of the memo control.
TRect rect = ClientRect;
// This is the font format we wish to calculate using, in this example our text
// will be left aligned, at the top of the rectangle.
fontformat = DT_LEFT | DT_TOP;
// Here we calculate the size of the text, both width and height are calculated
// and stored in the rect variable. Also note that we add the DT_CALCRECT to the
// fontformat variable, this makes DrawTextEx calculate the size of the text,
// without drawing it.
::DrawTextEx(canvas->handle,
textToTest.c_str(),
textToTest.Length(),
&rect,
fontformat | DT_CALCRECT,
NULL);
// The width is:
int width = rect.Width();
The fontformat is a parameter that specifies different options for how to align and layout the text, if you plan on drawing text it will be a good idea to check out the different possibilities it offers: DrawTextEx Function [1]
EDIT: Reading through your question again, it struck me that the function you might be searching for is: GetTextExtentExPoint Windows API documentation states the following about this function:
The GetTextExtentExPoint function
retrieves the number of characters in
a specified string that will fit
within a specified space and fills an
array with the text extent for each of
those characters. (A text extent is
the distance between the beginning of
the space and a character that will
fit in the space.) This information is
useful for word-wrapping calculations.
You can find more information about the GetTextExtentExPoint function here: GetTextExtentExPoint Function [2]
[1] http://msdn.microsoft.com/en-us/library/dd162499%28VS.85%29.aspx
[2] http://msdn.microsoft.com/en-us/library/dd144935%28VS.85%29.aspx
What you could do, if you have access to Win32 API functions, is create a RichEdit Window the same size as your TMemo window, place the text in the RichEdit window, send the EM_FORMATRANGE message to the window and from the result determine how many characters it will hold. Of course this method will work with multiple lines etc...

Resources