Page 1 of 2
RMB-menu for drives in fade-list by Alt+F1 / Alt+F2
Posted: 2012-04-19, 14:04 UTC
by MaxX
That's what I need -> working context menus for all drives in fade-list (list is shown by Alt+F1 / Alt+F2).
Just, we must get sth like this one:
http://savepic.su/1714899.png
Same menus we can get when click RMB on drive-buttons, but drive-buttons are taking too much workspace (when over 10 drive-letters, as I often have), which I can't give (that's why I have drive-buttons disabled).
And I have to run Explorer each time I need to RMB-ckick drive (unmount virtual, eject CDs, other commands from there).
Working RMB in fade-list is really needed function! Please, add it as soon as you can!
p.s.
We've still have time while beta-testing.

Posted: 2012-04-20, 16:39 UTC
by ghisler(Author)
Unfortunately dropdown comboboxes do not support right clicks, sorry.
Posted: 2012-04-20, 22:00 UTC
by MaxX
Why not?
Posted: 2012-04-21, 07:32 UTC
by MVV
MaxX, it is a question to M$/Borland, not to Mr. Ghisler.

BTW, you can choose which buttons TC won't show on drive bar: use
wincmd.ini parameter
DriveBarHide.
ghisler, maybe you can subclass combo box to support right-click? I think it would be nice and not so hard. You can use
GetComboBoxInfo function to get handle of drop-down part of combo box in order to replace its window procedure.
Posted: 2012-04-21, 09:34 UTC
by MaxX
2MVV
So, there's nothing difficult, as I see...
Re: RMB-menu for drives in fade-list by Alt+F1 / Alt+F2
Posted: 2012-04-21, 13:50 UTC
by Horst.Epp
MaxX wrote:That's what I need -> working context menus for all drives in fade-list (list is shown by Alt+F1 / Alt+F2).
Just, we must get sth like this one:
http://savepic.su/1714899.png
Same menus we can get when click RMB on drive-buttons, but drive-buttons are taking too much workspace (when over 10 drive-letters, as I often have), which I can't give (that's why I have drive-buttons disabled).
And I have to run Explorer each time I need to RMB-ckick drive (unmount virtual, eject CDs, other commands from there).
Working RMB in fade-list is really needed function! Please, add it as soon as you can!
p.s.
We've still have time while beta-testing.

You don't need Explorer to reach the RMB context menu of drives !
Mapping a button to TC's My Computer shows you all the drives
and you can reach any context for it.
Posted: 2012-04-21, 14:38 UTC
by MaxX
2Horst.Epp
But I do NOT need to open any folders. Only direct click needed.
Even more, sometimes I just can't change dir to another due to selections and other reasons.
Posted: 2012-04-21, 17:38 UTC
by MarcinW
ghisler(Author) is right - combobox control by default doesn't handle right clicks, when dropped down.
However, here comes a solution:
Code: Select all
unit ExtendedComboBox;
{Tested with Delphi 5 and Delphi 2006}
{Tested with Win95, Win98, WinME, WinNT4, Win2k, WinXP}
interface
uses
Windows, Messages, Forms, Classes, StdCtrls;
type
TComboBox = class(StdCtrls.TComboBox)
private
FObjectInstance : Pointer;
FDropDownWnd : HWND;
FDropDownWndProc : Pointer;
FHandlingDropDownContextMenu : LongWord;
procedure SubclassedListBoxWndProc(var Message : TMessage);
protected
procedure WndProc(var Message : TMessage); override;
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
implementation
uses
Menus;
constructor TComboBox.Create(AOwner : TComponent);
begin
FObjectInstance:=MakeObjectInstance(SubclassedListBoxWndProc);
inherited;
end;
{Every combobox window has it's own listbox window, however, listbox window
is not a child of combobox window. So we can't be sure that listbox window
will be destroyed before destroying combobox - we must un-subclass listbox
window before destroying combobox}
destructor TComboBox.Destroy;
begin
if FDropDownWnd <> 0 then
SetWindowLong(FDropDownWnd,GWL_WNDPROC,Integer(FDropDownWndProc));
if FObjectInstance <> nil then
FreeObjectInstance(FObjectInstance);
inherited;
end;
{In order to override WM_CTLCOLORLISTBOX handler, we must override WndProc -
because of special handling of WM_CTLCOLORLISTBOX by Delphi, "message
WM_CTLCOLORLISTBOX" handler doesn't work}
procedure TComboBox.WndProc(var Message: TMessage);
begin
inherited;
with Message do
begin
{Grab handle of the listbox}
if Msg = WM_CTLCOLORLISTBOX then
if FDropDownWnd = 0 then
begin
FDropDownWnd:=LParam;
FDropDownWndProc:=Pointer(SetWindowLong(FDropDownWnd,GWL_WNDPROC,Integer(FObjectInstance)));
end;
end;
end;
{Subclassed window procedure for listbox}
procedure TComboBox.SubclassedListBoxWndProc(var Message : TMessage);
var
SaveDropDownWnd : HWND;
Pt : TPoint;
TempPt : TPoint;
R : TRect;
Handled : Boolean;
PopupMenu : TPopupMenu;
TempMsg : TMsg;
begin
with Message do
begin
{Don't close listbox when displaying a popup menu}
if Msg = WM_CAPTURECHANGED then
if FHandlingDropDownContextMenu > 0 then
begin
Result:=0;
Exit;
end;
SaveDropDownWnd:=FDropDownWnd;
{Un-subclass listbox}
if Msg = WM_DESTROY then
begin
SetWindowLong(FDropDownWnd,GWL_WNDPROC,Integer(FDropDownWndProc));
FDropDownWnd:=0;
end;
Result:=CallWindowProc(FDropDownWndProc,SaveDropDownWnd,Msg,WParam,LParam);
{Handle right clicks on the listbox (on the basis of TControl.WMContextMenu)}
if Msg = WM_CONTEXTMENU then
if Result = 0 then {if not handled yet}
try
Inc(FHandlingDropDownContextMenu);
Pt:=SmallPointToPoint(TWMContextMenu(Message).Pos);
TempPt:=Pt;
if Pt.X >= 0 then {if not InvalidPoint(Pt) then}
begin
{Listbox has mouse captured, so we get mouse clicks from the whole
screen - so don't allow to display popup menu outside listbox}
if Windows.ScreenToClient(FDropDownWnd,TempPt) then
if Windows.GetClientRect(FDropDownWnd,R) then
if not PtInRect(R,TempPt) then
Exit;
TempPt:=ScreenToClient(Pt);
end;
Handled:=False;
DoContextPopup(TempPt,Handled);
Result:=Ord(Handled);
if not Handled then
begin
PopupMenu:=GetPopupMenu;
if PopupMenu <> nil then
if PopupMenu.AutoPopup then
begin
PopupMenu.PopupComponent:=Self;
if Pt.X < 0 then {if InvalidPoint(Pt) then}
Pt:=ClientToScreen(Point(0,0));
PopupMenu.Popup(Pt.X,Pt.Y);
Result:=1;
end;
end;
if GetCapture <> FDropDownWnd then {if popup menu has been displayed}
begin
SetCapture(FDropDownWnd);
{Remove all waiting WM_LBUTTONDOWN messages - so closing popup menu by
clicking left mouse button on the listbox will not close the listbox}
while PeekMessage(TempMsg,FDropDownWnd,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE) do;
end;
finally
Dec(FHandlingDropDownContextMenu);
end;
end;
end;
(******************************************************************************)
type
TPopupListEx = class(TPopupList)
protected
procedure WndProc(var Message : TMessage); override;
end;
{If the component, which is displaying a popup menu, is a combobox,
close its listbox when the popup menu item has been executed}
procedure TPopupListEx.WndProc(var Message : TMessage);
var
I : Integer;
begin
with Message do
begin
if Msg = WM_COMMAND then
Result:=1; {not handled}
inherited;
if Result = 0 then
Exit;
Result:=0;
for I:=0 to Count-1 do
with TPopupMenu(Items[I]) do
if FindItem(wParam,fkCommand) <> nil then
begin
if PopupComponent is TComboBox then
with TComboBox(PopupComponent) do
DroppedDown:=False;
Break;
end;
end;
end;
var
PopupListEx : TPopupListEx;
initialization
{Replace PopupList global variable with TPopupListEx object}
PopupListEx:=TPopupListEx.Create;
while PopupList.Count > 0 do
try
PopupListEx.Add(PopupList[0]);
finally
PopupList.Remove(PopupList[0]); {Force DeallocateHWnd call for the last item}
end;
PopupList.Free;
PopupList:=TPopupList(PopupListEx);
end.
Usage example: attach this unit _after_ StdCtrls, create combobox, assign a popup menu to the combobox and try:
Code: Select all
procedure TForm1.ComboBox1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
begin
with Sender as TComboBox do
if PopupMenu <> nil then
if PopupMenu.Items.Count > 0 then
PopupMenu.Items[0].Caption:=Text;
end;
or:
Code: Select all
procedure TForm1.ComboBox1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
begin
with Sender as TComboBox do
if PopupMenu <> nil then
if PopupMenu.Items.Count > 0 then
begin
PopupMenu.Items[0].Caption:=Text;
MousePos:=ClientToScreen(MousePos);
PopupMenu.PopupComponent:=TComboBox(Sender); {important!}
PopupMenu.Popup(MousePos.X,MousePos.Y);
Handled:=True;
end;
end;
Posted: 2012-04-21, 18:04 UTC
by Sir_SiLvA
2MarcinW
NICE, now rewrite that for delphi 2 wich is used...
AND for Lazerus for TC64Bit...
Posted: 2012-04-21, 20:02 UTC
by MVV
I think it would be simpler to write just Windows subclass procedure and use SetWindowLongPtr function to override it and send some message to parent window on mouse events... And it will be compatible with both 32/64.
Posted: 2012-04-21, 20:59 UTC
by MarcinW
MVV wrote:I think it would be simpler to write just Windows subclass procedure and use SetWindowLongPtr function to override it
Have you looked at the code above for more than 2 seconds? 2/3 of this code is just subclassed window procedure, and the code installing and uninstalling it. There are many comments there - everything is explained. If you have any working code, that is
simpler than the code above - feel free to put it here...
MVV wrote:"send some message to parent window on mouse events"
Sending "some messages" directly to combobox will not work - control will NOT display a context menu, when mouse click has been fired outside the control. But we want to display context menu in the place of drop-down list (which is not a part of combobox window), so we must handle context menu manually - see code marked as "Handle right clicks on the listbox".
Posted: 2012-04-22, 01:56 UTC
by MarcinW
Changes for Delphi 2:
1) change LongWord to Cardinal
2) declare:
Code: Select all
type
TWMContextMenu = packed record
Msg: Cardinal;
hWnd: HWND;
case Integer of
0: (
XPos: Smallint;
YPos: Smallint);
1: (
Pos: TSmallPoint;
Result: Longint);
end;
3) comment like this:
Code: Select all
Handled:=False;
// DoContextPopup(TempPt,Handled);
// Result:=Ord(Handled);
4) update Menus.pas: move TPopupList type and PopupList global variable to the interface section. Yes, I know that editing Delphi sources is not a good practice. However it's not a problem in our case:
Regards!
Posted: 2012-04-25, 15:40 UTC
by MaxX
So, solution is found.
How soon we'll see this feature in TC?
Posted: 2012-04-25, 18:13 UTC
by Sir_SiLvA
I hope more important things have more priority
(apart from the fact where is the Lazerus Solution wich is needed for TC64

)
Posted: 2012-04-26, 09:52 UTC
by MaxX
2Sir_SiLvA
What can be more imprortant than this daily-needed feature?