LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

add buttons to title bar

The top-level panel has a title bar with programme icon, title, and three buttons for minimize, maximize and close. Selecting the icon itself, gives a short menu with minimize, maximize, close, size and move.
Is it possible to add items to this icon-menu or to add buttons with callback to the title bar.

P.S. I want to keep the window (plot) area as large as possible and therefore I'am not looking for the standard menu or the toolbar.
0 Kudos
Message 1 of 14
(5,309 Views)
It is not possible to do this, unfortunately.

Have you considered putting this functionality in a context-menu that could be activated when the user right-clicks in the window? It's fairly easy to do, and it wouldn't take up any extra space in your window...

Luis
NI
0 Kudos
Message 2 of 14
(5,309 Views)
Thanks Luis for the idea.

I hadn't thought about this. And next project I certainly will consider this idea. However ...

Within this project, I already use left/right mouse inside the panel for zooming in/out the plot that covers the complete panel area. The mouse location itself is used as centre position for the zoom-activity.

So I have to try this where I cath the mouse in the title-bar itself. Because these are top-level panels, the left-mouse in the title-bar is already connected to move. And a right-click in the title-bar gives already the same menu as shown below the title icon and related to the minimize/maximize/close buttons.

So I am still looking for an extension of this menu; or for some extra buttons on the title bar each with its own call
back.

Meanwhile with respect to your idea: do you advise to use a panel with no size and a menu bar, or to use a panel with command buttons, or ... ...
0 Kudos
Message 3 of 14
(5,309 Views)
I wouldn't advise using command buttons because they take up space, and it sounds as if space in your panel is not something you have.

I can think of two other possibilities.

1. You can pop up the menu I suggested as a response to a keypress event, like for example. This would allow you to continue to use mouse clicks for zooming the graph.

2. Something a little more elaborate would be to use a floating toolbar instead of a menu. You could implement this fairly easily by creating a panel, setting its floating attribute, and then placing a few picture buttons on the panel. This would allow the end user to place this "toolbar" wherever he likes without you having to worry about making room for it.

Luis
0 Kudos
Message 4 of 14
(5,309 Views)
Hi Luis,
I am interested in using context-menu in my application.
Can you please tell me how do I do this?
Thanks.
Sheetal
Thanks.
CVI 2010
LabVIEW 2011 SP1
Vision Builder AI 2011 SP1
0 Kudos
Message 5 of 14
(5,311 Views)
The function that runs the context menu is RunPopupMenu. All you have to do is decide how you want to launch it. The most typical mechanism is to launch it as a result of a right-click menu in some panel or control. To do that, just call the function RunPopupMenu in the callback function for the panel or control, as a result of receiving an EVENT_RIGHT_CLICK event.

Prior to doing this you have to have created the menu. You can do that either in the UI Editor or programmatically, using NewMenuBar and then NewMenu.

For an example of this, check out this example program:

samples\userint\custctrl\easytab.prj

Hope this helps
- luis
0 Kudos
Message 6 of 14
(5,311 Views)
Thanks for your help Luis.
Thanks.
CVI 2010
LabVIEW 2011 SP1
Vision Builder AI 2011 SP1
0 Kudos
Message 7 of 14
(5,311 Views)
Hello Luis,

I have noticed that I used the wrong jargon in my question. Using information by Bilal Durrani (Thanks !)
from an exchange on system menu, I use windows SDK function to expand the title bar menu ie systemmenu. I have added (most) source below.

If you are experienced with SDK (I am not) please comment on the use of the ID value range I use for the new items ie 1001, ..., 1004. Another question of mine is with respect to the use of a
zero-pointer when I forward the call in 'OpenglMenuInterim'. Also please, can you give advise on resetting the function pointers eg do I need to reset the pointer hProcOld when a panel is closed?

/*****************************************************/
/* windows SDK is needed */
/*****************************************************/
#include
/*****************************************************/
/* some defines */
/*****************************************************/
#define MENUOFFSET 1000
#define MENUITEMSMAX 4
#define MENUSEPARATOR 1
#define MENUSAVE 2
#define MENUPRINT 3
#define MENUCLIPBOARD 4
#define OPGLMAXPANELS 8
#define OPGLFRAMEWIDTH 640
#define OPGLFRAMEHEIGHT 480
#define OPGLFRAMESWITCH 2000
#define OPGLPAPERSIZEX 240.0
#define OPGLPAPERSIZEY 180.0
#define OPGLFRAMEOFFSET 23
#define OPGLFRAMEBORDER 0
char WindowTitle[10]="OPGL";
char WindowHint[60]="(mouse-lft=zoom in / mouse-rght = zoom out / ESC=reset)\0";

/*****************************************************/
/* structure for panel housekeeping data */
/* note that some data is redundant; I' am lazy */
/* - the number will be sequence number 0,1,.. */
/* - active will be set when window is created */
/* - panelid is the CVI panel id */
/* - hSsystem is corresponding windows handle */
/* Ignore the prefix 'opgl' as I do this for */
/* multiple panels with an OGL control */
/*****************************************************/
struct opglpanel_data {
int number;
int active;
int panelid;
... ...
... ...
long hProcOld;
long hSystem;
... ...
... ...
};

/*****************************************************/
/* global variable array for housekeeping data */
/*****************************************************/
struct opglpanel_data opglpanel[OPGLMAXPANELS];

/*****************************************************/
/* main function including init all global variables */
/* and creating first panel */
/*****************************************************/
int main (int argc, char *argv[])
{
int i, first=0;
for (i = 0; i < OPGLMAXPANELS; i++)
{
opglpanel[i].number = i;
opglpanel[i].active = 0;
opglpanel[i].panelid = -1;
... ...
... ...
opglpanel[i].hProcOld = 0;
opglpanel[i].hSystem = -1;
... ...
... ...
}

OpenglControlCreate(first);
}

/************************************/
/* find panelnumber for CVI panelid */
/************************************/
int OpenglControlPanel(int panelid)
{
int i, found = -1, error = -1;
if (panelid < 0) return(error);
for (i = 0; i < OPGLMAXPANELS; i++)
if (opglpanel[i].panelid == panelid) found = i;
return found;
}
/*********************************************/
/* find panelnumber for windows panel handle */
/*********************************************/
int OpenglControlWindow(long hwnd)
{
int i, found = -1, error = -1;

if (hwnd < 0) return(error);
for (i = 0; i < OPGLMAXPANELS; i++)
if (opglpanel[i].hSystem == hwnd) found = i;
return found;
}

/*****************************************************/
/* furtherdown, OpenglMenuInterim replaces initial windows callback */
/* check and process if one of the new menuitems has been selected */
/* subsequently send callback onwards to original callback */
/*****************************************************/
LRESULT APIENTRY OpenglMenuInterim(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
long orgproc;
long menuitem;
int panel;

panel = OpenglControlWindow((long)hwnd);
if ((uMsg == WM_SYSCOMMAND) && (wParam > MENUOFFSET) && (wParam <= (MENUOFFSET + MENUITEMSMAX)))
{
menuitem = wParam - MENUOFFSET;
switch(menuitem)
{
case MENUSAVE:
printf("Menu Save hwnd: %8d (panel %02d)", hwnd, panel );
break;
case MENUPRINT:
printf("Menu Print hwnd: %8d (panel %02d)", hwnd, panel );
break;
case MENUCLIPBOARD:
printf("Menu Clipboard hwnd: %8d (panel %02d)", hwnd, panel );
break;
default:
break;
}
}
if (panel >= 0) orgproc = opglpanel[panel].hProcOld;
else orgproc = 0; /* ????? ????? ????? */
return(CallWindowProc((WNDPROC)orgproc, hwnd, uMsg, wParam, lParam));
}

/*****************************************************/
/* discard panel ie with close button */
/* also reset all redirected callbacks to empty callback */
/*****************************************************/
void OpenglControlDiscard(int i)
{
int panelid, pictureid, controlid, discardid;

if ((i < 0) || (i >= OPGLMAXPANELS)) return;
panelid = opglpanel[i].panelid;
if (panelid > 0)
{
... ...
... ...
DiscardPanel(panelid);
}
opglpanel[i].panelid = -1;
opglpanel[i].hProcOld = 0;
opglpanel[i].hSystem = -1;
opglpanel[i].active = 0;
}


/*****************************************************/
/* create panel */
/*****************************************************/
int OpenglControlCreate(int i)
{
int panel;
int error = -1;
char title[80];
int hsystem, hitem;
long hproc;
HMENU hmenu;

if ((i < 0) || (i >= OPGLMAXPANELS)) return (error);
OpenglControlDiscard(i);
panel = NewPanel (0, "Open GL Frame", OPGLFRAMEOFFSET, OPGLFRAMEOFFSET,
OPGLFRAMEHEIGHT + 2 * OPGLFRAMEBORDER,
OPGLFRAMEWIDTH + 2 * OPGLFRAMEBORDER);
if (panel < 0)
{
sprintf(opglmessage, "Cannot create new panel for Open GL frame");
MessagePopup("Error: Create OPGL frame", opglmessage);
return (error);
}
SetPanelAttribute (panel, ATTR_SCALE_CONTENTS_ON_RESIZE, 1);
sprintf(title, "%s Panel #%1d %s", WindowTitle, i, WindowHint);
SetPanelAttribute (panel, ATTR_TITLE, title);


GetPanelAttribute (panel, ATTR_SYSTEM_WINDOW_HANDLE, &hsystem);
hmenu = GetSystemMenu((HWND)hsystem, FALSE);
hitem = MENUOFFSET + MENUSEPARATOR;
InsertMenu(hmenu, -1, MF_BYPOSITION | MF_SEPARATOR, hitem, "\0");
hitem = MENUOFFSET + MENUSAVE;
InsertMenu(hmenu, -1, MF_BYPOSITION | MF_STRING | MF_ENABLED, hitem, "Save\0");
hitem = MENUOFFSET + MENUPRINT;
InsertMenu(hmenu, -1, MF_BYPOSITION | MF_STRING | MF_ENABLED, hitem, "Print\0");
hitem = MENUOFFSET + MENUCLIPBOARD;
InsertMenu(hmenu, -1, MF_BYPOSITION | MF_STRING | MF_ENABLED, hitem, "Clipboard\0");
hproc = SetWindowLongPtr((HWND)hsystem, GWLP_WNDPROC, (long)OpenglMenuInterim);

DisplayPanel(panel);
opglpanel[i].panelid = panel;
... ...
... ...
opglpanel[i].hSystem = (long)hsystem;
opglpanel[i].hProcOld = hproc;
opglpanel[i].active = 1;
return (panel);
}
0 Kudos
Message 8 of 14
(5,311 Views)
Hello,

Sorry it's taken me a while to reply. I haven't had a chance to check the forum in a while.

I think using 1000 as the item base is fine. As long as those numbers are unique within your application, I think it's all that matters.

You shouldn't call the original wnd proc if you don't have the proc pointer for it. It might crash, rather than just return an error. Granted, this situation shouldn't happen, since your proc should only be called for your windows, in which case you should be able to find the cached proc. But if you went to the trouble of checking for it, you might as well also not call the proc at all if you can't find it (by the way, it's a minor point, but in your "find" functions -- OpenglControlPanel and OpenglControlWind
ow -- you should exit out of your loop as soon as find the target. No need to continue searching).

When a panel is discarded you do need to clear the old proc, even if no message is likely to be sent for that window. But it looks as if you're already doing that in OpenglControlDiscard.

Luis
0 Kudos
Message 9 of 14
(5,311 Views)
Thanks Luis. I can use all information, especially on functions from Windows SDK.

You say that I should not return the original proc if its not the cached proc. I fully agree. But the function needs a return value of the type LRESULT APIENTRY. So with all my lack of wisdom, I entered 0 as a NULL pointer that hopefully gets ignored. Can you say what a safe return would be?

Secondly you mentioned the Discard function. While I have prepared this for clean up of all panel information, it lacks code for resetting the proc. I have a problem there. When I run this (test) programme in release mode, it runs fine. When I run it in Debug mode, I get errors on the OpenglControlDiscard. When the close icon has been used, the panel seems to disappear bef
ore I can clean up all functions. Typical I get errors when I want to reset callback functions to controls or panel because of invalid ID.
So without knowledge of the SDK, I did not try any proc-reset in the OpenglControlDiscard. I expect that the panel (and therefore hsystem) does not exist anymore. The use of SetWindowLongPtr with the old information seems risky. Please can you describe the code that I can use?

Jos
0 Kudos
Message 10 of 14
(5,311 Views)