unit UnitFramePopup;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, ComCtrls, UnitClipQueue,
  UnitMenuItemTagdata, unitMisc, Contnrs, UnitClipMenu, UnitTWideChar,
  UnitFrmTooltipNew, Generics.collections;

const USE_POPUP_KEYBOARD_HOOK = FALSE;

const TUsesClipMenu = [IT_POPUPCLIP, IT_CLIPBOARD, IT_PERMANENT, IT_PINNED, IT_TEMP];
const TContainsAClip = [IT_POPUPCLIP, IT_CLIPBOARD, IT_PINNED];
const TPastesOnClickj = TUsesClipMenu;
const TClickableLeftIcons = TUsesClipMenu + [IT_FULL, IT_CLIPSET_HEADER];
const TDoubleSized = [IT_POPUPCLIP, IT_CLIPBOARD, IT_PINNED];

type
TACPopupItem = class;
TACPopupItemCollection = class;
TACPopupItemClass = class of TACPopupItem;
TACPopup = class;


TPopupItemPosition = (
    pipLeftIcon, pipRightIcon, pipCaption, pipNone
);

TPopupItemStyle = (
    psNormal, psLine, psBreak, psSubmenu, psExpandable, psCheckable, psGap
);

TPopupEraseFlag = (
    peCLipboard, pePopupClips, peRemovedClips, peEverything
);

TACOpenWindowFlag = (
    owConfiguration, owEditHistory, owRemovedClips, owPermanentClips,
    owPasteSelected, owSearch, owAbout, owEditClipboard
);
TPopupDisplayMode = (
    pdmAutoHide, pdmFormMode, pdmStayOpen, pdmPinned
);

TACPopupMode = class(TObject)
    private
        fbaseMode : TPopupDisplayMode;
        flist : TStack<TPopupDisplayMode>;

        procedure PushValue;
        function PopValue : TPopupDisplayMode;
    public
        constructor Create;
        procedure setMode(mode : TPopupDisplayMode);
        function getMode : TPopupDisplayMode;
        function IsAutoClose : boolean;
        function equals(mode : TPopupDisplayMode) : boolean;
        procedure SetOverride(mode : TPopupDisplayMode);
        procedure ClearOverride;
        function getModeNoOverride : TPopupDisplayMode;
        procedure reset;
end;
TCustomTransparentControl = class(TCustomControl)
  private
    FInterceptMouse: Boolean;
  protected
    procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Invalidate; override;
    property InterceptMouse: Boolean read FInterceptMouse write FInterceptMouse default False;
  end;
TACPopupPrototype = class(TCustomTransparentControl)
    procedure CreateParams(var Params: TCreateParams);  override;
private
    timMouseSelectDelay: TTimer;

	crit : RTL_CRITICAL_SECTION;
    scroll : THandle;
    timHover: TTimer;
    timShowSubmenu: TTimer;
    timHideSubmenu: TTimer;
    timLeftIconHover : TTimer;
    timIgnoreMouseMove : TTimer;
    timModifier : TTimer;
    //lastHitTest : integer;
    ignoreHitTestOnce : boolean;

    FirstPaint : boolean;
    //PopupMode : TPopupDisplayMode;

    LastMouseX, LastMouseY : integer;

    fItems : TACPopupItem;
    fTools : TACPopupItem;
    fLastVisible : TACPopupItem;

    fKeystrokes : TStringList;
    fAltKeyDown : boolean;
    fMaxItemWidth : integer;

    fFullMode : boolean;
    fHover : TACPopupItem;
    fDownShift : TShiftState;
    FLastPosition : TPopupItemPosition;
    fToolTipNew : TFrmTooltipNew;

    fAcceleratorCount : integer;
    fAccelCharsUsed : string;
    fReservedCount : integer;
    fLastSubmenu : TACPopupItem;
    fQueuedSubmenu : TACPopupItem;
    fMainRect : TRect;


    fPoint : TPoint;
    fTopFixed, fLeftFixed : boolean;
    fim : TClipMenu;
    region1, region2 : HRGN;
    fMouseDownOn : TACPopupItem;

    fNewCanvas : TCanvas;
    fDragStarted : boolean;
    fDragMenuItem : TACPopupItem;
    fDropMenuItem : TACPopupItem;
    fDragX, fDragY : integer;

    fOnHideEvent : TNotifyEvent;
    fShowing : boolean;
    fIncludeEmpty : boolean;

    fIsTooTall : boolean;
    fTopOffset : integer;
    fTopOffsetEnable : boolean;
    fIgnoreMouseMove : boolean;
    fIgnoreKeypresses : boolean;
    fLastKeyDown : word;
    fLastModiferDown : TShiftState;

    fBackgroundColor,
    fHighlightColor,
    fFontColor,
    fClickedColor,
    fDisabledColor,
    fExpandedBackgroundColor,
    fColumnColor,
    fBorderColor,
    fColumnEdgeColor,
    fBackgroundBase,
    fCaptionColor : TColor;

    fGroup : TList<TACPopupITem>;
    fUseGrouping : boolean;
    fGroupingSize : integer;
    fCurrentGroup : Integer;
    fUseGroupingOnce : boolean;
    fUseGroupingOnceFailed : boolean;
    fAutoExpandOnce : TItemType;

    fLastClipSequence : cardinal;
    fTempBitmap : TBitmap;

    fCaptionPoint : TPoint;

    fLastExpandedSet : set of TItemType;

    fKeyActivated : boolean;
    fShowExpandedShortcuts : Boolean;
    fShowExpandedType : TItemType;
    fExpandedKeystrokes : TStringList;

    fHasFiles : boolean;
    fPasteFiles : TACPopupItem;

    AddLineToNext : boolean;
    ForceHide : boolean;
    IsClickWhilePinned : boolean;
    lastRebuildUsedKeyboard : boolean;

    TotalShortcutKeysAvailable : integer;
    CaptionHeight : integer;
    ShowCaption : boolean;
    ShowCaptionShortcuts : boolean;
    ShowOnTaskbar : boolean;
    leftToolsList : TList<TACPopupItem>;
    toolsAccelChars : string;
    toolsMinWidth : integer;
    lastActiveState : integer;

    function GetClipHeader(ci : TClipItem) : string;
    procedure timMouseSelectDelayTimer(Sender: TObject);
    procedure timHoverTimer(Sender: TObject);
    procedure timShowSubmenuTimer(Sender: TObject);
    procedure timHideSubmenuTimer(Sender: TObject);
    procedure timLeftIconHoverTimer(Sender: TObject);
    procedure timIgnoreMouseMoveTimer(Sender: TObject);
    procedure timModiferTimer(Sender: TObject);

    procedure HideTooltip; virtual;
    procedure StartHoverTooltip;

    procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE;
    procedure WMActivate(Var msg:tMessage); message WM_ACTIVATE;
    procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
    procedure WMSetCursor(Var M: TWMSetCursor); message WM_SETCURSOR;
	procedure WMMove(var Msg: TMessage) ; message WM_MOVE;

    function CalcWidth(fpi : TACPopupItem; ClipIt : boolean=true; MinWidth : boolean=true) : integer; virtual;
    function CalcToolWidth(pi : TACPopupItem) : integer;

    function CalcHeight(fpi : TACPopupItem) : integer;
    procedure CalcTotalSize(FixSubmenu:boolean=false);
    procedure EnsureVisibility(FixSubmenu:boolean=false);
    procedure WMKeyDown(var Message: TWMKeyDown);
    procedure MouseLeave(Sender: TObject);
    function IsLegalDrop(p : TACPopupItem) : boolean; virtual;
    function GetAccelerator(i: integer): char;
    function GetAcceleratorPopupClips(i: integer) : Char;

    procedure ReserveAccel;
    procedure AddAScrollbar;
    procedure DetectAutoScroll(top,bottom : integer);

    procedure CheckForAutoExpand(p : TACPopupItem);

    procedure SaveExpandedState;
    procedure LoadExpandedState;

    procedure AssignSubmenuShortcuts(p : TACPopupItem); virtual;




    procedure MouseCursorReset;
    procedure RebuildPopup(AutoPopulate : boolean=true);
    procedure SetHoverUnderMouse;
    procedure SetFormMode(value : boolean);
    function GetFormMode : boolean;
protected
    fPopupMode : TACPopupMode;

    procedure paint; override;
    procedure resize; override;

    function UseKeyboard : boolean; virtual;
    function UsePrefix : boolean; virtual;

    procedure GatherModifierKeys(p : TACPopupItem);
    procedure DetectKeystroke(p : TACPopupItem); virtual;
    procedure DrawItem(p : TACPopupItem);
    procedure DrawCheckgroup(p : TACPopupItem);
    procedure FullRedraw;

    procedure DrawDragmark;

    procedure ClipMenuShow(rightclick : boolean = false); virtual;
    procedure ClipMenuHide;
    procedure ClipMenuReportKey(key : Char); overload;
    procedure ClipMenuReportKey(key : word); overload;
    function ClipMenuVisible : Boolean;
    procedure HoverUp;
    procedure HoverLeft;
    procedure HoverRight;

    procedure HandleOnClick(p : TACPopupItem);
    procedure PreHandleCaptionViaKeystroke(p : TACPopupITem; key : char); virtual; abstract;
    function HandleMouseClick(p : TACPopupItem):boolean; virtual;
    procedure HandleCaptionClick(p : TACPopupItem); virtual;
    procedure HoverClick;
    procedure ShowSubmenuDelayed(p : TACPopupItem);
    procedure CancelShowSubmenu;
    procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;

    function GetItemAt(x,y : integer) : TACPopupItem;
    function MouseInPopup : boolean;
    procedure SetHover(value : TACPopupItem; tooltip:boolean=true);  virtual;
    property Hover : TACPopupItem read fHover;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;

    procedure EditCallback(Sender : Tobject);
    procedure DeleteClipCallback(Sender : TObject);
    procedure DestroyCallback(Sender : Tobject);
    procedure PasteCallback(Sender : Tobject);
    procedure MakePermanentCallback(Sender : Tobject);
    procedure FormModeCallback(Sender : TObject);
    procedure HideCallback(Sender : TObject);



    procedure DragMouseDown(p : TACPopupItem);
    function DragMouseMove(p, last : TACPopupItem) : boolean;
    function DragMouseUp(p : TACPopupItem) : boolean;

    function GetCanvas : TCanvas;
    procedure SetShowExpandedShortcuts(value : Boolean);
    property ShowExpandedShortcuts : boolean read fShowExpandedShortcuts write SetShowExpandedShortcuts;
public

    { Creation }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy;  override;

    function Add : TACPopupItem;
    function AddLine : TACPopupItem;
    function AddBreak : TACPopupItem;

    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;

    procedure AutoPopulate; virtual; abstract;
    procedure Clear;
    procedure ShowPopup(x,y : integer); overload; virtual;
    procedure ShowPopup(pt : TPoint); overload;
    procedure DodgePoint(pt : TPoint);
    procedure HoverDown;
    procedure Hide; virtual;

    {External Draw Routines}
    procedure SetCanvas(c : TCanvas);
    procedure DrawOnCanvas(fullmode : boolean=false);
    property UseCanvas : TCanvas read GetCanvas;
    property IncludeEmpty : boolean read fIncludeEmpty write fIncludeEmpty;

    { Cosmetics }
    //property Spacing : integer read fSPacing write fSpacing;
    property MaxItemWidth : integer read fMaxItemWidth write fMaxItemWidth;
    property OnHideEvent : TNotifyEvent read fOnHideEvent write fOnHideEvent;
    property Showing : boolean read fShowing;
    property FullMode : boolean read fFullMode write fFullMode;
    property UseGrouping : boolean read fUseGrouping write fUseGrouping;
    property ClipsPerSet : integer read fGroupingSize write fGroupingSize;
    property HasFiles : boolean read fHasFiles write fHasFiles;
    property UseFormMode : boolean read GetFormMode write SetFormMode;
end;
TACPopup = class(TACPopupPrototype)
    private
        filter : TEdit;
        fFilterTimer : TTimer;
        fFilterItem : TACPopupItem;

        fExplorerClickTimer : TTimer;
        fExplorerMode : boolean;
        fMouseReset : TTimer;

        searchRemoved : boolean;
        fGroupSwitchUsed : boolean;



        function IsLegalDrop(p : TACPopupItem) : boolean; override;
        procedure AssignSubmenuShortcuts(p : TACPopupItem); override;
        procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
                WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);

        procedure popupClipsChange;

        function GetPermanentFrom(p : TACPopupItem) : TClipItem;
    protected
        function CalcWidth(fpi : TACPopupItem; ClipIt : boolean=true; MinWidth : boolean=true) : integer; override;
        procedure KeyUp(var Key: Word; Shift: TShiftState); override;
        function HandleMouseClick(p : TACPopupItem) : boolean; override;
        procedure PreHandleCaptionViaKeystroke(p : TACPopupITem; key : char); override;
        procedure HandleCaptionClick(p : TACPopupItem); override;
        procedure DetectKeystroke(p : TACPopupItem); override;
        procedure SetHover(value : TACPopupItem; tooltip:boolean=true);  override;

        procedure HandleFormModeClick(Sender : TObject);
        procedure HandlePinnedModeClick(Sender : TOBject);

        procedure SetPrefix(p : TACPopupItem);
        procedure AddSubmenu(p : TACPopupItem);

        procedure AddPopupClips;
        procedure AddCancel;
        procedure AddFullConfigured;
        procedure AddCurrentClipboard;
        procedure AddLast;
        procedure AddCurrentPermanentItems;
        procedure AddSearch;
        procedure AddPastingTools;
        procedure AddProgramOptions;
        procedure AddSwitchToItems;
        procedure AddSwitchToSubmenu;
        procedure AddAllItemsSubmenu;
        procedure AddSystem;

        procedure AddTools;

        procedure ClipMenuShow(rightclick : boolean = false);  override;

        procedure SearchRemovedClicked(Sender : TObject);


        procedure HideFilter(clear : boolean=true);
        procedure FilterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure FilterKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure FIlterKeyPress(Sender: TObject; var Key: Char);
        procedure FilterTimer(Sender : TObject);
        procedure HandleFilter;

        function ClipSetCanExpand(Sender : TACPopupItem) : boolean;

        function HoverClipSetNext : boolean;
        function HoverClipSetPrevious : boolean;

        function PermGroupNext : boolean;
        function PermGroupPrev : boolean;

        procedure DeleteClip(i:integer);
        procedure MoveClip(oldindex,newindex:integer);

        procedure MouseReset(Sender: TObject);
        procedure ExplorerClickTimer(Sender: TObject);

        function FindByType(it : TItemType) : TACPopupItem;

        procedure SetPinnedMode(enabled : boolean);
        function UseKeyboard : boolean; override;
        function UsePrefix : boolean; override;
    public
        procedure AutoPopulate;  override;
        procedure ShowFilter(P : TACPopupItem);
        constructor Create(AOwner: TComponent); override;
        procedure ShowPopup(x,y : integer); override;
        procedure Hide; override;
        procedure KeyPress(var Key: Char); override;
        procedure SearchRemovedOn;

        procedure RefreshMenuItems;
        procedure DoForceHide;

        property ExplorerMode : boolean read fExplorerMode write fExplorerMode;
        procedure HandleHotkeyWhileVisible;

        property PopupMode : TACPopupMode read fPopupMode;
end;

TACIcon = class(TObject)
private
    fIcon : HICON;
    fIconBitmap : TBitmap;
    fIconOpacity : byte;
    fBitmap : TBitmap;
    fCliptypeBitmap : TBitmap;
    fHasCliptypeIcon : boolean;
    fHasIcon : boolean;

    fIconOnlyOnHover : boolean;
    fIconOnExpanded : boolean;

    procedure SetIcon(value : hicon);
    procedure SetBitmap(value : TBitmap);
    procedure SetCliptypeIcon(value : TBitmap);
public
    constructor Create();
    destructor Destroy();
    procedure SetFrom(icon : HICON); overload;
    procedure SetFrom(Bitmap : TBitmap); overload;

    property Icon : HICON read fIcon write SetIcon;
    property Bitmap : TBitmap read fBitmap write SetBitmap;
    property CliptypeIcon : TBitmap read fCliptypeBitmap write SetCliptypeIcon;
end;
TACPopupItemCanExpand = function (Sender: TACPopupItem) : boolean of object;
TACPopupItem = class(TObject)
private
    fLeftIcon : TACIcon;
    fCaptionTrailingBitmap : TBitmap;
    fCaptionIconOnlyOnHover : boolean;
    fCaption : string;
    fHoverOnlyCaption : string;
    fIconHoverCaption : string;
    fPrefix : string;

    fVisible : boolean;
    fSeparatorLine: boolean;
    fBottomLine: boolean;
    fSmallCaption: boolean;
    fStayOpenOnClick : boolean;

    fClip : TClipItem;
    fItemType : TItemType;
    fPermanentID, fPermanentGroupID : integer;

    fMaxHeight : integer;
    fColWidth : TIntList;
    fSubMenu : TACPopupItemCollection;
    fCheckgroup : TObjectList;
    fParent : TACPopupItem;
    fMyColumn : integer;

    fSubShowing : TACPopupItem;

    fExpanded : boolean;
    fCollapseParentOnClick : boolean;
    fChecked : boolean;

    fStyle : TPopupItemStyle;
    fBoundsRect : TRect;
    fDoubleHeight : boolean;
    fDisabled : boolean;
    fShowCollapseIcon : Boolean;

    fCanExpand : TACPopupItemCanExpand;
    fStaticRight : boolean;

    function IsOnClipboard : boolean;
    function IsPictureClip : boolean;
protected
    fBottom : integer;
    fLeft : integer;
    fTop : integer;
    fRight : integer;
    fOnClick : TNotifyEvent;
    fOnRightClick : TNotifyEvent;
    fctrlpressed, fShiftPressed, fMiddleClicked, fTabPressed, fAltpressed : boolean;
    fIntegerData : integer;

    fScaleLeftBitmapToHeight : boolean;

    fHint : string;
    
    procedure SetCaption(value : string);

    function CalcRight : integer;
    function GetIsInSubMenu : boolean;
    function GetIsInExpandedMenu : boolean;
    function GetColumnWidth : integer;
    function GetChecked : boolean;
    procedure SetChecked(value : boolean);

    function GetIsLine : boolean;
    procedure SetIsLine(value : boolean);
    function GetIsBreak : boolean;
    procedure SetIsBreak(value : boolean);
    function GetIsExpandable : boolean;
    procedure SetIsExpandable(value : boolean);
    function GetIsSubmenu : boolean;
    procedure SetIsSubmenu(value : boolean);
    function GetIsGap : boolean;
    procedure SetIsGap(value : boolean);

    function GetItem(Index : integer) : TACPopupItem;
    procedure SetItem(Index : integer; value : TACPopupItem);
    function GetExpanded : boolean;
    procedure SetExpanded(value : boolean);
    function GetIndex : integer;
    function GetOwnerIndex : integer;
    function GetVisibleParent : TACPopupItem;

    procedure SetBoundsRect(parenttop, parentleft : integer);
    function GetBoundsRect : TRect;
    procedure SetCaptionFromClip(value : TClipItem);


    procedure SetHoverOnlyCaption(value : string);
    function GetHoverOnlyCaption : string;
public

    constructor Create();
    destructor Destroy; override;

    property LeftIcon : TACIcon read fLeftIcon;
    function Add : TACPopupItem;
    function AddBreak : TACPopupITem;
    procedure CheckGrouped;
    function IsCheckGrouped : boolean;
    procedure SetShowingSubMenu;
    function DesiredWidth(c : TCanvas) : integer;
    procedure DrawCaption(AC : TACPopupPrototype; c : TCanvas; r : TRect; IsHovered, IsIcon :  boolean);
    procedure DrawCaptionBackground(AC: TACPopupPrototype; c : TCanvas; r : TRect);

    property Right : integer read CalcRight;
    property Left : integer read fLeft;
    property Top : integer read fTOp;
    property Bottom : integer read fBottom;
    property BoundRect : TRect read GetBoundsRect;
    property Clip : TClipItem read fClip write fClip;

    property Caption : String read fCaption write SetCaption;
    property CaptionFromClip : TClipItem write SetCaptionFromClip;


    property IsLine : boolean read GetIsLine write SetIsLine;
    property IsBreak : boolean read GetIsBreak write SetIsBreak;
    property IsExpandable : boolean read GetIsExpandable write SetIsExpandable;
    property IsSubmenu : boolean read GetIsSubmenu write SetIsSubmenu;
    property isGap : boolean read GetIsGap write SetIsGap;
    property Checked : boolean read GetChecked write SetChecked;
    property Expanded : boolean read GetExpanded write SetExpanded;
    property Style : TPopupItemStyle read fStyle;

    property OnClick : TNotifyEvent read fOnClick write fOnClick;
    property OnRightClick : TNotifyEvent read fOnRightClick write fOnRightClick;

    property Prefix : string read fPrefix write fPrefix;
    property ItemType : TItemType read fItemType write fItemType;
    property Visible : boolean read fVisible write fVisible;
    property IsInSubmenu : boolean read GetIsInSubMenu;
    property IsInExpandedMenu : boolean read GetIsInExpandedMenu;
    property ColumnWidth : integer read GetColumnWidth;
    property ColumnIndex : integer read fMyColumn;
    property Items[Index : integer] : TACPopupItem read GetItem write Setitem; default;
    property Index : integer read GetIndex;
    property OwnerIndex : integer read GetOwnerIndex;
    property VisibleParent : TACPopupItem read GetVisibleParent;
    property CtrlPressed : boolean read fCtrlPressed write fCtrlPressed;
    property ShiftPressed : boolean read fShiftPressed write fShiftPressed;
    property MiddleClicked : Boolean read fMiddleClicked write fMiddleClicked;
    property AltPressed : boolean read fAltpressed write fAltpressed;
    property TabPressed : Boolean read fTabPressed write fTabPressed;

    property IntegerData : integer read fIntegerData;
    property PermanentGroupID : integer read fPermanentGroupID;
    property PermanentID : integer read fPermanentID;

    property Hint : string read fHint write fHint;
    property DoubleHeight : boolean read fDoubleHeight write fDoubleHeight;
    property Disabled : boolean read fDisabled write fDisabled;

    property ShowCollapseIcon : Boolean read fShowCollapseIcon write fShowCollapseIcon;
    property CanExpand : TACPopupItemCanExpand read fCanExpand write fCanExpand;
    property StayOpenOnClick : boolean read fStayOpenOnClick write fStayOpenOnClick;
    property SeparatorLine : Boolean read fSeparatorLine write fSeparatorLine;
    property BottomLine : Boolean read fBottomLine write fBottomLine;
    property SmallCaption : Boolean read fSmallCaption write fSmallCaption;

    property HoverOnlyCpation : string read getHoverOnlyCaption write setHoverOnlyCaption;
end;
TACPopupItemCollection = class(TObjectList)
protected
    function GetItem(Index: Integer): TACPopupItem;
    procedure SetItem(Index: Integer; const Value: TACPopupItem);
public
    function Add : TACPopupItem; overload;
    property Items[Index: Integer]: TACPopupItem read GetItem write SetItem; default;
end;


implementation

uses Math, GraphUtil,  UnitFrmConfig, UnitPopupGenerate,
  UnitFrmClipboardManager, StrUtils, UnitToken, UnitFrmPermanentNew,
  UnitFrmMainPopup, UnitPaste, UnitFrmSysTrayMenu, UnitACPopupClicks,
  UnitKeyboardQuery, Clipbrd, UnitFrmEditTextExternal, UnitFrmEditItem,
  UnitFrmDummyClipboardBar, UnitFrmClipMenuNew, ShellAPi, UnitMyCursor,
  UnitFrmDebug, UnitFrmEditHistory, UnitClipDatabase, UnitFocusManager;

{$R *.dfm}


{ TACPopupPrototype }
procedure TACPopupPrototype.CreateParams(var Params: TCreateParams);
begin
    inherited CreateParams(params);

   	Params.Style := WS_POPUP or (WS_CLIPCHILDREN or WS_CLIPSIBLINGS) ;

    Params.ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;


    // setting the WS_EX_APPWINDOW at first lets the window toggle back to
    // this mode and immediately show on the taskbar

    // create() will change the mode to WS_EX_TOOLWINDOW


    {WS_EX_COMPOSITED WS_EX_TRANSPARENT screws up in WinXP - causing a blank redraw
    WS_EXPOMPOSTIED cannot be used in Aero}
end;
constructor TACPopupPrototype.Create(AOwner: TComponent);
begin
    self.InterceptMouse := true;
    self.Visible := false;
    inherited;
    if Win32MajorVersion >= 6 then begin
    	self.DoubleBuffered := true; // CANT use this with transparent on XP
    end;

    fPopupMode := TACPopupMode.Create;

    self.OnExit := self.MouseLeave;

    self.Width := 1;
    self.Height := 1;
    
    fToolTipNew := TFrmTooltipNew.Create(application);
    timhover := TTimer.Create(self);
    timHover.Enabled := false;
    //timHover.Interval := 300;
    timHover.OnTimer := self.timHoverTimer;
    timHideSubmenu := TTimer.Create(self);
    timHideSubmenu.Enabled := false;
    timHideSubmenu.Interval := 300;
    timHideSubmenu.OnTimer := self.timHideSubmenuTimer;
    timShowSubmenu := TTimer.Create(self);
    timShowSubmenu.Enabled := false;
    timShowSubmenu.Interval := 300;
    timShowSubmenu.OnTimer := self.timShowSubmenuTimer;

    timLeftIconHover := TTimer.Create(self);
    timLeftIconHover.Enabled := false;
    timLeftIconHover.Interval := 190;
    timLeftIconHover.ontimer :=  timLeftIconHoverTimer;

    timIgnoreMouseMove := TTimer.Create(self);
    timIgnoreMouseMove.Enabled := false;
    timIgnoreMouseMove.Interval := 100;
    timIgnoreMouseMove.OnTimer := timIgnoreMouseMoveTimer;

    timMouseSelectDelay := TTimer.Create(self);
    timMouseSelectDelay.Enabled := false;
    timMouseSelectDelay.Interval := 300;
    timMouseSelectDelay.OnTimer := timMouseSelectDelayTimer;

    timModifier := TTimer.Create(self);
    timModifier.Enabled := false;
    timModifier.Interval := 300;
    timModifier.OnTimer := timModiferTimer;


    fItems := TACPopupItem.Create();
    fTools := TACPopupItem.Create();
    fKeystrokes := TStringList.create;
    fExpandedKeystrokes := TStringList.Create;
    fExpandedKeystrokes.OwnsObjects := false;
    fExpandedKeystrokes.Duplicates := dupError;

    fTempBitmap := TBitmap.Create;

    fim := nil;

    self.fMaxItemWidth := 300;
    //fSpacing := 2;
    self.Width := 1;
    self.Height := 1;

    self.ParentColor := false;         /// MUST BE FALSE for transparent
    self.ParentBackground := false;    /// ditoo++

    timHover.Interval := Application.HintPause;
    fBorderColor := saturate(cl3DDkShadow,0.10);

    self.fGroup := TList<TACPopupItem>.Create;
    leftToolsList := TList<TACPopupItem>.create;

    Windows.InitializeCriticalSection(crit);
    scroll := 0;
end;
destructor TACPopupPrototype.Destroy;
begin
    fToolTipNew.Close;
    Windows.DeleteCriticalSection(crit);
    inherited;
end;




function TACPopupPrototype.GetClipHeader(ci : TClipItem) : string;
begin
	result := 'right-click for Clip Menu';
	if ci <> nil then begin
    	result := result + '    ('+IntToStr(ci.GetDataSize div 2)+' chars)';
    end;
end;



function TACPopupPrototype.Add: TACPopupItem;
begin
    result := fItems.add;
    if AddLineToNext then begin
        AddLineToNext := false;
        result.SeparatorLine := true;
    end;
end;



procedure TACPopupPrototype.ShowPopup(pt : TPoint);
begin
    self.ShowPopup(pt.x, pt.y);
end;
procedure TACPopupPrototype.ShowPopup(x, y: integer);
var t : Cardinal;
    procedure SetNoActivate;
    begin
        SetWindowLong(self.Handle, GWL_EXSTYLE,
            GetWindowLong(self.Handle, GWL_EXSTYLE) or WS_EX_NOACTIVATE);
    end;
    procedure ClearNoActivate;
    begin
        SetWindowLong(self.Handle, GWL_EXSTYLE,
            GetWindowLong(self.Handle, GWL_EXSTYLE) and not WS_EX_NOACTIVATE);
    end;
    procedure HandleTaksbarIcon;
    begin
        if (ShowOnTaskBar) then begin
            if not FirstPaint then begin
                SetWindowLong(
                    self.Handle,
                    GWL_EXSTYLE,
                    GetWindowLong(Application.Handle, GWL_EXSTYLE) and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW
                );
            end else begin
                if (fPopupMode.getMode <> pdmPinned) then begin
                    SetWindowLong(
                        self.Handle,
                        GWL_EXSTYLE,
                        GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW and not WS_EX_TOOLWINDOW
                    );
                end;
            end;
            ShowWindow(self.Handle, SW_HIDE);
        end;
    end;
begin
	if fshowing then begin
    	FrmDebug.appendlog('ACPopup.ShowPopup called twice');
    	EXIT;
    end;


    windows.EnterCriticalSection(crit);
    lastActiveState := -1;
    try
        HandleTaksbarIcon;

        t := Windows.GetTickCount;
        fShowing := true;
        fIgnoreMouseMove := false;
        fIsTooTall := false;
        fLastKeyDown := 0;
        fToolTipNew.MaxWidth := frmConfig.UDToolWidth.Position;
        fToolTipNew.MaxHeight := frmConfig.UDToolHeight.Position;
        FrmDebug.AppendLog('acpopup start');

        

        timHover.Interval := FrmConfig.tbTooltipDelay.Position;
        timHover.Enabled := false;

        fMaxItemWidth := FrmConfig.UDWidth.Position;
        fShowExpandedShortcuts := false;

        if fim = nil then begin
            fim := TClipMenu.Create(nil);
            self.ClipMenuHide;
            fim.OnRemoveClip := self.DeleteClipCallback;
            fim.OnDestroyClip := self.DeleteClipCallback;
            fim.OnFormMode := self.FormModeCallback;
            fim.OnHide := self.HideCallback;
            fim.OnPasteClip := self.PasteCallback;
        end;

        fpoint.x := x;
        fpoint.y := y;
        self.Left := X;
        self.Top := Y;
        self.CalcTotalSize;
        self.fIgnoreKeypresses := true;



        Windows.SetWindowPos(
            self.Handle,HWND_TOPMOST,
            self.left,self.top,self.width,self.Height,
            SWP_SHOWWINDOW or SWP_NOZORDER or SWP_NOACTIVATE
        );
        if FrmMainPopup.GetNeedsFocus then begin
            ClearNoActivate;
        end else begin
            SetNoActivate;
        end;
        self.visible := true;
        If FrmMainPopup.GetNeedsFocus then begin
            TFocusManager.ForceForeground(self.handle);
        end;
        self.HoverDown;
        FrmDebug.AppendLog('acpopup end - milliseconds=' + IntToStr(Windows.GetTickCount - t));
    finally
        if fitems.fsubmenu.count = 0 then begin
            FrmDebug.AppendLog('acpopup error - empty popup, hiding');
            self.fShowing := true;
            self.Hide;
        end;

        self.fIgnoreKeypresses := False;
        windows.LeaveCriticalSection(crit);
    end;
end;
procedure TACPopupPrototype.DodgePoint(pt : TPoint);
var m : TMonitor;
begin
    m := screen.MonitorFromPoint(pt);
    self.Top := pt.Y - 10 - self.Height;
    if (m <> nil) then begin
        if self.Top < m.Top then begin
            self.Top := m.Top;
        end;
    end;
end;

function SetLeftIcon(p : TACPopupItem; ci : TClipItem; forceType : boolean = false) : HICON;
var
    cdf : TClipFormatType;
begin
    if ci = nil then EXIT;

    if (frmconfig.GetIconType = CBXICONTYPE_CLIPTYPE) or forcetype then begin
        cdf := ci.GetFormatType;
        case cdf of
            FT_PICTURE:		p.lefticon.Bitmap := FrmClipboardManager.iPic.Picture.Bitmap;
            FT_HTML: 		p.lefticon.Bitmap  := FrmClipboardManager.iFormat.Picture.Bitmap;
            FT_RICHTEXT:	p.lefticon.Bitmap := FrmClipboardManager.iFormat.Picture.Bitmap;
            FT_FILE: 		p.lefticon.Bitmap := FrmClipboardManager.iFiles.Picture.Bitmap;
            else
            	p.lefticon.Bitmap := FrmClipboardManager.iText.Picture.Bitmap;
        end;
    end else begin
        p.lefticon.setfrom(ci.CData.GetHICON);
    end;
end;

const LEFT_SPACE = 18 + 4;
const LEFT_BORDER = 1;
const LEFT_EDGE = 2;
const PREFIX_TRAILING_SPACE_MULTIPLE = 2;
const RIGHT_SPACE = 20;
const RIGHT_SPACE_PADDING_MULTIPLE = 3;
const RIGHT_BORDER = 1;
const TOP_BORDER = 1;
const BOTTOM_BORDER = 1;
const CAPTION_LEFT = LEFT_SPACE+LEFT_EDGE; {missing fSpacing}
const FSPACING = 2;

const LINE_HEIGHT = 6;

const RIGHT_MENU_GRADIENT_WIDTH = 35;

function ImgToBitmap(img : TImage) : TBitmap;
begin
    result := img.Picture.Bitmap;
end;


{TACPopup}
constructor TACPopup.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);

    Filter := TEdit.Create(self);
    filter.ParentWindow := self.handle;
    filter.SetBounds(0,0,80,20);
    filter.visible := false;
    //filter.TabStop := false;
    filter.OnKeyUp := self.FilterKeyUp;
    filter.OnKeyDown := self.FilterKeyDown;
    filter.OnKeyPress := self.FIlterKeyPress;



    ffilterTimer := TTimer.Create(self);
    ffilterTimer.Enabled := false;
    ffiltertimer.OnTimer := self.filtertimer;
    fFilterTimer.Interval := 300;

    fMouseReset := TTimer.Create(self);
    fMouseReset.Enabled := false;
    fMouseReset.OnTimer := self.MouseReset;
    fMouseReset.Interval := 300;

    fExplorerClickTimer := TTimer.Create(self);
    fExplorerClickTimer.Enabled := false;
    fExplorerClickTimer.OnTimer := self.ExplorerClickTimer;
    fExplorerClickTimer.Interval := 40;


    self.OnMouseWheel := self.FormMouseWheel;
end;

procedure TACPopup.HandleHotkeyWhileVisible;
begin
    if fpopupMode.equals(pdmPinned) then begin
        TFocusManager.ForceForeground(self.Handle);
    end;
    self.HoverDown;
end;
procedure TACPopup.RefreshMenuItems;
begin
    self.RebuildPopup;
end;
procedure TACPopup.DoForceHide;
begin
    self.ForceHide := true;
    self.Hide;
end;
//
// Filter Related Routines
//
procedure TACPopup.MouseReset(Sender: TObject);
begin
    fMouseReset.Enabled := false;
    screen.Cursor := crMyCursor;
end;

procedure TACPopup.SearchRemovedOn;
begin
    searchRemoved := true;
end;

procedure TACPopup.popupClipsChange;
begin
    self.RebuildPopup;
end;

procedure TACPopup.ShowPopup(x,y : integer);
begin

    self.HideFilter;



    inherited ShowPopup(x,y);
    if frmconfig.cbFilterAlways.Checked then begin
        if assigned(fFilterItem) then self.ShowFilter(fFilterItem);
    end;

    if not self.UseKeyboard then begin
        fExplorerClickTimer.Enabled := true;
    end;

    ClipQueue.addListener(popupClipsChange);

    ACPopupClicks.SetPopup(self);
end;
procedure TACPopup.ShowFilter(P : TACPopupItem);
var
    saccept : string;
    scancel : string;
begin
    if filter.Visible then begin
        self.HideFilter;
        self.HandleFilter;
    end else begin
        filter.Top := p.Top;
        filter.Left := CAPTION_LEFT-fspacing;
        filter.Width := 80;
        filter.Visible := true;
        filter.Text := '';
        filter.Font := UseCanvas.Font;
        filter.Height := UseCanvas.TextHeight('HELO') + 2;

        filter.Top := filter.Top + max(0,((p.Bottom - p.top) - filter.Height) div 2) + 1;

        Windows.SetFocus(filter.Handle);

        self.fCurrentGroup := 0;

        (*
        fToolTipNew.SingleLineOnce := true;
        if frmconfig.cbxFilterEnter.ItemIndex = 1 then begin
            saccept := saccept + 'Enter ';
        end else begin
            scancel := scancel + 'Enter ';
        end;
        if frmconfig.cbxFilterESC.ItemIndex = 1 then begin
            saccept := saccept + 'Esc ';
        end else begin
            scancel := scancel + 'Esc ';
        end;
        if frmconfig.cbxFilterTab.ItemIndex = 1 then begin
            saccept := saccept + 'Tab ';
        end else begin
            scancel := scancel + 'Tab ';
        end;


        fToolTipNew.ShowTooltip('accept [ '+saccept+']'#13#10'cancel [ '+scancel+']',point(
            filter.left+filter.Width+self.left+4,
            filter.top+self.top)
        );
        *)
    end;
end;
procedure TACPopup.HideFilter;
begin
    if filter.Visible then begin
        filter.Visible := false;
        if clear then begin
            filter.Text := '';
        end;
        fFilterTimer.Enabled := false;

        Windows.SetFocus(self.Handle);

    end;
end;
procedure TACPopup.FilterKeyPress(Sender: TObject; var Key: Char);
begin
  case key of
    #9,#13,#27:// Tab,Enter,ESC
        begin
            key := #0;
            EXIT;
        end;
  end;
end;
procedure TACPopup.FilterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
    case key of
    VK_DOWN:
        begin
            HideFilter(false);
            self.HandleFilter;

            self.SetHover(nil);
            self.HoverDown;

            EXIT;
        end;
    end;

    fFilterTimer.Enabled := false;
    fFilterTimer.Enabled := true;
    MouseCursorReset;
end;
procedure TACPopup.FilterKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    function AcceptFilter(c : TComboBox) : boolean;
    begin
        result := c.ItemIndex = 1;

        self.HideFilter(not result);
        if not result then begin
            self.HandleFilter;
        end;
    end;
begin
    if shift = [] then begin
        case key of
        VK_RETURN:
            begin
                AcceptFilter(frmconfig.cbxFilterEnter);
                key := 0;
            end;
        VK_ESCAPE:
            begin
                AcceptFilter(frmconfig.cbxFilterESC);
                key := 0;
            end;
        VK_TAB:
            begin
                AcceptFilter(frmconfig.cbxFilterTab);
                key := 0;
            end;
        end;
    end;
end;
procedure TACPopup.FilterTimer(Sender : TObject);
begin
    fFilterTimer.Enabled := false;
    self.HandleFilter;
end;
procedure TACPopup.HandleFilter;
begin
    fFilterTimer.Enabled := false;
    self.RebuildPopup;

    MouseCursorReset;
end;
procedure TACPopup.SetHover(value : TACPopupItem; tooltip:boolean=true);
var
    prevHover : TACPopupItem;
begin
    prevHover := self.Hover;
    inherited SetHover(value, tooltip);

    if filter.Visible then begin
        if value <> prevHover then begin
            self.HideFilter(false);
            self.HandleFilter;
        end;
    end;


    fMouseReset.Enabled := false;
    if (value<>nil) and
        (value.ItemType in TContainsAClip) and (FLastPosition = pipCaption) and
        PtInRect(
            rect(value.left,value.top,value.Right+1,value.bottom+1),
            self.ScreenToClient(mouse.CursorPos)) then begin
        screen.Cursor := crMyCursor;
    end else begin
        screen.Cursor := crDefault;
    end;
end;

procedure TACPopup.SearchRemovedClicked(Sender : TObject);
begin
    searchRemoved := not searchRemoved;
    self.RebuildPopup;
end;

//
function TACPopup.ClipSetCanExpand(Sender : TACPopupItem) : boolean;
var
    i : integer;
    groupid : integer;
begin
    if sender.expanded then begin
//        // handle Filter trigger
//        if sender.lefticon.fHasIcon then begin
//            self.ShowFilter(sender);
//        end;
        self.SetHover(sender);
    end else begin
        // find the collapsed group and trigger a refresh

        self.fCurrentGroup :=  sender.fIntegerData;
        groupid := sender.fIntegerData;

        self.RebuildPopup;

        for i := 0 to self.fGroup.Count-1 do begin
            if i = groupid then begin
                self.SetHover( TACPopupItem(self.fGroup.Items[i]) );
                BREAK;
            end
        end;
    end;

    // expanding is done manually, cancel the automatic handling
    result := false;
end;


// ClipSet/PermClips Navigation Routines
//
procedure TACPopup.FormMouseWheel(Sender: TObject; Shift: TShiftState;
    WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var b : boolean;
    ac : TACPopupItem;
    pt : TPoint;
begin
    case FrmConfig.GetMouseWheelAction of
    WA_CLIPSET:
        begin
            pt := ScreenToClient(mouse.CursorPos);
            ac := GetItemAt(pt.x,pt.Y);
            if wheeldelta > 0 then begin
                if (ac<>nil) and
                    (
                        (ac.ItemType in [IT_POPUPCLIP, IT_CLIPSET_HEADER]) or
                        (filter.Text<>'')
                    ) then begin
                    b := self.HoverClipSetPrevious;
                end else if (ac=nil) or (ac.ItemType in [IT_PERMANENT, IT_SWITCH]) then begin
                    self.PermGroupPrev;
                end;
            end else begin
                if (ac<>nil) and
                    (
                        (ac.ItemType in [IT_POPUPCLIP, IT_CLIPSET_HEADER]) or
                        (filter.Text<>'')
                    ) then begin
                    b := self.HoverClipSetNext;
                end else if (ac=nil) or (ac.ItemType in [IT_PERMANENT, IT_SWITCH]) then begin
                    self.PermGroupNext;
                end;
            end;
            timHover.Enabled := false;
        end;
    WA_HIGHLIGHT:
        begin
            if wheeldelta > 0 then begin
                self.HoverUp;
            end else begin
                self.HoverDown;
            end;
        end;
    end;
end;
procedure TACPopup.KeyUp(var Key: Word; Shift: TShiftState);
    function IsMovePopupClips : boolean;
    begin
        result := false;
        if ([ssShift]=shift) and (key in [VK_UP,VK_DOWN]) then begin
            if (hover<>nil) and (hover.ItemType=IT_POPUPCLIP) then begin
                case key of
                VK_UP:
                    begin
                        self.MoveClip(hover.IntegerData, hover.IntegerData-1);
                    end;
                VK_DOWN:
                    begin
                        self.MoveClip(hover.IntegerData, hover.IntegerData+1);
                    end;
                end;
            end;
            result := true;
        end;
    end;
    function IsShowClipMenu : boolean;
    begin
        result := false;
        if ((key=VK_LEFT) and ([ssCtrl]=shift))
            or (key=VK_APPS) then begin
            HideTooltip;
            self.ClipMenuShow(false);
            result := true;
        end;
    end;
    function IsReportToClipMenu : boolean;
    begin
        result := false;
        if self.ClipMenuVisible then begin
            if key in [VK_UP, VK_DOWN, VK_LEFT,VK_RIGHT, VK_RETURN, VK_ESCAPE] then begin
                ClipMenuReportKey(key);
            end;
            result := true;
        end;

    end;
    function IsPreviousNext : boolean;
    begin
        result := false;
        case key of
        VK_PRIOR:
            begin
                result := HoverClipSetPrevious;
            end;
        VK_NEXT:
            begin
                result := HoverClipSetNext;
            end;
        VK_HOME:
            begin
                result := PermGroupPrev;
            end;
        VK_END:
            begin
                result := PermGroupNext;
            end;
        end;
    end;
    function IsShowCaptionShortcuts : boolean;
    begin
        result := false;
        if (key=VK_TAB) and (FrmConfig.GetTabClickAction = CA_Show_Titlebar_Shortcut_Keys) then begin
            ShowCaptionShortcuts := not ShowCaptionShortcuts;
            self.RebuildPopup;
            result := true;
        end else if (key = vk_menu) then begin
            self.ShowCaptionShortcuts := not self.ShowCaptionShortcuts;
            self.RebuildPopup;
            result := true;
        end;
    end;
begin
    if fLastKeyDown in [VK_MENU, VK_CONTROL, VK_SHIFT] then begin
        HideTooltip;
        timModifier.Enabled := false; // was TRUE
    end;

    if IsReportToClipMenu then EXIT;
    if IsShowClipMenu then EXIT;
    if IsMovePopupClips then EXIT;

    inherited KeyUp(key, shift);

    if IsPreviousNext then EXIT;
    if IsShowCaptionShortcuts then EXIT;

    if hover = nil then EXIT;

    case key of
    VK_DELETE:
        begin
            case hover.ItemType  of
                IT_POPUPCLIP:
                    begin
                        self.DeleteClip(ClipQueue.IndexOf(hover.clip));
                    end;
                IT_CLIPBOARD: begin
                    frmClipboardManager.ClearClipboard;
                    self.DeleteClipCallback(nil);
                end;
            end;
        end;
    VK_APPS:
        begin
//            self.ClipMenuShow(false);
        end;
    VK_TAB:
        begin
            if (hover.fItemType in TContainsAClip) then begin
                self.Hover.TabPressed := true;
                // self.HoverClick; // Tab is now a configurable modifier
            end;
        end;
    end;
end;
function TACPopup.HoverClipSetNext : boolean;
var p : TACPopupItem;
    i : integer;
begin
    result := false;
    p := self.Hover;
    if p = nil then begin
        i := 0;
    end else begin
        i := p.Index + 1;
    end;
    if i >= self.fitems.fSubMenu.Count then EXIT;

    p := self.fItems.Items[i];
    while p.ItemType <> IT_CLIPSET_HEADER do begin
        inc(i);
        if i >= self.fitems.fSubMenu.Count then EXIT;
        p := self.fItems.Items[i];
    end;

    SetHover(p, false);
    if not p.Expanded then begin
        HoverClick;
    end;
    HoverDown;
    result := true;
end;
function TACPopup.HoverClipSetPrevious : boolean;
var P : TACPopupItem;
    i : integer;
begin
    result := false;
    p := self.Hover;
    if p = nil then p := self.fItems.fSubMenu.GetItem(self.fItems.fSubMenu.count-1);

    if p.IsInExpandedMenu and (p.fParent.ItemType = IT_CLIPSET_HEADER) then begin
        i := p.fParent.Index - 1;
    end else begin
        i := p.Index - 1;
    end;
    if i < 0 then EXIT;

    p := self.fItems.Items[i];
    while p.ItemType <> IT_CLIPSET_HEADER do begin
        dec(i);
        if i < 0 then EXIT;
        p := self.fItems.Items[i];
    end;

    SetHover(p, false);
    if not p.Expanded then begin
        HoverClick;
    end;
    HoverDown;
    result := true;
end;
function TACPopup.PermGroupNext : boolean;
var i : integer;
begin
    result := false;
    i := FrmPermanent.GetPermanentPathIndex;
    inc(i);
    if (i>=frmPermanent.PermFoldersGetCount) then EXIT;
    if FrmPermanent.PermFolderIsSystem(i) then inc(i);

    if (i>=frmPermanent.PermFoldersGetCount) then EXIT;
    FrmPermanent.SetPermanentGroup(i);
    self.RebuildPopup;
    FrmPermanent.AssignPIG(FrmMainPopup.TargetData.ExeName);
    result := true;
end;
function TACPopup.PermGroupPrev : boolean;
var i : integer;
begin
    result := false;
    i := FrmPermanent.GetPermanentPathIndex;
    dec(i);
    if (i<0) then EXIT;
    if FrmPermanent.PermFolderIsSystem(i) then dec(i);
    if FrmPermanent.PermFolderIsSystem(i) then EXIT;

    if (i<0) then EXIT;
    FrmPermanent.SetPermanentGroup(i);
    self.RebuildPopup;
    FrmPermanent.AssignPIG(FrmMainPopup.TargetData.ExeName);
    result := true;
end;
function TACPopup.CalcWidth(fpi : TACPopupItem; ClipIt : boolean=true;MinWidth : boolean=true) : integer;
begin
    result := inherited CalcWidth(fpi, ClipIt, MinWidth);

    if not ClipIt and (fpi.ItemType = IT_POPUPCLIP) then begin
        result := max(self.fMaxItemWidth, result);
    end;
end;
procedure  TACPopup.PreHandleCaptionViaKeystroke(p : TACPopupItem; key : char);
var
    i, j : integer;
    p2 : TACPopupItem;
    ci : TClipItem;
    dt : string;
    it : TItemType;
begin
    if p.ItemType = IT_PERMANENT then begin
        ci := self.GetPermanentFrom(p);
        dt := ci.getDisplayText;
        if AnsiStartsText(KEYS_STR, dt) or
            AnsiStartsText(KEYS_IGNORENL_STR, dt) then begin
            KeyboardQuery.WaitUntilRelease( VkKeyScan(key) );
        end;
        myfree(ci);

        EXIT;
    end;
end;
procedure TACPopup.KeyPress(var Key: Char);
var
    i, j : integer;
    p, p2 : TACPopupItem;
    ci : TClipItem;
    dt : string;
    it : TItemType;
begin
    inherited KeyPress(Key);
    if (key = #0) then EXIT;

    windows.EnterCriticalSection(crit);



    windows.LeaveCriticalSection(crit);
end;


//
// Popup Clips edited while the popup is open
//
procedure TACPopup.DeleteClip(i:integer);
var x, j : integer;
    it : TItemType;
begin
    x := i;
    ClipQueue.DeleteItem(i);
    self.RebuildPopup;

    for j := 0 to fitems.fSubMenu.Count-1 do begin
        if (fitems[j].ItemType = IT_POPUPCLIP) and (fitems[j].integerdata=x) then begin
            sethover(fitems[j],false);
        end;
    end;
end;
procedure TACPopup.MoveClip(oldindex,newindex:integer);
var x, j : integer;
begin
    x := newindex;
    if not ClipQueue.Move(oldindex,newindex) then EXIT;

    self.RebuildPopup;

    for j := 0 to fitems.fSubMenu.Count-1 do begin
        if (fitems[j].ItemType = IT_POPUPCLIP) and (fitems[j].integerdata=x) then begin
            sethover(fitems[j],false);
        end;
    end;
end;


// Detect When user tries to "off-click" to hide the popup
procedure TACPopup.ExplorerClickTimer(Sender: TObject);
begin
    if KeyboardQuery.IsClicked(leftButton) then begin
        if not self.MouseInPopup then begin
            self.Hide;
            fExplorerClickTimer.Enabled := false;
        end;
    end;
end;
procedure TACPopup.Hide;
    function FocusLostFromClipMenuClick : boolean;
    begin
        result := self.fim.showing and self.fim.MouseInMenu
    end;
begin
    FrmDebug.AppendLog('Hide Request');
    if ClipMenuVisible then begin
        ClipMenuHide;
    end;
    if not self.ForceHide then begin
        if (fPopupMode.equals(pdmPinned)) and (not IsClickWhilePinned) then begin
            if (UseKeyboard <> self.lastRebuildUsedKeyboard) then
                self.RebuildPopup;
        end;

        if fPopupMode.getMode in [pdmFormMode, pdmPinned, pdmStayOpen] then EXIT;
        if FocusLostFromClipMenuClick then EXIT;
    end else begin
        ForceHide := false;
    end;

    inherited Hide;

    ClipQueue.removeListener(popupClipsChange);
    if self.fshowing = false then EXIT;
    fExplorerClickTimer.Enabled := false;
    SetPinnedMode(false);
end;

procedure TACPopup.SetPinnedMode(enabled : boolean);
begin
    if enabled then  begin
        fpopupMode.setMode(pdmPinned);

        if (ShowOnTaskbar) then begin
            SetWindowLong(
                self.Handle,
                GWL_EXSTYLE,
                GetWindowLong(Application.Handle, GWL_EXSTYLE) or (WS_EX_APPWINDOW) and not WS_EX_TOOLWINDOW
            );

            ShowWindow(self.Handle,SW_NORMAL);
        end;
    end else begin
        fpopupMode.setMode(pdmAutoHide);

        if (ShowOnTaskbar) then begin
            SetWindowLong(
                self.Handle,
                GWL_EXSTYLE,
                GetWindowLong(Application.Handle, GWL_EXSTYLE) and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW
            );
            ShowWindow(self.Handle,SW_NORMAL);
        end;
        TFocusManager.ForceForeground(self.Handle);
    end;
    self.RebuildPopup;
end;
function TACPopup.UseKeyboard : boolean;
begin
    result := (not fExplorerMode) and  inherited;
end;
function TACPopup.UsePrefix : boolean;
begin
    result := inherited and not fExplorerMode;
end;

function TACPopup.IsLegalDrop(p: TACPopupItem): boolean;
begin
    result := false;
    if inherited IsLegalDrop(p) then begin
        case fdragmenuitem.itemtype of
            IT_POPUPCLIP, IT_PERMANENT, IT_TEMP, IT_PINNED: begin
                if fDragMenuItem.ItemType = p.ItemType then begin
                    result := true;
                end;
            end;
            else begin
                if fDragMenuItem.IsExpandable or
                    (fdragmenuitem.ItemType in [IT_CLIPBOARD, IT_SEARCH, IT_FULL,IT_POPUPCLIP,IT_PERMANENT]) then begin
                    if p.IsExpandable or
                    (p.ItemType in [IT_CLIPBOARD, IT_SEARCH, IT_FULL,IT_POPUPCLIP, IT_PERMANENT]) then begin
                        result := true;
                    end;
                end;
            end;
        end;
    end;
end;
function TACPopup.HandleMouseClick(p : TACPopupItem):boolean;
    procedure DoIt;
    begin
        FrmMainPopup.SkipFocusReturnOnce;
        self.hide;
    end;
begin
    result := false;
	{handle Icon clicks, pass of Caption cliks}
    {handle right clicks}
    IsClickWhilePinned := fPopupMode.equals(pdmPinned);
    if ([ssLeft, ssMiddle] * fDownShift) <> [] then begin
        if hover=nil then begin
            SetHover(p,false);
        end;
        case FLastPosition of
            pipLeftIcon: begin
                case hover.itemtype of
                    IT_PERMANENT:
                        begin
                            DoIt;

                            FrmEditHistory.ShowPermanent(hover.fPermanentGroupID, hover.fPermanentID);
                        end;
                    IT_FULL:
                        begin
                            DoIt;
                            FrmConfig.pcPanels.ActivePage := FrmConfig.tsMenuOrder;
                            frmConfig.Show;
                            TFocusManager.ForceForeground(frmconfig.Handle);
                        end;
                    IT_LINE, IT_NONE:
                        begin
                            // do nothing, Lines have not icons
                        end
                else
                    begin
                        if p.SmallCaption then EXIT;

                        fim.SetACPopupItem(hover);
                        fim.SetPopupClip(hover.Clip);
                        case FrmConfig.GetIconClickAction of
                        CBXICONCLICKACTION_EDIT:
                            begin
                                DoIt;
                                if frmConfig.cbEditClipWindow.checked then begin
                                    FrmEditItem.SetText(hover.clip.GetAsPlaintext, nil);
                                    FrmMainPopup.ShowPreviewEditForm;
                                end else begin
                                    frmEditTextExternal.EditClip(hover.clip);
                                end;
                            end;
                        CBXICONCLICKACTION_PIN:
                            fim.btnPin.Click;
                        CBXICONCLICKACTION_DELETE:
                            fim.btnDelete.Click;
                        CBXICONCLICKACTION_DESTROY:
                            fim.btnDestroy.Click;
                        CBXICONCLICKACTION_CLIPBOARD:
                            fim.btnClipboard.Click;
                        CBXICONCLICKACTION_MIMIC:
                            fim.btnMimic.Click;
                        CBXICONCLICKACTION_SHIFTINSERT:
                            fim.btnShiftInsert.Click;
                        CBXICONCLICKACTION_CTRLV:
                            fim.btnCtrlV.Click;
                        end;
                    end;
                end;
            end;
            pipCaption: begin
                inherited HandleMouseClick(p);
            end;
            pipNone: ;
        end;
    end else if (ssRight in fDownShift) then begin
        if hover=nil then begin
            SetHover(p,false);
        end;

        self.CancelShowSubmenu;
        timHover.Enabled := false;
        timLeftIconHover.Enabled := false;
        if (p.Style = psNormal) and (p.ItemType in TUsesClipMenu) then begin
            self.ClipMenuShow(true);
//            FrmClipMenuNew.ShowForm;
        end;
    end;
end;
procedure TACPopup.HandleCaptionClick(p : TACPopupItem);
begin
    case p.Style of
    psNormal:;
    psLine:;
    psBreak:;
    psSubmenu:;
    psExpandable:
        begin
            if (p.ItemType = IT_PASTING_TOOLS) and self.UseFormMode then begin
            end;
        end;
    psCheckable:;
    psGap:;
    end;




    inherited HandleCaptionClick(p);
end;
procedure TACPopup.HandleFormModeClick(Sender : TObject);
var
    p : TACPopupItem;
begin
    p := TACPopupItem(Sender);
    self.UseFormMode := p.Checked;
    p.Expanded := false;
    self.RebuildPopup(true);
end;
procedure TACPopup.HandlePinnedModeClick(Sender : TOBject);
var
    p : TACPopupItem;
begin
    p := TACPopupItem(Sender);

    self.SetPinnedMode( not fpopupMode.equals(pdmPinned) );
    if (p.ItemType = IT_PINNED) then begin
        p.checked := not fpopupMode.equals(pdmPinned);
        p.Expanded := false;
    end;


//    self.RebuildPopup(true);
end;

procedure TACPopup.DetectKeystroke(p: TACPopupItem);
var
	c : char;
    i : integer;
begin
    inherited DetectKeystroke(p);

    i := fkeystrokes.IndexOfObject(p);
    if i <> -1 then begin
        c := fKeystrokes.Strings[i][1];

        if p.ItemType = IT_PERMANENT then begin
            p.Prefix := '&' + c;
            if Pos('&'+c+' ', p.fCaption) = 1 then begin
                p.fCaption := UnitToken.clipManyChars(p.fCaption, 3);
            end;
        end;
    end;
end;
procedure TACPopup.AssignSubmenuShortcuts(p : TACPopupItem);
begin
    if p.ItemType = IT_CLIPSET_HEADER then EXIT;

    inherited AssignSubmenuShortcuts(p);
end;


procedure TACPopup.AddCancel;
var p : TACPopupItem;
begin
    p := self.Add;
    p.ItemType := IT_CANCEL;
    if self.UseKeyboard then begin
        p.Caption := 'Cancel   (ESC)';
    end else begin
        p.Caption := 'Cancel';
    end;
    p.fIntegerData := Integer(MOT_CANCEL);
end;
procedure TACPopup.AddPastingTools;
var
    p, sub : TACPopupItem;
    s : string;
    sl : TStringList;
    i : integer;

    procedure AddFormMode;
    begin
        sub := p.add;
        sub.SeparatorLine := true;
        //frmmainpopup.UseFormMode;
        sub.Caption := 'Form Mode';

        //sub.LeftIcon := GetIconFromBitmap(frmmainpopup.imgEdit.Picture.Bitmap);
        sub.Checked := self.GetFormMode;
        sub.hint := 'Enabled pasting of multiple clips';
        sub.ItemType := IT_FORMMODE;
        sub.OnClick := Self.HandleFormModeClick;
    end;
    procedure AddPinnedMode;
    begin
        sub := p.add;
        sub.Caption := 'Pin to Desktop';

        sub.Checked := fPopupMode.equals(pdmPinned);
        sub.hint := 'Enabled pasting of multiple clips';
        sub.ItemType := IT_PINNEDMODE;
        sub.OnClick := Self.HandlePinnedModeClick;
    end;
begin
    p := self.Add;
    p.IsExpandable := true;

    p.Caption := 'Pasting Tools';
    p.LeftIcon.SetFrom( ImgToBitmap(frmmainpopup.ImgMisc) );
    SetPrefix(p);
    p.fIntegerData := Integer(MOT_PASTEUTILS);
    p.ItemType := IT_PASTING_TOOLS;


   if (not self.UseFormMode) then begin
        sub := p.add;
        sub.caption := 'Paste All';
        sub.LeftIcon.SetFrom(ImgToBitmap(frmmainpopup.imgPasteAll));
        sub.Hint := 'Pastes all Popup Clips as a single text clip';
        sub.leftIcon.fIconOnlyOnHover := true;
        sub.OnClick  := ACPopupClicks.PasteAllClick;

        sub := p.add;
        sub.caption := 'Paste All Files';
        sub.LeftIcon.SetFrom( ImgToBitmap(frmmainpopup.imgPasteAll) );;
        sub.Hint := 'Pastes all File Clips as a single clip';
        sub.lefticon.fIconOnlyOnHover := true;
        sub.OnClick  := ACPopupClicks.PasteAllFilesClick;
        sub.Disabled := not self.fHasFiles;
        self.fPasteFiles := sub;


        sub := p.add;
        sub.caption := 'Paste Selected Text...';
        sub.LeftIcon.SetFrom( ImgToBitmap(frmmainpopup.imgPaste) );
        sub.fIntegerData := Integer(owPasteSelected);
        sub.OnClick := ACPopupClicks.OpenWindowCommand;
        sub.Hint := 'Shows the ''Paste Selected'' Window';
        sub.lefticon.fIconOnlyOnHover := true;
        sub.fCaptionTrailingBitmap := ImgToBitmap(FrmMainPopup.imgNewWindow);


        sub := p.Add;
        sub.Caption := 'Search and Paste ...';
        sub.fCaptionTrailingBitmap := ImgToBitmap(FrmMainPopup.imgSearch);
        sub.ItemType := IT_SEARCH;
        sub.fIntegerData := Integer(owSearch);
        sub.OnClick := ACPopupClicks.OpenWindowCommand;
        sub.hint := 'Shows the ''Search'' Window';

        AddFormMode;
//        AddPinnedMode;
    end else begin
        sl := TStringList.Create;
        TClipDatabase.LoadPermanentNames(sl, FORM_MODE_FOLDER);
        i := 0;
        for s in sl do begin
            sub := p.add;
            sub.caption := s;
            sub.Hint := 'Simulates a keystrokes using a macro';
            sub.ItemType := IT_NEXTFIELD;
            sub.fIntegerData := i;
            inc(i);
        end;
        myfree(sl);


        AddFormMode;

        sub := p.Add;
        sub.Caption := 'Form Mode Keystrokes...';
        sub.fCaptionTrailingBitmap := ImgToBitmap(FrmMainPopup.imgNewWindow);
        sub.OnClick := ACPopupClicks.OpenWindowCommand;
        sub.fIntegerData := Integer(owPermanentClips);
        sub.fPermanentGroupID := FrmPermanent.PermFolderToIndex(FORM_MODE_FOLDER);
    end;



    if fPopupMode.getMode in [pdmFormMode] then begin
        p.expanded := true;
    end;

    self.CheckForAutoExpand(p);
    //sub.LeftIcon := GetIconFromBitmap(frmmainpopup.imgEdit.Picture.Bitmap);
end;
procedure TACPopup.AddAllItemsSubmenu;
var i, j : integer;
    m, main, sub, subm2 : TACPopupItem;

    s : string;
    wc : TWideChar;
    ci : TClipItem;
    cl : TClipList;
begin
    main := nil;

    if (not FrmConfig.cbShowAllAsSubmenus.checked) then begin
        main := self.Add;
        main.Caption := 'All Permanent';
        main.lefticon.SetFrom( ImgToBitmap(frmmainpopup.imgPermCasc) );
        main.IsExpandable := true;
        main.fIntegerData := Integer(MOT_ALLPERMANENT);
        main.ItemType := IT_ALLPERM_MENU;
        SetPrefix(main);
    end;
    s := lowercase(frmPermanent.GetPermanentPath);

    FrmDebug.AppendLog('PermFolders count='+IntToStr(frmPermanent.PermFoldersGetCount));
    for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
        if FrmPermanent.PermFolderIsSystem(i) then CONTINUE;

        if (FrmConfig.cbShowAllAsSubmenus.checked) then begin
            m := self.add;
            m.LeftIcon.SetFrom(ImgToBitmap(frmmainpopup.imgPermCasc));
            SetPrefix(m);
        end else begin
            m := main.Add;
        end;
        m.Caption := frmPermanent.PermFoldersGetItem(i);
        m.itemtype := IT_POPUP;
        AddSubmenu(m);


        cl := TClipList.Create(true);
        TClipDatabase.LoadPermanentClips(cl, m.Caption);
        FrmDebug.AppendLog('PermCount='+IntToSTr(cl.Count));
        for j := 0 to cl.count - 1 do begin

            ci := cl[j];
            subm2 := m.add;
            subm2.Caption := ci.getDisplayText;
            subm2.itemtype := IT_PERMANENT;
            subm2.fPermanentGroupID := i;
            subm2.fPermanentID  := j;

            subm2.LeftIcon.SetFrom( ImgToBitmap(FrmMainPopup.ImgEdit) );
            subm2.fIconHoverCaption := 'Edit ...';
            subm2.lefticon.fIconOnlyOnHover := true;

            case ci.GetFormatType of
            FT_FILE: 		subm2.lefticon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgFile);
            FT_PICTURE: 	subm2.lefticon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgPic);
            FT_HTML:		subm2.lefticon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgHTML);
            FT_RICHTEXT:	subm2.lefticon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgRichText);
            FT_UNICODE: 	subm2.lefticon.fHasCliptypeIcon := false;
            end;


            subm2.OnClick := ACPopupClicks.PermanentClipClick;
        end;
        cl.Clear;
        myfree(cl);
    end;

    if (not FrmConfig.cbShowAllAsSubmenus.checked) then begin
        if FrmConfig.cbPermanentItemsSubmenu.Checked then begin
            subm2 := main.Add;
            self.AddSubmenu(subm2);
            subm2.Caption := '[Switch Group]';
        end;
        for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin

            if FrmPermanent.PermFolderIsSystem(i) then CONTINUE;

            if FrmConfig.cbPermanentItemsSubmenu.Checked then begin
                sub := subm2.add;
            end else begin
                sub := main.add;
                if (i=0) then
                    sub.SeparatorLine := true;
            end;

            //sub.Caption := FrmPermanent.PermFoldersGetItem(i);
            sub.fPermanentGroupID := i;
            sub.itemtype := IT_SWITCH;
            sub.fCollapseParentOnClick := true;
            sub.OnClick := ACPopupClicks.PermanentGroupClick;
            wc := TWideChar.create;
            wc.Append(WideChar($2192)); {right arrow}
            if (lowercase(FrmPermanent.PermFoldersGetItem(i)) <> s) then begin
                sub.Checked := false;
                sub.CheckGrouped;
            end else begin
                sub.checked := true;
                sub.CheckGrouped;
            end;
            wc.AppendUnicode('[' +FrmPermanent.PermFoldersGetItem(i) + ']');
            sub.fcaption := wc.GetString;
            sub.hint := 'Changes the current Permanent Clips group';
        end;

	end;

    if (not FrmConfig.cbShowAllAsSubmenus.checked) then begin
        if (main.fSubMenu.Count>0) then begin

            if (FrmConfig.cbShowAllAsSubmenus.checked) then begin
                self.AddLine;
            end else begin
                m := main.Add;
            end;
            m.Caption := 'Edit ...';
            m.SeparatorLine := true;
            m.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
            m.fIntegerData := Integer(owPermanentClips);
            m.fPermanentGroupID := -1;
            m.OnClick := ACPopupClicks.OpenWindowCommand;

            self.CheckForAutoExpand(main);
        end;
    end;
end;

procedure TACPopup.AddSwitchToSubmenu;
var i : integer;
    p, sub : TACPopupItem;
    s : string;
    wc : TWideChar;
begin
    p := self.add;
    p.Caption := 'Permanent Groups';
    p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgPermCasc);
    p.IsExpandable := true;
    p.fIntegerData := Integer(MOT_SWITCH);
    p.ItemType := IT_SWITCH_MENU;
    SetPrefix(p);
    s := lowercase(frmPermanent.GetPermanentPath);


    for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
        if FrmPermanent.PermFolderIsSystem(i) then CONTINUE;

        sub := p.add;
        //sub.Caption := FrmPermanent.PermFoldersGetItem(i);
        sub.fPermanentGroupID := i;
        sub.itemtype := IT_SWITCH;
        sub.fCollapseParentOnClick := true;
        sub.OnClick := ACPopupClicks.PermanentGroupClick;
        wc := TWideChar.create;
        wc.Append(WideChar($2192)); {right arrow}
        if (lowercase(FrmPermanent.PermFoldersGetItem(i)) <> s) then begin

            sub.Checked := false;
            sub.CheckGrouped;
        end else begin
            sub.checked := true;
            sub.CheckGrouped;
        end;
        wc.Append('[' +FrmPermanent.PermFoldersGetItem(i) + ']');
        sub.fcaption := wc.GetString;
        sub.hint := 'Changes the current Permanent Clips group';
    end;

//    p.addline;
    sub := p.add;
    sub.Caption := 'Edit ...';
    sub.SeparatorLine := true;
    sub.fIntegerData := Integer(owPermanentClips);
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.fPermanentGroupID := -1;
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);

    self.CheckForAutoExpand(p);
end;
procedure TACPopup.AddCurrentClipboard;
var
    p : TACPopupItem;
begin
    CurrentClipboard.GetClipboardItem(0);
    if CurrentClipboard.GetDataSize <> 0 then begin
        p := self.Add;
        p.ItemType := IT_CLIPBOARD;

        p.Clip := CurrentClipboard;
        self.SetPrefix(p);
        p.fIntegerData := Integer(MOT_CURRENT);

        p.CaptionFromClip := p.clip;


        p.OnClick := ACPopupClicks.PopupClipClick;
        p.OnRightClick := ACPopupClicks.PopupClipRightClip;

        SetLeftIcon(p, p.clip, true);
    end else begin
        p := self.Add;
        p.ItemType := IT_CLIPBOARD;
        self.SetPrefix(p);
        p.fIntegerData := Integer(MOT_CURRENT);
        p.fcaption := '[empty]';
        p.LeftIcon.Bitmap := FrmClipboardManager.iText.Picture.Bitmap;
        p.Disabled := true;
    end;

    p.HoverOnlyCpation := 'Current Clipboard';
end;
procedure TACPopup.AddCurrentPermanentItems;
var i : integer;

    p, sub : TACPopupItem;
    ci : TPermanentClipItem;
    sl : TCaptionFormatList;
    s : TCaptionFormat;
    procedure AddSmallSwitchSubmenu;
    var i : integer;
        wc : TWideChar;
        s : string;
    begin
        // Default/_System
        if FrmPermanent.PermFoldersGetCount <= 2 then EXIT;

        p := self.add;
        p.IsSubmenu := true;
        p.ItemType := IT_SWITCH;
        p.SmallCaption := true;
        p.BottomLine := true;
        s := FrmPermanent.GetPermanentPath;
        p.fCaption := s;
        s := lowercase(s);
        for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
            if FrmPermanent.PermFolderIsSystem(i) then CONTINUE;

            sub := p.add;
            //sub.Caption := FrmPermanent.PermFoldersGetItem(i);
            sub.fPermanentGroupID := i;
            sub.itemtype := IT_SWITCH;
            sub.fCollapseParentOnClick := true;
            sub.OnClick := ACPopupClicks.PermanentGroupClick;
            wc := TWideChar.create;
            wc.Append(WideChar($2192)); {right arrow}
            if (lowercase(FrmPermanent.PermFoldersGetItem(i)) <> s) then begin

                sub.Checked := false;
                sub.CheckGrouped;
            end else begin
                sub.checked := true;
                sub.CheckGrouped;
            end;
            wc.Append('[' +FrmPermanent.PermFoldersGetItem(i) + ']');
            sub.fcaption := wc.GetString;
            sub.hint := 'Changes the current Permanent Clips group';
        end;
    end;
begin
    if frmPermanent.GetCount = 0 then EXIT;

    if not fGroupSwitchUsed then begin
        AddSmallSwitchSubmenu;
    end;

    sl := TCaptionFormatList.Create();
    TClipDatabase.LoadPermanentCaptionsAndTypes(sl, FrmPermanent.GetPermanentPath);

    ci := TPermanentClipItem.Create;
    i := 0;
	for s in sl do begin
    	p := self.add;
        p.fCaption := s.Key; {bypass the clip cleaning routings}

		p.LeftIcon.Bitmap  := ImgToBitmap(FrmMainPopup.ImgEdit);
        p.fIconHoverCaption := 'Edit ...';

        p.LeftIcon.fIconOnlyOnHover := true;
        p.itemtype := IT_PERMANENT;
        p.fPermanentGroupID := -1;
        p.fPermanentID := i;
        // TODO: Fix this to not use FrmPermanent
//        p.fPermanentText := FrmPermanent.GetItemText(i);
        p.OnClick := ACPopupClicks.PermanentClipClick;
        p.OnRightClick := ACPopupClicks.PopupClipRightClip;

        case TClipFOrmatType(s.value ) of
        FT_FILE: 		p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgFile);
        FT_PICTURE: 	p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgPic);
        FT_HTML:		p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgHTML);
        FT_RICHTEXT:	p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgRichText);
        FT_UNICODE: 	p.LeftIcon.fHasCliptypeIcon := false;
        end;

        SetPrefix(p);
        inc(i);
	end;
    myfree(sl);
end;
procedure TACPopup.AddFullConfigured;
var p : TACPopupItem;
begin
    p := self.Add;
    p.ItemType := IT_FULL;
    if self.UseKeyboard then begin
    	p.Prefix := '&' +FrmConfig.GetAccelSymbols[length(frmconfig.GetAccelSymbols)]+  ' ';
    end;
    if fFullMode then begin
        p.Caption := 'Show Less';
        p.Hint := 'Show only configured items';
        p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgConfMode);
    end else begin
        p.Caption := 'Show More';
        p.Hint := 'Show all possible items';
        p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgConfMode);
    end;
    SetPrefix(p);
    p.fIconHoverCaption := 'Edit Menu Order ...';
end;
procedure TACPopup.AddLast;

begin
{
    if PData.LastClickedText <> '' then begin
        p := self.add;
        p.Caption := 'Last: ' + PData.LastClickedText;
        self.AddPrefix(p);
    end else begin
        if fFullMode = false then
            inc(fReservedCount);
    end;
}
end;
procedure TACPopup.SetPrefix(p: TACPopupItem);
var accel : char;
	i, j  : integer;
    s : string;
begin
	if self.UsePrefix = false then EXIT;

    if fkeystrokes.count >= self.TotalShortcutKeysAvailable then EXIT;

    s := stringreplace(p.Caption,'&&','',[rfReplaceAll]);
    if (Pos('&', s)=0) and (pos('&', p.Prefix)=0)  then begin

        j := 0;
        repeat
//        	if j <> 0 then appendlog('Accel key take: ' + accel);

        	accel := GetAccelerator(j);
            if accel = ' ' then begin
                FrmDebug.AppendLog('out of accelerator keys');
                EXIT;
            end;

            i := fKeystrokes.IndexOf(accel);
            if (i=-1) then begin
                i := Pos(accel, fAccelCharsUsed);
                if i=0 then i:=-1;
            end;
            inc(j);
        until i = -1;
		inc(fAcceleratorCount);

        p.Prefix := '&' + accel  + ' ';
        fKeystrokes.AddObject(accel, p);
    end else begin
		if (p.ItemType in [IT_POPUPCLIP, IT_PERMANENT, IT_FULL])  then begin
            DetectKeystroke(p);
        end;
    end;
end;
procedure TACPopup.AddProgramOptions;
var p, sub, sub2 : TACPopupItem;
    i : integer;
    s : string;
begin
    p := self.Add;
    s := lowercase(FrmMainPopup.TargetData.ExeName);
    p.caption := '['+TokenString(s,'.exe') + '] Options';
    p.fCaption[2] := Uppercase(p.fCaption[2])[1];
    p.IsExpandable := true;
    p.LeftIcon.Icon := FrmMainPopup.TargetData.icon;
    if p.LeftIcon.Icon = 0 then p.LeftIcon.Icon := UnitClipQueue.ClipDataDefaultIcon;
    p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgAICon);

    p.ItemType := IT_PROGRAM_MENU;
    p.fIntegerData := Integer(MOT_PROGRAM);
    SetPrefix(p);
    p.Hint := 'Per-program options for Pasting and Monitoring';
    i := Integer(Paste.GetPasteMethod(FrmMainPopup.TargetData.ExeName));


    sub2 := p.Add;
    sub2.Caption := 'Paste Method';
    sub2.ItemType := IT_POPUP;
    AddSubmenu(sub2);

        sub := sub2.add;
        sub.Caption := '( Use Default )';
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 4);
        sub.fIntegerData := 4;
        sub.CheckGrouped;
        sub.OnClick := ACPopupClicks.PasteMethodClick;

        sub := sub2.add;
        sub.Caption := 'Mimic Typing';
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 2);
        sub.fIntegerData := 2;
        sub.CheckGrouped;
        sub.OnClick := ACPopupClicks.PasteMethodClick;

        sub := sub2.add;
        sub.Caption := 'Clipboard Only';
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 3);
        sub.fIntegerData := 3;
        sub.CheckGrouped;
        sub.OnClick := ACPopupClicks.PasteMethodClick;

        sub := sub2.add;
        sub.Caption := 'keypress [CTRL+V]';
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 0);
        sub.fIntegerData :=0;
        sub.CheckGrouped;
        sub.OnClick := ACPopupClicks.PasteMethodClick;


        sub := sub2.add;
        sub.Caption := 'keypress [SHIFT+Insert]';
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 1);
        sub.fIntegerData := 1;
        sub.CheckGrouped;
        sub.OnClick := ACPopupClicks.PasteMethodClick;

        sub := sub2.add;
        sub.Caption := 'Custom Macro';
        sub.SeparatorLine := true;
        sub.ItemType := IT_PASTE_METHOD;
        sub.Checked := (i = 6);
        sub.fIntegerData := 6;
        sub.CheckGrouped;
        sub.Disabled := frmSysTrayMenu.GetProgramMacro(FrmMainPopup.TargetData.ExeName) = '';
        sub.OnClick := ACPopupClicks.PasteMethodClick;


    sub := p.add;
    sub.caption := 'Disable Monitoring';
    sub.SeparatorLine := true;
    sub.ItemType := IT_PASTE_METHOD;
    sub.Checked := FrmSysTrayMenu.IsDisabledEXE(FrmMainPopup.TargetData.ExeName);
    sub.OnClick := ACPopupClicks.ProgramOptionDisableMonitoring;

    sub := p.add;
    sub.caption := 'Disable ''Mouse Button Trigger''';
    sub.ItemType := IT_PASTE_METHOD;
    sub.Checked := FrmSysTrayMenu.IsNoRightClickEXE(FrmMainPopup.TargetData.ExeName);
    sub.OnClick := ACPopupClicks.ProgramOptionDisableRightClickPopup;

    sub := p.add;
    sub.caption := 'Explorer Compatibility';
    sub.ItemType := IT_PASTE_METHOD;
    sub.Checked := FrmSysTrayMenu.IsExplorerCompatEXE(FrmMainPopup.TargetData.ExeName);
    sub.OnClick := ACPopupClicks.ProgramOptionExplorerCompat;

    sub := p.add;
    sub.caption := 'More ...';
    sub.SeparatorLine := true;
    sub.ItemType := IT_PASTE_METHOD;
    sub.fIntegerData := Integer(owConfiguration);
    sub.OnClick := ACPopupClicks.ConfigurationPerProgram;
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);

    self.CheckForAutoExpand(p);
end;
procedure TACPopup.AddSearch;
var p : TACPopupItem;
begin
    p := self.Add;
    p.Caption := 'Search and Paste ...';
    p.fCaptionTrailingBitmap := ImgToBitmap(FrmMainPopup.imgSearch);
    p.ItemType := IT_SEARCH;
    p.fIntegerData := Integer(owSearch);
    p.OnClick := ACPopupClicks.OpenWindowCommand;
    p.hint := 'Shows the ''Search'' Window';
    SetPrefix(p);
end;
procedure TACPopup.AddSubmenu(p: TACPopupItem);
begin
    p.IsSubMenu := true;
    p.Disabled := true;
    p.ItemType := IT_POPUP;
    p.LeftIcon.fIconOnlyOnHover := true;
end;
procedure TACPopup.AddSwitchToItems;
var i : integer;
    sub : TACPopupItem;
    s : string;
    wc : TWideChar;
begin
    s := lowercase(frmPermanent.GetPermanentPath);
    for i := 0 to frmPermanent.PermFoldersGetCount - 1 do begin
    	if (lowercase(frmPermanent.PermFoldersGetItem(i)) = s) then CONTINUE;
        if FrmPermanent.PermFolderIsSystem(i) then CONTINUE;

        sub := self.add;
        sub.fPermanentGroupID := i;
        sub.itemtype := IT_SWITCH;
        sub.OnClick := ACPopupClicks.PermanentGroupClick;
        wc := TWideChar.create;
        if (lowercase(FrmPermanent.PermFoldersGetItem(i)) <> s) then begin
            wc.Append(WideChar($2192)); {right arrow}
        end;
        wc.AppendUnicode('[' +FrmPermanent.PermFoldersGetItem(i) + ']');
        sub.fcaption := wc.GetString;
        sub.hint := 'Changes the current Permanent Clips group';
        sub.LeftIcon.Bitmap := ImgToBitmap(frmmainpopup.imgPermCasc);
        SetPrefix(sub);
    end;
end;
procedure TACPopup.AddSystem;
var p, sub, sub2 : TACPopupItem;
begin
    p := self.add;
    p.Caption := 'System';
    p.LeftIcon.Bitmap := ImgToBitmap(frmmainpopup.imgAICon);
    p.IsExpandable := true;
    SetPrefix(p);
    p.fIntegerData := Integer(MOT_SYSTEM);
    p.ItemType := IT_SYSTEM_MENU;


    sub := p.Add;
    sub.Caption := 'Configuration ...';
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
    sub.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgA);
    sub.LeftIcon.fIconOnlyOnHover := true;
    sub.ItemType := IT_SYSTEM;
    sub.fIntegerData := Integer(owConfiguration);
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.hint := 'Shows the ''Configuration'' Window';
    sub.fCaptionIconOnlyOnHover := true;

//    p.addline;

//    sub := p.Add;
//    sub.Caption := 'Permanent Clips/Macros ...';
//    sub.SeparatorLine := true;
//    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
//    sub.fLeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgPermCasc);
//    sub.fLeftIconOnlyOnHover := true;
//    sub.ItemType := IT_SYSTEM;
//    sub.fIntegerData := Integer(owPermanentClips);
//    sub.OnClick := ACPopupClicks.OpenWindowCommand;
//    sub.hint := 'Shows the ''Permanent Clips'' Window';
//    sub.fCaptionIconOnlyOnHover := true;

    sub := p.Add;
    sub.Caption := 'Edit Clips/Macros ...';
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
    sub.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgEdit);
    sub.LeftIcon.fIconOnlyOnHover := true;
    sub.ItemType := IT_SYSTEM;
    sub.fIntegerData := Integer(owEditHistory);
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.hint := 'Shows the ''Edit Clips'' Window';
    sub.fCaptionIconOnlyOnHover := true;

    sub := p.Add;
    sub.Caption := 'Edit Clipboard ...';
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
    sub.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgPaste);
    sub.LeftIcon.fIconOnlyOnHover := true;
    sub.ItemType := IT_SYSTEM;
    sub.fIntegerData := Integer(owEditClipboard);
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.fClip := CurrentClipboard;
    sub.hint := 'Edits the clipboard using an external program';
    sub.fCaptionIconOnlyOnHover := true;

//    p.AddLine;

    sub := p.Add;
    sub.caption := 'Flush History';
    sub.SeparatorLine := true;
    sub.ItemType := IT_POPUP;
    AddSubmenu(sub);
//    sub.Hint := 'Erase Clipboad History';

    sub2 := sub.add;
    sub2.Caption := 'Erase Clipboard';
    sub2.fIntegerData := Integer(peClipboard);
    sub2.OnClick := ACPopupClicks.EraseHistory;
    sub2 := sub.add;
    sub2.Caption := 'Erase Popup Clips';
    sub2.fIntegerData := Integer(pePopupClips);
    sub2.OnClick := ACPopupClicks.EraseHistory;
    sub2 := sub.add;
    sub2.Caption := 'Erase Removed Clips';
    sub2.fIntegerData := Integer(peRemovedClips);
    sub2.OnClick := ACPopupClicks.EraseHistory;
//    sub.AddLine;
    sub2 := sub.add;
    sub2.Caption := 'Erase Everything';
    sub2.SeparatorLine := true;
    sub2.fIntegerData := Integer(peEverything);
    sub2.OnClick := ACPopupClicks.EraseHistory;


    sub := p.Add;
    sub.Caption := 'Toggle Clipboard Bar';
    sub.LeftIcon.Bitmap := ImgToBitmap(frmmainpopup.imgPaste);
    sub.ItemType := IT_SYSTEM;
    sub.Checked := frmClipboardBar.IsVisible;
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.hint := 'Shows or hides the Clipboard Bar';
    sub.LeftIcon.fIconOnlyOnHover := true;
    sub.onclick := ACPopupClicks.ToggleClipboardBar;

//    p.addline;

    sub := p.Add;
    sub.Caption := 'About ...';
    sub.SeparatorLine := true;
    sub.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
    sub.ItemType := IT_SYSTEM;
    sub.fIntegerData := Integer(owAbout);
    sub.OnClick := ACPopupClicks.OpenWindowCommand;
    sub.hint := 'Shows the ''About'' Window';

    sub := p.Add;
    sub.Caption := 'Exit';
    sub.ItemType := IT_SYSTEM;
    sub.OnClick := frmSysTrayMenu.ExitMenuItemClickEvent;
    sub.hint := 'Closes the program';

    self.CheckForAutoExpand(p);
end;

procedure TACPopup.AddTools;
var
    p : TACPopupItem;
    s : string;

    prefix : string;
    procedure AddFilter;
    begin
        p := ftools.Add;
        p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgSearchTool);
        p.ItemType := IT_TOOL;
        leftToolsList.Add(p);
        p.OnClick := ACPopupClicks.ToolFilterClick;
        p.Prefix := '&'+toolsAccelChars[1];
        fKeystrokes.AddObject(toolsAccelChars[1],p);
        p.Hint := 'Filter';
        if (p.fprefix <> '') and (not p.Disabled) then begin
            p.Hint := p.Hint +'  [Key '+p.fPrefix[2]+']';;
        end;
        if (Filter.Text <>'') then begin
            p.Caption := '('+Filter.Text+')';
        end;
        if not UseKeyboard then HideFilter;
        if (fExplorerMode) then begin
            p.Disabled := true;
            p.LeftIcon.fIconOpacity := 100;
        end;
    end;
    procedure AddLessMore;
    begin
        p := fTools.Add;
        if self.UsePrefix then begin
            p.Prefix := '&' +prefix+  ' ';
        end;
        if not fFullMode then begin
            p.Hint := 'Show More  [Key '+prefix+' ]';
            p.caption := 'More';
            p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgMore);
        end else begin
            p.Hint := 'Show Less  [Key '+prefix+' ]';
            p.caption := 'Less';
            p.LeftIcon.Bitmap :=  ImgToBitmap(FrmMainPopup.imgLess);
        end;
        fKeystrokes.AddObject(prefix, p);
        leftToolsList.Add(p);
        p.ItemType := IT_TOOL;
        p.OnClick := ACPopupClicks.ToolMoreLessClick;
        p.StayOpenOnClick := true;
        p.fScaleLeftBitmapToHeight := true;
    end;
    procedure HandleCaption;
    begin
        if (fExplorerMode) then begin
            p := ftools.Add;
            p.ItemType := IT_TOOL;
            p.isGap := true;
            p.SmallCaption := true;
            p.Caption := '[Explorer Mode]';

            leftToolsList.Add(p);
        end else if Paste.GetClipboardOnlyOnce and not Paste.GetClipboardOnly then begin
            p := ftools.Add;
            p.ItemType := IT_TOOL;
            p.isGap := true;
            p.SmallCaption := true;
            p.fCaption := '[Clipboard Only]';

            leftToolsList.Add(p);
        end;
    end;
    procedure AddSystem;
    begin
        p := fTools.Add;
        p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgSystem);
        p.Hint := 'System Menu';
        p.Caption := '';
        p.OnClick := ACPopupClicks.ToolSystemMenuClick;
        p.ItemType := IT_TOOL;
    //    setPrefix(p);
        p.StayOpenOnClick := true;
        p.fScaleLeftBitmapToHeight := true;
    end;
    procedure AddPin;
    begin
        p := fTools.Add;
        if (fpopupMode.equals(pdmPinned)) then begin
            p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgPin2);
        end else begin
            p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgPin);
        end;
        p.fScaleLeftBitmapToHeight := true;
        p.Hint := 'Pin to Desktop';
        p.ItemType := IT_TOOL;
        p.OnClick := HandlePinnedModeClick;
    end;
var
    i : integer;
    wd : integer;
begin
    fTools.fSubMenu.Clear;
    prefix := FrmConfig.GetAccelSymbols[length(frmconfig.GetAccelSymbols)];

    leftToolsList.Clear;

    // left to right
    AddFilter;
    AddLessMore;
    HandleCaption;

    // right to left
    AddSystem;
    AddPin;


{
    p := fTools.Add;
    p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.ImgMisc);
    p.Caption := '';
    s := lowercase(FrmMainPopup.TargetData.ExeName);
    p.Hint :=  '['+TokenString(s,'.exe') + '] Options';
    p.itemType := IT_TOOL;
    p.OnClick := ACPopupClicks.ToolProgramOptionsClick;
    p.StayOpenOnClick := true;
    p.fScaleLeftBitmapToHeight := true;
}
end;
type
    cliphelper = class helper for TClipItem
public
    procedure setFormat(format : word);
end;
procedure cliphelper.setFormat(format : word);
begin
    self.cformat := self.FileFormatToFormat(format);
end;
procedure TACPopup.AddPopupClips;
var i, clipcnt, lastClipcnt : integer;
    lastIcon : HICON;
    lastBM : TBitmap;
    p : TACPopupItem;
    group : TACPopupItem;
    clp : TClipItem;
    clipFormat : word;
    str, text : string;
    sl : TStringList;
    removedCnt: integer;
CONST LEFT_OPACITY = 200;
    procedure SetRightIcon(p : TACPopupItem);
    begin
        case p.fclip.GetFormatType of
        FT_FILE:
            begin
                self.fHasFiles := true;
                p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgFile);
            end;
        FT_PICTURE:
            begin

                p.LeftIcon.fHasCliptypeIcon := false;
                if p.ItemType = IT_PERMANENT then begin
                    p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgPic);
                end;
            end;
        FT_HTML:		p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgHTML);
        FT_RICHTEXT:	p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgRichText);
        FT_UNICODE: 	p.LeftIcon.fHasCliptypeIcon := false;
        end;

        if p.LeftIcon.CliptypeIcon <> nil then
        	p.LeftIcon.CliptypeIcon.TransparentColor := $AAAAAA;
    end;
    procedure SetPopupPrexif(p : TACPopupItem);
    begin
        if FrmConfig.cbPinnedShortcuts.Checked then begin
            p.prefix :=  '&' + GetAcceleratorPopupClips(clipcnt+PinnedClipQueue.GetQueueCount) +' ';
        end else begin
            p.prefix :=  '&' + GetAcceleratorPopupClips(clipcnt) +' ';
        end;
    end;
    procedure AddPinnedClips;
    var i : integer;
    begin
        if PinnedClipQueue.GetQueueCount > 0 then begin
            for i := (PinnedClipQueue.GetQueueCount - 1) downto 0 do begin
                p := self.add;
                p.Clip := PinnedClipQueue.GetClipItem(i);
                p.CaptionFromClip := p.clip;
                //p.Prefix := '  ';
                if self.UsePrefix and frmconfig.cbPinnedShortcuts.checked then begin
                    p.prefix := '&' + GetAcceleratorPopupClips((PinnedClipQueue.GetQueueCount-1)-i) +' ';
                end;
                p.ItemType := IT_PINNED;
                SetLeftIcon(p, p.Clip);
                p.LeftIcon.fIconOpacity := LEFT_OPACITY;
                p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgUnkown);
                p.OnClick := ACPopupClicks.PopupClipClick;
                p.OnRightClick := ACPopupClicks.PopupClipRightClip;
                p.fIntegerData := i;

                SetRightIcon(p);
                DetectKeystroke(p);
            end;
            Self.AddLine;
        end;
    end;
    procedure HandleGroupingSetup;
    begin
         //
        // use group when enabled and history > set size
        // use group ONCE when popup too tall and a large enough history
        // use group when a filter is present

        if frmconfig.rbClipSetsAlways.Checked then begin
            self.fUseGrouping := true;
        end else begin
            self.fUseGrouping := (ClipQueue.GetQueueCount > FrmConfig.udClipsPerSet.Position)
                and FrmConfig.cbEnableClipSets.Checked;
            if self.fUseGroupingOnce then begin
                Self.fUseGroupingOnce := false;
                self.fUseGrouping := (ClipQueue.GetQueueCount > FrmConfig.udClipsPerSet.Position);
                self.fUseGroupingOnceFailed := not self.fUseGrouping;
            end;
        end;
        self.ClipsPerSet := FrmConfig.udClipsPerSet.Position;

        if Filter.Text <> '' then self.fUseGrouping := true;
        fFilterItem := nil;
    end;
    function GetCurrentGroup(forceNew : boolean = false; Title : string = '  Clip Set  ') : TACPopupItem;
    var
        rem : integer;
    begin
        result := group;
        if (clipcnt<>0) and (lastclipcnt = clipcnt) then EXIT;

        rem := clipcnt mod self.ClipsPerSet;
        if ( (rem = 0) and
            not ((clipcnt=0) and (fgroup.count<>0))
            ) or forceNew then begin
            lastIcon := 0;
            lastBM := nil;
            lastClipcnt := clipcnt;
            group := self.Add;
            group.IsExpandable := true;
            group.ItemType := IT_CLIPSET_HEADER;
            if (clipcnt < 10) then begin
                group.Caption := Title+' ('+IntToStr(clipcnt+1)+'-'+
                    IntToStr(clipcnt + (ClipsPerSet -  rem))+')';
            end else begin
                group.Caption := Title+' ('+IntToStr(clipcnt+1)+'-'+
                    IntToStr(clipcnt + (ClipsPerSet -  rem))+')';
            end;
            group.Expanded := false;
            group.ShowCollapseIcon := false;
            group.CanExpand := self.ClipSetCanExpand;
            group.fIntegerData := fgroup.count;


            SetPrefix(group);
            Dec(Self.fAcceleratorCount);   // kludge to keep the shortcut key for the first submenu right
            fGroup.Add(group);
        end;
        result := group;
    end;
    procedure HandleIconVisual;
    begin
        p.LeftIcon.fIconOpacity := LEFT_OPACITY;
        case frmconfig.GetIconType of
        CBXICONTYPE_PROGRAM:
            begin
                SetLeftIcon(p, p.Clip);
                case FrmConfig.GetRepeatIcons of
                CBXREPEATICONS_DIMMED:
                    begin
                        if (p.LeftIcon.Icon = lasticon) and (lasticon<>0) then begin
                            p.LeftIcon.fIconOpacity := 25;

                        end;
                        lasticon := p.LeftIcon.Icon;
                    end;
                CBXREPEATICONS_NORMAL:
                    begin
                    end;
                CBXREPEATICONS_HIDDEN:
                    begin
                        if (p.LeftIcon.Icon = lasticon) and (lasticon<>0) then begin
                            p.LeftIcon.fIconOpacity := 0;
                        end;
                        lasticon := p.LeftIcon.Icon;
                    end;
                end;
            end;
        CBXICONTYPE_CLIPTYPE:
            begin
                SetLeftIcon(p, p.Clip);
                case FrmConfig.GetRepeatIcons of
                CBXREPEATICONS_DIMMED:
                    begin
                        if (p.LeftIcon.Bitmap = lastBM) and (lastBM<>nil) then begin
                            p.LeftIcon.fIconOpacity := 25;
                        end;
                        lastBM := p.LeftIcon.Bitmap;
                    end;
                CBXREPEATICONS_NORMAL:
                    begin

                    end;
                CBXREPEATICONS_HIDDEN:
                    begin
                        if (p.LeftIcon.Bitmap = lastBM) and (lastBM<>nil) then begin
                            p.LeftIcon.Bitmap := nil;
                        end else begin
                            lastBM := p.LeftIcon.Bitmap;
                        end;
                    end;
                end;

            end;
        CBXICONTYPE_NONE:
            begin

            end;
        end;

    end;
begin
    CurrentClipboard.GetClipboardItem(0);

    self.fHasFiles := false;

    AddPinnedClips;
    HandleGroupingSetup;

    self.fGroup.Clear;

    clipcnt := 0;
    lastClipcnt := 0;
    {$region 'Generate Popup Clips'}
    // extract Clip, Caption, Prefix, and 2 possible icons
    for i := 0 to ClipQueue.GetQueueCount - 1 do begin
        clp := ClipQueue.GetClipItem(i);
        if self.fUseGrouping then begin
            p := GetCurrentGroup;
            if filter.Text <> '' then begin
                if not ContainsText(clp.GetAsPlaintext, filter.Text)then begin
                    CONTINUE;
                end;
            end;
            p := p.Add;
        end else begin
            p := self.add;
        end;

        p.Clip := clp;
        p.CaptionFromClip := p.clip;
        if self.UsePrefix then begin
            if (not FrmConfig.cbPopupCharLimit.Checked) or
                (clipcnt < frmconfig.udPopupKeysLimit.Position) then begin
                SetPopupPrexif(p);
            end;
        end;
        inc(clipcnt);
        p.ItemType := IT_POPUPCLIP;
        HandleIconVisual;
        p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgUnkown);
        p.OnClick := ACPopupClicks.PopupClipClick;
        p.fIntegerData := i; // ClipQueue Index - not a mistake

        SetRightIcon(p);
        DetectKeystroke(p);
    end;
    {$endregion}
    {$region 'Handle No Clips with Grouping on'}
    if self.fUseGrouping and (clipcnt=0) then begin
        if fgroup.count = 0 then GetCurrentGroup;
        p := self.Add;
        p.Caption := '[No Clips]';
        p.ItemType := IT_NONE;
        p.Disabled := true;
    end;
    {$endregion}

    {$region 'Search Removed checkbox'}
    if (filter.Text <> '')  then begin
        p := self.Add;
        p.Caption := 'Search Removed';
        p.ItemType := IT_SYSTEM;
        p.OnClick := self.SearchRemovedClicked;
        p.StayOpenOnClick := true;
        p.Checked := self.searchRemoved;
        p.SeparatorLine := true;
        SetPrefix(p);

    end;
    {$endregion}

    {$region 'Removed Clips open window'}
    if ((self.fUseGrouping and (fgroup.count > 1)) or
        (clipqueue.GetQueueSize=ClipQueue.GetQueueCount)) and
        (filter.Text = '') then begin
        if fgroup.count>=1 then begin
            p := TACPopupItem(fgroup.items[fgroup.count-1]).Add;
            p.Caption := 'Removed Clips ...';
            p.SeparatorLine := true;
            p.fCaptionTrailingBitmap := ImgToBitmap(frmmainpopup.imgNewWindow);
            p.LeftIcon.Bitmap := ImgToBitmap(FrmMainPopup.imgRemoved);
            p.LeftIcon.fIconOnlyOnHover := true;
            p.ItemType := IT_SYSTEM;
            p.OnClick := ACPopupClicks.OpenWindowCommand;
            p.fIntegerData := integer(owRemovedClips);
        end;
    end;
    {$endregion}


    if (searchRemoved and (filter.text <> '')) then begin
        clipcnt := 0;
        lastClipcnt := 0;
        clp := TClipItem.Create;
        TClipDatabase.StartTextOnlyData;
        i := 0;
        str := filter.Text;
        str := StringReplace(str, chr($20), chr($a0),[rfReplaceAll]);
        removedCnt := 0;
        while (TClipDatabase.LoadNextText(text,clipFormat)) do begin
            if ContainsText(text, str) then begin
                clp.setFormat(clipFormat);
                p := GetCurrentGroup(removedCnt=0,'  Removed Clips  ');
                p := p.Add;
                p.Clip := clp;
                p.Caption := text;
                if self.UsePrefix then begin
                    if (not FrmConfig.cbPopupCharLimit.Checked) or
                        (clipcnt < frmconfig.udPopupKeysLimit.Position) then begin
                        SetPopupPrexif(p);
                    end;
                end;
                inc(removedCnt);
                p.ItemType := IT_PERMANENT;
                HandleIconVisual;
                p.LeftIcon.CliptypeIcon := ImgToBitmap(FrmMainPopup.imgUnkown);
                p.OnClick := ACPopupClicks.RemovedClicked;
                p.fIntegerData := i;

                SetRightIcon(p);
                DetectKeystroke(p);
                inc(clipcnt);

                p.clip := nil;
            end;
            inc(i);
        end;
        TClipDatabase.EndTextOnlyData;
        myfree(clp);
    end;
    if self.fUseGrouping and searchRemoved and (removedCnt = 0) and (filter.text <> '') then begin
        //if fgroup.count = 0 then  getCurrentGroup;
        p := self.Add;
        p.Caption := '[No Removed Clips]';
        p.ItemType := IT_NONE;
        p.Disabled := true;
    end;


    if self.UseGrouping and (fgroup.Count <>0) then begin
        if not (self.fCurrentGroup < fgroup.Count) then begin
            self.fCurrentGroup := 0;
        end;
        TACPopupItem(fGroup.Items[self.fCurrentGroup]).Expanded := true;
    end;
end;

procedure TACPopup.AutoPopulate;
var i, x, cnt : integer;
	c : char;
    linebefore : boolean;
    mot : TMenuOrderType;
    s : string;
    b : boolean;
    procedure InitCaption;
    var c : TCanvas;
    begin
        ShowCaption := true;

        UseCanvas.Font := FrmConfig.GetFont;
        UseCanvas.Font.Size := FrmConfig.GetFont.Size;
        UseCanvas.font.Style := FrmConfig.getfont.style;
        CaptionHeight :=  max(16, UseCanvas.TextHeight('AZ')) + FSPACING ;
        CaptionHeight := max(CaptionHeight, frmconfig.udMinHeight.Position+1);
    end;
    procedure EmptyMenuOrderWorkaround;
    begin
        if (FrmConfig.lvOrder.items.Count=0) then begin
            FrmConfig.lvOrder.HandleNeeded;
            if (FrmConfig.lvOrder.items.Count=0) then begin
                raise Exception.Create('Error: [Configuration>Popup>Menu Order] is empty.');
                EXIT;
            end;
        end;
    end;
    procedure SetupColor;
    begin
        // default colors
        fBackgroundColor := ColorToRGB(clBtnFace);
        fHighlightColor := ColorToRGB(clHighlight);
        fFontColor := ColorToRGB(clBtnText);


        fClickedColor := $00790079;

        // config colors
        if FrmConfig.cbFontColor.Checked then begin
            fFontColor := ColorToRGB(FrmConfig.pnlFontColor.color);
        end;
        if FrmConfig.cbHighlightColor.Checked then begin
            fHighlightColor := ColorToRGB(FrmConfig.pnlHighlightColor.color);
        end;
        if FrmConfig.cbBackgroundColor.Checked then begin
            fBackgroundColor := ColorToRGB(FrmConfig.pnlBackgroundColor.color);
        end;
        if frmconfig.cbClickedColor.Checked then begin
            fClickedColor := ColorToRGB(FrmConfig.pnlClickedColor.color);
        end;



        // derived colors
        fExpandedBackgroundColor := BlendOrReverse(fBackgroundColor, clWhite, clBlack, 90);

        //fExpandedBackgroundColor := DimColorOrReverse(fBackgroundColor, 1.02);
        fColumnColor := BlendOrReverse(fBackgroundColor, $000000, clWhite, 93);
        fColumnEdgeColor := DimColorOrReverse(fBackgroundColor,0.86);
        fDisabledColor := BlendOrReverse(fFontColor, clBlack, clWhite, 90);
        fCaptionColor := fColumnColor;

//        fCaptionColor := Blend(fColumnColor, clBlue, 99);
        if (frmConfig.cbTitleColor.Checked) then begin
            fCaptionColor := ColorToRGB(FrmConfig.pnlTitleColor.Color);
        end;
        if not UseKEyboard then begin
            fCaptionColor := DimColorOrReverse(fCaptionColor, 0.93);
        end;
    end;
    procedure ReserveUserSetPermanentKeys;
    var i,j : integer;
    begin
        fGroupSwitchUsed := false;
        // reserve user set permanent keys
        for i := 0 to FrmConfig.lvOrder.items.Count - 1 do begin
            mot := TMenuOrderType(frmConfig.lvOrder.Items[i].data);
            if frmConfig.lvOrder.Items[i].Checked or
                fFullMode or
                ((mot = MOT_PASTEUTILS) and self.GetFormMode)  then begin
                case mot of
                    MOT_PERMANENT: begin
                        for j := 0 to FrmPermanent.GetCount - 1 do begin
                            s := FrmPermanent.GetItemName(j);
                            s := StringReplace(s,'&&','',[rfReplaceAll]);
                            x := pos('&', s);
                            if (x<>0) then begin
                                if x<length(s) then begin
                                    c := upcase(s[x+1]);
                                    fAccelCharsUsed := fAccelCharsUsed + c;
                                end;
                            end;
                        end;
                    end;
                    MOT_SWITCH:
                        begin
                            fGroupSwitchUsed := true;
                        end;
                end;
            end;
        end;
        FrmDebug.AppendLog('PermKeys= '+fAccelCharsUsed);
        FrmDebug.AppendLog('FrmConfig.lvOrder.items.Count='+IntToStr(FrmConfig.lvOrder.items.Count));
    end;
    procedure HandleExplorerMode;
    var
        p : TACPopupItem;
    begin
        EXIT;

        if not self.fExplorerMode then begin
            if Paste.GetClipboardOnlyOnce and not Paste.GetClipboardOnly then begin
                p := self.Add;
                p.isGap := true;
                p.SmallCaption := true;
                p.fCaption := '(Clipboard Only)';
                p.BottomLine := true;
            end;
            EXIT;
        end;

        p := self.Add;
        p.isGap := true;
        p.SmallCaption := true;
        p.fCaption := '(Explorer Compatibility)';
        p.BottomLine := true;
    end;

var t : Cardinal;
begin
    t := Windows.GetTickCount;
    FrmDebug.AppendLog('Clear Popup');
    EmptyMenuOrderWorkaround;
    self.Clear;
    fitems.fSubShowing := nil;

    InitCaption;


    self.TotalShortcutKeysAvailable := length(frmConfig.GetAccelAlphaNumeric) + length(frmConfig.GetAccelSymbols);

    if (frmconfig.getalwaysClearFilter) and not self.Showing then begin
        filter.text := '';
    end;

    SetupColor;

    timHover.Enabled := false;
    fKeystrokes.Clear;
    fExpandedKeystrokes.Clear;

    fHover := nil; {the ONLY exception for touching the fHover value}
    fReservedCount := 0;


    if FrmConfig.cbPopupCharLimit.Checked then begin
        if frmConfig.cbPinnedShortcuts.Checked then begin
            fAcceleratorCount := Min(ClipQueue.GetQueueSize, FrmConfig.udPopupKeysLimit.position) +
                 PinnedClipQueue.GetQueueCount;
        end else begin
            fAcceleratorCount := Min(ClipQueue.GetQueueSize, FrmConfig.udPopupKeysLimit.position);
        end;
    end else begin
        if frmConfig.cbPinnedShortcuts.Checked then begin
            fAcceleratorCount := ClipQueue.GetQueueSize + PinnedClipQueue.GetQueueCount;
        end else begin
            fAcceleratorCount := ClipQueue.GetQueueSize;
        end;
    end;
    if (ShowCaption) then begin
        toolsAccelChars := toolsAccelChars + GetAcceleratorPopupClips(fAcceleratorCount);
        inc(fAcceleratorCount); // Filter

    end;
    fAccelCharsUsed := '';
    if (ShowCaption) then begin
        self.AddTools;
    end;


    HandleExplorerMode;



    if frmConfig.cbFilterSimplified.Checked and
        (filter.Text <> '')  then begin
        self.AddPopupClips;
        if not self.UseKeyboard then begin
            self.AddLine;
            self.AddCancel;
        end;
    end else begin
        ReserveUserSetPermanentKeys;



        for i := 0 to FrmConfig.lvOrder.items.Count - 1 do begin

            linebefore := (FrmConfig.lvOrder.items[i].SubItems[0] = 'Yes');

            mot := TMenuOrderType(frmConfig.lvOrder.Items[i].data);
            b := fFullMode;
            if MOT = MOT_CANCEL then begin
                // always show CANCEL when forced keyboard off detected
                if (not FrmMainPopup.GetNeedsFocus) then begin
                    fFullMode := true;
                end;
            end;

            if frmConfig.lvOrder.Items[i].Checked or
                fFullMode or
                ((mot = MOT_PASTEUTILS) and self.GetFormMode)  then begin
                if linebefore and (fitems.fSubMenu.Count > 0) then begin
                   self.AddLine;
                end;
                cnt := fItems.fSubMenu.Count;
                case mot of
                    MOT_MENU : begin
                        self.AddPopupClips;
                    end;
                    MOT_CANCEL : self.AddCancel;
                    MOT_CURRENT : self.AddCurrentClipboard;
                    MOT_PROGRAM :
                    begin
                        self.AddProgramOptions;
                    end;
                    MOT_SYSTEM : self.AddSystem;
                    MOT_PASTEUTILS : self.AddPastingTools;
                    MOT_PERMANENT : begin
                        // don't show in full mode, unless configured to show normally
                        if not (fFullMode and (not frmConfig.lvOrder.Items[i].Checked)) then begin
                            self.AddCurrentPermanentItems;
                        end;
                    end;
                    MOT_SWITCH :
                        begin
                            if frmconfig.cbPermanentItemsSubmenu.checked then
                                self.AddSwitchToSubmenu
                            else
                                self.AddSwitchToItems;
                        end;
                    MOT_FULL : self.AddFullConfigured;
                    MOT_ALLPERMANENT :
                        begin
                            self.AddAllItemsSubmenu;
                        end;
                    MOT_SEARCH: self.AddSearch;
                    MOT_BREAK:  if not (ffullMode and (not frmConfig.lvOrder.Items[i].Checked)) then begin
                         self.AddBreak; // don't add breaks in Full Mode
                    end;

                end;
                // remove lines for items that generate no new menuitems
                if linebefore and (cnt = fItems.fSubMenu.count) then begin
                    if cnt <> 0 then begin
                        AddLineToNext := false;
                    end;
                end;
            end;
            fFullMode := b;
        end;

    end;

    fAutoExpandOnce := IT_NONE;

    if fPasteFiles <> nil then begin
        fPasteFiles.Disabled := not self.fHasFiles;
    end;



    FrmDebug.AppendLog('End of AutoPopulate = '+ IntToStr(fitems.fsubmenu.count));
    fIncludeEmpty := false;
end;

{utility}
procedure TACPopup.ClipMenuShow(rightclick : boolean = false);
    procedure CheckForVisibility;
    begin
        fim.Top := max(screen.DesktopRect.top, fim.top);
        fim.Left := max(screen.DesktopRect.left, fim.Left);

        if fim.Width + fim.Left > screen.DesktopRect.right  then begin
            fim.left := screen.DesktopRect.right - fim.Width;
        end;
        if fim.Height + fim.Top > screen.DesktopRect.bottom then begin
            fim.top := screen.DesktopRect.bottom - fim.Height;
        end;
    end;
    procedure ShowIt;
    var fm : TPopupDisplayMode;
    begin
        CheckForVisibility;
        self.fPopupMode.PushValue;
        fPopupMode.setMode(pdmStayOpen);
        fim.show;

        if not self.fExplorerMode then begin
            TFocusManager.ForceForeground(fim.handle);
        end;
        fPopupMode.PopValue;
    end;
begin
	if hover = nil then EXIT;
    if (not UseKeyboard) then EXIT;

    if (hover = fim.GetACPopupItem) and fim.showing then exit;

    self.MouseCursorReset;
    {under or leftside}
    if rightclick then begin
        fim.Top := self.Top + hover.top;
        fim.Left := mouse.CursorPos.X - 40;
    end else begin
        if (fim.Top <> hover.ftop) then begin
            fim.Top := self.Top + hover.ftop-2;
            fim.Left := self.left + hover.fleft -  fim.Width;
        end;
    end;

    self.ClipMenuHide;
    case hover.ItemType of
        IT_PERMANENT:
            begin
                fim.SetPermanentClipMode;
                fim.SetPermanentClip(hover.fPermanentGroupID, hover.fPermanentID);
                fim.SetACPopupItem(hover);
                ShowIt;
            end;
        IT_POPUPCLIP,
        IT_TEMP,
        IT_CLIPBOARD,
        IT_PINNED:
            begin
                fim.SetPopupClipMode;
                fim.SetACPopupItem(hover);
                fim.SetPopupClip(Hover.Clip);
                ShowIt;
            end;
    else
        begin
        end;
    end;

end;
function TACPopup.GetPermanentFrom(p : TACPopupItem) : TClipItem;
var
    s : string;
begin
    result := nil;
    if p.ItemType = IT_PERMANENT then begin
        result := TClipITem.Create;
        if (p.fPermanentGroupID = -1) then begin
            s := FrmPermanent.GetPermanentPath;
        end else begin
            s := FrmPermanent.PermFoldersGetItem(p.fPermanentGroupID)
        end;
        TClipDatabase.LoadPermanent(
            result,
            p.fPermanentID,
            s
        );
    end;
end;
function TACPopup.FindByType(it : TItemType) : TACPopupItem;
var i : integer;
begin
    result := nil;
    for i := 0 to fitems.fSubMenu.Count-1 do begin
        if fitems.fSubMenu[i].fItemType = it then begin
            result := fitems.fSubMenu[i];
            EXIT;
        end;
    end;
end;


{Popuplate Menu}
procedure TACPopupPrototype.RebuildPopup(AutoPopulate : boolean=true);
begin
    FrmDebug.AppendLog('RebuildPopup');
    if AutoPopulate then begin
        self.lastRebuildUsedKeyboard := self.UseKeyboard;
        self.AutoPopulate;
    end;
    self.CalcTotalSize;
    self.Invalidate;
end;
procedure TACPopupPrototype.DetectKeystroke(p: TACPopupItem);
var s : string;
	c : char;
    i : integer;
begin
    // detect non-literal '&' accelerators

    s := p.Prefix + p.Caption;
    s := StringReplace(s,'&&','',[rfReplaceAll]);
    i := Pos('&', s);
    if i <> 0 then begin
        c := s[i+1];
        c := upcase(c);
        p.fcaption := StringReplace(p.fcaption, '&'+c,'&'+c,[rfIgnoreCase]);
        fKeystrokes.AddObject(c, p);
    end;
end;
function TACPopupPrototype.GetAcceleratorPopupClips(i: integer) : Char;
begin
    if FrmConfig.cbPopupCharLimit.Checked then begin
        Result := self.GetAccelerator(
            i - (fAcceleratorCount+fReservedCount)
        );
    end else begin
        if FrmConfig.cbPinnedShortcuts.checked then begin
            Result := self.GetAccelerator(
                i - (ClipQueue.GetQueueSize+PinnedClipQueue.GetQueueCount+fReservedCount)
            );
        end else begin
            Result := self.GetAccelerator(
                i - (ClipQueue.GetQueueSize+fReservedCount)
            );
        end;
    end;
end;
function TACPopupPrototype.GetAccelerator(i: integer): char;
var other : string;
	alphanumeric : string;
begin
    result := ' ';
    inc(i, fAcceleratorCount+fReservedCount);

    if (i>TotalShortcutKeysAvailable) then
        EXIT;

    alphanumeric := frmconfig.GetAccelAlphaNumeric;
    if (i<=length(alphanumeric)) then begin
    	result := alphanumeric[i+1];
    end else begin
    	other := FrmConfig.GetAccelSymbols;
        if (i-length(alphanumeric)) < length(other) then begin {exclude the last character}
        	result := other[i-length(alphanumeric)]; {start with 1 as an index}
        end;
    end;
end;
procedure TACPopupPrototype.CheckForAutoExpand(p : TACPopupItem);
begin
    if p.ItemType = fAutoExpandOnce then begin
        p.Expanded := true;
    end;
end;

procedure TACPopupPrototype.SaveExpandedState;
var i : integer;
begin
    fLastExpandedSet := [];

    for i := 0 to self.fItems.fSubMenu.count - 1 do begin
        with fItems.fSubMenu.Items[i] as TACPopupItem do begin
            if IsExpandable and Expanded then begin
                fLastExpandedSet := fLastExpandedSet + [ItemType];
            end;
        end;
    end;
end;
procedure TACPopupPrototype.LoadExpandedState;
var i : Integer;
begin
    for i := (self.fItems.fSubMenu.count - 1) downto 0 do begin
        with fItems.fSubMenu.Items[i] as TACPopupItem do begin
            if (IsExpandable) and (ItemType in fLastExpandedSet) then begin
                Expanded := true;
            end;
        end;
    end;
end;

function TACPopupPrototype.AddBreak: TACPopupItem;
begin
    result := fItems.AddBreak;
end;
function TACPopupPrototype.AddLine: TACPopupItem;
begin
//    result := fitems.AddLine;
    AddLineToNext := true;
end;
procedure TACPopupPrototype.Clear;
begin
    fitems.fsubmenu.Clear;
    self.fPasteFiles := nil;
end;



{utility routines}
function TACPopupPrototype.IsLegalDrop(p: TACPopupItem): boolean;
begin
	result := false;

	if p = nil then EXIT;
    if fDragMenuItem = nil then EXIT;
	if p = fDragMenuItem then EXIT;

    result := true;
end;
function TACPopupPrototype.GetItemAt(x, y: integer): TACPopupItem;
var i : integer;
    p : TACPopupItem;

    function CheckSubmenus(p : TACPopupItem) : TACPopupItem;
    var i : integer;
        sub : TACPopupItem;
    begin
        result := nil;
        if p = nil then EXIT;

        if (p.fSubShowing <> nil) then begin
            // check nested submenu first
            result := CheckSubmenus(p.fSubShowing);
            if result <> nil then EXIT;
        end;
        for i := 0 to p.fsubmenu.count-1 do begin
            sub := p.fSubMenu[i];

            if (x >= sub.fLeft) and (x <= sub.fRight) then begin
                if (y <= sub.fBottom) and (y >= sub.fTop) then begin
                    result := sub;
                    EXIT;
                end;
            end;
        end;
    end;
begin
    // check submenus first
    result := CheckSubmenus(fitems.fSubShowing);
    if result <> nil then EXIT;

    for i := 0 to fitems.fsubmenu.count-1 do begin
        p := fitems.fsubmenu.Items[i];
        {same column}
        if (x >= p.fLeft) and (x <= p.fRight) then begin
            if (y <= p.fBottom) and (y>=p.fTop) then begin
            	if p.isbreak then EXIT;

                result := p;
                EXIT;
            end;
        end;
        p := nil;
    end;

    if (p=nil) and (result=nil) then begin
        for i := 0 to ftools.fSubMenu.Count-1 do begin
            p := ftools.fSubMenu.Items[i];
            if (x >= p.fLeft) and (x <= p.fRight) then begin
                if (y <= p.fBottom) and (y>=p.fTop) then begin
                    if p.isbreak then EXIT;

                    result := p;
                    EXIT;
                end;
            end;
        end;
    end;
end;
function TACPopupPrototype.MouseInPopup : boolean;
var r : TRect;
begin
    r := Rect(self.left, self.Top,self.Left+self.Width,self.Top+self.Height);

    result := PtInRect(r, mouse.CursorPos);
    if not result then begin
        if fitems.fSubShowing <> nil then begin
            r := Rect(
                fitems.fSubShowing.Left,fitems.fSubShowing.Top,
                fitems.fSubShowing.right, fitems.fSubShowing.bottom);
            result := PtInRect(r, mouse.CursorPos);
        end;
    end;
end;
procedure TACPopupPrototype.AssignSubmenuShortcuts(p : TACPopupItem);
var i,j : integer;
begin
    if self.fKeyActivated and fShowExpandedShortcuts then begin
        if p.IsSubmenu or p.IsExpandable then begin
            self.fShowExpandedType := p.ItemType;
            j := 0;
            fExpandedKeystrokes.Clear;
            for i := 0 to p.fSubMenu.Count - 1 do begin
                with p.fSubMenu.Items[i] do begin
                    if not IsLine and not IsGap then begin
                        Prefix := '&' +self.GetAcceleratorPopupClips(j);
                        fExpandedKeystrokes.AddObject(Prefix[2], p.fSubMenu.Items[i]);
                        Inc(j);
                    end;
                end;
            end;
        end;
    end else begin
        if p.IsSubmenu or p.IsExpandable then begin
            for i := 0 to p.fSubMenu.Count - 1 do begin
                with p.fSubMenu.Items[i] do begin
                    if not IsLine and not IsGap then begin
                        Prefix := '';
                    end;
                end;
            end;
        end;
    end;
end;
procedure TACPopupPrototype.SetShowExpandedShortcuts(value : Boolean);
begin
    fShowExpandedShortcuts := value;
end;
procedure TACPopupPrototype.SetHoverUnderMouse;
var pt : TPoint;
    ac : TACPopupItem;
begin
    Application.ProcessMessages;
    pt := ScreenToClient(mouse.CursorPos);
    ac := self.GetItemAt(pt.X,pt.y);
    SetHover(ac, false);
end;
function TACPopupPrototype.UseKeyboard : boolean;
var
    isForeground : boolean;
begin
    isForeground := (GetForegroundWindow = self.Handle);
    result := (frmconfig.cbUseKeyboard.Checked and (FrmMainPopup.GetNeedsFocus));

    if (fPopupMode.equals(pdmPinned)) then result := isForeground;
end;
function TACPopupPrototype.UsePrefix : boolean;
begin
    result := UseKeyboard or (fPopupMode.equals(pdmPinned));
end;
procedure TACPopupPrototype.SetFormMode(value : boolean);
begin
    if value then begin
        fPopupMode.setMode(pdmFormMode);
    end else begin
        fPopupMode.setMode(pdmAutoHide);
    end;
end;
function TACPopupPrototype.GetFormMode : boolean;
begin
    result := fPopupMode.equals(pdmFormMode);
end;



{Drawing Routines}
procedure TACPopupPrototype.SetCanvas(c: TCanvas);
begin
    fNewCanvas := c;
end;
function TACPopupPrototype.GetCanvas: TCanvas;
begin
    if fNewCanvas = nil then begin
    	result := self.Canvas;
    end else begin
        result := fNewCanvas;
    end;
end;
function TACPopupPrototype.CalcHeight(fpi: TACPopupItem): integer;
var i : integer;
    s : string;
    tempr : TRect;
begin
    result := max(
        UseCanvas.TextHeight('AZW'),
        frmconfig.udMinHeight.Position
    );

    if fpi.SmallCaption and not (fpi.ItemType = IT_TOOL) then begin
        i := UseCanvas.Font.Size;
        UseCanvas.Font.Size := i-1;

        result := UseCanvas.TextHeight('AZW');

        UseCanvas.Font.Size := i;
    end;
    if fpi.DoubleHeight then begin
        s := 'AZ'#13#10'AZ';
        DrawTextW(UseCanvas.Handle, pwidechar(s), length(s),
            tempr, DT_CALCRECT);
        result := max(result,tempr.Bottom-tempr.Top)
    end;

    if fpi.SeparatorLine then inc(result,LINE_HEIGHT);
end;
function TACPopupPrototype.CalcWidth(fpi: TACPopupItem; ClipIt : boolean=true; MinWidth : boolean=true): integer;
var
    s : string;
const
    MIN_WIDTH = 120;
begin
    result := LEFT_BORDER + ({LEFT_SPACE}16) +LEFT_EDGE + fpi.DesiredWidth(UseCanvas) +RIGHT_BORDER;

    if fpi.IsExpandable or fpi.IsSubmenu then begin
        inc(result, RIGHT_SPACE);
    end;

    if ClipIt then begin
    	result := min(result, self.fMaxItemWidth);
    end;
    if (MinWidth) then begin
        if ShowCaption then begin
            result := max(result, toolsMinWidth);
        end;
        result := max(MIN_WIDTH, result);
    end;
end;
function TACPopupPrototype.CalcToolWidth(pi : TACPopupItem) : integer;
begin
    result := CalcWidth(pi, false, false);
    if not ShowCaptionShortcuts and (pi.fPrefix <> '') then begin
        dec(result, FSPACING * PREFIX_TRAILING_SPACE_MULTIPLE);
    end;
    if  (pi.LeftIcon.Bitmap<>nil) and (pi.LeftIcon.Bitmap.Width <> 16) then begin
        dec(result, 16);
        inc(result, pi.LeftIcon.Bitmap.Width);
    end;
    if (pi.LeftIcon.Bitmap = nil) then begin
        dec(result, 16);
    end;
    if (leftToolsList.Contains(pi)) then begin
        if (pi.Prefix <> '') and not ShowCaptionShortcuts then begin
            dec(result, UseCanvas.TextWidth('W'));
        end;
    end;
end;

procedure TACPopupPrototype.CalcTotalSize(FixSubmenu:boolean=false);
    function CalcRect(p : TACPopupItem; top,left : integer) : TRect;
    const GAP_SIZE = 20;
    var wd,ht,i,col, totalwd, maxht, originaltop : integer;
        sub : TACPopupItem;
        r : TRect;
        pop : TACPopupItem;
        procedure TallyColumn;
        begin
            FrmDebug.AppendLog('New Column');
            inc(totalwd, wd);
            p.fColWidth[col] := wd;
            wd := 0;
            inc(col);
            ht := 0;
            if (ShowCaption) then begin
                inc(ht, CaptionHeight+TOP_BORDER);
        end;
        end;
        procedure CalcItem(sub : TACPopupItem);
        var
            twd, itemht : integer;
            drawablePic : boolean;
            IsPic : boolean;
            isWide : boolean;
        begin
           if sub.isBreak then begin
                sub.ftop := originaltop+ht + TOP_BORDER;
                sub.fBottom := sub.fTop;
                sub.fleft := left + totalwd;
                sub.fMyColumn := col;
                TallyColumn;

                maxht := max(ht, maxht);
            end else begin
                sub.ftop := top+ht + TOP_BORDER;
                if sub.IsLine then begin
                    ht := ht + fSpacing + 5;
                end else begin
                	twd := CalcWidth(sub, false);
                	wd := max(wd, min(self.fMaxItemWidth,twd));
                    IsPic := (sub.IsPictureClip);
                    drawablePic := IsPic and
                        (FrmConfig.cbNoThumbnails.Checked=false);

                    isWide := ((twd+CAPTION_LEFT) > trunc(fMaxItemWidth*1.3));
                	if (sub.ItemType in TDoubleSized) and
                    	(drawablePic or ((not IsPic) and frmConfig.cbDoubleHeight.checked and isWide)) then begin
                        sub.DoubleHeight := true;
                        itemht :=  CalcHeight(sub) + 2;
                    end else begin
                        sub.DoubleHeight := false;
                    	itemht := CalcHeight(sub); //adding spacing screws up the aesthetics
                    end;

                    if (sub.DoubleHeight) then begin
                        if (sub.Clip.GetFormatType = FT_PICTURE) and
                            (sub.Clip.GetPicHeight < itemht)then begin
                            sub.DoubleHeight := false;
                            itemht := CalcHeight(sub); //adding spacing screws up the aesthetics
                        end;
                    end;
                    inc(ht, itemht);
                end;

                sub.fBottom := top+ht + TOP_BORDER;
                sub.fleft := left + totalwd;
                sub.fMyColumn := col;

                maxht := max(ht, maxht);
                inc(ht); // otherwise the next "top" will be the exact same as the previous bottom
            end;
        end;
    begin
        wd := 0;
        ht := 0;
        if (ShowCaption) and (top = 0) then begin
            inc(ht, CaptionHeight+TOP_BORDER);
        end;

        originaltop := top;
        col := 0;
        totalwd := 0; maxht := 0;
        p.fColWidth[col] := 0;

        for i := 0 to p.fSubMenu.count - 1 do begin
            sub := p.fSubMenu.Items[i];
            CalcItem(sub);
        end;

        TallyColumn;
        result.top := originaltop;
        result.Left := left;
        result.Bottom := originaltop + maxht + TOP_BORDER+BOTTOM_BORDER + 1;
        result.Right := left + (totalwd);
        p.fMaxHeight := maxht;

        if top=0 then begin
            fMainRect.Top := result.Top;
            fMainRect.left := result.Left;
            fMainRect.Right := result.Right;
            fMainRect.bottom := result.bottom;
        end;

        {no regions, no shadows}
       	if CheckWin32Version(6, 0) then
        if region1 = 0 then begin
            region1 := Windows.CreateRectRgnIndirect(result);
        end else begin
            region2 := Windows.CreateRectRgnIndirect(result);
            windows.CombineRgn(region1,region1,region2, RGN_OR);
            Windows.DeleteObject(region2);
        end;



        if p.fSubShowing <> nil then begin
            {lower the menu so the mouse won't hover it}
            if FixSubmenu then begin
                if fTopFixed and ((p.fSubShowing.fMaxHeight+p.fSubShowing.top)>fitems.fMaxHeight) then begin
                	{move the submenu up to be even with the bottom of the main popup}
                    {this prevents a recursvise shift-newhover loop}
                    r := CalcRect(p.fSubShowing,
                    	max(0,fitems.fMaxHeight - (p.fSubShowing.fMaxHeight+fspacing)),
                        //fitems.fMaxHeight - (p.fSubShowing.fMaxHeight+fspacing),
                        p.fsubshowing.right+1
                    );
                end else begin
                    if (p.fSubShowing.fSubMenu.Count <> 0) and
                        (not p.fSubShowing.fSubMenu.Items[0].isGap) then begin
                        pop := p.fSubShowing.add;
                        pop.SetIsGap(true);
                        p.fSubShowing.fSubMenu.Move(p.fSubShowing.fSubMenu.Count-1, 0);
                    end;

                    r := CalcRect(p.fSubShowing, p.fSubShowing.fTop, p.fSubShowing.right+1);
                end;
            end else begin
                r := CalcRect(p.fSubShowing,p.fSubShowing.ftop, p.fSubShowing.right+1);
            end;

            inc(r.Bottom);
            inc(r.Right);
            result := System.Types.UnionRect(result, r);
            dec(r.Right);
            dec(r.Bottom);
        end;
    end;
    procedure CalcTools(p : TACPopupItem; top,left : integer);
    var
        leftoffset : integer;
        rightoffset : integer;
        procedure CalcItem(sub : TACPopupItem);
        var
            twd, itemht : integer;
            drawablePic : boolean;
            IsPic : boolean;
            isWide : boolean;
        begin
            sub.ftop := top + TOP_BORDER;
            twd := CalcToolWidth(sub);
            //itemht := CalcHeight(sub);
            itemht := CaptionHeight-BOTTOM_BORDER;

            sub.fBottom := sub.ftop + itemht;
            if (not leftToolsList.Contains(sub)) then begin
                sub.fLeft := rightoffset-twd;
                dec(rightoffset,twd);
            end else begin
                sub.fleft := leftoffset;
                inc(leftoffset, twd);
            end;

            sub.fStaticRight := true;
            sub.fRight := sub.fleft + twd;
        end;
    var
        i : integer;
        sub : TACPopupItem;
    begin
        leftoffset := 0;
        rightoffset := fLastVisible.Right;
        for i := 0 to p.fSubMenu.count - 1 do begin
            sub := p.fSubMenu.Items[i];
            CalcItem(sub);
        end;
    end;

    var r : TRect;
    p : TACPopupItem;
    i : integer;
    procedure FixEmptySpace(sub : TACPopupItem);
    var sub2 : TACPopupItem;
    begin
        if (top+p.fmaxheight+1) - sub.fBottom > BOTTOM_BORDER then begin
            sub2 := TACPopupItem.create;
            sub2.ftop := sub.fbottom;
            sub2.fleft := sub.fleft;
            sub2.fRight := sub.fRight;
            sub2.fMyColumn := sub.fMyColumn;
            sub2.fParent := sub.fParent;
            sub2.fBottom := top+p.fmaxheight+2;
            sub2.IsBreak := true;
            sub2.ItemType := IT_POPUPCLIP;
            dec(sub2.fBottom);

            r.top := sub2.ftop;
            r.left := sub2.fleft;
            r.Right := sub2.fRight;
            r.Bottom := sub2.Bottom;
            usecanvas.Brush.color := fBackgroundColor;
            inc(r.bottom);
            UseCanvas.FillRect(r);
            dec(r.bottom);

            self.DrawItem(sub2);
        end;
    end;
var
    top : integer;
    wd : integer;
begin
    FrmDebug.AppendLog('calcsize start');
    region1 := 0;
    top := 0;

    toolsMinWidth := 0;
    for i := 0 to ftools.fSubMenu.Count-1 do begin
        inc(toolsMinWidth, CalcToolWidth(ftools.fSubMenu.Items[i]));
    end;


    r := CalcRect(fitems, top, 0);


    self.Width := r.Right;
    self.Height := r.Bottom;
   	if CheckWin32Version(6, 0) then
		Windows.SetWindowRgn(self.Handle,region1,false);

    FrmDebug.AppendLog('Find the last visible item');
    i := fitems.fSubMenu.count-1;
    if i >= 0 then begin
        repeat
            p := fitems.fSubMenu.GetItem(i);
            dec(i);
        until not p.IsBreak or (i=0);
    end;
    fLastVisible := p;
//    FixEmptySpace;

    if ShowCaption then begin
        calcTools(self.fTools, 0, 0);
    end;

    wd := 0;
    for i:= 0 to ftools.fSubMenu.Count-1 do begin
        inc(wd, (ftools.fSubMenu.Items[i].left -ftools.fSubMenu.Items[i].left) );
    end;
    toolsMinWidth := wd;

    {Windows.DeleteObject(region1);} // Windows owns this handle now
    self.EnsureVisibility(FixSubmenu);
    FrmDebug.AppendLog('calcsize end');
end;
procedure TACPopupPrototype.EnsureVisibility(FixSubmenu:boolean=false);
var x,y : integer;
	m : TMonitor;
    expandedset : set of TItemType;
begin
    {Fudge it up or left to keep it on the screen}
    x := fpoint.X;
    y := fpoint.y;


    fTopFixed := false;
    fLeftFixed := false;
    if (x + self.Width > screen.DesktopRect.right) then begin
        x := x - ((x+self.width+fspacing) - screen.desktoprect.right);
        fLeftFixed := true;
    end;

    // try turning on Clip Sets before altering the top position, if it's too tall
    // - make sure any previously expanded menus are re-expanded

    expandedset := [];
    if not self.fUseGrouping and (self.Height > screen.DesktopRect.Bottom) then begin
        if FrmConfig.cbEnableClipsSetsWhenTall.Checked then begin
            if (ClipQueue.GetQueueCount > FrmConfig.udClipsPerSet.Position) then begin
                self.SaveExpandedState;
                    Self.fUseGroupingOnce := True;
                    self.Clear;
                    self.AutoPopulate;
                self.LoadExpandedState;

                self.CalcTotalSize(FixSubmenu);
                Self.Invalidate;
            end;
        end;
    end;

    if (y + self.Height > screen.DesktopRect.Bottom) then begin
        if fTopOffsetEnable then begin
            inc(y, fTopOffset);
        end else begin
            y := y - ((y+self.height+fspacing) - screen.desktoprect.bottom);
        end;
        fTopFixed := true;
        fIsTooTall := true;
    end;

    {update for mismatched monitor resolutions}
    m := screen.MonitorFromWindow(self.Handle);
    if (m <> nil) then begin
        if (y+self.Height) > m.BoundsRect.Bottom then begin
            //y := y - (m.BoundsRect.Bottom- (y+self.Height));
            fIsTooTall := true;
        end;
    end;



    {Recursive Call to fix visibility problems caused by submenus}
    if not FixSubmenu then begin
    	{Detect a submenu and a position change}
		FixSubmenu := fitems.fSubShowing <> nil;
        if FixSubmenu and (fLeftFixed or fTopFixed) then begin
            self.CalcTotalSize(FixSubmenu);
        end else begin
        	fIgnoreMouseMove := true;
            timIgnoreMouseMove.Enabled := true;
            self.Left := x;
            self.Top := y;
        end;
    end else begin
    	{Override the popup point until the popup is closed}
        fIgnoreMouseMove := true;
        timIgnoreMouseMove.Enabled := true;
        self.Left := x;
        self.Top := y;
        fpoint.x := x; {neither option is great, but this is the lesser evil}
       // fpoint.y := y; {this causes a shift due to a side submenu to stay after}
                        {the submenu closes}
    end;
end;
procedure TACPopupPrototype.DrawCheckgroup(p: TACPopupItem);
var i : integer;
begin
    for i := 0 to p.fParent.fCheckgroup.count  - 1 do begin
        DrawItem( TACPopupItem(p.fParent.fCheckgroup[i]));
    end;
end;
procedure TACPopupPrototype.DrawDragmark;
var
	pa : Array of TPoint;
    r : TRect;
const wd = 7;
begin
	with UseCanvas do begin
        brush.Color := clActiveCaption;
        pen.color := fFontColor;
        r := fmainrect;
        InflateRect(r,-1,-1);
        setlength(pa,3);
        pa[0] := point(r.Right-wd,r.bottom);
        pa[1] := point(r.Right, r.bottom-wd);
        pa[2] := point(r.Right, r.Bottom);
        polygon(pa);
    end;
end;

procedure TACPopupPrototype.DrawItem(p: TACPopupItem);
var r : Trect;
    wc : TWideChar;
    s : string;
    len: integer;
    c : TColor;

    mainr : TRect;
    sd : TScrollDirection;
    prefixwidth : integer;
    clipboardleft : integer;
    programname : string;
const
    BLEND_CLICKED = 97;
    BLEND_CLICKED_ORIGINAL = 99;
    DESATURATE_PERCENT = 60;
    procedure HandleBottomBorder;
        function IsLastInExpandable(p : TACPopupItem) : boolean;
        begin
            result := p.IsInExpandedMenu and (
                p.fParent.fSubMenu.Items[p.fParent.fSubMenu.Count-1] = p
            );
        end;
    begin
        if (p.IsExpandable and p.Expanded) or IsLastInExpandable(p) then begin
            GetCanvas.Pen.Color := DimColor(fColumnColor, 0.90);
            GetCanvas.MoveTo(mainr.Left, mainr.Bottom);
            GetCanvas.LineTo(mainr.Right,mainr.Bottom);
        end;
    end;
    function CaptionLeft : integer;
    begin
        if (p.ItemType = IT_POPUPCLIP) and (FrmConfig.GetIconType = CBXICONTYPE_NONE) then begin
            result := mainr.left + LEFT_EDGE-1;
        end else if (p.ItemType = IT_TOOL) and (p.fLeftIcon.Bitmap=nil) then begin
            result := mainr.Left;
        end else begin
            result := mainr.left + LEFT_SPACE+LEFT_EDGE-1;
        end;
    end;
    procedure MyFillRect(r : TRect);
    begin
        inc(r.bottom);
        inc(r.Right);
        UseCanvas.FillRect(r);
    end;
    procedure MyGradientFill(c1, c2 : TColor; r : TRect; d : TGradientDirection);
    begin
        inc(r.Bottom);
        inc(r.Right);
        GraphUtil.GradientFillCanvas(UseCanvas,c1,c2,r,d);
    end;
    procedure VerticalLines;
    begin
//        if (p.ItemType = IT_POPUPCLIP) and (FrmConfig.GetIconType = CBXICONTYPE_NONE) then EXIT;
        // outside boundary line
        // reserve this space
        CopyRect(r,mainr);
        inc(r.Bottom);
        UseCanvas.pen.Color := fBorderColor;
        UseCanvas.MoveTo(r.Left,r.top);
        UseCanvas.LineTo(r.left,r.bottom+1);
        inc(r.Left);
        UseCanvas.pen.Color := dimColor(fBackgroundColor,1.02);
        UseCanvas.MoveTo(r.Left,r.top);
        UseCanvas.LineTo(r.left,r.bottom+1);

        {reserve this space}
        inc(mainr.Left);
    end;
    procedure LeftIconBackground(nohover : boolean=false);
        function ClickableHoveredIcon : boolean;
        begin
            result := (not nohover) and(hover = p) and
                (p.ItemType in TClickableLeftIcons) and p.LeftIcon.fHasIcon
                and not p.Disabled;
        end;
    var r : trect;
    begin
        {icon column}
        CopyRect(r,mainr);
        r.Right := CaptionLeft;
        UseCanvas.brush.Style := bsSolid;
        UseCanvas.Brush.Color := fColumnColor;
        if p.IsInExpandedMenu then begin
            UseCanvas.Brush.Color := fExpandedBackgroundColor;
        end;
        if (p.ItemType = IT_TOOL) then begin
            UseCanvas.Brush.Color := fCaptionColor;
        end;
        myFillRect(r);


        if ClickableHoveredIcon and not p.IsExpandable then begin
            UseCanvas.Brush.Color := Blend(UseCanvas.Brush.Color,fFontColor,93);
        end;
        dec(r.right,1);
        dec(r.Bottom);
        MyFillRect(r);

        {focus rectangle}
        if ClickableHoveredIcon then begin
            if FLastPosition = pipLeftIcon then begin
                UseCanvas.Pen.Color := fFontColor;
                UseCanvas.Pen.style := psDot;
                UseCanvas.Rectangle(r);
                UseCanvas.Pen.style := psSolid;
            end else begin
                UseCanvas.Pen.Color := BlendOrReverse(UseCanvas.Brush.Color,clWhite,clBlack, 70);
                UseCanvas.MoveTo(r.Left, r.top);
                UseCanvas.LineTo(r.Right, r.top);

                UseCanvas.Pen.Color := BlendOrReverse(UseCanvas.Brush.Color,clBlack,clWhite, 75);
                UseCanvas.MoveTo(r.Left, r.bottom+1);
                UseCanvas.LineTo(r.Right, r.bottom+1);
            end;
        end;
    end;
    procedure CaptionBackground(forceplain : boolean = false);
        procedure Fill(r : TRect);
        var b : boolean;
            c, c1,c2 : TColor;
            procedure BaseColor;
            begin
                c := UseCanvas.Brush.Color;
                UseCanvas.Brush.Color := DimColorOrReverse(c, 0.98);
                fbackgroundBase := UseCanvas.Brush.Color;
                MyFillRect(r);
            end;
            procedure BottomColor;
            begin
                Inc(r.Top,(r.Bottom-r.Top) div 2);
                c1 := UseCanvas.Brush.Color;
                c2 :=  DimColorOrReverse(UseCanvas.Brush.Color, 0.96);
                GraphUtil.GradientFillCanvas(UseCanvas,c1,c2,r,gdVertical);
                if p.Index <> (p.fParent.fSubMenu.Count-1) then begin
                    with UseCanvas do begin
                        pen.Color := DimColorOrReverse(c2, 0.94);
                        MoveTo(r.Left+(fspacing+5), r.bottom-1);
                        LineTo(r.right-(fspacing+5), r.bottom-1);
                    end;
                end;
            end;
        begin
            b := false;

            if (frmConfig.cbDoubleHeight.checked) and
                not ((p.fClip <> nil)and(p.fClip.CData.Clicked)) then begin
                if (p.fclip <> nil) and (p.ItemType = IT_POPUPCLIP) and (p.fclip.GetFormatType <> FT_PICTURE) and
                    p.DoubleHeight then begin
                    BaseColor;
                    BottomColor;
                end else begin
                    MyFillRect(r);
                end;
            end else begin
                MyFillRect(r);
            end;

        end;
    var c1, c2 : TColor;
        liner : TRect;
        procedure ExpandedBoxing;
        begin
           if p.Expanded then begin
                c1 := fBackgroundBase;
                c2 := BlendOrReverse(c1, clBlack,clWhite, 90);

                UseCanvas.brush.Color := c1;
                MyFillRect(r);

                copyrect(liner, r);
                liner.Left := liner.right - RIGHT_MENU_GRADIENT_WIDTH;
                MyGradientFill(c1,c2,liner,gdHorizontal);


            end else begin
                c1 := fBackgroundBase;
                UseCanvas.brush.Color := c1;
                MyFillRect(r);

                c2 := BlendOrReverse(c1, clBlack,clWhite, 90);
                copyrect(liner, r);
                liner.Left := liner.right - RIGHT_MENU_GRADIENT_WIDTH;
                MyGradientFill(c1,c2,liner,gdHorizontal);

                // top line
//              UseCanvas.Pen.Color := blend(fBackgroundColor,clWhite, 85);
//                UseCanvas.MoveTo(r.Left, r.top);
//                UseCanvas.LineTo(r.Right, r.top);
//                UseCanvas.MoveTo(r.Left, r.top);
//                UseCanvas.LineTo(r.Left, r.bottom);

                //bottom line

//                UseCanvas.Pen.Color := blend(fBackgroundColor,clBlack, 90);
//                UseCanvas.MoveTo(r.Left, r.bottom);
//                UseCanvas.LineTo(r.Right, r.bottom);
//                UseCanvas.MoveTo(r.Right-1, r.top);
//                UseCanvas.LineTo(r.Right-1, r.bottom);
            end;
        end;
    begin
        CopyRect(r,mainr);
        r.Left := CaptionLeft;

        UseCanvas.Brush.Style := bsSolid;

        UseCanvas.brush.Color := fBackgroundColor;
        MyFillRect(r);
        fbackgroundBase := 0;

        if forceplain then begin
            fBackgroundBase := UseCanvas.Brush.Color;
            p.DrawCaptionBackground(self,usecanvas,r);
            EXIT;
        end;

        if p.IsExpandable then begin
            fbackgroundBase := fColumnColor;
        end else begin
            fbackgroundBase := fBackgroundColor;
        end;

        if p.IsExpandable then begin
            ExpandedBoxing;
        end else begin
            p.DrawCaptionBackground(self, UseCanvas, r);
        end;

        if p.BottomLine then begin
            UseCanvas.Pen.Color := blend(fFontColor, fBackgroundBase, 18);
            UseCanvas.MoveTo(r.Left+6,r.bottom-1);
            UseCanvas.LineTo(r.Right-6,r.bottom-1);
        end;
    end;
    procedure LeftColumnEdge;
    begin
        CopyRect(r, mainr);
        inc(r.bottom); // off-by-one drawing
        r.Right :=  r.left + LEFT_SPACE;
        UseCanvas.pen.Color := fColumnEdgeColor;
        if p.IsInExpandedMenu then begin
            UseCanvas.pen.Color := BlendOrReverse(fBackgroundColor, fColumnEdgeColor,clWhite, 90);
        end;
        UseCanvas.MoveTo(r.right,r.top);
        UseCanvas.LineTo(r.right,r.bottom);
    end;
    procedure SeparatorLine;
    var y : integer;
    begin
        if p.SeparatorLine then begin
            y := r.Top + ((LINE_HEIGHT-2) div 2);
            LeftIconBackground(true);
            LeftColumnEdge;
            CaptionBackground(true);


            UseCanvas.Pen.Color := blend(fBackgroundBase,clwhite, 70);
            UseCanvas.MoveTo(r.Left+6,y);
            UseCanvas.LineTo(r.Right-6,y);

            UseCanvas.Pen.Color := blend(fBackgroundBase,clGray,  70);
            UseCanvas.MoveTo(r.Left+6,y+1);
            UseCanvas.LineTo(r.Right-6,y+1);

            inc(mainr.Top,LINE_HEIGHT);
        end;
    end;
    procedure DrawLine;
    begin
        {edge in between the rows}
        Copyrect(r, mainr);
        dec(r.Right);
        r.Left := CaptionLeft;
        r.Top := p.fTop + fSpacing+1;
        r.Bottom := r.top+1;
        UseCanvas.Brush.Color := 0;
        UseCanvas.pen.Color := dimColor(fBackgroundColor,0.95);
        UseCanvas.MoveTo(r.Left, r.top);
        UseCanvas.LineTo(r.Right, r.top);
        UseCanvas.pen.Color := dimColor(fBackgroundColor,1.10);
        UseCanvas.MoveTo(r.Left, r.Bottom);
        UseCanvas.LineTo(r.Right, r.bottom);
    end;
    procedure HanldeDoubleHeightMarker;
    var
        halfwd : integer;
        quarterwd : integer;
        box : TRect;
        c : TColor;
    begin
        if p.DoubleHeight then begin
            halfwd := (r.Right - r.Left) div 2;
            quarterwd := halfwd div 2;

            CopyRect(box, r);
            //box.left := box.right - quarterwd;

            c := BlendOrReverse(
                fBackgroundColor,
                Blend(clblack,clWhite,90),
                Blend(clwhite,clBlack,10),
                98);
            UseCanvas.pen.Color := c;
            UseCanvas.MoveTo(box.Left, box.Top);
            UseCanvas.LineTo(box.right, box.Top);
            UseCanvas.MoveTo(box.Left, box.bottom);
            UseCanvas.LineTo(box.right, box.bottom);
        end;
    end;
    procedure DrawHoverHilite;
    var startc : TColor;
        back : TColor;

        procedure Outline;
        begin
            c := fHighlightColor;
            c := Blend(c, fFontColor, 95);
            UseCanvas.pen.Color := UnitMisc.Blend(  fHighlightColor, fFontColor, 92);
            UseCanvas.RoundRect(
                r.left,r.top,r.Right,r.bottom,
                2,2
            );
        end;
    begin
        // Since it's only called once, there's no need to optimized the
        // colors

        copyrect(r,mainr);
        if not (p.ItemType = IT_TOOL) then begin
            r.Left := CaptionLeft;
        end else begin
            if (p.Caption = '') and not (ShowCaptionShortcuts and (p.ItemType=IT_TOOL) and (p.fPrefix<>'')) then begin
                r.Right := r.Left + p.LeftIcon.Bitmap.Width + FSPACING*3;
            end;
        end;
        dec(r.right, RIGHT_BORDER-1);

        back := fBackgroundColor;
        if p.IsInExpandedMenu then begin
            back := DimColorOrReverse(fBackgroundColor, 1.04);
        end;
        back := unitMisc.Blend(back, fHighlightColor, 70);   // was 90% background


        {focus rectangle}

        {inner gradient}
        //inc(r.Top);
        inc(r.left);

        if (p.Disabled) then begin
            startc :=  UnitMisc.blend(fBackgroundBase, fDisabledColor, 90);
        end else begin
            startc := UnitMisc.Blend(
                fBackgroundBase,
                fHighlightColor,
                50
            );
        end;
        UseCanvas.Brush.Color := startc;
        UseCanvas.Pen.Color :=   dimColor(startc, 0.90);
        UseCanvas.Rectangle(r.Left,r.Top,r.Right,r.bottom);


        inc(r.Bottom);
        dec(r.Top);
        dec(r.Left);

    end;
    procedure LeftIcon;
    var ht : integer;
        wd : integer;

        doicon : boolean;
        procedure DrawBox(checked : boolean);
        var
            center, chevronwd, chevronht : integer;
        begin
            copyrect(r,mainr);

            r.right := r.left+LEFT_SPACE;
            center := (r.Right+r.left) div 2;
            chevronwd := 14;
            chevronht := 14;
            inc(r.top, ((r.Bottom-r.Top) - chevronht) div 2);
            r.bottom := r.top + chevronht;
            r.left := (center - chevronwd div 2);
            r.Right := (center + chevronwd div 2);
            inc(r.right);

            UseCanvas.brush.Color := dimColor(fBackgroundColor,1.01);
            UseCanvas.Brush.Style := bsSolid;
            UseCanvas.pen.Color := saturate(clActiveCaption, 0.10);
            UseCanvas.Rectangle(r);

            UseCanvas.pen.Color := clBtnText;
            UseCanvas.Brush.Style := bsSolid;
            inc(r.Top, chevronht div 2);
            inc(r.Left, chevronwd div 2 - 3);
            if checked then begin
                GraphUtil.DrawCheck(UseCanvas,point(r.left,r.top),2);
            end;
        end;
        procedure DrawHIcon(wd,ht : integer; opacity:byte=255);
        var
            BlendFunc: TBlendFunction;
            clr : TColor;
        begin
            if (opacity=0) and not (p=hover) then EXIT;

            if (opacity=255) or (p=hover) then begin
                DrawIconEx(UseCanvas.handle,
                    r.left, r.top,
                    p.lefticon.icon, wd,ht, 0, 0, DI_NORMAL);
            end else begin
                if (p.LeftIcon.fIconBitmap = nil) then begin
                    p.LeftIcon.fIconBitmap := TBitmap.Create;
                    p.LeftIcon.fIconBitmap.PixelFormat := pf24bit;
                    p.LeftIcon.fIconBitmap.Width := 16;
                    p.LeftIcon.fIconBitmap.Height := 16;
                    p.LeftIcon.fIconBitmap.canvas.Brush.Color := fColumnColor;
                    if p.IsInExpandedMenu then begin
                        p.LeftIcon.fIconBitmap.canvas.Brush.Color := fExpandedBackgroundColor;
                    end;
                    p.LeftIcon.fIconBitmap.Canvas.FillRect(p.LeftIcon.fIconBitmap.Canvas.ClipRect);

                    DrawIconEx(p.LeftIcon.fIconBitmap.Canvas.Handle,
                        0, 0,
                        p.LeftIcon.icon, wd,ht, 0, 0, DI_NORMAL);

                    UnitMisc.desaturate(p.LeftIcon.fIconBitmap, DESATURATE_PERCENT, p.LeftIcon.fIconBitmap.canvas.Brush.Color);

                    BlendFunc.BlendOp := AC_SRC_OVER;
                    BlendFunc.BlendFlags := 0;
                    BlendFunc.SourceConstantAlpha := opacity;
//                    BlendFunc.SourceConstantAlpha := 255;
                    BlendFunc.AlphaFormat := 0;
                    Windows.AlphaBlend(UseCanvas.Handle, r.left,r.top, 16,16, p.LeftIcon.fIconBitmap.Canvas.Handle,
                        0,0, 16,16, BlendFunc);

                    p.LeftIcon.fIconBitmap.Canvas.CopyRect(rect(0,0,16,16),UseCanvas, rect(r.Left,r.Top,r.Left+16,r.Top+16));
                end else begin
                    UseCanvas.Draw(r.Left,r.Top, p.LeftIcon.fIconBitmap);
                end;
            end;
        end;
        procedure DrawBitmap(x,y,wd,ht : integer; opacity:byte=255);
        var
            BlendFunc: TBlendFunction;
            clr : TColor;
        begin
            if (opacity=0) and not (p=hover) then EXIT;

            if (opacity=255) or (p=hover) and (not p.Disabled) then begin
                UseCanvas.StretchDraw(rect(x,y,x+wd,y+ht), p.LeftIcon.Bitmap);
            end else begin
                if (p.LeftIcon.fIconBitmap = nil) then begin
                    p.LeftIcon.fIconBitmap := TBitmap.Create;
                    p.LeftIcon.fIconBitmap.PixelFormat := pf24bit;
                    p.LeftIcon.fIconBitmap.Width := 16;
                    p.LeftIcon.fIconBitmap.Height := 16;
                    p.LeftIcon.fIconBitmap.canvas.Brush.Color := fColumnColor;
                    if p.IsInExpandedMenu then begin
                        p.LeftIcon.fIconBitmap.canvas.Brush.Color := fExpandedBackgroundColor;
                    end;
                    p.LeftIcon.fIconBitmap.Canvas.FillRect(p.LeftIcon.fIconBitmap.Canvas.ClipRect);

                    p.LeftIcon.fIconBitmap.Canvas.Draw(0,0,p.LeftIcon.Bitmap);

                    UnitMisc.desaturate(p.LeftIcon.fIconBitmap, DESATURATE_PERCENT, p.LeftIcon.fIconBitmap.canvas.Brush.Color);

                    BlendFunc.BlendOp := AC_SRC_OVER;
                    BlendFunc.BlendFlags := 0;
                    BlendFunc.SourceConstantAlpha := opacity;
//                    BlendFunc.SourceConstantAlpha := 255;
                    BlendFunc.AlphaFormat := 0;
                    Windows.AlphaBlend(UseCanvas.Handle, r.left,r.top, 16,16, p.LeftIcon.fIconBitmap.Canvas.Handle,
                        0,0, 16,16, BlendFunc);

                    p.LeftIcon.fIconBitmap.Canvas.CopyRect(rect(0,0,16,16),UseCanvas, rect(r.Left,r.Top,r.Left+16,r.Top+16));
                end else begin
                    UseCanvas.Draw(r.Left,r.Top, p.LeftIcon.fIconBitmap);
                end;
            end;
        end;
    begin
        if (p.ItemType = IT_POPUPCLIP) and (FrmConfig.GetIconType = CBXICONTYPE_NONE) then EXIT;
        copyrect(r,mainr);


        case p.Style of
        psNormal, psExpandable, psSubmenu : begin
            doicon := false;
            if not (p.LeftIcon.fIconOnlyOnHover or p.LeftIcon.fIconOnExpanded) then begin
                doicon := true;
            end;
            if p.LeftIcon.fIconOnlyOnHover and (p = Hover) then begin
                doicon := true;
            end;
            if p.LeftIcon.fIconOnExpanded and (p.Expanded = true) then begin
                doicon := true;
            end;
            if doicon then begin
                r.right := r.left + left_space;
                wd := r.Right-r.left;
                ht := r.bottom-r.top;
                if ((p.ItemType = IT_PINNED) or (p.LeftIcon.fHasCliptypeIcon)) and
                    not ((p=hover) and (FLastPosition=pipLeftIcon)) then begin
                    dec(r.Left, 2);
                end;
                if (hover=p) and (p.ItemType in TContainsAClip) and (self.FLastPosition = pipLeftIcon) then begin
                    // Edit Icon Hover
                    if (ht > 18)  then begin
                        {center it vertically}
                        r.Top := r.top + (ht - 16) div 2;
                        r.Left := r.left + (wd - 16) div 2;
                    end else begin
                        r.Top := r.top + (ht-(ht-2)) div 2;
                        r.Left := r.left + (wd -(ht-2)) div 2;
                    end;
                    UseCanvas.Draw(r.Left,r.Top, ImgToBitmap(FrmMainPopup.ImgEdit));
                end else begin
                    if (ht > 18)  then begin
                        {center it vertically}
                        r.Top := r.top + (ht - 16) div 2;
                        r.Left := r.left + (wd - 16) div 2;
                        if p.LeftIcon.Bitmap <> nil then begin
                            r.right := r.Left + p.LeftIcon.Bitmap.Width;
                            r.bottom := r.top + p.LeftIcon.Bitmap.Height;


                            DrawBitmap(r.Left,r.Top,p.LeftIcon.Bitmap.Width,p.LeftIcon.Bitmap.Height,
                                p.LeftIcon.fIconOpacity);
                        end else if (p.LeftIcon.fHasIcon) and(p.LeftIcon.icon <> 0) then begin
                            DrawHIcon(16,16, p.LeftIcon.fIconOpacity);
                        end;
                    end else begin
                        r.Top := r.top + (ht-(ht-2)) div 2;
                        r.Left := r.left + (wd -(ht-2)) div 2;
                        {scale it to the menu height}
                        if p.LeftIcon.Bitmap <> nil then begin
                            r.right := r.Left + p.LeftIcon.Bitmap.Width;
                            r.bottom := r.top + p.LeftIcon.Bitmap.Height;
                            DrawBitmap(
                                r.Left,r.Top,
                                p.LeftIcon.Bitmap.Width,p.LeftIcon.Bitmap.Height,
                                p.LeftIcon.fIconOpacity
                            );
                        end else if (p.LeftIcon.fHasIcon) and(p.LeftIcon.icon <> 0) then begin
                            DrawHIcon(ht-2,ht-2, p.LeftIcon.fIconOpacity);
                        end;
                    end;

                    if p.ItemType = IT_PINNED then begin
                        r.Left := r.Left + LEFT_SPACE -  frmClipboardManager.iPin.Width; //8x8 icon
                        Inc(r.Top,4);
                        dec(r.left);
                        UseCanvas.Draw(r.Left, r.Top, FrmClipboardManager.iPin.Picture.Graphic);
                    end;
                end;
            end;
        end;
        psCheckable: begin
            if not p.IsCheckGrouped  then begin
                DrawBox(p.checked);
            end else if p.Checked then begin
                DrawBox(p.checked);
            end;
        end;
        end;
    end;
    procedure Caption;
 
    begin
        CopyRect(r,mainr);
        r.Left := CaptionLeft;

        case p.Style of
        psExpandable, psSubmenu:
            begin
                r.Right := r.Right - (RIGHT_SPACE+RIGHT_BORDER);
            end;
        else
            r.right := r.Right - fspacing;
        end;

        p.DrawCaption(self, UseCanvas, r, p=Hover, FLastPosition = pipLeftIcon);
    end;
    procedure CliptypeIcon;
    var center, cm : integer;
        chevronwd, chevronht, wd, ht : integer;
        bm : TBitmap;
        chev : TRect;
        pc : TColor;
    begin
        if (p.ItemType = IT_POPUPCLIP) and (FrmConfig.GetIconType = CBXICONTYPE_NONE) then EXIT;

        copyrect(r,mainr);
        UseCanvas.brush.Style := bsSolid;
        case p.Style of
        psNormal:
            begin
                if p.LeftIcon.fHasCliptypeIcon and (frmconfig.GetIconType=CBXICONTYPE_PROGRAM) and
                    not ((hover = p) and (Self.FLastPosition = pipLeftIcon))  then begin
                    wd := r.Right-r.left;
                    ht := r.bottom-r.top;

                    UseCanvas.Brush.Color := fBackgroundColor;

                    if p.ItemType = IT_PERMANENT then begin
                        r.top := r.top + (ht-p.LeftIcon.CliptypeIcon.Height) div 2;
                    end else begin
                        r.Top := r.Top + ((ht-16) div 2) + 2;
                        // same top as program icon - moved down a little
                    end;
                    r.left := mainr.Left + CAPTION_LEFT;
                    r.Left := r.Left- 2 - p.LeftIcon.CliptypeIcon.Width;

                    UseCanvas.Draw(r.left, r.top, p.LeftIcon.CliptypeIcon);
                end;
            end;
        end;
    end;

    procedure RightIcon;
    var center : integer;
        chevronwd, chevronht, wd : integer;
        bm : TBitmap;
        chev : TRect;
        pc : TColor;
    begin
        copyrect(r,mainr);
        r.Left := r.Right - (RIGHT_SPACE+RIGHT_BORDER);

        UseCanvas.brush.Style := bsSolid;
        case p.Style of
        psSubmenu:
            begin
                if p.Disabled then begin
                    UseCanvas.pen.Color := fDisabledColor;
                end else begin
                    UseCanvas.pen.Color := fFontColor;
                end;
                GraphUtil.DrawArrow(UseCanvas,sdRight,
                    point(r.right-fspacing*2-RIGHT_BORDER-3,(r.top+r.bottom)div 2 -4),3);
            end;
        psExpandable:
            begin
                if p.Expanded  then begin
                    sd := sdUp;
                    bm := ImgToBitmap(FrmMainPopup.ImgUp);
                end else begin
                    sd := sdDown;
                    bm := ImgToBitmap(FrmMainPopup.imgDown);
                end;

                if not ((sd=sdup) and not p.ShowCollapseIcon) then begin

                    copyrect(r,mainr);
                    dec(r.right);
                    r.left := (r.right - RIGHT_SPACE) and not 1;
                    center := (r.Right+r.left) div 2;
                    chevronwd := 14;
                    chevronht := 14;
                    inc(r.top, ((r.Bottom-r.Top) - chevronht) div 2);
                    r.bottom := r.top + chevronht;
                    r.left := (center - chevronwd div 2)+1;
                    r.Right := (center + chevronwd div 2);
                    inc(r.right,2);

                    UseCanvas.brush.Color := clNone;
                    UseCanvas.Brush.Style := bsClear;

                    UseCanvas.pen.Color := blend(fbackgroundBase, fFontColor, 80);
                    UseCanvas.Rectangle(r);

                    CopyRect(chev, r);
                    inc(chev.Top, chevronht div 2 - 1);
                    inc(chev.Left, chevronwd div 2 - 3);
                    UseCanvas.Brush.Style := bsSolid;
                    if (p = hover) or (p.Expanded) then begin
                        pc := UseCanvas.Pen.Color;
                        UseCanvas.pen.Color := clBtnText;
                        UseCanvas.Brush.Color := clBtnFace;
                        UseCanvas.FillRect(r);
                        {if p.expanded then begin
                            UseCanvas.FillRect(r);
                        end else begin
                            inc(r.Right,1);
                            inc(r.Bottom,2);
                            UseCanvas.FillRect(r);
                            DrawEdge(
                                UseCanvas.Handle,
                                r,BDR_RAISEDOUTER or EDGE_RAISED,
                                BF_RECT or BF_SOFT
                            );
                        end;}
                    end else begin
                        if p.Disabled then begin
                            UseCanvas.pen.Color := clGrayText;
                        end;
                    end;
                    GraphUtil.DrawChevron(UseCanvas,sd,point(chev.left,chev.top),3);
                end;
            end;
        end;
    end;
    procedure DrawHoverLine;
    begin
    	copyrect(r,mainr);
        inc(r.Top);
        r.Left := CaptionLeft;
        dec(r.Right, fSpacing);
    	if (fDragStarted) and (p=fDropMenuItem)  then begin
            if (fDragMenuItem.ItemType = IT_POPUPCLIP) or (p.ItemType = IT_POPUPCLIP) then begin
             	if (fDragMenuItem.ItemType = IT_POPUPCLIP) and (p.ItemType = IT_POPUPCLIP) then begin
                    UseCanvas.pen.Color := fFontColor;
                    UseCanvas.MoveTo(r.Left,r.top);
                    UseCanvas.LineTo(r.right,r.top);
                end;
            end else if (fDragMenuItem.ItemType = IT_PERMANENT) or (p.ItemType = IT_PERMANENT) then begin
             	if (fDragMenuItem.ItemType = IT_PERMANENT) and (p.ItemType = IT_PERMANENT) then begin
                    UseCanvas.pen.Color := fFontColor;
                    UseCanvas.MoveTo(r.Left,r.top);
                    UseCanvas.LineTo(r.right,r.top);
                end;
            end else begin
            	if not (p.Style = psLine) and not (p.ItemType in [IT_NONE])  then begin
                    UseCanvas.pen.Color := fFontColor;
                    UseCanvas.MoveTo(r.Left,r.top);
                    UseCanvas.LineTo(r.right,r.top);
                end;
            end;
        end;
    end;
var
    i : integer;
    clr : TColor;
begin
    p.SetBoundsRect(self.Top, self.left);

    {main item rect}
    mainr.Top := p.fTop;
    mainr.Left := p.fLeft;
    mainr.Right := p.Right;
    mainr.Bottom := p.fbottom;
    p.fRight := mainr.Right;  // TODO remember why this strange case was needed

    if (p.itemType <> IT_TOOL) then begin
        VerticalLines;
    end else begin
        inc(mainr.Left);
    end;
    SeparatorLine;

    UseCanvas.Brush.Style := bsSolid;
    UseCanvas.Brush.Color := fBackgroundColor;

    i := UseCanvas.Font.Size;
    if p.SmallCaption then begin
        UseCanvas.Font.Size := i-1;
    end;




    LeftIconBackground;
    if (p.itemType <> IT_TOOL) then begin
        LeftColumnEdge;
    end;
    CaptionBackground;

    if (p.IsBreak)  then begin
        {nothing needed}
    end else if (p.IsLine) then begin
        DrawLine;
    end else begin
        //HanldeDoubleHeightMarker;

        if (p = hover) and (not p.isGap) then begin
            DrawHoverHilite
        end;
        LeftIcon;
        CliptypeIcon;

        Caption;
        RightIcon;
    end;
    DrawHoverLine;
    HandleBottomBorder;

    if p = fLastVisible then begin
    	DrawDragmark; 
    end;

    UseCanvas.Font.Size := i;
end;
procedure TACPopupPrototype.DrawOnCanvas(fullmode : boolean=false);
begin
	self.fFullMode := fullmode;

    UseCanvas.Font := FrmConfig.GetFont;
    UseCanvas.Font.Size := FrmConfig.GetFont.Size;
    UseCanvas.Font.Style := FrmConfig.getfont.style;

    self.CalcTotalSize;
    self.Paint;
end;
procedure TACPopupPrototype.FullRedraw;
    procedure DrawMenu(p : TACPopupItem; const top,left : integer);
    var i : integer;
        sub, sub2 : TACPopupItem;
        r : TRect;
    begin
        if p.fSubMenu.Count = 0 then EXIT;

        r.top := top;
        r.Left := left;
        r.Right := p.fSubMenu[p.fSubMenu.Count-1].right+1;
        r.Bottom := p.fSubMenu[p.fSubMenu.Count-1].Bottom+1;

        usecanvas.Brush.color := fBackgroundColor;
        inc(r.Bottom,3);
        UseCanvas.FillRect(r);
        dec(r.Bottom,3);
        //UseCanvas.FillRect(UseCanvas.ClipRect);

        {top line}
        UseCanvas.pen.color := fBorderColor;
        UseCanvas.Pen.Width := 1;
        UseCanvas.MoveTo(r.left, r.top);
        UseCanvas.lineto(r.right, r.top);
        {bottom line}
        UseCanvas.pen.color := fBorderColor;
        UseCanvas.MoveTo(r.left, UseCanvas.ClipRect.Bottom-1);
        UseCanvas.lineto(r.right, UseCanvas.ClipRect.Bottom-1);
        {right line}
        UseCanvas.pen.color := fBorderColor;
        UseCanvas.MoveTo(r.right, r.top);
        UseCanvas.lineto(r.right, r.bottom);
        {left line}
//        UseCanvas.pen.color := fBorderColor;
//        UseCanvas.MoveTo(r.left, r.top);
//        UseCanvas.lineto(r.left, r.bottom);


        // draw individual items
        for i := 0 to p.fsubmenu.count - 1 do begin
            sub := p.fsubmenu.Items[i];
            if sub.IsBreak  then begin
                // handle blank space
                if r.bottom - sub.fBottom > BOTTOM_BORDER then begin
                    sub.fBottom := r.Bottom;
                    self.DrawItem(sub);
                end;
            end else begin
                self.DrawItem(sub);
            end;
        end;
        // handle blank space
        if (top+p.fmaxheight+1) - sub.fBottom > BOTTOM_BORDER then begin
            sub2 := TACPopupItem.create;
            sub2.ftop := sub.fbottom;
            sub2.fleft := sub.fleft;
            sub2.fRight := sub.fRight;
            sub2.fMyColumn := sub.fMyColumn;
            sub2.fParent := sub.fParent;
            if sub2.fParent.fParent <> nil then begin
                sub2.fParent := sub2.fParent.fParent;
            end;
            sub2.fBottom := top+p.fmaxheight+2;
            sub2.IsBreak := true;
            sub2.ItemType := IT_PERMANENT;
            dec(sub2.fBottom);

            r.top := sub2.ftop;
            r.left := sub2.fleft;
            r.Right := sub2.fRight;
            r.Bottom := sub2.Bottom;
            usecanvas.Brush.color := fBackgroundColor;
            inc(r.bottom);
            UseCanvas.FillRect(r);
            dec(r.bottom);

            self.DrawItem(sub2);
        end;

        if p.fSubShowing <> nil then begin
            DrawMenu(p.fSubShowing, p.fSubShowing.fTop, p.fSubShowing.Right+1);
        end;
    end;
    procedure DrawTools(p : TACPopupItem; const top,left : integer);
    var
        i : integer;
        sub : TACPopupItem;
        r : TRect;
        procedure leftline;
        begin
            UseCanvas.pen.color := fBorderColor;
            UseCanvas.MoveTo(left, r.top);
            UseCanvas.lineto(left, r.bottom+1);
        end;
        procedure bottomline;
        begin
            UseCanvas.pen.color := BlendOrReverse(fCaptionColor, clblack, clwhite, 93);
            UseCanvas.MoveTo(r.left+1, r.bottom);
            UseCanvas.lineto(r.right, r.bottom);
        end;
    begin
        r.Top := top+TOP_BORDER;
        r.Left := left;
        r.Right := fLastVisible.Right;
        r.Bottom := r.Top+ CaptionHeight;
        UseCanvas.Brush.Color := fCaptionColor;
        UseCanvas.FillRect(r);

        for i := 0 to p.fSubMenu.Count-1 do begin
            sub := p.fSubMenu.Items[i];
            self.DrawItem(sub);
        end;

        leftline;
        bottomline;
    end;
begin
    drawmenu(fitems, 0,0);
    if ShowCaption then begin
        drawtools(ftools, 0,0);
        if (false) then begin
            UseCanvas.pen.color := fColumnEdgeColor;
            UseCanvas.Pen.Width := 1;
            UseCanvas.MoveTo(0, CaptionHeight);
            UseCanvas.lineto(fLastVisible.right, CaptionHeight);

        UseCanvas.pen.color := fColumnEdgeColor;
        UseCanvas.Pen.Width := 1;
        UseCanvas.MoveTo(0, 0);
        UseCanvas.lineto(0, 0 + CaptionHeight);
        end;
    end;




    FirstPaint := true;


    DrawDragmark;


    if self.GetFormMode then begin
        SetWindowLong(self.Handle,GWL_EXSTYLE, GetWindowLong(self.handle, GWL_EXSTYLE) or WS_EX_LAYERED);
        SetLayeredWindowAttributes(self.handle,0,trunc(255 * 0.80), LWA_ALPHA);
    end else begin
		SetWindowLong(self.Handle,GWL_EXSTYLE, GetWindowLong(self.handle, GWL_EXSTYLE) and not WS_EX_LAYERED);
    end;
end;

procedure TACPopupPrototype.AddAScrollbar;
begin
   { r := self.fMainRect;
	i := GetSystemMetrics(SM_CYVTHUMB);

    self.Width := self.Width + i*2;
    inc(r.Right,i);

	scroll := CreateWindow('SCROLLBAR', nil,
    WS_CHILD or WS_VISIBLE or SBS_VERT or SBS_RIGHTALIGN,
    r.left,r.top,r.right-i,r.bottom,
    self.Handle,
     IDC_VSCROLL,
     hInstance,
     nil);

	SetScrollRange(scroll, SB_CTL, 0, self.Height, FALSE);
    }

end;

procedure TACPopupPrototype.ReserveAccel;
var c : char;
begin
    c := self.GetAccelerator(0);
    while pos(c, fAccelCharsUsed) <> 0 do begin
        inc(fReservedCount);
    	c := self.GetAccelerator(0);
    end;
    inc(fReservedCount);
end;

{Clip Menu Routines}
function TACPopupPrototype.ClipMenuVisible : Boolean;
begin
    result := fim.Visible;
end;
procedure TACPopupPrototype.ClipMenuReportKey(key : Char);
begin
    fim.ReportKeypress(key);
end;
procedure TACPopupPrototype.ClipMenuReportKey(key : word);
begin
    fim.ReportKeypress(key);
end;
procedure TACPopupPrototype.ClipMenuHide;
begin
    if fim.showing then begin
        fim.Hide;
    end;
end;
procedure TACPopupPrototype.ClipMenuShow(rightclick : boolean = false);
begin

end;

procedure TACPopupPrototype.DeleteClipCallback(Sender: TObject);
begin
    self.RebuildPopup;
end;
procedure TACPopupPrototype.MakePermanentCallback(Sender: Tobject);
begin
    self.hide;
end;
procedure TACPopupPrototype.EditCallback(Sender: Tobject);
begin
    self.Hide;
end;
procedure TACPopupPrototype.PasteCallback(Sender: Tobject);
begin
    self.hide;
end;
procedure TACPopupPrototype.FormModeCallback(Sender : TObject);
begin
    if fPopupMode.equals(pdmStayOpen) then begin
        fPopupMode.setMode(pdmAutoHide);
    end else begin
        fPopupMode.setMode(pdmStayOpen);
    end;

    if (not self.UseFormMode) and FrmMainPopup.GetNeedsFocus then
            TFocusManager.ForceForeground(self.Handle);
end;


procedure TACPopupPrototype.DestroyCallback(Sender: Tobject);
begin
    self.RebuildPopup;
end;
procedure TACPopupPrototype.HideCallback(Sender : TObject);
begin
    self.ClipMenuHide;
end;
{//User Input//}

{Mouse Events}
procedure TACPopupPrototype.MouseCursorReset;
begin
    screen.Cursor := crDefault;
end;
procedure TACPopupPrototype.CMMouseLeave(var Message: TMessage);
begin
    HideTooltip;
    FLastPosition := pipNone;
end;
procedure TACPopupPrototype.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var p : TACPopupItem;

begin
    inherited;
    p := GetItemAt(x, y);

    if DragMouseUp(p) then EXIT;

    FrmDebug.AppendLog('MouseUp hover is nil='+BoolToStr(hover=nil));
    FrmDebug.AppendLog('MouseUp p is nil='+BoolToStr(p=nil));

    if p <> nil then  begin
        if (p = fMouseDownOn) then begin
            //if lastHitTest = HTCAPTION then EXIT;
            if p.Disabled  then EXIT;

            if (ssLeft in fDownShift) or (ssMiddle in fDownShift) then begin
                if (ssMiddle in fDownShift) then begin
                   p.MiddleClicked := true;
                end;
            end;

            self.fKeyActivated := false;
            HandleMouseClick(p);
        end;
    end else begin
        if (fPopupMode.equals(pdmPinned)) then begin
            if (GetForegroundWindow <> self.Handle) then begin
                TFocusManager.ForceForeground(self.Handle);
            end;
            self.RebuildPopup;
        end else if self.UseKeyboard then begin
            if (GetForegroundWindow <> self.Handle) then begin
                TFocusManager.ForceForeground(self.Handle);
                Windows.SetFocus(self.Handle);
            end;
        end;
    end;
    FrmDebug.AppendLog('MouseUp End');
end;
procedure TACPopupPrototype.MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
begin
    inherited;

    timHover.Enabled := false;

    fDownShift := shift;
    fMouseDownOn := GetItemAt(x,y);



    self.DragMouseDown(Hover);
end;
procedure TACPopupPrototype.MouseLeave(Sender: TObject);
begin
    HideTooltip;
end;
procedure TACPopupPrototype.MouseMove(Shift: TShiftState; X, Y: Integer);
var last : TACPopupItem;
    lastpos : TPopupItemPosition;
    pt : TPoint;

    procedure ClearSubmenus(pc : TACPopupItem);
    begin
        repeat
             pc.fSubShowing := nil;
             pc := pc.fParent;
        until pc = nil;
    end;
    function IsChild(parent, pc : TACPopupItem) : boolean;
    begin

        result := false;
        if pc = nil then EXIT;

        repeat
             if Parent = pc.fparent then begin
                //result := true;
                 BREAK;
             end;

             pc := pc.fParent;
        until pc.fParent = nil;

        result := not (pc = fItems);
    end;
    function IsAutoScroll : boolean;
    var
        m : TMonitor;
    begin
        result := false;
        if (fIsTooTall) then begin
            pt := mouse.CursorPos;
            m := screen.MonitorFromPoint(pt);
            if m <> nil then begin
                pt.Y := pt.Y + m.top;
                if (pt.y = m.boundsrect.Top) or
                    (pt.y = m.BoundsRect.bottom+m.boundsrect.top-1) then begin
                    if (pt.y = m.boundsrect.Top) then begin
                        self.top := m.top;
                        fTopOffset := 0;
                    end else begin
                        fTopOffset := (self.Height - m.Height)*-1;
                    end;
                    self.Top := m.top + fTopOffset;
                    self.fTopOffsetEnable := true;
                    result := true;
                end;
            end;
        end;
    end;
var
    p : TACPopupItem;
begin
    inherited;

    if fIgnoreMouseMove then begin
        lastmousex := x;
        lastmousey := y;
    	EXIT;
    end;
    last := Hover;
    if IsAutoScroll then EXIT;

    if (Lastmousex=x) and (lastmousey=y) then begin
        {Mouse Move gets triggers after showing a tooltip, even though
        nothing has changed}
        EXIT;
    end;

    if self.fKeyActivated then begin
        self.fKeyActivated := false;
        self.ShowExpandedShortcuts := false;
        self.Invalidate;
    end;

    if not fDragStarted and (fDragMenuItem <> nil) then begin
        if (abs(fDragX - mouse.cursorpos.x) > mouse.DragThreshold) or
            (abs(fdragy - mouse.cursorpos.y) > mouse.DragThreshold) then begin
            fDragStarted := true;
            screen.Cursor := crDrag;
        end;
    end;

    LastMouseX := x;
    LastMouseY := y;

    p := GetItemAt(x,y);
    if (p <> nil) and p.IsLine then begin
        HideTooltip;
        SetHover(p); // Windows will show no hover over a line
        if not p.IsInSubmenu  then begin
            timHideSubmenu.Enabled := true;
        end;
        if last <> nil then
            DrawItem(last);

        EXIT;
    end;
    if self.DragMouseMove(p, last) then EXIT;

    { perform hit test }
    lastpos := FLastPosition;
    FLastPosition := pipNone;
    if (p <> nil) then begin
        FLastPosition := pipCaption;
        if (x - p.fLeft) < LEFT_SPACE then begin
            if (p.ItemType in TClickableLeftIcons) and
                not ((p.ItemType=IT_POPUPCLIP)and(FrmConfig.GetIconType=CBXICONTYPE_NONE)) then begin
                FLastPosition := pipLeftIcon;
            end;
        end;
    end;
    if (FLastPosition = pipNone) then begin
        timHideSubmenu.Enabled := true;
    end;
    if (lastPos <> FLastPosition) then begin
        if (hover<>nil) then begin
            {update to show or remove focus rectangle}
            DrawItem(hover);
        end;
        HideTooltip;
        StartHoverTooltip;
    end;
    if FLastPosition=pipLeftIcon then begin
        //ClipMenuShow
        if (hover <> nil) then begin
            //DrawItem(hover);
            timLeftIconHover.Enabled := false;
            timLeftIconHover.Enabled := true;
        end else begin

        end;
    end else begin
        timLeftIconHover.Enabled := false;
        self.ClipMenuHide;
    end;

    // update hover timers and set hover
    if (last <> p) then begin
        if (p <> nil) then begin
            self.CancelShowSubmenu;
            self.timMouseSelectDelay.Enabled := true;
            {current is a submenu, nested submenu}
            if (p.IsSubmenu) then begin
                if (p.IsInSubmenu)  then begin
                    {nested submenu}
                    {may not be possible}
                end else begin
                    {show me, if not showing}
                    if p <> p.fParent.fSubShowing then begin
                        self.ShowSubmenuDelayed(p);
                    end;
                end;
            end;
            if (not p.IsInSubmenu) then begin
                if (fLastSubmenu <> nil) and (fLastSubMenu <> p) then begin
                    timHideSubmenu.Enabled := true;
                end;
            end else begin
                if IsChild(p, fLastSubmenu) then begin
                    timHideSubmenu.Enabled := false;
                end else begin
                    // TODO: Figure out what the intent was here
                    {if (p <> fLastSubmenu) then begin
                        self.ShowSubmenuDelayed(p);
                    end;}
                end;
            end;

            SetHover(p);
        end;
    end;

    if not (FLastPosition = pipCaption) and (screen.Cursor > 0) then begin
        self.MouseCursorReset;
    end;
end;
procedure TACPopupPrototype.timMouseSelectDelayTimer(Sender: TObject);
begin
    timMouseSelectDelay.Enabled := false;
end;
{Keyboard Events}
procedure TACPopupPrototype.KeyDown(var Key: Word; Shift: TShiftState);

begin
    inherited KeyDown(key, shift);

    fLastKeyDown := key;
    fLastModiferDown := Shift;
    if (key in [VK_SHIFT, VK_MENU, VK_CONTROL]) and
        (hover<>nil) and (hover.ItemType in TUsesClipMenu) then begin
        if not (fToolTipNew.Showing and (ftooltipnew.lblHeader.Visible=false)) then begin
            timModifier.Enabled := true;
        end;
    end;


    if self.ClipMenuVisible then begin
        // consume the keystroke
        key := 0;
    end else begin
        // allow for auto-repeat using the Down message
        if (shift=[]) then begin
            fKeyActivated := true;

            case key  of
            VK_DOWN:    self.HoverDown;
            VK_UP:      self.HoverUp;
            VK_RIGHT:   self.HoverRight;
            VK_LEFT:    self.HoverLeft;
            else
                fKeyActivated := false;
            end;
        end;
    end;
end;
procedure TACPopupPrototype.KeyUp(var Key: Word; Shift: TShiftState);
var ch : char;
    i : integer;
    p : TACPopupItem;
begin
    inherited KeyUp(key, shift);

    if hover = nil then EXIT;

    case key of
    VK_MENU, VK_CONTROL, VK_SHIFT:
        begin
            // detect when only a modifier was pressed and released
            HideTooltip;
            timModifier.Enabled := false;

        end;
    VK_RETURN, VK_SPACE:
        begin
            self.fKeyActivated := true;
            self.HoverClick;
        end;
    end;

    if (fLastModiferDown <> []) and (fLastKeyDown <> 0) then begin
        i := fkeystrokes.IndexOf(string(char(fLastKeyDown)));
        if (i<>-1) then begin
            p := TACPopupItem(fkeystrokes.Objects[i]);
            p.fAltpressed := (ssAlt in fLastModiferDown);
            p.fShiftPressed := (ssShift in fLastModiferDown);
            p.fctrlpressed := (ssCtrl in fLastModiferDown);

            setHover(p);
            self.FLastPosition := pipCaption;
            self.HandleCaptionClick(p);
        end;
    end;
end;
procedure TACPopupPrototype.KeyPress(var Key: Char);
var i, j : integer;
    p, p2 : TACPopupItem;

    it : TItemType;
begin
    inherited;
    if self.fIgnoreKeypresses then EXIT;

    if word(key) = VK_ESCAPE then begin
        self.ForceHide := true;
        self.Hide;
        EXIT;
    end;

    if self.ClipMenuVisible then begin
        Self.ClipMenuReportKey(key);
        key := #0;
        EXIT;
    end;


    if (self.fShowExpandedShortcuts) then begin
        i := fExpandedKeystrokes.IndexOf(string(key));
        if i <> -1 then begin
            self.fKeyActivated := True;
            p := TACPopupItem(fExpandedKeystrokes.Objects[i]);
            self.GatherModifierKeys(p);
            self.FLastPosition := pipCaption;
            if Assigned(p.OnClick) then
                while KeyboardQuery.IsPressed(VK_SHIFT) do begin
                    Application.ProcessMessages;
                    Sleep(50);
                end;

            PreHandleCaptionViaKeystroke(p, key);
            if p.IsSubmenu then begin
                SetHover(p);
                self.HandleCaptionClick(p);
            end else begin
                self.HandleCaptionClick(p);
            end;

            EXIT;
        end;
    end;



    i := fKeystrokes.IndexOf(string(key));
    if i <> -1 then begin
        self.fKeyActivated := true;
        p := TACPopupItem(fKeystrokes.Objects[i]);
        self.FLastPosition := pipCaption;

        PreHandleCaptionViaKeystroke(p, key);
        {highlight expandable items}
        if p.IsSubmenu then begin
            SetHover(p);
            self.CancelShowSubmenu;
            Self.HandleCaptionClick(p);
        end else if p.IsExpandable then begin
            if Assigned(p.OnClick) then
                while KeyboardQuery.IsPressed(VK_SHIFT) do begin
                    Application.ProcessMessages;
                    Sleep(50);
                end;

            self.HandleCaptionClick(p);
//            if it <> IT_CLIPSET_HEADER then
//                for j := 0 to fitems.fSubMenu.count - 1 do begin
//                    p2 := fitems.fSubMenu[j];
//                    if p2.IsExpandable and (p2.ItemType = it) then begin
//                        SetHover(p2);
//                        BREAK;
//                    end;
//                end;
        end else begin
            self.HandleCaptionClick(p);
        end;
    end;

end;

{Click Event Processing}
procedure TACPopupPrototype.GatherModifierKeys(p : TACPopupItem);
begin
    p.fCtrlPressed := KeyboardQuery.IsPressed(VK_CONTROL);
    p.fShiftPressed := KeyboardQuery.IsPressed(VK_SHIFT);
    p.fAltpressed := KeyboardQuery.IsPressed(VK_MENU);
end;
function TACPopupPrototype.HandleMouseClick(p: TACPopupItem) : boolean;
begin
    result := false;
	{handle Icon clicks, pass of Caption cliks}
    {handle right clicks}

    if ([ssLeft,ssMiddle] * fDownShift) <> [] then begin
        case FLastPosition of
            pipCaption: begin
                result := true;

                GatherModifierKeys(p);

                if (p.fItemType = IT_CANCEL) then fPopupMode.setMode(pdmAutoHide);

                self.HandleCaptionClick(p);
            end;
        end;
    end;
end;
procedure TACPopupPrototype.HandleCaptionClick(p: TACPopupItem);
var wasChecked, wasExpanded, wasGrouped, wasExpandedShortcuts : boolean;
	i : integer;
    p2 : TACPopupItem;
    it : TItemType;
    ci : TClipITem;
begin
    {handle special controls ourselves, pass off everything else to the click handler}
    case p.Style  of
    psLine: ;
    psBreak: ;
    psSubmenu: begin
        p.SetShowingSubMenu;

        fExpandedKeystrokes.Clear;
        fShowExpandedType := it;
        ShowExpandedShortcuts := self.fKeyActivated;
        self.AssignSubmenuShortcuts(p);

        self.RebuildPopup(false);
    end;
    psExpandable: begin
    	timHover.Enabled := false;
        it := p.ItemType;
        fAutoExpandOnce := IT_NONE;
        if assigned(p.fCanExpand) then begin
            if not p.fCanExpand(p) then EXIT;
        end;

        FrmDebug.AppendLog('Normal Expand');
        wasExpanded := p.Expanded;
        fShowExpandedType := it;

        if p.fDisabled then EXIT;
        wasExpandedShortcuts := fShowExpandedShortcuts;
        fShowExpandedShortcuts := false;
        if (fKeyactivated  and (fExpandedKeystrokes.Count = 0) and wasExpanded) then begin
            p.Expanded := false;
            fShowExpandedShortcuts := true;
            fAutoExpandOnce := it;
            fKeyActivated := true;
            self.RebuildPopup;
            fKeyActivated := true;
            p2 := nil;
            for i := 0 to fitems.fSubMenu.count - 1 do begin
                p2 := fitems.fSubMenu[i];
                if p2.ItemType = it then begin
                    BREAK;
                end;
            end;
            p := p2;
        end else begin
            if ((FrmConfig.cbAutoCollapse.checked ) and (not p.Expanded))
                 then begin
    //        	simulate a show and an expand event - a known 'working' method for expanding
                self.AutoPopulate;
                p2 := nil;
                for i := 0 to fitems.fSubMenu.count - 1 do begin
                    p2 := fitems.fSubMenu[i];
                    if p2.ItemType = it then begin
                        BREAK;
                    end;
                end;
                if p2<>nil then begin
                    p2.Expanded := true;
                    ShowExpandedShortcuts := self.fKeyActivated;

                    self.RebuildPopup(false);
                    self.SetHover(p2);
                    p := p2;
                end;
            end else begin
                p.Expanded := not p.Expanded;
                ShowExpandedShortcuts := self.fKeyActivated and p.Expanded;
                self.RebuildPopup(false);
            end;
        end;


        fExpandedKeystrokes.Clear;
        self.AssignSubmenuShortcuts(p);
        RebuildPopup(false);

        fAutoExpandOnce := IT_NONE;
    end;
    psCheckable: begin
    	wasChecked := p.Checked;
        p.Checked := not p.Checked;
        DrawItem(p);
        DrawCheckgroup(p);
        if assigned(p.OnClick) then begin
            p.OnClick(p);
        end;
        if p.ItemType = IT_SWITCH then begin
            if (waschecked = true) and (p.checked) then begin
            end else begin
                self.RebuildPopup;
            end;
        end;
        DrawItem(p);
    end;
    psNormal: begin
        case FLastPosition of
        pipLeftIcon: begin
            case p.ItemType of
            IT_FULL:
                begin
                    self.Hide;
                    FrmConfig.pcPanels.ActivePage := FrmConfig.tsMenuOrder;
                    frmConfig.Show;
                    TFocusManager.ForceForeground(frmconfig.Handle);
                    FrmMainPopup.SkipFocusReturnOnce;
                end;
            IT_CLIPSET_HEADER:
                begin

                end;
            end;
        end;
        pipNone: ;
        pipCaption: begin
            self.fCaptionPoint.X := self.left + p.Left;
            self.fCaptionPoint.Y := self.top + p.Top;

            if p.IsInExpandedMenu and p.fCollapseParentOnClick then begin
                if assigned(p.onclick) then begin
                    p.OnClick(p);
                    p.fParent.Expanded := false;
                    self.RebuildPopup;
                end;
            end else begin
                case p.ItemType  of
                IT_NEXTFIELD:begin
                    ci := TClipItem.Create;
                    TClipDatabase.LoadPermanent(ci, p.IntegerData, FORM_MODE_FOLDER);
                    TFocusManager.ForceForeground(FrmMainPopup.TargetData.ForegroundWindow);
                    Paste.SendMacro(ci.GetAsPlaintext);
                    myfree(ci);
                    mysleep(30);
                end;
                IT_FULL: begin
                    if FLastPosition=pipCaption then begin
                        fFullMode := not fFullMode;
                        if fFullMode then begin
                            p.Caption := 'Configured Mode';
                        end else begin
                            p.Caption := 'Full Mode'
                        end;
                        self.RebuildPopup;
                    end else begin
                    end;
                end;
                IT_CANCEL: begin
                    self.Hide;
                end;
                else
                    HandleOnClick(p);
                end;
            end;
        end;

        end;
    end;
    end;
end;
procedure TACPopupPrototype.HandleOnClick(p: TACPopupItem);
    function SafeClick(p : TACPopupItem) : boolean;
    begin
        result := false;
        if assigned(p.OnClick) then begin
            result := true;
            p.OnClick(p);
        end;
    end;
var
    h : THandle;
    savedMode : TPopupDisplayMode;
begin
    HideTooltip;

    if p.ItemType = IT_POPUPCLIP then begin
        if p.Clip <> nil then  begin
            p.Clip.CData.Clicked := true;
        end;
    end;


    case ACPopupClicks.OverrideClickType(p) of
    OC_NONE:
        begin
        end;
    OC_STAY_OPEN:
        begin
            fPopupMode.PushValue;
            fPopupMode.setMode(pdmStayOpen);

            ACPopupClicks.StayOpenClick(p);
            fPopupMode.PopValue;

            if FrmMainPopup.GetNeedsFocus then begin
                TFocusManager.ForceForeground(self.Handle);
            end;
            self.RebuildPopup;
            EXIT;
        end;
    OC_RIGHT_CLICK:
        begin
            self.ClipMenuShow;
            EXIT;
        end;
    OC_PIN_TO_LIST:
        begin
            if SafeClick(p) then begin
                self.RebuildPopup;
            end;
            EXIT;
        end;
    OC_TITLEBAR_SHORTCUTS:
        begin
            ShowCaptionShortcuts := true;
            self.RebuildPopup;
            EXIT;
        end;
    end;

//	if UseFormMode then begin
//    	if (p.ItemType in TPastesOnClickj) then begin
//            p.OnClick(p);
//            {move to cursor?}
//            self.UseFormMode := true;
//            self.RebuildPopup;
//
//            if (fKeyActivated) then begin
//                ForceForeground(self.Handle);
//            end;
//        end;
//    	EXIT;
//    end;


    case p.ItemType  of
    IT_POPUPCLIP,IT_PINNED,IT_PERMANENT, IT_CLIPBOARD,IT_TEMP,IT_SYSTEM,IT_SEARCH,
    IT_PASTE_METHOD,IT_TOOL {IT_SELECTED,IT_LAST} : begin
        case FLastPosition  of
        pipLeftIcon: ;
        pipCaption: begin
            if assigned(p.fOnClick) then begin

                if (not p.fStayOpenOnClick) and fPopupMode.equals(pdmAutoHide) and (p.ItemType <> IT_TOOL) then
                    self.Hide;
                ACPopupClicks.SetMenuPoint(self.fCaptionPoint);

                if (p.itemType = IT_TOOL) and p.fStayOpenOnClick and fpopupMode.equals(pdmAutoHide) then begin
                    fPopupMode.SetOverride(pdmStayOpen);
                end;
                SafeClick(p);
                if (p.ItemType = IT_TOOL) and fPopupMode.equals(pdmStayOpen) and p.fStayOpenOnClick then begin
                    fPopupMode.ClearOverride;
                end;
                if (fPopupMode.equals(pdmPinned)) then begin
                    if (frmConfig.getReturnPopupFocusWhenPinned) then begin
                        TFocusManager.ForceForeground(self.handle);
                    end;
                    IsClickWhilePinned := false;
                    self.RebuildPopup;
                end;
                if (fPopupMode.equals(pdmFormMode)) then begin
                    self.RebuildPopup;

                    if (fKeyActivated) then begin
                        TFocusManager.ForceForeground(self.Handle);
                    end;
                end;
            end;
        end;
        pipNone: ;
        end;
    end;
    IT_NONE: begin {TODO thinkg about this}
        if assigned(p.fOnClick) then begin
            self.Hide;
            SafeClick(p);
        end;
    end;
    IT_SWITCH: begin
        if SafeClick(p) then begin
            if p.IsInExpandedMenu then
            	p.fParent.Expanded := false;

            self.RebuildPopup;
        end;
    end;
    end;
end;

{Drag-and-Drop routines}
procedure TACPopupPrototype.DragMouseDown(p: TACPopupItem);
begin
    if (p <> nil) and (fDragMenuItem = nil) then begin
        if not (p.ItemType in [IT_NONE, IT_LINE]) then begin
            fDragMenuItem := p;
            if p <> nil then begin
            	fDragX := mouse.cursorpos.x; fDragY := mouse.cursorpos.y;
            end;
        end;
    end;
end;
function TACPopupPrototype.DragMouseMove(p, last: TACPopupItem) : boolean;
var temp : TACPopupItem;
begin
	result := false;
    if (p <> nil) and fDragStarted then  begin
    	temp := fDropMenuItem;
        fDropMenuItem := p;
        //last := fDropMenuItem;
        if (p <> last) then begin
            DrawItem(p);
            if IsLegalDrop(p) then begin


                screen.Cursor := crDrag;
                //appendlog('legaldrop');
            end else begin
                screen.Cursor := crNoDrop;
                FrmDebug.appendlog('no legaldrop');
            end;

            //if last <> nil then DrawItem(last);
            if temp <> nil then DrawItem(temp);
        end else begin
            if p = fDragMenuItem then begin
            	screen.Cursor := crNoDrop;
            end;
            if temp <> nil then DrawItem(temp);
            DrawItem(p);

        end;

        result := true;
    end else if fDragStarted  then begin
       	screen.Cursor := crNoDrop;
        temp := fDropMenuItem;
        fDropMenuItem := p;
		if temp <> nil then DrawItem(temp);
    end;
end;
function TACPopupPrototype.DragMouseUp(p: TACPopupItem) : boolean;
var m1, m2 : TMenuOrderType;
begin
	result := false;

    if fDragStarted then
        MouseCursorReset;


    if fDragStarted and (p<>nil) then begin
        fDragStarted := false;
        if IsLegalDrop(p) then begin
            if fDragMenuItem.IsExpandable then begin
                m1 := TMenuOrderType(fdragmenuitem.integerdata);
            end else begin
                case fdragmenuitem.ItemType  of
                IT_POPUPCLIP:	m1 := MOT_MENU;
                IT_PERMANENT: m1 := MOT_PERMANENT;
                IT_CLIPBOARD:	m1 := MOT_CURRENT;
                //IT_LAST: 	m1 := MOT_LAST;
                IT_SEARCH: 	m1 := MOT_SEARCH;
                IT_FULL: 	m1 := MOT_FULL;
                end;
            end;
            if p.IsExpandable then begin
            	m2 := TMenuOrderType(p.integerdata);
            end else begin
                case p.ItemType  of
                IT_POPUPCLIP:	m2 := MOT_MENU;
                IT_PERMANENT: m2 := MOT_PERMANENT;
                IT_CLIPBOARD: m2 := MOT_CURRENT;
                //IT_LAST: 	m2 := MOT_LAST;
                IT_SEARCH: 	m2 := MOT_SEARCH;
                IT_FULL: 	m2 := MOT_FULL;
                end;
            end;
            if (m1 = MOT_MENU) then begin
                ClipQueue.Move(fDragMenuItem.IntegerData,p.IntegerData)
            end else if (m1 = MOT_PERMANENT) then begin
            	if fDragMenuItem.fPermanentGroupID = -1 then begin
                	FrmPermanent.MoveClip(fDragMenuItem.fPermanentID, p.fPermanentID);
                end;
            end else if (p.ItemType = IT_PINNED) then begin
                PinnedClipQueue.Move(fDragMenuItem.IntegerData,p.IntegerData)
            end else begin
        		FrmConfig.MoveItem(m1, m2);
            end;
            self.RebuildPopup;
        end else begin
        	DrawItem(p);
        end;
        fDragMenuItem := nil;
        fdragx := 0; fdragy := 0;

    	result := true;
    end else begin
    	fDragStarted := false;
        fDragMenuItem := nil;
        fDropMenuItem := nil;
    end;
end;

{Timed Hide/Show Events}
procedure TACPopupPrototype.ShowSubmenuDelayed(p: TACPopupItem);
begin
    fQueuedSubmenu := p;
    timShowSubmenu.interval := 300;
    if timMouseSelectDelay.Enabled then begin
        timShowSubmenu.interval := 600;
    end;
    timShowSubmenu.Enabled := true;
end;
procedure TACPopupPrototype.timShowSubmenuTimer(Sender: TObject);
begin
    timShowSubmenu.Enabled  := false;

    if fQueuedSubmenu <> nil then begin
        fLastSubmenu := fQueuedSubmenu;
        fQueuedSubmenu.SetShowingSubMenu;
        if not fKeyActivated then
            fShowExpandedShortcuts := false;
        self.AssignSubmenuShortcuts(fQueuedSubmenu);
        fQueuedSubmenu := nil;



        self.RebuildPopup(false);
    end;
end;
procedure TACPopupPrototype.timHideSubmenuTimer(Sender: TObject);
    procedure ClearSubmenus(pc : TACPopupItem);
    begin
        if pc = nil then EXIT;

        repeat
             pc.fSubShowing := nil;
             pc := pc.fParent;
        until pc = nil;
    end;
var P : TACPopupItem;
begin
    timHideSubmenu.Enabled := false;
    timHideSubmenu.Interval := 300;

    p := fItems;
    if p.fSubShowing = nil then begin

    end else begin
        while p.fSubShowing <> nil do begin
            p := p.fSubShowing;
        end;
        fLastSubmenu := p;
        if fLastSubmenu <> nil then begin
            ClearSubmenus(fLastSubmenu);
            fLastSubmenu := nil;
            self.RebuildPopup(false);
        end;
    end;
end;
procedure TACPopupPrototype.timHoverTimer(Sender: TObject);
var pt : TPoint;
    cix : TClipItem;
    r : TRect;
    s : string;
    hotkeyname : string;

    procedure SingleMode;
    begin
        fToolTipNew.HideHeader;
        fToolTipNew.SingleLineOnce := true;
        fToolTipNew.SmallFontOnce := true;
    end;
    procedure showClipTooltip(clip : TClipItem; useTimestamp : boolean);
    begin
        s := '';
        if (Clip <> nil) and (clip.GetFormatType = FT_PICTURE) then begin
            s := Clip.GetFormatName;
        end;

        fToolTipNew.ShowTooltip(clip, pt, GetClipHeader(clip),'',
            useTimestamp);
    end;
begin
    timHover.Enabled := false;

    if hover = nil then EXIT;
    if FLastPosition = pipNone then EXIT;
	if fDragStarted then EXIT;

    r := hover.BoundRect;
    pt := point(r.Right - trunc((r.Right-r.Left) / 3.5), r.bottom + 2);
    
    if hover.IsExpandable and FrmConfig.cbAutoExpand.checked then begin
    	if not hover.expanded then begin
        	self.HoverClick;
        end;
        timHover.Enabled := false;
    	EXIT;
    end;


    case hover.ItemType  of
        IT_PERMANENT: begin
            case FLastPosition  of
            pipCaption: begin
                cix := TClipItem.Create;
                s := FrmPermanent.GetPermanentPath;
                if Hover.fPermanentGroupID <> -1 then begin
                    s := FrmPermanent.PermFoldersGetItem(Hover.fPermanentGroupID);
//                    hotkeyname := FrmPermanent.GetItemHotkeyName(Hover.fPermanentID);
//                    cix := FrmPermanent.GetItemClip(hover.fPermanentID);
                end;
                hotkeyname := TClipDatabase.LoadPermanentHotkey(hover.fPermanentID, s);
                TClipDatabase.LoadPermanent(cix, hover.fPermanentID, s );
                fToolTipNew.ShowTooltip(cix, pt, GetClipHeader(cix), hotkeyname);
                myfree(cix);
            end;
            end;
        end;
        IT_POPUPCLIP,IT_PINNED,
        IT_PERMANENT_GROUP,
        IT_TEMP,
        IT_CLIPBOARD,
        IT_SELECTED,
        IT_FULL: begin
            case FLastPosition of
            pipCaption: begin
                if hover.Hint <> '' then begin
                    SingleMode;
                    fTooltipNew.ShowTooltip(Hover.hint,pt);
                end else if hover.fClip <> nil then begin
                    showClipTooltip(hover.fclip, (hover.ItemType in [IT_POPUPCLIP]) and (hover.clip.CData.CreationDateUsed));
                end else begin
                    if (hover.ItemType = IT_TEMP) then begin
                        cix := RemovedQueue.GetItemClip(hover.IntegerData);
                        showClipTooltip(cix, false);
                        myfree(cix);
                    end;

                end;
            end;
            pipLeftIcon: begin
                if hover.ItemType = IT_FULL then begin
                	SingleMode;
                    fToolTipNew.ShowTooltip('Edit Menu Order', pt);
                end;
            end;
            end;
        end else begin
            if hover.Hint <> '' then begin
                SingleMode;
                if (hover.ItemType = IT_TOOL) then begin
                    fTooltipNew.SmallFontOnce := false;
                end;

                fTooltipNew.ShowTooltip(Hover.hint,pt);
            end;
        end;
    end;
end;
procedure TACPopupPrototype.timIgnoreMouseMoveTimer(Sender: TObject);
begin
	fIgnoreMouseMove := false;
    timIgnoreMouseMove.Enabled := false;
end;
procedure TACPopupPrototype.timLeftIconHoverTimer(Sender: TObject);
begin
    timLeftIconHover.Enabled := false;

    if FLastPosition = pipLeftIcon then
    	self.ClipMenuShow;
end;
procedure TACPopupPrototype.timModiferTimer(Sender: TObject);
var
    r : TRect;
    pt : TPoint;
    i : integer;
begin
    timModifier.Enabled := false;
    if (hover = nil) then EXIT;


    r := hover.BoundRect;
    pt := point(r.Right - trunc((r.Right-r.Left) / 3.5), r.bottom + 2);
    i := fToolTipNew.MinWidth;

    fToolTipNew.MinWidth := 40;

    if KeyboardQuery.IsPressed(VK_SHIFT) then begin
        fToolTipNew.HideHeader;
        fTooltipNew.ShowTooltip( frmConfig.cbxShiftClickAction.text ,pt);
        timHover.Enabled := false;
        EXIT;
    end else if KeyboardQuery.IsPressed(VK_MENU) then begin
        fToolTipNew.HideHeader;
        fTooltipNew.ShowTooltip( frmConfig.cbxAltClickAction.text,pt);
        timHover.Enabled := false;
        EXIT;
    end else if KeyboardQuery.IsPressed(VK_CONTROL) then begin
        fToolTipNew.HideHeader;
        fTooltipNew.ShowTooltip( frmConfig.cbxCtrlClickAction.text,pt);
        timHover.Enabled := false;
        EXIT;
    end else begin
        fToolTipNew.HideHeader;
    end;

    fToolTipNew.MinWidth := i;
end;

procedure TACPopupPrototype.CancelShowSubmenu;
begin
    fQueuedSubmenu := nil;
    timShowSubmenu.Enabled := false;
end;
procedure TACPopupPrototype.HideTooltip;
begin
    timHover.Enabled := false;
    timModifier.Enabled := false;
    fToolTipNew.Hide;
end;
procedure TACPopupPrototype.StartHoverTooltip;
begin
    timModifier.Enabled := false;
    timHover.Enabled := false;
    timHover.Enabled := true;
end;
{Highlight routines}
procedure TACPopupPrototype.DetectAutoScroll(top,bottom : integer);
var
	pt : TPoint;
    m : TMonitor;
begin
	if fIsTooTall then begin
    	if top <> -1 then begin
           	pt.y := top;
            pt.x := 0;
            pt := self.ClientToScreen(pt);

            m := screen.MonitorFromWindow(self.handle);
            if (m <> nil) then begin
                if pt.y < m.top then begin
                	fIgnoreMouseMove := true;
                    timIgnoreMouseMove.Enabled := true;
                    self.Top := m.Top;
                    EXIT;
                end;
            end;
        end;

        if bottom <> -1 then begin
            pt.Y := bottom;
            pt.x := 0;
            pt := self.ClientToScreen(pt);


            m := screen.MonitorFromWindow(self.handle);
            if (m <> nil) then begin
                pt.Y := pt.y + m.top;
                if pt.y > m.BoundsRect.Bottom  then begin
                	fIgnoreMouseMove := true;
                    timIgnoreMouseMove.Enabled := true;
                    self.Top := m.top - (self.Height - m.Height);
                end;
            end;
        end;
    end;
end;

procedure TACPopupPrototype.SetHover(value: TACPopupItem; tooltip:boolean=true);
var last : TACPopupItem;
begin
    // this is the must be the ONLY method that sets fhover directly

	if fShowing = false then EXIT;
    {hotkey pasting will call this method, even if the PopupItem hide the popup}
    
    last := fHover;
    fHover := value;
    HideTooltip;
    if tooltip and
        (last <> fHover) and (fHover <> nil) and (last <> nil) then begin
        StartHoverTooltip;
    end;


    if FLastPosition <> pipLeftIcon then begin
        self.ClipMenuHide;
    end;

    if (value <> nil) then begin
        // Detect when Shortcut Keys need to shift up a level
        if (fKeyActivated) and
            (last<>nil) and (last.IsSubmenu) then begin
            if fHover.IsInExpandedMenu and not fhover.IsSubmenu and last.IsSubmenu then begin
                fShowExpandedType := fHover.ItemType;
                fShowExpandedShortcuts := True;
                Self.AssignSubmenuShortcuts(fhover.fparent);
                self.Invalidate;
            end;
        end;

        if last<>nil then DrawItem(Last);
        if fhover <> nil then DrawItem(fHover);

        // detect the mouse moving from a submenu to a child - don't
        // close the submenu when mouse selected
        if fLastSubmenu <> nil then begin
            if timMouseSelectDelay.Enabled then begin
                if fLastSubmenu.IsSubmenu and (fhover.VisibleParent = fLastSubmenu) then begin
                    self.timHideSubmenu.Enabled := false;
                end;
            end else begin
                // don't close the submenu when moving from parent to child (via keyboard)
                if not (fLastSubmenu.IsSubmenu and (fhover.VisibleParent = fLastSubmenu)) then begin
                    self.timHideSubmenuTimer(self);
                end;
            end;
        end;
        if fhover.IsSubmenu then begin
            if (last<>nil) and (last.IsSubmenu) then begin
                if timMouseSelectDelay.Enabled then begin
                    self.CancelShowSubmenu;
                    self.timHideSubmenu.Enabled := false;
                    self.timHideSubmenu.Enabled := true;
                end else begin
                    self.CancelShowSubmenu;
                    self.timHideSubmenuTimer(self);
                end;
            end;

            self.ShowSubmenuDelayed(fHover);
        end else if fhover.IsInSubmenu then begin

        end else begin
            if timMouseSelectDelay.Enabled then begin
                self.CancelShowSubmenu;
                self.timHideSubmenu.Enabled := false;
                self.timHideSubmenu.Enabled := true;
            end else begin
                self.CancelShowSubmenu;
                self.timHideSubmenuTimer(self);
            end;
        end;
    end;
end;
procedure TACPopupPrototype.HoverClick;
begin
    if Hover <> nil then begin
        FLastPosition := pipCaption;
        GatherModifierKeys(Hover);
        HandleCaptionClick(Hover);
    end;
end;
procedure TACPopupPrototype.HoverDown;
var i : integer;
    daddy, p : TACPopupItem;
begin
    if fItems.fSubMenu.Count = 0 then begin
        FrmDebug.AppendLog('HoverDown: Empty Popup');
        EXIT;
    end;

    // init or select next item, no matter what it is
    if Hover = nil then begin
        i := 0;
        p := fItems.fSubMenu[i];
        daddy := fItems;
    end else begin
        daddy := Hover.VisibleParent;

        i := Hover.Index;
        i := (i + 1) mod daddy.fSubMenu.Count;
        p := daddy[i];
    end;

    while (p.Style in [psLine, psBreak, psGap]) do begin
        i := (i + 1) mod daddy.fSubMenu.Count;
        p := daddy.fSubMenu[i];
    end;


    FLastPosition := pipCaption;
    SetHover(p);
    self.DetectAutoScroll(p.top,p.bottom);
end;
procedure TACPopupPrototype.HoverLeft;
var p : TACPopupItem;
    i : integer;
    procedure CheckForExpandable(p : TACPopupItem);
    begin
        if (p.IsInExpandedMenu) then begin
            ShowExpandedShortcuts := self.fKeyActivated;
            fShowExpandedType := p.ItemType;
        end;
    end;
begin

    if hover = nil then EXIT;
    {close submenu, if in submenu}
    if Hover.IsInSubmenu then begin
        ShowExpandedShortcuts := False;

        SetHover(Hover.fparent);
        self.CancelShowSubmenu;
        timHideSubmenuTimer(self);

        CheckForExpandable(Hover);
        if Hover.fParent.IsExpandable then
            self.AssignSubmenuShortcuts(hover.fparent);
        self.Invalidate;
    end else if Hover.IsSubmenu and (fitems.fSubShowing <> nil) and (hover.fSubMenu.Count <> 0)  then begin
        // close submenu only
        ShowExpandedShortcuts := False;
        CheckForExpandable(Hover);

        SetHover(hover);
        self.CancelShowSubmenu;
        timHideSubmenuTimer(self);

        Self.AssignSubmenuShortcuts(hover.fparent);
        self.Invalidate;

    end else begin
        if hover.ColumnIndex = 0  then EXIT;

        p := getItemAt(hover.fLeft - 5, (hover.fTop+ hover.fBottom)div 2);
        if p = nil then begin
            p := hover;
            i := p.Index;
            while (p.ColumnIndex = hover.ColumnIndex) or p.IsBreak do begin
            	dec(i);
                p := p.visibleparent[i];
            end;
        end;

        i := p.Index;
        while p.isline and (i > 0)do begin
            dec(i);
            p := p.VisibleParent[i];
        end;
        if p <> nil then begin
        	FLastPosition := pipCaption;
            SetHover(p);
        end;
    end;
end;
procedure TACPopupPrototype.HoverRight;
var i : integer;
    p : TACPopupItem;
begin
    if hover = nil then EXIT;

    if hover.IsSubmenu then begin
        if (Hover.fSubMenu.Count > 0) then begin
            hover.SetShowingSubMenu;
            fLastSubmenu := Hover;
            self.AssignSubmenuShortcuts(hover);
            self.RebuildPopup(false);
            i := 0;

            while (hover.fSubMenu[i].isGap) do begin
                inc(i);
            end;
            SetHover( hover.fSubMenu[i] );
        end;
    end else begin
        p := getItemAt(hover.right + 5, (hover.fTop+ hover.fBottom)div 2);
        if p = nil then begin
            if fitems.fColWidth.Count > 1 then begin
                p := fitems.fSubMenu[fitems.fsubmenu.count-1];
            end else begin
                EXIT;
            end;
        end;

        i := p.Index;
        while (p.isline or p.isGap) and (i > 0)do begin
            inc(i);
            p := p.VisibleParent[i];
        end;
        if p <> nil then begin
        	FLastPosition := pipCaption;
            SetHover(p);
        end;
    end;

end;
procedure TACPopupPrototype.HoverUp;
var i : integer;

    daddy, p : TACPopupItem;

begin

    // init or select next item, no matter what it is
    if Hover = nil then begin
        i := 0;
        daddy  := fItems;
        p := fItems.fSubMenu[daddy.fSubMenu.Count - 1];
    end else begin
        daddy := Hover.VisibleParent;
        i := Hover.index;
        dec(i);
        if i < 0 then i := daddy.fSubMenu.Count - 1;
        p := daddy[i];
    end;

    while (p.Style in [psLine, psBreak, psGap]) do begin
        dec(i);
        if i < 0 then i := daddy.fSubMenu.Count - 1;
        p := daddy.fSubMenu[i];
    end;



    FLastPosition := pipCaption;
    SetHover(p);
    self.DetectAutoScroll(p.top,p.bottom);
end;


{Control Events}
procedure TACPopupPrototype.paint;
var c : Cardinal;
begin
    c := WIndows.GetTickCount;
	inherited;
    self.FullRedraw;
    FrmDebug.AppendLog('paint ms=' + IntToStr(Windows.GetTickCount - c));
end;
procedure TACPopupPrototype.resize;
begin
    //inherited;
    {not handling gets rid of flicker}
    FrmDebug.AppendLog('resize');
end;
procedure TACPopupPrototype.Hide;
begin
	if fShowing = false then begin
    	FrmDebug.AppendLog('acpopup.hide called twice');
        EXIT;
    end;
    fShowing := false;

    //inherited;
    FrmDebug.AppendLog('acpopup hide start');
    Windows.ShowWindow(self.Handle, SW_HIDE);

    timHover.Enabled := false;
    timShowSubmenu.Enabled := false;
    timHideSubmenu.Enabled := false;
    timLeftIconHover.Enabled := false;


    if assigned(fTooltipNew) then HideTooltip;
    self.ClipMenuHide;

    fFullMode := false;
    fPopupMode.reset;

    self.visible := false;
    FirstPaint := false;
    self.MouseCursorReset;
    self.fTopOffsetEnable := false;

    ShowCaptionShortcuts := false;
    FrmDebug.AppendLog('acpopup hide end');
end;
procedure TACPopupPrototype.WMActivate(var msg: tMessage);
var
    pt : TPoint;
    p : TACPopupItem;
    h : THandle;
begin
    {ignore all the inactive messages that appear until we've had a chance
    to paint and be visible to the user}
    case msg.WParam of
    WA_INACTIVE: begin
        if (lastActiveState <> WA_INACTIVE) then  begin
            FrmDebug.AppendLog('WA_INACTIVE');
            if self.FirstPaint then begin
                self.hide;
                if self.showing then begin
                    self.RebuildPopup;
                end;
            end;
            FrmDebug.AppendLog('WA_INACTIVE End');
        end;
        lastActiveState := WA_INACTIVE;
    end;
    WA_ACTIVE, WA_CLICKACTIVE: begin
        if (lastActiveState <> WA_ACTIVE) and self.Visible then begin
            FrmDebug.AppendLog('WA_ACTIVE');
            if fPopupMode.equals(pdmPinned) then begin
                h := FrmMainPopup.GetNextWindow(self.Handle);
                if WindowHandleToEXEName(h) = 'explorer.exe' then begin
                    h := FrmMainPopup.GetNextWindow(h);
                end;
                FrmMainPopup.GatherTargetWindowData(h);
            end;
            if fPopupMode.equals(pdmPinned) and (msg.WParam=WA_CLICKACTIVE) then begin
                // set focus when a non-menu item is clicked
                pt := ScreenToClient(mouse.CursorPos);
                p := GetItemAt(pt.X,pt.y);
                if (p = nil) or (p.ItemType = IT_CLIPSET_HEADER) then begin
                    FrmDebug.AppendLog('WA_ACTIVE: NIL Item');
                    TFocusManager.ForceForeground(self.Handle);
                    if (not lastRebuildUsedKeyboard) then begin
                        self.RebuildPopup;
                    end;
                end else if (p.ItemType = IT_TOOL) then begin
                    TFocusManager.ForceForeground(self.Handle);
                end else begin
                    SetHover(p);
                end;
            end;
            FrmDebug.AppendLog('WA_ACTIVE End');
        end;
        lastActiveState := WA_ACTIVE;
    end;
    end;
end;
procedure TACPopupPrototype.WMGetDlgCode(var Msg: TMessage);
begin
	{Tell Windows we want arrow keys}
    inherited;
    Msg.Result:= Msg.Result or DLGC_WANTARROWS;
end;
procedure TACPopupPrototype.WMKeyDown(var Message: TWMKeyDown);
begin
	{TODO - what does this do again?}
    if message.CharCode in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT] then begin
    end else begin
        inherited;
    end;
end;
procedure TACPopupPrototype.WMNCHitTest(var Message: TWMNCHitTest);
var pt : tpoint;
    r : TRect;
    i : integer;
    p : TACPopupItem;
const THRESHOLD = 6;
begin
	inherited;


    if not self.fDragStarted then begin
        // Detect mouse over Drag Point
        pt := point(message.XPos, message.YPos);
        pt := self.ScreenToClient(pt);
        CopyRect(r,fMainRect);
        r.Left := r.Right - THRESHOLD;
        r.Top := r.Bottom - THRESHOLD;

        if PtInRect(r, pt) then begin
            message.Result := HTCAPTION;
            EXIT;
        end else begin
            if ShowCaption then begin
                if (pt.Y < CaptionHeight) then   begin
                    p := GetItemAt(pt.X, pt.y);
                    if  (p = nil) or (p.isGap) then begin
                        message.result := HTCAPTION;
                    end else begin
                        message.result := HTCLIENT;
                    end;
                end;
            end else begin
                message.result := HTCLIENT;
            end;
        end;
    end;



end;
procedure TACPopupPrototype.WMSetCursor(var M: TWMSetCursor);
begin
	if m.CursorWnd = self.Handle then begin
        if m.HitTest = HTCAPTION then begin
            screen.Cursor := crSizeAll;
            m.Result := 1;
        end else begin
            if screen.Cursor <= 0 then begin
                screen.Cursor := crArrow;
                m.result := 1;
            end;
        end;
    end;
end;
procedure TACPopupPrototype.WMMove(var Msg : TMessage);
begin
   fpoint.X := self.Left;
   fpoint.Y := self.Top;
end;

{ TACPopupItemCollection }
function TACPopupItemCollection.Add: TACPopupItem;
begin
    result := TACPopupItem.Create;
    result.Visible := true;

    self.add(result);
end;
function TACPopupItemCollection.GetItem(Index: Integer): TACPopupItem;
begin
    result := TACPopupItem(inherited GetItem(Index));
end;
procedure TACPopupItemCollection.SetItem(Index: Integer; const Value: TACPopupItem);
begin
    inherited SetItem(Index, Value);
end;



{
//
// TACIcon
//
}
constructor TACIcon.Create;
begin
    self.fBitmap := nil;
    self.fHasIcon := false;
    self.fIcon := 0;
    self.fCliptypeBitmap := nil;
    self.fHasCliptypeIcon := false;
    self.fIconOpacity := 255;
end;
procedure TACIcon.SetBitmap(value: TBitmap);
begin
    self.fHasIcon := true;
    self.fBitmap := value;
end;
procedure TACIcon.SetIcon(value: hicon);
begin
    self.fHasIcon := value <> 0;
    fIcon := value;
end;
procedure TACIcon.SetCliptypeIcon(value: TBitmap);
begin
    self.fCliptypeBitmap := value;
    self.fHasCliptypeIcon := true;
end;
procedure TACIcon.SetFrom(icon : HICON);
begin
    SetIcon(icon);
end;
procedure TACIcon.SetFrom(Bitmap : TBitmap);
begin
    SetBitmap(Bitmap);
end;
destructor TACIcon.Destroy();
begin
    if fIconBitmap <> nil then fIconBitmap.Free;
end;


{
//
// TACPopupMode
//
}
constructor TACPopupMode.Create;
begin
    flist := TStack<TPopupDisplayMode>.create;
    setMode(pdmAutoHide);
end;
procedure TACPopupMode.setMode(mode : TPopupDisplayMode);
begin
    PopValue;
    flist.Push(mode);
    if (flist.Count = 1) then begin
        fbaseMode := mode;
    end;
end;
function TACPopupMode.getMode : TPopupDisplayMode;
begin
    result := flist.Peek;
end;
function TACPopupMode.IsAutoClose : boolean;
begin
    result := getMode in [pdmAutoHide];
end;
function TACPopupMode.equals(mode : TPopupDisplayMode) : boolean;
begin
    result := getMode = mode;
end;
procedure TACPopupMode.PushValue;
begin
    flist.Push(pdmAutoHide);
end;
function TACPopupMode.PopValue : TPopupDisplayMode;
begin
    result := pdmAutoHide;
    if flist.Count > 0 then
        result := flist.Pop;
end;
procedure TACPopupMode.SetOverride(mode: TPopupDisplayMode);
begin
    PushValue;
    setmode(mode);
end;
procedure TACPopupMode.ClearOverride;
begin
    PopValue;
end;
function TACPopupMode.getModeNoOverride;
begin
    result := self.fbaseMode;
end;
procedure TACPopupMode.reset;
begin
    flist.Clear;
    setMode(pdmAutoHide);
end;
{
//
// TACPopupItem
//
}
constructor TACPopupItem.Create();
begin
    inherited;

    fSubMenu := TACPopupItemCollection.Create();
    fCheckgroup := TObjectList.Create;

    fLeftIcon := TACIcon.create();
    fLeftIcon.fIconOpacity := 255;

    fCheckgroup.OwnsObjects := false;
    fColWidth := TIntList.Create;
    fStyle := psNormal;


    fShowCollapseIcon := True;


    self.fPrefix := '';
    self.fCaption := '';
    self.fHoverOnlyCaption := '';
    self.fClip := nil;
end;
destructor TACPopupItem.Destroy;
begin
    fColWidth.Free;
    fCheckgroup.Free;

    if (fStyle = psExpandable) and (fexpanded = false) then begin
        fSubMenu.Free;
    end;

    inherited;
    fLeftIcon.Free;
end;

{Drawing Routines}
function TACPopupItem.DesiredWidth(c : TCanvas) : integer;
var s : string;
    i,j : integer;
    wd : integer;
begin
    j := 0;
    if (fprefix <> '') then begin
        j := c.TextWidth('W');
    end;

    result := fspacing + j + fspacing*PREFIX_TRAILING_SPACE_MULTIPLE;

    if fCaptionTrailingBitmap <> nil then
        inc(result, fCaptionTrailingBitmap.Width);

    if (ItemType = IT_PROGRAM_MENU) then begin
        result := result + 16 + fSpacing;
    end;
    if (ItemType in TContainsAClip) and
        (fClip<>nil) and (fClip.GetFormatType = FT_PICTURE) then begin
        // dib AAAxYYYY
        try
            s := fClip.GetFormatName;
            UnitToken.TokenString(s,')');
            s := UnitToken.TokenString(s,'x');
            result := result +  StrToInt(s);
        except
        end;
    end else begin
        if SmallCaption then begin
            i := c.Font.Size;
            c.Font.Size := i-1;
        end;
        wd := c.TextWidth(fCaption);
        if (wd <> 0) then begin
            inc(result, fspacing*3 + wd + (fSpacing*RIGHT_SPACE_PADDING_MULTIPLE));
        end;
        if SmallCaption then begin
            c.Font.Size := i;
        end;
    end;
end;
procedure TACPopupItem.DrawCaption(ac:TACPopupPrototype; c : TCanvas; r : TRect; IsHovered, IsIcon :  boolean);
    var
        ClipboardLeft, prefixwidth : integer;
        wc : TWideChar;

    procedure TextColorSet;
    begin
        c.brush.Style := bsClear;
        c.pen.Color := 0;
        if fDisabled then begin
            c.pen.Color := ac.fDisabledColor;
        end else begin
            c.pen.Color := ac.fFontColor;
            if (fClip <> nil) and fClip.CData.Clicked then begin
                c.pen.Color := ac.fClickedColor;
            end;
        end;

        SetTextColor(c.Handle, ColorToRGB(c.pen.Color));
    end;
    procedure DrawPic;
    var
        st : TStream;
        pnt : Pointer;
        sz : Int64;
        tempr : TRect;
        bm : TBitmap;
    begin
        if not assigned(Clip.CData.thumb) then begin
            Clip.BuildMenuCaption;
        end;
        if assigned(Clip.CData.thumb) then begin
            //
            // Detect already scaled thumbs
            // Otherwise, just draw the entire picture or a crop of
            // the picture
            //
            with Clip.CData do begin
                if (thumb.Width = r.Width) and (thumb.Height = r.Height) then begin
                    c.Draw(r.Left,r.Top, thumb);
                end else if ((thumb.Width + fSpacing) = r.Width) and
                    (thumb.Height = r.Height) then begin
                    c.Draw(r.Left,r.Top, thumb);
                end else begin
                    tempr.Top := r.top;
                    tempr.Left := r.left;
                    tempr.Width := min(thumb.Canvas.ClipRect.Width, r.Width);
                    tempr.Height := min(thumb.Canvas.ClipRect.Height, r.Height);
                    if (tempr.Height < r.Height) then begin
                        tempr.Top := tempr.Top + ((r.Height-tempr.Height) div 2);
                    end;

                    c.CopyMode := cmSrcCopy;
                    c.CopyRect(tempr, thumb.Canvas, rect(0,0,tempr.width, tempr.Height));
                end;
            end;
        end else begin
            try
                bm := TBitmap.Create;
                clip.DibToBitmap(BM);
                c.CopyMode := cmSrcCopy;
                c.CopyRect(r,bm.canvas,rect(0,0,bm.Width,r.Height));
                bm.Free;
            except
                FrmDebug.AppendLog('DrawPic: couldn''t draw bitmap',true);
            end;
        end;

        // Windows is doing something shady. Unless the BitmapInfo and the bit
        // buffer are continguous, the StretchDIBits call is failing
//            DrawDib(usecanvas, p.Clip.GetStream, r);
    end;
    procedure DrawClipboardMark;
    begin
        with FrmMainPopup.imgPasteMini.Picture do begin

            c.Draw(
                clipboardleft - 4,
                Max(r.Top + (r.Height - Bitmap.height) div 2, 0),
                Bitmap
            );
            r.Left := r.left + Bitmap.Width-2;
        end;
    end;
    procedure HandlePrefix(r:TRect);
    var
        i : integer;
        ch : Char;
        function IsSkippedPrefix : boolean;
        begin
            result := ((IsInSubmenu or IsInExpandedMenu) and (ItemType <> IT_POPUPCLIP))
                or ((ItemType = IT_TOOL) and not AC.ShowCaptionShortcuts);
        end;
        procedure DrawPrefix;
        var
            c1 : TColor;
            bs : TBrushStyle;
            c2 : TColor;
            square : TRect;
            ht : integer;
            atop : integer;
            len : integer;
        begin
            bs := c.Brush.Style;
            c2 := c.Brush.Color;
            c1 := c.Pen.Color;

            c.Brush.Style := bsSolid;
            c.Pen.Style := psSolid;
            if (ac.UseKeyboard) then begin
                wc.Appendunicode(trim(fPrefix));
            end else begin
                wc.Appendunicode(trim(fPrefix[2]));
            end;
            len := wc.StrLength;


            prefixwidth := c.TextWidth('W');
            CopyRect(square, r);
            inc(square.Left, fspacing);
            square.right := square.left + prefixwidth;
            inc(square.Right,1);
            dec(square.Left,1);
            ht := c.TextHeight('WZ');
            atop := max(0,(((square.Bottom-square.Top)-(ht)) div 2));
            inc(square.top, atop);
            square.bottom := square.Top + ht + 1;
            if IsHovered then begin
                c.Brush.Color := DimColorOrReverse(ac.fbackgroundBase, 0.86);
            end else begin
                c.Brush.Color := DimColorOrReverse(ac.fbackgroundBase, 0.92);
            end;

            c.FrameRect(square);

            prefixwidth := square.right-square.left;


            c.Brush.Color := c2;

            if c1 <> clGrayText then begin
                c.Pen.Color := DimColorOrReverse(ac.fFontColor, 1.05);
            end else begin
                c.Pen.Color := c1;
            end;
            if (not ac.UseKeyboard) then begin
                c.Pen.Color := ac.fDisabledColor;
            end;

            SetTextColor(c.Handle, ColorToRGB(c.pen.Color));

            r.Right := r.Left + prefixwidth;
            c.Brush.Style := bsClear;
            square.Top := r.Top-1;
            square.Bottom := r.Bottom+1;
            DrawTextW(c.Handle, PWideChar(wc.Memory), len,
                square, DT_VCENTER or DT_SINGLELINE or DT_CENTER );

            SetTextColor(c.Handle, ColorToRGB(c.pen.Color));
            c.Pen.Color := c1;
            c.Brush.Style := bs;
        end;
    begin
        prefixwidth := 0;
        if (fPrefix <> '') then begin
            wc := TWideChar.Create;

            if (ac.fShowExpandedShortcuts) then begin
                if IsSkippedPrefix then begin
                    // draw normally skipped prefix, if it's referenced
                    ch := fprefix[2];
                    i := ac.fExpandedKeystrokes.IndexOf(string(ch));
                    if (i<>-1) and (ac.fExpandedKeystrokes.IndexOfObject(self) = i)
                         then begin
                        DrawPrefix;
                    end;
                end else begin
                    // draw "always drawn" prefix, only if not overriden
                    ch := fprefix[2];
                    i := ac.fExpandedKeystrokes.IndexOf(string(ch));
                    if (i=-1) then begin
                        DrawPrefix;
                    end;
                end;
            end else if not IsSkippedPrefix then begin
                DrawPrefix;
            end;
            myfree(wc);
        end;
    end;
    procedure HandlePosssibleIcon;
    var ht : integer;
        y : integer;
        left : integer;
        icon : TIcon;
        bm : TBitmap;
        BlendFunc: TBlendFunction;
    begin
        if fCaptionIconOnlyOnHover and (not IsHovered) then EXIT;

        if (fItemType = IT_PROGRAM_MENU) or (fCaptionTrailingBitmap <> nil) then begin
            ht := r.Bottom-r.Top;
            if ht < 16 then begin
                y := r.top;
            end else begin
                y := r.Top + max(0, ((ht)-16)div 2);
            end;

            left := r.Left + c.TextWidth(wc.GetString) + fspacing*2;

            if (ItemType <> IT_PROGRAM_MENU) then begin
                c.Draw(left, y, fCaptionTrailingBitmap);
            end else begin
                inc(y);
                left := r.Left;

                icon := TIcon.Create;
                icon.Handle := DuplicateIcon(0, fLeftIcon.Icon);
                bm := TBitmap.Create;
                bm.Width := 16;
                bm.Height := 16;
                bm.PixelFormat := pf24bit;
                bm.TransparentColor := clWhite;

                bm.Canvas.CopyRect(rect(0,0,16,16), c, rect(left,y,left+16,y+16));
                //c.Draw(left, y, icon);
                DrawIconEx(c.handle,
                    left, y+1,
                    fleftIcon.icon, 16,16, 0, 0, DI_NORMAL);

                BlendFunc.BlendOp := AC_SRC_OVER;
                BlendFunc.BlendFlags := 0;
                BlendFunc.SourceConstantAlpha := 120;
                BlendFunc.AlphaFormat := 0;
                Windows.AlphaBlend(c.Handle, left,y, 16,16, Bm.Canvas.Handle,
                    0,0, 16,16, BlendFunc);


                bm.Free;
                icon.Free;
            end;
        end;
    end;
    procedure HandleDoubleHeightMarkers(r : TRect);
    var
        bs : TBrushStyle;
        c1, c2 : TColor;

    begin
        EXIT;

        bs := c.Brush.Style;
        c2 := c.Brush.Color;
        c1 := c.Pen.Color;

        c.Brush.Style := bsSolid;
        c.Pen.Style := psSolid;

        c.Pen.Color := AC.fFontColor;


        c.Brush.Style := bs;
        c.Brush.Color := c2;
        c.Pen.Color := c1;
    end;
    procedure HandleClipPasteCue(bm : TBitmap);
    begin
        if IsHovered and not IsIcon and (fItemType in TPastesOnClickj) then begin
            c.Draw(
                r.left,
                r.Top+max(0,((r.Bottom-r.Top)-bm.Height) div 2) ,
                bm
            );
        end;
    end;

    function HasCaption : boolean;
    begin
        result := fcaption <> '';
    end;

var
    options : integer;
    fs : TFontStyles;
    s : string;
    len : integer;
    bm : TBitmap;
    tempr : TRect;
    ht : integer;
begin
    TextColorSet;

    HandlePrefix(r);
    if prefixwidth <> 0 then begin
        inc(r.left, fspacing+ prefixwidth);
    end;
    inc(r.Left, fspacing*(PREFIX_TRAILING_SPACE_MULTIPLE-1));


    if (isOnClipboard) then begin
        clipboardleft := r.left;
        if not ((fClip <> nil) and (fClip.GetFormatType = FT_PICTURE)) then begin
            DrawClipboardMark;
        end;
    end;

    r.right := r.Right - (fSpacing*RIGHT_SPACE_PADDING_MULTIPLE);
    wc := TWideChar.Create;
    if HasCaption or (fClip = nil) or (fClip.GetFormat <> CF_UNICODETEXT) then begin
        if HasCaption or (fClip = nil) then begin
            s := fcaption;
        end else begin
            if fClip.GetFormat = CF_DIB then begin
                s := fClip.GetFormatName;
            end else begin
                s := fclip.GetAsPlaintext;
            end;
        end;

        wc.AppendUnicode(s);
        wc.Replace(WideChar(' '),{NO BREAK SPACE}WideChar($00A0));
    end else begin
        wc.AppendUnicode(fClip.GetAsPlaintext);
    end;

    fs := c.Font.Style;
    if (IsHovered) and (fIconHoverCaption <> '') and (IsIcon) then begin
        // icon hover override
        wc.Clear;
        wc.Append(fIconHoverCaption);
        c.Font.Style := c.Font.Style + [fsBold];

        if fItemType in [IT_FULL, IT_PERMANENT] then begin
            fCaptionTrailingBitmap := ImgToBitmap(FrmMainPopup.imgNewWindow);
        end;
    end else begin
        if fItemType in [IT_FULL, IT_PERMANENT] then begin
            fCaptionTrailingBitmap := nil;
        end;
    end;
    if IsHovered and (fHoverOnlyCaption <> '') and not IsIcon then begin
        wc.Clear;
        wc.Append(fHoverOnlyCaption);
        c.Font.Style := c.Font.Style + [fsBold];
    end;

    len := min(100, wc.StrLength);
    SetBkMode(c.Handle, TRANSPARENT) ;


    options := 0;
    if fItemType in TContainsAClip then begin
        options := options or DT_NOPREFIX;
    end;
    if SmallCaption then begin
        options := options or DT_CENTER;
    end;

    // rect2 is either the size of the caption, or smaller if the picture is smaller

    TextColorSet;
    if (FrmConfig.cbNoThumbnails.Checked=false) and IsPictureClip then begin
        DrawPic;
        if IsOnClipboard then begin
            r.Left := clipboardleft-4;
            DrawClipboardMark;
        end;
    end else begin
        if fItemType = IT_PROGRAM_MENU then begin
            inc(r.Left, 16+fspacing);
        end;

        if DoubleHeight then begin
            // DT_VCENTER only works for single line text
            dec(r.bottom,2);
            DrawTextW(c.Handle, PWideChar(wc.Memory), len,
                r, DT_VCENTER or DT_WORDBREAK or DT_EDITCONTROL or options  );

            HandleDoubleHeightMarkers(r);
        end else begin
            inc(r.Bottom);
                DrawTextW(c.Handle, PWideChar(wc.Memory), len,
                    r, DT_VCENTER or DT_SINGLELINE or options);
            dec(r.Bottom);
        end;

    end;




    if fItemType = IT_PROGRAM_MENU then begin
        dec(r.Left, 16+fspacing);
    end;
    HandlePosssibleIcon;



    myfree(wc);

    SetBkMode(c.Handle, OPAQUE);
    c.Font.Style := fs;
end;
procedure TACPopupItem.DrawCaptionBackground(AC: TACPopupPrototype; c : TCanvas; r : TRect);
const
    BLEND_CLICKED = 97;
    BLEND_CLICKED_ORIGINAL = 99;
    DIVIDER_HALF_WIDTH = 60;
var
    c1,c2 : TColor;
    liner : TREct;
    m : integer;
    procedure MyFillRect(r : TRect);
    begin
        inc(r.bottom);
        inc(r.Right);
        c.FillRect(r);
    end;
    procedure MyGradientFill(c1, c2 : TColor; r : TRect; d : TGradientDirection);
    begin
        inc(r.Bottom);
        inc(r.Right);
        GraphUtil.GradientFillCanvas(c,c1,c2,r,d);
    end;
    procedure SetBrush(color : TColor);
    begin
        c.Brush.color := color;
        if DoubleHeight then begin
            c.Brush.Color := Blend(c.Brush.Color, ac.fColumnColor, 80);
        end;
    end;
begin
    CopyRect(liner, r);
    if  (fItemType in [IT_CANCEL,IT_FULL]) then begin
        SetBrush(ac.fColumnColor);
        ac.fBackgroundBase := c.brush.Color;
        MyFillRect(r);

        c1 := ac.fColumnColor;
        c2 := dimColor(ac.fColumnColor, 0.94);
        liner.Left := liner.right - RIGHT_MENU_GRADIENT_WIDTH;
    end else if IsInExpandedMenu then begin
        SetBrush(ac.fExpandedBackgroundColor);
        if (fClip <> nil) and fClip.CData.Clicked then begin
            c.Brush.Color := unitMisc.Blend(c.brush.Color, ac.fClickedColor, BLEND_CLICKED);
        end;
        ac.fBackgroundBase := c.brush.Color;
        MyFillRect(r);
    end else begin
        if (fItemType = IT_PINNED) then begin
            SetBrush(DimColorOrReverse(ac.fBackgroundColor,1.03));
            ac.fBackgroundBase := c.brush.Color;
        end else if (fItemType = IT_TOOL) then begin
            SetBrush(ac.fCaptionColor);
            ac.fBackgroundBase := c.brush.Color;
        end else begin
            SetBrush(ac.fBackgroundBase);
        end;
        MyFillRect(r);
    end;
end;

{utils}
function TACPopupItem.IsOnClipboard : boolean;
begin
    result :=  (fItemType = IT_CLIPBOARD);
    result := result or (
        (fItemType = IT_POPUPCLIP) and
        (fClip.CData <> nil) and
        (fClip.CData.Hash = CurrentClipboard.CData.Hash)
    );
end;
function TACPopupItem.IsPictureClip : boolean;
begin
    result :=
        (fItemType in TContainsAClip) and
        (fClip<>nil) and
        (fClip.GetFormatType = FT_PICTURE);
end;




function TACPopupItem.GetBoundsRect: TRect;
begin
    result := fBoundsRect;
end;

function TACPopupItem.GetChecked: boolean;
begin
    result := fChecked;
end;
function TACPopupItem.GetColumnWidth: integer;
begin
    result := fParent.fColWidth[fMyColumn];
end;
function TACPopupItem.GetExpanded: boolean;
begin
    result := fExpanded;
end;

function TACPopupItem.GetIndex: integer;
begin
    {The index refers to the visible parent, not the owner}
    result := GetVisibleParent.fSubMenu.IndexOf(self);
end;

function TACPopupItem.GetOwnerIndex : integer;
begin
    result := fParent.fSubMenu.IndexOf(self);
end;

function TACPopupItem.GetIsBreak: boolean;
begin
    result := fStyle = psBreak;
end;
function TACPopupItem.GetIsExpandable: boolean;
begin
    result := fStyle = psExpandable;
end;
function TACPopupItem.GetIsInExpandedMenu: boolean;
begin
    result := fParent.IsExpandable;
end;
function TACPopupItem.GetIsInSubMenu: boolean;
begin
    result := (fparent.fParent <> nil) and not fparent.IsExpandable;
end;
function TACPopupItem.GetIsLine: boolean;
begin
    result := fStyle = psLine;
end;
function TACPopupItem.GetIsSubmenu: boolean;
begin
    result := fStyle = psSubmenu;
end;
function TACPopupItem.GetIsGap : boolean;
begin
    result := fStyle = psGap;
end;

function TACPopupItem.GetItem(Index : integer): TACPopupItem;
begin
    result := fSubMenu[index];
end;

function TACPopupItem.GetVisibleParent: TACPopupItem;
begin
    {In an expanded menu, the visible parent will be twice removed}
    result := fParent;
    if self.IsInExpandedMenu  then
        result := fParent.fParent;
end;


procedure TACPopupItem.CheckGrouped;
begin
    fParent.fCheckgroup.Add(self);
end;
function TACPopupItem.IsCheckGrouped : boolean;
begin
    result := fparent.fCheckgroup.IndexOf(self) <> -1;
end;
function TACPopupItem.Add: TACPopupItem;
begin
    result := self.fSubMenu.Add;
    result.fParent := self;

    if self.IsSubmenu then begin
        self.Disabled := false;
    end;
end;


function TACPopupItem.AddBreak: TACPopupITem;
begin
    result := self.add;
    result.IsBreak := true;
end;
function TACPopupItem.CalcRight: integer;
begin
    if self.fStaticRight then begin
        result := self.fRight;
        EXIT;
    end;
    if self.fParent.IsExpandable  then begin
        result := self.fLeft + self.fParent.fparent.fColWidth[self.fMyColumn] - RIGHT_BORDER;
    end else begin
        result := self.fLeft + self.fParent.fColWidth[self.fMyColumn] - RIGHT_BORDER;
    end;
    self.fRight := result;
end;
procedure TACPopupItem.SetBoundsRect(parenttop, parentleft: integer);
begin
    with fBoundsRect do begin
        top := ftop + parenttop;
        bottom := fbottom + parenttop;
        left := fleft + parentleft;
        right := self.right + parentleft;
    end;
end;

procedure TACPopupItem.SetCaption(value: string);
begin
    fCaption := value;
    if (length(fCaption) > 300) then begin
        fCaption := leftstr(fCaption, 300) + '...';
    end;
    // tabs make the windows too damn long
    // the #10 will make a funky box in the tab's place
    while pos(#9#9, fCaption) > 0 do begin
        fCaption := stringreplace(fCaption, #9#9, #9, [rfreplaceall]);
    end;
    fCaption := stringreplace(fCaption, #9,chr($B0), [rfReplaceAll]); {unicode middle dot}

    {escape the special hotkey character}
    fCaption := stringreplace(fCaption, '&', '&&', [rfReplaceAll]);
end;
procedure TACPopupItem.SetCaptionFromClip(value: TClipItem);
begin
    if value.CData.displaytext <> '' then begin
        fCaption := value.CData.displaytext;
        EXIT;
    end;
    case value.GetFormatType of
    FT_UNICODE, FT_RICHTEXT, FT_HTML:
        begin
            value.BuildMenuCaption;
            fCaption := value.CData.displaytext;
        end;
    FT_PICTURE:
        begin
            fCaption := value.GetFormatName()
        end;
    else
        begin
            SetCaption(value.GetAsPlaintext);
        end;
    end;
    value.CData.displaytext := fCaption;
end;

procedure TACPopupItem.SetChecked(value: boolean);
var i : integer;
    p : TACPopupItem;
begin
    if (fParent.fCheckgroup.IndexOf(self) <> -1) then begin
        if (self.fChecked = false) and value then begin
            for i := 0 to fParent.fCheckgroup.Count - 1 do begin
                p := TACPopupItem(fParent.fCheckgroup[i]);
                p.fChecked := false;
            end;
            self.fChecked := true;
        end;
    end else begin
        self.fChecked := value;
    end;

    self.fStyle := psCheckable;
    self.fStayOpenOnClick := true;
end;
procedure TACPopupItem.SetExpanded(value: boolean);
var i : integer;
begin
    if FExpanded = value then EXIT;

    fExpanded := value;

    if value then begin
        for i := fSubMenu.count - 1 downto 0 do begin
            fparent.fSubMenu.Insert(self.index+1,fsubmenu[i]);
        end;
    end else begin
        for i := fSubMenu.count - 1 downto 0 do begin
            fparent.fSubMenu.Extract(fSubmenu[i]); // Don't Free the object
        end;
    end;
end;

procedure TACPopupItem.SetIsBreak(value: boolean);
begin
    if value then
        fStyle := psBreak;
end;
procedure TACPopupItem.SetIsExpandable(value: boolean);
begin
    if value then begin
        fStyle := psExpandable;
        fLeftIcon.fIconOnlyOnHover := false;
        fLeftIcon.fIconOnExpanded := true;
        fStayOpenOnClick := true;
    end;
end;
procedure TACPopupItem.SetIsLine(value: boolean);
begin
    if value then begin
        fStyle := psLine;
        fStayOpenOnClick := true;
    end;
end;
procedure TACPopupItem.SetIsSubmenu(value: boolean);
begin
    if value then begin
        fStyle := psSubmenu;
        fStayOpenOnClick := true;
    end;
end;
procedure TACPopupItem.SetIsGap(value : boolean);
begin
    if value then begin
        fStyle := psGap;
        fStayOpenOnClick := true;
    end;

end;
procedure TACPopupItem.SetItem(Index: integer; value: TACPopupItem);
begin
    fSubMenu[index] := value;
end;


procedure TACPopupItem.SetShowingSubMenu;
begin
    if self.IsInExpandedMenu  then begin
        fParent.fParent.fSubShowing := self;
    end else begin
        fParent.fSubShowing := self;
    end;

end;


procedure TACPopupItem.SetHoverOnlyCaption(value : string);
begin
    self.fHoverOnlyCaption := value;
end;
function TACPopupItem.GetHoverOnlyCaption : string;
begin
    result := fHoverOnlyCaption;
end;


//
// Handling transparency
//
constructor TCustomTransparentControl.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);
    ControlStyle := ControlStyle + [csOpaque];
    Brush.Style := bsClear; {required for XP to make backgroun transparent}
end;
procedure TCustomTransparentControl.CreateParams(var Params: TCreateParams);
begin
    inherited CreateParams(Params);

    // dropshadow
    if CheckWin32Version(5, 1) then
       params.WindowClass.Style := params.WindowClass.style or CS_DROPSHADOW;
end;
procedure TCustomTransparentControl.WMNCHitTest(var Message: TWMNCHitTest);
begin
    if not FInterceptMouse then begin
        Message.Result := HTTRANSPARENT
    end else begin
        inherited;
    end;
end;
procedure TCustomTransparentControl.Invalidate;
begin
    FrmDebug.AppendLog('invalidate');
	inherited Invalidate;
end;

initialization
begin

end;
end.
