How to add custom commands and menu items  SOLVED

PDF-XChange Editor SDK for Developers

Moderators: TrackerSupp-Daniel, Tracker Support, Paul - Tracker Supp, Vasyl-Tracker Dev Team, Chris - Tracker Supp, Sean - Tracker, Ivan - Tracker Software, Tracker Supp-Stefan

Forum rules
DO NOT post your license/serial key, or your activation code - these forums, and all posts within, are public and we will be forced to immediately deactivate your license.

When experiencing some errors, use the IAUX_Inst::FormatHRESULT method to see their description and include it in your post along with the error code.
Post Reply
espens
User
Posts: 45
Joined: Wed Jan 14, 2009 7:31 am

How to add custom commands and menu items

Post by espens »

Could you provide a sample on how I would go about to add my own command and also how I would add a menu item?

I would like to add a menu option to the File menu just after the Save As item, when clicked it should execute my custom command or notify my code/raise an event.
User avatar
Ivan - Tracker Software
Site Admin
Posts: 3549
Joined: Thu Jul 08, 2004 10:36 pm
Location: Vancouver Island - Canada
Contact:

Re: How to add custom commands and menu items  SOLVED

Post by Ivan - Tracker Software »

First of all you will need to implement IUIX_CmdHandler interface:

Code: Select all

class CMyCmdHandler : public IUIX_CmdHandler
{
public:
	STDMETHODIMP OnCreateNewCtl(IUIX_Cmd* pCmd, IUIX_CmdBar* pParent, IUIX_Obj** ppCtl)
	{
		return E_NOTIMPL;
	}
	STDMETHODIMP OnGetCtlSizes(IUIX_CmdItem* pItem, SIZE* pSize, SIZE* pMinSize, SIZE* pMaxSize)
	{
		return E_NOTIMPL;
	}
	// item state
	STDMETHODIMP OnGetItemState(IUIX_Cmd* pCmd, IUIX_CmdItem* pItem, IUIX_Obj* pOwner, LONG* pState)
	{
		if (!pCmd || !pItem || !pState)		// check just in case
			return S_FALSE;
		long nCmdID = 0;
		pCmd->get_ID(&nCmdID);
		switch (nCmdID)
		{
		case myCmdID:
			....
			*pState = UIX_CmdItemState_Normal;	// combination of UIX_CmdItemState flags
			break;
		// the same handler may be used to handle multiple commands
		}
		return S_OK;
	}
	// item notify (UIX_CmdNotifyID)
	STDMETHODIMP OnNotify(LONG nCode, IUIX_Cmd* pCmd, IUIX_CmdItem* pItem, IUIX_Obj* pOwner, SIZE_T pNotifyData)
	{
		if (!pCmd)
			return S_FALSE;
		long nCmdID = 0;
		pCmd->get_ID(&nCmdID);
		if (nCode == UIX_CmdNotify_Exec)
		{
			// do the action
		}
		return S_OK;
	}

	STDMETHODIMP OnDrawItemIcon(IUIX_RenderContext* pRC, IUIX_CmdItem* pItem, RECT* pIconRect, RECT* pClip)
	{
		return E_NOTIMPL;
	}

	STDMETHODIMP OnGetItemSubMenu(IUIX_CmdItem* pItem, IUIX_CmdMenu** ppSubMenu)
	{
		return E_NOTIMPL;
	}
};
Now a function to create new command:

Code: Select all

HRESULT fCreateCommand(IUIX_Inst* pUI, long nCmdID, CMyCmdHandler* pHandler)
{
	HRESULT hr = S_OK;
	do
	{
		CComPtr<IUIX_CmdManager> cmdMan;
		hr = pUI->get_CmdManager(&cmdMan);
		if (cmdMan == nullptr)
			break;
		CComPtr<IUIX_CmdCollection> cmdCol;
		hr = cmdMan->get_Cmds(&cmdCol);
		if (cmdCol == nullptr)
			break;

		CComPtr<IUIX_Cmd> cmd;
		hr = cmdCol->AddNew2(nCmdID, 0, pHandler, &cmd);
		if (cmd == nullptr)
			break;
		cmd->put_Title(L"My Command");
		// command my also have an associated icon, tooltip, etc.

	} while (false);
	return hr;
}
And to add the command (by its ID) to the File submenu after "Save As..." (or at the end):

Code: Select all

HRESULT fInsertCommand(IPXV_Inst* pInst, long nCmdID)
{
	HRESULT hr = S_OK;
	do
	{
		CComPtr<IPXV_MainFrame> pMF;
		hr = pInst->get_ActiveMainFrm(&pMF);
		if (!pMF)
			break;
		CComPtr<IPXV_MainView> pMV;
		pMF->get_View(&pMV);
		if (!pMV)
			break;
		CComPtr<IUIX_CmdBar> pMB;
		pMV->get_MenuBar(&pMB);
		if (!pMB)
			break;

		CComPtr<IUIX_CmdItem> pFileCmdItem;
		pMB->FindFirstItemByCmdName(L"cmd.file", &pFileCmdItem);
		if (pFileCmdItem == nullptr)
			break;
		CComPtr<IUIX_CmdMenu> pFileSubmenu;
		pFileCmdItem->get_SubMenu(&pFileSubmenu);
		if (pFileSubmenu == nullptr)
			break;
		// lookup for position of "Save As..."
		LONG nSaveAsPos = -1;
		pFileSubmenu->FindFirstItemByCmdName(L"cmd.saveAs", &nSaveAsPos);
		if (nSaveAsPos >= 0) // will add after "Save As"; otherwise -1 means to add to the end
			nSaveAsPos++;
		pFileSubmenu->InsertItem2(nCmdID, nSaveAsPos);
	} while (false);
	return hr;
}
And now, how to use that:

Code: Select all

// Lets say we an instance of our class CMyCmdHandler that implements IUIX_CmdHandler interface
// created and stored in the variablle pMyCmdHandler;
CComPtr<CMyCmdHandler> pMyCmdHandler;
// 
// register our command ID in strings table
long myCmdID = 0;
pInst->Str2ID("myCmd_unuqie_ID", &myCmdID)

// Create new command;
CComQIPtr<IUIX_Inst> pUIInst;
CComPtr<IUnknown> pUnk;
pInst->GetExtension(L"UIX", &pUnk);
pUIInst = pUnk;
fCreateCommand(pUIInst, myCmdID, pMyCmdHandler);

// now add newly created command to the main bar;
fInsertCommand(pInst, myCmdID);
Tracker Software (Project Director)

When attaching files to any message - please ensure they are archived and posted as a .ZIP, .RAR or .7z format - or they will not be posted - thanks.
User avatar
MartinCS
User
Posts: 153
Joined: Thu Apr 07, 2011 10:01 am
Contact:

Re: How to add custom commands and menu items

Post by MartinCS »

Hello Ivan,

your code works perfectly!

As I'm using C#.NET for our Windows application I translated your code to C#. It might be helpful for other developers:

IUIX_CmdHandler interface implementation:

Code: Select all

    class PdfEditorCommandHandler : IUIX_CmdHandler
    {
        public void OnCreateNewCtl(IUIX_Cmd pCmd, IUIX_CmdBar pParent, out IUIX_Obj pCtl)
        {
            pCtl = null;
        }

        public void OnGetCtlSizes(IUIX_CmdItem pItem, ref tagSIZE nSize, ref tagSIZE nMinSize, ref tagSIZE nMaxSize)
        {
            //throw new System.NotImplementedException();
        }

        public void OnGetItemState(IUIX_Cmd pCmd, IUIX_CmdItem pItem, IUIX_Obj pOwner, out int nState)
        {
            nState = (int)UIX_CmdItemState.UIX_CmdItemState_Unknown;

            if (pCmd == null || pItem == null)
            {
                return;
            }

            switch (pCmd.ID)
            {
                case 8141: // integer result of str2id method
                    nState = (int)UIX_CmdItemState.UIX_CmdItemState_Normal;
                    break;
            }
        }

        public void OnGetItemSubMenu(IUIX_CmdItem pItem, out IUIX_CmdMenu pSubMenu)
        {
            pSubMenu = null;
        }

        public void OnNotify(int nCode, IUIX_Cmd pCmd, IUIX_CmdItem pItem, IUIX_Obj pOwner, uint nNotifyData)
        {
            if (pCmd == null)
            {
                return;
            }

            if (nCode == (int)UIX_CmdNotifyCodes.UIX_CmdNotify_Exec)
            {
                MessageBox.Show("Test Method - CLICK", "Pdf Viewer", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }

        public void OnDrawItemIcon(IUIX_RenderContext pRC, IUIX_CmdItem pItem, ref tagRECT stIconRect, ref tagRECT stClip)
        {
            //throw new System.NotImplementedException();
        }
    }
CreateMenuCommand implementation:

Code: Select all

        public static void CreateMenuCommand(int cmdId, PdfEditorCommandHandler pdfEditorCommandHandler)
        {
            if (Globals.UiInst.CmdManager == null || Globals.UiInst.CmdManager.Cmds == null)
            {
                return;
            }

            var cmd = Globals.UiInst.CmdManager.Cmds.AddNew2(cmdId, 0, pdfEditorCommandHandler);

            if (cmd == null)
            {
                return;
            }

            cmd.Title = "Sub Menu - TEST ... ";
        }
InsertMenuCommand implementation:

Code: Select all

        public static void InsterMenuCommand(int cmdId)
        {
            if (SingeltonUtils.Instance.PxvInst.ActiveMainFrm == null)
            {
                return;
            }

            var fileCmdItem = SingeltonUtils.Instance.PxvInst.ActiveMainFrm.View.MenuBar.FindFirstItemByCmdName("cmd.file");

            if (fileCmdItem == null)
            {
                return;
            }

            var subMenuPos = fileCmdItem.SubMenu.FindFirstItemByCmdName("cmd.saveAs");

            if (subMenuPos >= 0)
            {
                subMenuPos++;
            }

            fileCmdItem.SubMenu.InsertItem2(cmdId, subMenuPos);
        }
Usage of implementation:

Code: Select all

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            if (Globals.PdfEditorCommandHandler == null)
            {
                Globals.PdfEditorCommandHandler = new PdfEditorCommandHandler();
            }

            var cmdId = this.pdfCtl.Inst.Str2ID("cmd.SubMenueTEST", true);

            PdfEditorEx.CreateMenuCommand(cmdId, Globals.PdfEditorCommandHandler);
            PdfEditorEx.InsterMenuCommand(cmdId);
        }

Martin
Last edited by MartinCS on Wed Sep 09, 2015 11:38 am, edited 1 time in total.
User avatar
Tracker Supp-Stefan
Site Admin
Posts: 17824
Joined: Mon Jan 12, 2009 8:07 am
Location: London
Contact:

Re: How to add custom commands and menu items

Post by Tracker Supp-Stefan »

Hi Martin,

Glad to hear all works properly! And thanks for sharing the C# "translation" :)

Regards,
Stefan
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Hello all,

Great examples, thanks. I was able to get this to work well in VB.Net. I just have a follow-up question on the same subject. How can I associate an icon with a specific command? Can anybody share some example code?

For example, I have a command menu under Tools for launching a calculator. The menu simply reads Calculator, but I thought it would be a nice touch to add an icon if it wouldn't be too difficult to do.

Thanks!
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

There is a way of doing that - will write it to you tomorrow at work (UTC+02:00).

Cheers,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

I've added new icon to the Resources folder. Then, to add an icon to the command - use the following code:

Code: Select all

			PDFXEdit.IAFS_Name name = fsInst.DefaultFileSys.StringToName(System.IO.Directory.GetParent(System.Environment.CurrentDirectory).Parent.FullName + "\\Resources\\calculator.png");
			PDFXEdit.IAFS_File file = fsInst.DefaultFileSys.OpenFile(name, (int)PDFXEdit.AFS_OpenFileFlags.AFS_OpenFile_Read | (int)PDFXEdit.AFS_OpenFileFlags.AFS_OpenFile_ShareRead);
			cmd.Icon = uiInst.CreateIconFromIStream(file.GetStream());
This should be inserted in the CreateMenuCommand method when we've successfully created new command. In our case - after the

Code: Select all

cmd.Title = "Sub Menu - TEST ... ";
HTH,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Awesome! Thanks!

Here's the code in VB.Net in case anyone is interested:

Code: Select all

Dim name As PDFXEdit.IAFS_Name = fsInst.DefaultFileSys.StringToName("...\Resources\calculator.png")
Dim file As PDFXEdit.IAFS_File = fsInst.DefaultFileSys.OpenFile(name, CInt(PDFXEdit.AFS_OpenFileFlags.AFS_OpenFile_Read) Or CInt(PDFXEdit.AFS_OpenFileFlags.AFS_OpenFile_ShareRead))
cmd.Icon = uiInst.CreateIconFromIStream(file.GetStream())
And here is the final result:
Image

Cheers,
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Glad that worked for you and thanks for the VB.Net sample :wink:
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Hello folks,

I have another question regarding removing certain buttons from command bars. For example, I would like to delete/disable the Sound annotation tool. I am able to remove it from the main menu under "Tools --> Comment and Markup Tools" but it's unclear to me how I could remove it from cmdbar_comments so that it no longer shows up as an accessible button. The button itself doesn't appear to be linked to a command name like cmd.tool.annot.sound. I am trying the following to try to delete the button:

Code: Select all

        Dim MyCmdItem = pdfCtrl.Inst.ActiveMainFrm.View.CmdBar2(nIDS(CInt(IDS.cmdbar_commenting))).FindFirstItemByCmdName("cmd.tool.annot.sound")

        If MyCmdItem Is Nothing Then
            Return
        End If
        Dim nCmdId = pdfCtrl.Inst.Str2ID("cmd.tool.annot.sound")
        MyCmdItem.SubMenu.DeleteItemsByCmdID(nCmdId)
What am I missing here?

Thanks,
Doc.It Development
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Shortly after posting the previous I realized that these buttons are referred to as CmdItemBox.

Here is the VB.Net code I used to get rid of a box which is attached to a cmd:

Code: Select all

        Dim MyBoxItem = pdfCtrl.Inst.ActiveMainFrm.View.CmdBar2(nIDS(CInt(IDS.cmdbar_commenting))).FindFirstItemByCmdName("cmd.tool.annot.sound").Box
        MyBoxItem.Delete()
Regards,
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

Glad you found an answer and thanks for your sample :wink:
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Hello folks,

I'm trying to figure out how to create a menu for an existing submenu. Let's say for the sake of example that I have a submenu under Help called Languages, and inside languages I want there to be a list of other menu commands. Much like how your "Basic tools" menu behaves in the Tools menu, where inside it you have your list of tools.

How might this be accomplished? I have tried using the SetSubMenu property but I'm having difficulties. Not sure if this is the method I'm looking for.

Thanks,
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

The following steps should help:
1) You get the Menu bar from the IPXV_MainView:
https://sdkhelp.pdf-xchange.com/vie ... ew_MenuBar
2) Then you use https://sdkhelp.pdf-xchange.com/vie ... nst_Str2ID method to get the Menu Bar command ID where you would want to insert your submenu.
3) Use https://sdkhelp.pdf-xchange.com/vie ... temByCmdID to find the index of the correspondent command in the MenuBar.
4) Use https://sdkhelp.pdf-xchange.com/vie ... latGetItem to find the command item by index.
5) Then use this https://sdkhelp.pdf-xchange.com/vie ... em_SubMenu property to get the submenu.
6) If it does not exist use https://sdkhelp.pdf-xchange.com/vie ... ateCmdMenu
7) You can add it to the command item using the same property as described in 5
And there you have it =)

HTH,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Hello Alex,

This doesn't quite answer my question. My question is that I want to be able to add a submenu to the submenu, if that makes sense?

I get the menu bar,

Code: Select all

Dim menubar = pdfCtrl.Inst.ActiveMainFrm.View.MenuBar
I get the cmdid,

Code: Select all

Dim CmdHelpID = pdfCtrl.Inst.Str2ID("cmd.help")
I get the Index,

Code: Select all

 Dim Cmdindx = menubar.FlatFindFirstItemByCmdID(CmdHelpID)
I get the item,

Code: Select all

Dim cmditem = menubar.FlatGetItem(Cmdindx)
Then, I create a submenu,

Code: Select all

Dim SubMenu1 = uiInst.CreateCmdMenu
        Dim CmdEN As Integer = pdfCtrl.Inst.Str2ID("cmd.help.english")
        Dim CmdFR As Integer = pdfCtrl.Inst.Str2ID("cmd.help.french")
        SubMenu1.InsertItem2(CmdEN)
        SubMenu1.InsertItem2(CmdFR)
Then I add it to the command item

Code: Select all

cmditem.SubMenu = SubMenu1
But how do I create a submenu for one of the commands in SubMenu1?

Regards,
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

OK, so you have the SubMenu1 aka. https://sdkhelp.pdf-xchange.com/vie ... IX_CmdMenu
You can eather:
1) Do https://sdkhelp.pdf-xchange.com/vie ... mByCmdName (for example search for "cmd.help.english") to get the corrspondent submenu item index.
or
2) Use the https://sdkhelp.pdf-xchange.com/vie ... dMenu_Item property to get the correspondent https://sdkhelp.pdf-xchange.com/vie ... IX_CmdMenu
3) Use the https://sdkhelp.pdf-xchange.com/vie ... nsertItem2 or any other insert method to insert needed commands

HTH,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Thanks Alex,

I think I was overlooking this property https://sdkhelp.pdf-xchange.com/vie ... dMenu_Item. It's working now, sort of.

I am having an additional issue. The submenu does not open up. I do have an arrow on the item now which indicates it does have a valid submenu, but upon clicking to expand the submenu, nothing happens.

Can you please tell me what I am missing here? Should I be doing something in the OnGetItemSubMenu of the command handler?
Also, please take a look at the two snips I took comparing my new menu to an existing Tracker menu. The styles of the menu are different, and I'm wondering how I can get the look and feel of the Tracker menu.

Thanks,
Doc.It Development
Attachments
Pictures.zip
(38.66 KiB) Downloaded 171 times
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

Try setting the UIX_CmdItemStyle_HasPopup | UIX_CmdItemStyle_WholePopup style to that Command Item and see whether it works.
If not - paste a short code sample here on which I can test this behavior (C# preferable).

HTH,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Hi Alex,

Thanks, that help to provide the right "look" of the button, but not the right behaviour when you click or hover over the button; no submenu is displayed. Here is my code translated to C#...

Code: Select all

private void cmdSubMenuTest_Click(System.Object sender, System.EventArgs e)
{
	dynamic CmdLang = pdfCtrl.Inst.Str2ID("cmd.help.language");
	dynamic CmdHelp = pdfCtrl.Inst.Str2ID("cmd.help");
	dynamic fileCmdItem = pdfCtrl.Inst.ActiveMainFrm.View.MenuBar.FindFirstItemByCmdID(CmdHelp);
	dynamic indexoflang = fileCmdItem.SubMenu.FindFirstItemByCmdID(CmdLang);
	dynamic CmdLangMenu = fileCmdItem.SubMenu.Item(indexoflang);

	CmdLangMenu.SetStyle(UIX_CmdItemStyleFlags.UIX_CmdItemStyle_HasPopup + UIX_CmdItemStyleFlags.UIX_CmdItemStyle_WholePopup);

	dynamic CmdEN = pdfCtrl.Inst.Str2ID("cmd.help.english");
	dynamic CmdFR = pdfCtrl.Inst.Str2ID("cmd.help.french");

	CmdLangMenu.InsertItem2(CmdEN, 0);
	CmdLangMenu.InsertItem2(CmdFR, 1);

}
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Hello docu-track99,

I found the problem - the thing is that in your custom command handler, you'll need to overload a certain method correctly:

Code: Select all

public void OnGetItemSubMenu(PDFXEdit.IUIX_CmdItem pItem, out PDFXEdit.IUIX_CmdMenu pSubMenu)
{
	pSubMenu = pItem.SubMenu;
}
And everything will work =)

HTH,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
docu-track99
User
Posts: 518
Joined: Thu Dec 06, 2007 8:13 pm

Re: How to add custom commands and menu items

Post by docu-track99 »

Awesome, thanks. It does work now.


Regards,
Doc.It Development
Sasha - Tracker Dev Team
User
Posts: 5522
Joined: Fri Nov 21, 2014 8:27 am
Contact:

Re: How to add custom commands and menu items

Post by Sasha - Tracker Dev Team »

Glad that worked for you docu-track99, we'll mark this topic as closed.

Cheers,
Alex
Subscribe at:
https://www.youtube.com/channel/UC-TwAMNi1haxJ1FX3LvB4CQ
Post Reply