WM_DRAWITEM of SysTabControl32 is overpainted? - winapi

I have to restyle our SysTabControl32, so I'm trying to use TCS_OWNERDRAWFIXED and WM_DRAWITEM. Everything works well BUT it seems that the Tabs are still overpainted by the system.
Unfortunately the code is in Visual Objects which makes things more complicated. I already tried a lot of things during the last hours and for the time being I'm clueless. Maybe some of you guys can help or give ma a hint.
Here are some Pictures:
"Naked" Tabcontrol with TCS_OWNERDRAWFIXED. No code at WM_DRAWITEM.
You will notice that the tabs are not filled, but the 3D-Style is painted.
And this is my main problem, because as long as I know this shouldn't happen.
Ownerdrawn Tabs with Text and Background Color (ugly but useful in order to see the Problem)
The same TabControl but with TCS_FLATBUTTONS and TCS_EX_FLATSEPARATORS set. Still the problem with the grey background.
As you know WM_DRAWITEM will be catched in the parent window. I also tried to overwrite or ignore WM_PAINT in the TabControl itself. But it don't help.
Also I played with WM_ERASEBKGND, but I'm stuck at this point.
At all pages starting from codeplex to codeguru or even vbAccelerator it should work. Should :) Don't know if it's visual objects, but API are API and this is still a standard control.
WM_DRAWITEM contains this code, which seems okay. item is DRAWITEMSTRUCT.
hdc := item.hdc
tabIndex := item.itemID
lSelected := (item.itemState == ODS_SELECTED)
wBrush := CreateSolidBrush(RGB(128,128,255))
FillRect(hdc, #item.rcItem, wBrush)
DeleteObject(wBrush)
SetBkMode(hdc,TRANSPARENT)
tTI := MemAlloc(_SizeOf(_winTC_ITEM))
tTI.cchTextMax := 255
tTI.pszText := String2Psz(Buffer(255))
tTI.mask := TCIF_TEXT
lr := SendMessage(item.hwndItem, TCM_GETITEM, item.itemID, LONG(_CAST, tTI))
if (lr != 0)
if (lSelected)
SetTextColor(hdc,RGB(255,0,0))
ELSE
SetTextColor(hdc,RGB(0,0,255))
ENDIF
DrawText(hdc,tTI.pszText,-1,#item.rcItem, _OR(DT_SINGLELINE, DT_VCENTER, DT_CENTER))
ENDIF
MemFree(tTI)

This is my trick to custom draw SysTabControl32
RECT defaultRect = lpDrawItemStruct->rcItem;
//
// Begin of WM_DRAWITEM, we clear the clip rect
SelectClipRgn(lpDrawItemStruct->hDC, NULL);
..
..
..
// End of WM_DRAWITEM, we create a clip rect to disable default system border
ExcludeClipRect(lpDrawItemStruct->hDC,
defaultRect.left - 3,
defaultRect.top - 2,
defaultRect.right + 3,
defaultRect.bottom + 2);
Reference:
https://github.com/pladaria/emule/blob/master/srchybrid/ClosableTabCtrl.cpp

Related

Scroll to selected row in GtkListBox

I'm a bit out of ideas here. I want a very simple thing: to be able to select a given GtkListBox row programmatically and then scroll the list box (which is wrapped in a ScrolledWindow and a Viewport).
Selecting a row is trivial (my code is Go & gotk3, but that's not so important):
listBox.SelectRow(row)
But scrolling to the row proved to be a real challenge. Whatever I tried, I failed:
I tried to focus the row, but it helped nothing
I tried to figure out the row's Y-coordinate using gtk_widget_translate_coordinates(), but it returns -1 for any row
Perhaps I can find out which row is at the top and the bottom of the list box and use that to scroll the ScrolledWindow but I can't figure out how to do that.
Update: I've tried what's proposed here: Manually scroll to a child in a Gtk.ScrolledWindow, but it didn't work as still no scrolling occurred:
listbox.SelectRow(rowToSelect)
listbox.SetFocusVAdjustment(listbox.GetAdjustment())
if rowToSelect != nil {
rowToSelect.GrabFocus()
}
I also tried the same with rowToSelect's child using the code below, to no avail:
if c, err := rowToSelect.GetChild(); err == nil {
c.GrabFocus()
}
I've finally nailed it thanks to the hint by Emmanuel Touzery. I didn't have to go as far as to use timers, but the problem was indeed that at the moment of filling of the list box the row hasn't been realised yet so no coordinate translation could possibly happen.
What I did is scheduled the scrolling using GLib's idle_add(), which makes it happen later downstream, and that seemed to have worked perfectly: see this commit for details.
In short, it all boils down to the following code:
func ListBoxScrollToSelected(listBox *gtk.ListBox) {
// If there's selection
if row := listBox.GetSelectedRow(); row != nil {
// Convert the row's Y coordinate into the list box's coordinate
if _, y, _ := row.TranslateCoordinates(listBox, 0, 0); y >= 0 {
// Scroll the vertical adjustment to center the row in the viewport
if adj := listBox.GetAdjustment(); adj != nil {
_, rowHeight := row.GetPreferredHeight()
adj.SetValue(float64(y) - (adj.GetPageSize()-float64(rowHeight))/2)
}
}
}
}
The above function has to be called using the glib.IdleAdd() and not in the code that fills the list box.
So, I had the same issue but managed to make it work in my case. I think there are good chances my solution will work for you too.
Since the grab_focus method didn't work, I started implementing a workaround solution using listbox_get_row_at_y. Highly unsatisfying, but hopefully it was going to work. And.. it didn't work, because get_row_at_y would always return null, for all the y values I'd feed it. And I knew the listbox wasn't empty. So that made me realize I was trying to focus a row that I had just been adding to the listbox.. The row wasn't realized yet, it couldn't be focused because it wasn't ready for that yet.
So I changed my code to fill the listbox, wait a 100ms timeout, and only then call grab_focus. And that worked!
I'm actually using a library which is wrapping the timeout call for me, but I think you could use g_timeout_add in 'raw' gtk for that purpose.
Note that this means that calling grab_focus on a listbox that was already filled beforehand and the items realized on screen should work directly. If that's your situation then this won't help you.

How to disable the vertical header tracking line in Win32 ListView Control

I am customizing Win32 ListView control and I want to remove the vertical line that is automatically drawn when I resize the headers. I am talking about the line drawn in the row area not in the header. The vertical tracking line can be restricted by handling the HDN_TRACK notification and changing the cxy value in notification data but there seems to be no way to restrict or remove the vertical tracking line in the row area. Anyone has any ideas on how to remove/hide/restrict that line?
The above screenshot was taken while I am tracking the header
Removing the line just makes it harder for the user to use the control!
The easy method is probably to enable visual styles/comctl32 v6, it seems to use live resizing instead but that might depend on the chosen theme/style.
I was able to come up with a ugly hack for the classic control:
HWND hLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|LVS_REPORT, ...);
SendMessage(hLV, CCM_SETVERSION, 5, 0); // <--- Important
...
case WM_NOTIFY:
{
HWND hLV = ...;
NMHDR&nmh = *(NMHDR*) lparam;
switch(nmh.code)
{
case HDN_BEGINTRACKA:case HDN_BEGINTRACKW:
LockWindowUpdate(hLV); // Block all drawing in the listview
return false;
case HDN_ENDTRACKA:case HDN_ENDTRACKW:
LockWindowUpdate(NULL);
return false;
}
This might depend on the HDS_FULLDRAG header style and you probably don't want to do this when visual styles are enabled.

Custom styled Firemonkey list box item not highlighted on click on android and iOS

I'm building multiplatform( iOS, Android, OSX, Windows APP) in Firemonkey. One of the things I'm trying to do is create a custom listbox item( with more data elements) that will work on all these platforms:
will give you ability to select item(s), display properly.
According to research I did, probably the best way for this is to create custom style for list box item and define data elements there. That's what I did.
I'm creating items from client dataset in this procedure:
procedure TMasterDetailForm.LoadAvailable;
var i: Integer;
Item: TListBoxItem;
begin
lstAvailable.Clear;
//Add Header
lstAvailable.BeginUpdate;
Item := TListBoxItem.Create( lstAvailable );
Item.Parent := lstAvailable;
Item.Height := 70;
//Item.OnApplyStyleLookup := ListItemApplyStyleLookupHandler;
Item.StyleLookup := AvailableListHeaderStyle;
//Add Details
cdsAvailable.First;
for I := 1 to cdsAvailable.RecordCount do
begin
Item := TListBoxItem.Create( lstAvailable );
Item.Parent := lstAvailable;
Item.Height := 50;
//Item.Selectable := True;
//Item.OnApplyStyleLookup := ListItemApplyStyleLookupHandler;
Item.StyleLookup := AvailableListItemStyle;
//Item.StyleLookup := 'ListboxItem1Style1';
Item.StylesData[ txtWoNum ] := cdsAvailable.FieldByName( 'work package' ).AsString;
Item.StylesData[ txtAircraft ] := cdsAvailable.FieldByName('aircraft').AsString;
Item.StylesData[ txtTaskDescription ] := cdsAvailable.FieldByName('task').AsString;
cdsAvailable.Next;
end;
lstAvailable.EndUpdate;
end;
Everything gets styled properly on all platforms, except that tapping(clicking) on ListBoxItem on Android or iOS, doesn't highlight the ListBoxItem. If I unissign style then selecting items also works.I can't figure out how to fix this.
Btw, onclick event on ListBox seems to work properly( itemindex changes).
Any input will be greatly appreciated.
Edit( 12/12/2014) : I tried simplifying the example by adding items manually in the ListBox editor and discarding this code here, and I found out that animation for selecting the listbox item changes. So, I customized the listbox item and only changed TextColor to blue. In runtime on Android when you select the listbox item it just changes the color of the text to black instead of painting the whole row. Any ideas how to have listbox behave in similar way like when there is no style attached to it?
Sorry my english is bad.
I have a solution (tested in XE7):
Open a form
Change the IDE Style to "iOS"
Select the TListBox an open a context menu and select "Edit Default
Style": the StyleBook2 is created.
Add a TRectangle component in the style "listboxstyle/background"
with the name "selection". This is the magic!
Now, Firemonkey found the 'selection' component and work fine!
If you already have StyleBook2 component before these steps, you may need to delete it, be careful!

IUP, menu, webbrowser, tree, tabs

I have such menu situation:
int menu_create(Ihandle *menu)
{
hamburger = IupItem("&Hamburger", "hamburger");
IupSetAttributes(hamburger, "AUTOTOGGLE=YES, RADIO=YES");
char* ce = "Ćev&apčići";
cevapcici = IupItem(utf8_to_cp1250(ce), "cevapcici");
IupSetAttributes(cevapcici, "AUTOTOGGLE=YES, RADIO=YES");
exit = IupItem("Exit\tAlt+F4", "exit");
img4 = IupLoadImage("icons\\delete_16x16.ico");
IupSetAttributeHandle(exit, "TITLEIMAGE", img4);
menu = IupMenu(
IupSubmenu("File",
IupMenu(
hamburger,
cevapcici,
IupSeparator(),
IupItem("Carro&t", "carrot"),
IupSeparator(),
exit,
NULL)),
NULL);
IupSetFunction("exit", (Icallback)mnu_exit);
... etc...
IupSetHandle("menu", menu);
return IUP_DEFAULT;
}
How to get "radio toggle group" functionality with items hamburger and cevapcici so first turns off a second checkmark and opposite. This is my try but it don't work.
2) I try webbrowser example from IUP suite on my windows 7. Problem is that bad black flickering appear's during resize (increase). Also, background of webbrowser flicker black during showing.
I try a same example on Ubuntu and there flickering appear's too but it is not so much visible since background is there white.
Is here any way to get rid of those flickering or if not to get white background of webbrowser window on windows?
3) Since webbrowser is ole object (on windows) is it possible to use say "print preview" or "zoom" function by reference from IUP handle or at any other way like we used to do from MS programming tools?
wbInstance.ExecWB(Exec.OLECMDID_OPTICAL_ZOOM, ExecOpt.OLECMDEXECOPT_DONTPROMPTUSER, 150, DBNull.Value)
4) How can I get key_up event fired from IupTree?
5) Interesting situation with IupTabs:
frame3 = IupHbox(mat, val, NULL);
vboxt1 = IupVbox(frame3, NULL);
vboxt2 = IupVbox(frame3, NULL);
IupSetAttribute(vboxt1, "TABTITLE", "First documents... ");
IupSetAttribute(vboxt2, "TABTITLE", "Second documents... ");
tabs = IupTabs(vboxt1, vboxt2, NULL);
hbox1 = IupHbox(tabs, IupVbox(frame, tree, frame2, NULL), NULL);
dlg = IupDialog(hbox1);
When I set frame3 which should be a same for both tabs my GUI frozes.
However, I have to got same "mat" (IupMatrix) in both tabs because by changing tabs other data load in matrix but similar enough to use same matrix and related functions.
What to do here?
1) The RADIO attribute belongs to the IupMenu, not to the IupItem. This also means that all the IupItems inside that menu will be part of the radio.
A workaround would be to manually unset the other toggle inside the action callback.
2) That flicker is not caused by IUP. Don't know why the native controls are doing it.
3) Yes, but you will have to program that using the OLE API. If you take a look at the IupOleControl and IupWebBrower source code and send me the code to do it, I will be happy to add it to IUP.
4) You don't. Use the K_ANY callbacks.
5) You can not reuse a control in different places in any dialog. So you must have two different frames, with two different matrices. What you can do is to encapsulate your matrix, so the same function will create a matrix with the same attributes and callbacks any time you want one.

Capturing a Window that is hidden or minimized

I followed this tutorial (there's a bit more than what's listed here because in my code I get a window via mouse click) for grabbing a window as a bitmap and then rendering that bitmap in a different window.
My question:
When that window is minimized or hidden (SW_HIDE) my screen capture doesn't work, so is it possible to capture a window when it is minimized or hidden?
The PrintWindow api works well, I use it for capturing thumbnails for hidden windows. Despite the name, it is different than WM_PRINT and WM_PRINTCLIENT, it works with pretty much every window except for Direct X / WPF windows.
I added some code (C#) but after reviewing how I used the code, I realized that the window isn't actually hidden when I capture its bitmap, its just off screen so this may not work for your case. Could you show the window off screen, do a print and then hide it again?
public static Bitmap PrintWindow(IntPtr hwnd)
{
RECT rc;
WinUserApi.GetWindowRect(hwnd, out rc);
Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
bool succeeded = WinUserApi.PrintWindow(hwnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
if (!succeeded)
{
gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size));
}
IntPtr hRgn = WinGdiApi.CreateRectRgn(0, 0, 0, 0);
WinUserApi.GetWindowRgn(hwnd, hRgn);
Region region = Region.FromHrgn(hRgn);
if (!region.IsEmpty(gfxBmp))
{
gfxBmp.ExcludeClip(region);
gfxBmp.Clear(Color.Transparent);
}
gfxBmp.Dispose();
return bmp;
}
There are WM_PRINT and WM_PRINTCLIENT messages you can send to the window, which cause its contents to be rendered into the HDC of your choice.
However, these aren't perfect: while the standard Win32 controls handle these correctly, any custom controls in the app might not.
I am trying to get the bitmap of partially hidden controls.
I used code before that did the drawing, but included windows overlapping it. So.. maybe you want to try this.
The WM_PRINTCLIENT should (in my understanding) redraw all inside the control, even if it is not really visible.
const int WM_PRINT = 0x317, WM_PRINTCLIENT = 0x318, PRF_CLIENT = 4,
PRF_CHILDREN = 0x10, PRF_NON_CLIENT = 2,
COMBINED_PRINTFLAGS = PRF_CLIENT | PRF_CHILDREN | PRF_NON_CLIENT;
SendMessage(handle, WM_PRINTCLIENT, (int)hdc, COMBINED_PRINTFLAGS);
//GDIStuff.BitBlt(hdc, 0, 0, width, height, hdcControl, 0, 0, (int)GDIStuff.TernaryRasterOperations.SRCCOPY);
The before code is commented out now. It is based on the code found here: Pocket PC: Draw control to bitmap (accepted answer). It is basically the same as Tim Robinson suggests in this thread.
Also, have a look here
http://www.tcx.be/blog/2004/paint-control-onto-graphics/

Resources