From 717a57c2fabb054c8f00dc5dae70df1d03cfe532 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 2 Nov 1999 01:25:43 +0000 Subject: [PATCH] 1. wxMenu changes: wxMenuBase appears, several new functions for dynamic menu handling as well 2. new sample: menu 3. small corrections to wxFileHistory made possible by wxMenu changes 4. ugly fix for panel loaded from resources and TABbing 5. wxDataObject &c doc updates git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4288 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/bmpdatob.tex | 106 ++----- docs/latex/wx/classes.tex | 2 + docs/latex/wx/dataobj.tex | 181 ++++++++--- docs/latex/wx/fildatob.tex | 35 ++- docs/latex/wx/stattext.tex | 16 +- docs/latex/wx/tclipbrd.tex | 44 +-- docs/latex/wx/topics.tex | 5 +- docs/latex/wx/txtdatob.tex | 68 ++-- docs/latex/wx/wx.hpj | 6 +- include/wx/gtk/menu.h | 112 ++----- include/wx/gtk/menuitem.h | 5 + include/wx/gtk1/menu.h | 112 ++----- include/wx/gtk1/menuitem.h | 5 + include/wx/menu.h | 196 +++++++++++- include/wx/menuitem.h | 23 +- include/wx/msw/menu.h | 181 +++-------- include/wx/msw/menuitem.h | 8 +- samples/font/font.cpp | 2 + samples/menu/menu.cpp | 482 ++++++++++++++++++++++++++++ samples/toolbar/test.cpp | 67 +--- src/common/docview.cpp | 20 +- src/common/menucmn.cpp | 398 +++++++++++++++++++++++- src/common/resource.cpp | 2 +- src/gtk/menu.cpp | 622 +++++++++++++------------------------ src/gtk1/menu.cpp | 622 +++++++++++++------------------------ src/msw/dialog.cpp | 4 +- src/msw/frame.cpp | 5 +- src/msw/menu.cpp | 554 +++++++++++++-------------------- src/msw/menuitem.cpp | 78 +++-- 29 files changed, 2188 insertions(+), 1773 deletions(-) create mode 100644 samples/menu/menu.cpp diff --git a/docs/latex/wx/bmpdatob.tex b/docs/latex/wx/bmpdatob.tex index 634794c0e1..3e654b6ea6 100644 --- a/docs/latex/wx/bmpdatob.tex +++ b/docs/latex/wx/bmpdatob.tex @@ -1,16 +1,21 @@ \section{\class{wxBitmapDataObject}}\label{wxbitmapdataobject} -wxBitmapDataObject is a specialization of wxDataObject for bitmap data. It can be -used without change to paste data into the \helpref{wxClipboard}{wxclipboard} -or a \helpref{wxDropSource}{wxdropsource}. A user may wish to derive a new class -from this class for providing a bitmap on-demand in order to minimize memory consumption -when offering data in several formats, such as a bitmap and GIF. +wxBitmapDataObject is a specialization of wxDataObject for bitmap data. It can +be used without change to paste data into the +\helpref{wxClipboard}{wxclipboard} or a \helpref{wxDropSource}{wxdropsource}. A +user may wish to derive a new class from this class for providing a bitmap +on-demand in order to minimize memory consumption when offering data in several +formats, such as a bitmap and GIF. -In order to offer bitmap data on-demand \helpref{GetSize}{wxbitmapdataobjectgetsize} -and \helpref{WriteData}{wxbitmapdataobjectwritedata} will have to be overridden. +\wxheading{Virtual functions to override} + +This class may be used as is, but +\helpref{GetBitmap}{wxbitmapdataobjectgetbitmap} may be overridden to increase +efficiency. \wxheading{Derived from} +\helpref{wxDataObjectSimple}{wxdataobjectsimple} \helpref{wxDataObject}{wxdataobject} \wxheading{Include files} @@ -19,64 +24,17 @@ and \helpref{WriteData}{wxbitmapdataobjectwritedata} will have to be overridden. \wxheading{See also} +\helpref{Clipboard and drag and drop overview}{wxclipboardonfigoverview}, +\helpref{wxDataObject}{wxdataobject}, +\helpref{wxDataObjectSimple}{wxdataobjectsimple}, +\helpref{wxFileDataObject}{wxfiledataobject}, +\helpref{wxTextDataObject}{wxtextdataobject}, \helpref{wxDataObject}{wxdataobject} -\latexignore{\rtfignore{\wxheading{Members}}} - -\membersection{wxBitmapDataObject::wxBitmapDataObject}\label{wxbitmapdataobjectwxbitmapdataobject} - -\func{}{wxBitmapDataObject}{\void} - -Default constructor. Call \helpref{SetBitmap}{wxbitmapdataobjectsetbitmap} later -or override \helpref{WriteData}{wxbitmapdataobjectwritedata} and -\helpref{GetSize}{wxbitmapdataobjectgetsize} for providing data on-demand. - -\func{}{wxBitmapDataObject}{\param{const wxBitmap\& }{bitmap}} - -Constructor, passing a bitmap. - -\membersection{wxBitmapDataObject::GetSize}\label{wxbitmapdataobjectgetsize} - -\constfunc{virtual size\_t}{GetSize}{\void} - -Returns the data size. By default, returns the size of the bitmap data -set in the constructor or using \helpref{SetBitmap}{wxbitmapdataobjectsetbitmap}. -This can be overridden to provide size data on-demand. Note that you'd -have to call the inherited GetSize method as this is the only way -to get to know the transfer size of the bitmap in a platform dependent -way - a bitmap has different size under GTK and Windows. In practice, -this would look like this: - -\begin{verbatim} -size_t MyBitmapDataObject::GetSize() -{ - // Get bitmap from global container. This container - // should be able to "produce" data in all formats - // offered by the application but store it only in - // one format to reduce memory consumption. +\func{}{wxBitmapDataObject}{\param{const wxBitmap\& }{bitmap = wxNullBitmap}} - wxBitmap my_bitmap = my_global_container->GetBitmap(); - - // temporarily set bitmap - - SetBitmap( my_bitmap ); - - size_t ret = wxBitmapDataObject::GetSize(); - - // unset bitmap again - - SetBitmap( wxNullBitmap ); - - retrun ret; -} -\end{verbatim} - -TODO: Offer a nicer way to do this. Maybe by providing a platform -dependent function in this class like - -\begin{verbatim} -size_t GetBitmapSize( const wxBitmap &bitmap ) -\end{verbatim} +Constructor, optionally passing a bitmap (otherwise use +\helpref{SetBitmap}{wxbitmapdataobjectsetbitmap} later) \membersection{wxBitmapDataObject::GetBitmap}\label{wxbitmapdataobjectgettext} @@ -91,26 +49,8 @@ the \helpref{wxClipboard}{wxclipboard}. \func{virtual void}{SetBitmap}{\param{const wxBitmap\& }{bitmap}} -Sets the bitmap associated with the data object. This method is called -internally when retrieving data from the \helpref{wxClipboard}{wxclipboard} -and may be used to paste data to the clipboard directly (instead of -on-demand). - -\membersection{wxBitmapDataObject::WriteData}\label{wxbitmapdataobjectwritedata} - -\constfunc{virtual void}{WriteData}{\param{void}{*dest} } - -Write the data owned by this class to {\it dest}. By default, this -calls \helpref{WriteBitmap}{wxbitmapdataobjectwritebitmap} with the bitmap -set in the constructor or using \helpref{SetBitmap}{wxbitmapdataobjectsetbitmap}. -This can be overridden to provide bitmap data on-demand; in this case -\helpref{WriteBitmap}{wxbitmapdataobjectwritebitmap} must be called from -within th overriding WriteData() method. - -\membersection{wxBitmapDataObject::WriteBitmap}\label{wxbitmapdataobjectwritebitmap} - -\constfunc{void}{WriteBitmap}{\param{const wxBitmap\& }{bitmap}\param{void}{*dest} } +Sets the bitmap associated with the data object. This method is called when the +data object receives data. Usually there will be no reason to override this +function. -Writes the the bitmap {\it bitmap} to {\it dest}. This method must be called -from \helpref{WriteData}{wxbitmapdataobjectwritedata}. diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index bcc41dae7f..ac4974f463 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -40,6 +40,8 @@ \input cursor.tex \input database.tex \input dataobj.tex +\input dobjcomp.tex +\input dobjsmpl.tex \input datstrm.tex \input date.tex \input dc.tex diff --git a/docs/latex/wx/dataobj.tex b/docs/latex/wx/dataobj.tex index 024b7a2de8..e0df5ff8a7 100644 --- a/docs/latex/wx/dataobj.tex +++ b/docs/latex/wx/dataobj.tex @@ -1,38 +1,118 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: dataobj.tex +%% Purpose: wxDataObject documentation +%% Author: Vadim Zeitlin +%% Modified by: +%% Created: 18.10.99 +%% RCS-ID: $Id$ +%% Copyright: (c) wxWindows team +%% Licence: wxWindows licence +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \section{\class{wxDataObject}}\label{wxdataobject} A wxDataObject represents data that can be copied to or from the clipboard, or -dragged and dropped. There are two classes directly derived from wxDataObject: -wxDataObjectSimple and wxDataObjectComposite. As you will guess, wxDataObjectSimple -holds data for a single format (such as HTML or text) and wxDataObjectComposite -can hold any number of wxDataObjectSimple classes. Please note that this is an -easy way to use Drag'n'Drop and the clipboard with multiple formats, but not the -most efficient one as each wxDataObjectSimple would contain the whole data in its -respective formars. Now imagine that you want to paste 200 pages of text in your -proprietary format, as well as Word, RTF, HTML, Unicode and plain text to the -clipboard and even today's computers are in trouble. For this case, you will have -to derive from wxDataObject directly and make it enumerate its formats and provide -the data in the requested format on demand. - -Note that neither the GTK data transfer mechanisms for the clipboard and Drag'n'Drop -nor the OLE data transfer copies any data until another application actually -requests the data. This is in contrast to the "feel" offered to the user of a -program who would normally think that the data resides in the clipboard after -having pressed "Copy" - in reality it is only declared to be available. - -There are several predefined data object classes derived from wxDataObjectSimple: -\helpref{wxFileDataObject}{wxfiledataobject}, \helpref{wxTextDataObject}{wxtextdataobject} -and \helpref{wxBitmapDataObject}{wxbitmapdataobject} which can be used without change. - -You may also derive your own data object classes from \helpref{wxCustomDataObject}{wxprivatedataobject} -for user-defined types. The format of user-defined data is given as mime-type string literal, -such as "application/word" or "image/png". These strings are used as they are under Unix (so -far only GTK) to identify a format and are translated into their Windows equivalent under -Win32 (using the OLE IDataObject for data exchange to and from the clipboard and for Drag'n'Drop). -Note that the format string translation under Windows is not yet finnished. +dragged and dropped. The important thing about wxDataObject is that this is a +"smart" piece of data unlike usual "dumb" data containers such as memory +buffers or files. Being "smart" here means that the data object itself should +know what data formats it supports and how to render itself in each of +supported formats. + +A supported format, incidentally, is exactly the format in which the data can +be requested from a data object or from which the data object may be set. In +the general case, an object may support different formats on "input" and +"output", i.e. it may be able to render itself in a given format but not be +created from data on this format or vice versa. wxDataObject defines an +enumeration type + +\begin{verbatim} +enum Direction +{ + Get = 0x01, // format is supported by GetDataHere() + Set = 0x02 // format is supported by SetData() +}; +\end{verbatim} + +which allows to distinguish between them. See +\helpref{wxDataFormat}{wxdataformat} documentation for more about formats. + +Not surprizingly, being "smart" comes at a price of added complexity. This is +reasonable for the situations when you really need to support multiple formats, +but may be annoying if you only want to do something simple like cut and paste +text. + +To provide a solution for both cases, wxWindows has two predefined classes +which derive from wxDataObject: +\helpref{wxDataObjectSimple}{wxdataobjectsimple} and +\helpref{wxDataObjectComposite}{wxdataobjectcomposite}. +\helpref{wxDataObjectSimple}{wxdataobjectsimple} is +the simplest wxDataObject possible and only holds data in a single format (such +as HTML or text) and \helpref{wxDataObjectComposite}{wxdataobjectcomposite} is +the simplest way to implement wxDataObject which does support multiple formats +because it achievs this by simply holding several wxDataObjectSimple objects. + +So, you have several solutions when you need a wxDataObject class (and you need +one as soon as you want to transfer data via the clipboard or drag and drop): + +\begin{twocollist} +\twocolitem{0. Use one of built-in classes}{You may use wxTextDataObject, +wxBitmapDataObject or wxFileDataObject in the simplest cases when you only need +to support one format and your data is either text, bitmap or list of files} +\twocolitem{1. Derive your class from wxDataObjectSimple}{This is the simplest +solution for custom data - you will only support one format and so probably +won't be able to communicate with other programs, but data transfer will work +in your program (or between different copies of it).} +\twocolitem{2. Use wxDataObjectComposite}{This is a quite simple, but rather +powerful solution which allows you to support any number of formats (either +standard or custom if you combine it with the previous solution).} +\twocolitem{3. Derive from wxDataObject directly}{This is the solution of +maximal flexibility and efficiency, but it also is the most difficult to +implement.} +\end{twocollist} + +Please note that the easiest way to use Drag'n'Drop and the clipboard with +multiple formats is by using wxDataObjectComposite, but it is not the most +efficient one as each wxDataObjectSimple would contain the whole data in its +respective formars. Now imagine that you want to paste 200 pages of text in +your proprietary format, as well as Word, RTF, HTML, Unicode and plain text to +the clipboard and even today's computers are in trouble. For this case, you +will have to derive from wxDataObject directly and make it enumerate its +formats and provide the data in the requested format on demand. + +Note that neither the GTK data transfer mechanisms for the clipboard and +Drag'n'Drop nor the OLE data transfer copies any data until another application +actually requests the data. This is in contrast to the "feel" offered to the +user of a program who would normally think that the data resides in the +clipboard after having pressed "Copy" - in reality it is only declared to be +available. + +There are several predefined data object classes derived from +wxDataObjectSimple: \helpref{wxFileDataObject}{wxfiledataobject}, +\helpref{wxTextDataObject}{wxtextdataobject} and +\helpref{wxBitmapDataObject}{wxbitmapdataobject} which can be used without +change. + +You may also derive your own data object classes from +\helpref{wxCustomDataObject}{wxprivatedataobject} for user-defined types. The +format of user-defined data is given as mime-type string literal, such as +"application/word" or "image/png". These strings are used as they are under +Unix (so far only GTK) to identify a format and are translated into their +Windows equivalent under Win32 (using the OLE IDataObject for data exchange to +and from the clipboard and for Drag'n'Drop). Note that the format string +translation under Windows is not yet finnished. + +\wxheading{Virtual functions to override} + +Each class derived directly from wxDataObject must override and implement all +of its functions which are pure virtual in the base class. + +The data objects which only render their data or only set it (i.e. work in +only one direction), should return 0 from +\helpref{GetFormatCount}{wxdataobjectgetformatcount}. \wxheading{Derived from} -\helpref{wxObject}{wxobject} +None \wxheading{Include files} @@ -40,13 +120,16 @@ Note that the format string translation under Windows is not yet finnished. \wxheading{See also} +\helpref{Clipboard and drag and drop overview}{wxclipboardonfigoverview}, +\helpref{DnD sample}{samplednd}, \helpref{wxFileDataObject}{wxfiledataobject}, \helpref{wxTextDataObject}{wxtextdataobject}, \helpref{wxBitmapDataObject}{wxbitmapdataobject}, \helpref{wxPrivateDataObject}{wxprivatedataobject}, -\helpref{Drag and drop overview}{wxdndoverview}, \helpref{wxDropTarget}{wxdroptarget}, +\helpref{wxDropTarget}{wxdroptarget}, \helpref{wxDropSource}{wxdropsource}, -\helpref{wxTextDropTarget}{wxtextdroptarget}, \helpref{wxFileDropTarget}{wxfiledroptarget} +\helpref{wxTextDropTarget}{wxtextdroptarget}, +\helpref{wxFileDropTarget}{wxfiledroptarget} \latexignore{\rtfignore{\wxheading{Members}}} @@ -62,17 +145,21 @@ Constructor. Destructor. -\membersection{wxDataObject::GetFormatCount}\label{wxdataobjectgetformatcount} +\membersection{wxDataObject::GetAllFormats}\label{wxdataobjectgetallformats} -\constfunc{virtual size_t}{GetFormatCount}{\void} +\constfunc{virtual void}{GetAllFormats}{ + \param{wxDataFormat *}{formats}, + \param{Direction}{ dir = Get}} -Return the number of available formats. +Copy all supported formats in the given direction to the array pointed to by +{\it formats} (there is enough place for GetFormatCount(dir) formats in it). \membersection{wxDataObject::GetDataHere}\label{wxdataobjectgetdatahere} -\constfunc{virtual bool}{GetDataHere}{\param{const wxDataFormat\&}{ format}, \param{void}{*buf} } +\constfunc{virtual bool}{GetDataHere}{\param{const wxDataFormat\&}{ format}, \param{void }{*buf} } -The method will write the data of the format {\it format} in the buffer {\it buf}. +The method will write the data of the format {\it format} in the buffer {\it +buf} and return TRUE on success, FALSE on failure. \membersection{wxDataObject::GetDataSize}\label{wxdataobjectgetdatasize} @@ -80,16 +167,30 @@ The method will write the data of the format {\it format} in the buffer {\it buf Returns the data size of the given format {\it format}. +\membersection{wxDataObject::GetFormatCount}\label{wxdataobjectgetformatcount} + +\constfunc{virtual size\_t}{GetFormatCount}{\param{Direction}{ dir = Get}} + +Return the number of available formats for rendering or setting the data. + \membersection{wxDataObject::GetPreferredFormat}\label{wxdataobjectgetpreferredformat} -\constfunc{virtual wxDataFormat}{GetPreferredFormat}{\void} +\constfunc{virtual wxDataFormat}{GetPreferredFormat}{\param{Direction}{ dir = Get}} -Returns the preferred format. Usually the first format in the list of available formats. +Returns the preferred format for either rendering the data (if {\it dir} is +{\tt Get}, its default value) or for setting it. Usually this will be the +native format of the wxDataObject. \membersection{wxDataObject::SetData}\label{wxdataobjectsetdata} -\func{virtual bool}{SetData}{\param{const wxDataFormat\&}{ format}, \param{size_t}{ len}, \param{const void}{*buf} } +\func{virtual bool}{SetData}{ + \param{const wxDataFormat\&}{ format}, + \param{size\_t}{ len}, + \param{const void }{*buf} } + +Set the data in the format {\it format} of the length {\it len} provided in the +buffer {\it buf}. -Set the data of the format {\it format} and the size {\it len} provided in the buffer {\it buf}. +Returns TRUE on sucess, FALSE on failure. diff --git a/docs/latex/wx/fildatob.tex b/docs/latex/wx/fildatob.tex index 149bbb2c94..c6bd03af78 100644 --- a/docs/latex/wx/fildatob.tex +++ b/docs/latex/wx/fildatob.tex @@ -1,9 +1,18 @@ \section{\class{wxFileDataObject}}\label{wxfiledataobject} -wxFileDataObject is a specialization of wxDataObject for file names. +wxFileDataObject is a specialization of \helpref{wxDataObject}{wxdataobject} +for file names. Unlike other predefined wxDataObject derivations, it only works +in one direction - the one of setting the data, i.e. the program can only +receive files dropped on it using it and there is no way (currently) to +initiate a drag and drop file operation. + +\wxheading{Virtual functions to override} + +None. \wxheading{Derived from} +\helpref{wxDataObjectSimple}{wxdataobjectsimple} \helpref{wxDataObject}{wxdataobject} \wxheading{Include files} @@ -12,31 +21,23 @@ wxFileDataObject is a specialization of wxDataObject for file names. \wxheading{See also} +\helpref{wxDataObject}{wxdataobject}, +\helpref{wxDataObjectSimple}{wxdataobjectsimple}, +\helpref{wxTextDataObject}{wxtextdataobject}, +\helpref{wxBitmapDataObject}{wxbitmapdataobject} \helpref{wxDataObject}{wxdataobject} \latexignore{\rtfignore{\wxheading{Members}}} -\membersection{wxFileDataObject::wxFileDataObject}\label{wxfiledataobjectwxfiledataobject} +\membersection{wxFileDataObject}\label{wxfiledataobjectwxfiledataobject} \func{}{wxFileDataObject}{\void} Constructor. -\membersection{wxFileDataObject::GetFormat}\label{wxfiledataobjectgetformat} - -\constfunc{virtual wxDataFormat}{GetFormat}{\void} - -Returns wxDF\_FILENAME. - -\membersection{wxFileDataObject::AddFile}\label{wxfiledataobjectaddfile} - -\func{virtual void}{AddFile}{\param{const wxString\& }{file}} - -Adds a filename to the data object. - -\membersection{wxFileDataObject::GetFiles}\label{wxfiledataobjectgetfiles} +\membersection{wxFileDataObject::GetFilenames}\label{wxfiledataobjectgetfilenames} -\constfunc{virtual wxString}{GetFiles}{\void} +\constfunc{const wxArrayString\& }{GetFilenames}{\void} -Returns files as a zero-separated list. +Returns the \helpref{array}{wxarraystring} of file names. diff --git a/docs/latex/wx/stattext.tex b/docs/latex/wx/stattext.tex index 81d1505b58..aea19213d2 100644 --- a/docs/latex/wx/stattext.tex +++ b/docs/latex/wx/stattext.tex @@ -15,7 +15,18 @@ A static text control displays one or more lines of read-only text. \wxheading{Window styles} -There are no special styles for this control. +\twocolwidtha{5cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{\windowstyle{wxALIGN\_LEFT}}{Align the text to the left} +\twocolitem{\windowstyle{wxALIGN\_RIGHT}}{Align the text to the right} +\twocolitem{\windowstyle{wxALIGN\_CENTRE}}{Center the text (horisontally)} +\twocolitem{\windowstyle{wxST\_NO\_AUTORESIZE}}{By default, the control will +adjust its size to exactly fit to the size of the text when +\helpref{SetLabel}{wxstatictextsetlabel} is called. If this style flag is +given, the control will not change its size (this style is especially useful +with controls which also have wxALIGN\_RIGHT or CENTER style because otherwise +they won't make sense any longer after a call to SetLabel)} +\end{twocollist} See also \helpref{window styles overview}{windowstyles}. @@ -75,7 +86,8 @@ Returns the contents of the control. \func{virtual void}{SetLabel}{\param{const wxString\& }{ label}} -Sets the static text label. +Sets the static text label and updates the controls size to exactly fit the +label unless the control has wxST\_NO\_AUTORESIZE flag. \wxheading{Parameters} diff --git a/docs/latex/wx/tclipbrd.tex b/docs/latex/wx/tclipbrd.tex index b2c3e57c3f..e22440d9c4 100644 --- a/docs/latex/wx/tclipbrd.tex +++ b/docs/latex/wx/tclipbrd.tex @@ -1,4 +1,4 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Name: tclipbrd.tex %% Purpose: Data transfer (clipboard and drag and drop) overview %% Author: Vadim Zeitlin @@ -7,7 +7,7 @@ %% RCS-ID: $Id$ %% Copyright: (c) Vadim Zeitlin %% Licence: wxWindows licence -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Clipboard and drag and drop overview}\label{wxclipboardonfigoverview} @@ -17,23 +17,24 @@ Classes: \helpref{wxDataObject}{wxdataobject}, \helpref{wxDropSource}{wxdropsource}, \helpref{wxDropTarget}{wxdroptarget} +See also: \helpref{DnD sample}{samplednd} + This overview discusses data transfer through clipboard or drag and drop. In wxWindows, these two ways to transfer data (either between different applications or inside one and the same) are very similar which allows to -implement both of them using almost the same code - or in other +implement both of them using almost the same code - or, in other words, if you implement drag and drop support for your application, you get clipboard support for free and vice versa. In the heart of both clipboard and drag and drop operations lies the -\helpref{wxDataObject}{wxdataobject} class. The objects of this class (or, to be -precise, classes derived from it) represent the data which is being carried by -the mouse during drag and drop operation or copied to or pasted from the -clipboard. wxDataObject is a "smart" piece of data -because it knows which formats it supports (see -GetFormatCount and GetAllFormats) and knows how to render -itself in any of them (see GetDataHere). -It can also receive its value from the outside in a format it supports if it -implements the SetData method. +\helpref{wxDataObject}{wxdataobject} class. The objects of this class (or, to +be precise, classes derived from it) represent the data which is being carried +by the mouse during drag and drop operation or copied to or pasted from the +clipboard. wxDataObject is a "smart" piece of data because it knows which +formats it supports (see GetFormatCount and GetAllFormats) and knows how to +render itself in any of them (see GetDataHere). It can also receive its value +from the outside in a format it supports if it implements the SetData method. +Please see the documentation of this class for more details. Both clipboard and drag and drop operations have two sides: the source and target, the data provider and the data receiver. These which may be in the same @@ -44,10 +45,10 @@ should do. \subsection{The data provider (source) duties}{wxdataobjectsource} The data provider is responsible for creating a -\helpref{wxDataObject}{wxdataobjectwxdataobject} containing the data to be -transfered. Then it should either pass it to the clipboard using -\helpref{AddData}{wxclipboardadddata} or \helpref{SetData}{wxclipboardsetdata} -functions or to \helpref{wxDropSource}{wxdropsource} and call +\helpref{wxDataObject}{wxdataobject} containing the data to be +transfered. Then it should either pass it to the clipboard using +\helpref{SetData}{wxclipboardsetdata} function or to +\helpref{wxDropSource}{wxdropsource} and call \helpref{DoDragDrop}{wxdropsourcedodragdrop} function. The only (but important) difference is that the object for the clipboard @@ -74,9 +75,10 @@ data formats you need and pass it as argument to no data in (any of) the supported format(s) is available. If it returns {\tt TRUE}, the data has been successfully transfered to wxDataObject. -{\bf TODO} document drag and drop side when the API is finalised +For drag and drop case, the \helpref{wxDropTarget::OnData}{wxdroptargetondata} +virtual function will be called when a data object is dropped, from which the +data itself may be requested by calling +\helpref{wxDropTarget::GetData}{wxdroptargetwxdroptarget} method which fills +the data object. + -% !!!!!!!!!!!!!!!!!!!!!!!!!!!!! -% Vadim, please remember the new line at the end of each file. Please -% also remember to compile the .hlp file to check for bad references etc., -% before checking in. I have removed references that were unresolved. - JACS diff --git a/docs/latex/wx/topics.tex b/docs/latex/wx/topics.tex index 6d3dbcf106..7daf692886 100644 --- a/docs/latex/wx/topics.tex +++ b/docs/latex/wx/topics.tex @@ -4,6 +4,7 @@ This chapter contains a selection of topic overviews. +\input tsamples.tex \input tapp.tex \input tstring.tex \input tcontain.tex @@ -38,7 +39,6 @@ This chapter contains a selection of topic overviews. \input tvalidat.tex \input texpr.tex \input tgrid.tex -\input tdnd.tex \input tthreads.tex \input tfile.tex \input ti18n.tex @@ -46,3 +46,6 @@ This chapter contains a selection of topic overviews. \input tusage.tex \input ttips.tex \input fs.tex + +% \input tdnd.tex + diff --git a/docs/latex/wx/txtdatob.tex b/docs/latex/wx/txtdatob.tex index 63cfc3cff3..13cce6cb88 100644 --- a/docs/latex/wx/txtdatob.tex +++ b/docs/latex/wx/txtdatob.tex @@ -1,16 +1,28 @@ \section{\class{wxTextDataObject}}\label{wxtextdataobject} wxTextDataObject is a specialization of wxDataObject for text data. It can be -used without change to paste data into the \helpref{wxClipboard}{wxclipboard} -or a \helpref{wxDropSource}{wxdropsource}. A user may wish to derive a new class -from this class for providing text on-demand in order to minimize memory consumption -when offering data in several formats, such as plain text and RTF. +used without change to paste data into the \helpref{wxClipboard}{wxclipboard} +or a \helpref{wxDropSource}{wxdropsource}. A user may wish to derive a new +class from this class for providing text on-demand in order to minimize memory +consumption when offering data in several formats, such as plain text and RTF +because by default the text is stored in a string in this class, but it might +as well be generated when requested. For this, +\helpref{GetTextLength}{wxtextdataobjectgettextlength} and +\helpref{GetText}{wxtextdataobjectgettext} will have to be overridden. -In order to offer text data on-demand \helpref{GetSize}{wxtextdataobjectgetsize} -and \helpref{WriteData}{wxtextdataobjectwritedata} will have to be overridden. +Note that if you already have the text inside a string, you will not achieve +any efficiency gain by overriding these functions because copying wxStrings is +already a very efficient operation (data is not actualyl copied because +wxStrings are reference counted). + +\wxheading{Virtual functions to override} + +This class may be used as is, but all of data transfer functions may be +overridden to increase efficiency. \wxheading{Derived from} +\helpref{wxDataObjectSimple}{wxdataobjectsimple} \helpref{wxDataObject}{wxdataobject} \wxheading{Include files} @@ -19,25 +31,24 @@ and \helpref{WriteData}{wxtextdataobjectwritedata} will have to be overridden. \wxheading{See also} -\helpref{wxDataObject}{wxdataobject} +\helpref{Clipboard and drag and drop overview}{wxclipboardonfigoverview}, +\helpref{wxDataObject}{wxdataobject}, +\helpref{wxDataObjectSimple}{wxdataobjectsimple}, +\helpref{wxFileDataObject}{wxfiledataobject}, +\helpref{wxBitmapDataObject}{wxbitmapdataobject} \latexignore{\rtfignore{\wxheading{Members}}} \membersection{wxTextDataObject::wxTextDataObject}\label{wxtextdataobjectwxtextdataobject} -\func{}{wxTextDataObject}{\void} +\func{}{wxTextDataObject}{\param{const wxString\& }{text = wxEmptyString}} -Default constructor. Call \helpref{SetText}{wxtextdataobjectsettext} later -or override \helpref{WriteData}{wxtextdataobjectwritedata} and -\helpref{GetSize}{wxtextdataobjectgetsize} for providing data on-demand. +Constructor, may be used to initialise the text (otherwise +\helpref{SetText}{wxtextdataobjectsettext} should be used later) -\func{}{wxTextDataObject}{\param{const wxString\& }{strText}} +\membersection{wxTextDataObject::GetTextLength}\label{wxtextdataobjectgettextlength} -Constructor, passing text. - -\membersection{wxTextDataObject::GetSize}\label{wxtextdataobjectgetsize} - -\constfunc{virtual size\_t}{GetSize}{\void} +\constfunc{virtual size\_t}{GetTextLength}{\void} Returns the data size. By default, returns the size of the text data set in the constructor or using \helpref{SetText}{wxtextdataobjectsettext}. @@ -59,25 +70,8 @@ the \helpref{wxClipboard}{wxclipboard}. \func{virtual void}{SetText}{\param{const wxString\& }{strText}} Sets the text associated with the data object. This method is called -internally when retrieving data from the \helpref{wxClipboard}{wxclipboard} -and may be used to paste data to the clipboard directly (instead of -on-demand). - -\membersection{wxTextDataObject::WriteData}\label{wxtextdataobjectwritedata} - -\constfunc{virtual void}{WriteData}{\param{void}{*dest} } - -Write the data owned by this class to {\it dest}. By default, this -calls \helpref{WriteString}{wxtextdataobjectwritestring} with the string -set in the constructor or using \helpref{SetText}{wxtextdataobjectsettext}. -This can be overridden to provide text data on-demand; in this case -\helpref{WriteString}{wxtextdataobjectwritestring} must be called from -within the overriding WriteData() method. - -\membersection{wxTextDataObject::WriteString}\label{wxtextdataobjectwritestring} - -\constfunc{void}{WriteString}{\param{const wxString\& }{str}\param{void}{*dest} } +when the data object receives the data and, by default, copies the text into +the member variable. If you want to process the text on the fly you may wish to +override this function. -Writes the the string {\it str} to {\it dest}. This method must be called -from \helpref{WriteData}{wxtextdataobjectwritedata}. diff --git a/docs/latex/wx/wx.hpj b/docs/latex/wx/wx.hpj index 43d8c37176..b8f8205dae 100644 --- a/docs/latex/wx/wx.hpj +++ b/docs/latex/wx/wx.hpj @@ -1,14 +1,14 @@ [OPTIONS] -BMROOT=d:\wx2\wxWindows\docs\latex\wx ; Assume that bitmaps are where the source is +BMROOT=L:\wxWindows\docs\latex\wx ; Assume that bitmaps are where the source is TITLE=wxWindows Manual CONTENTS=Contents COMPRESS=HIGH [FILES] -wx.rtf +Wx.rtf [CONFIG] -CreateButton("Up", "&Up", "JumpId(`wx.hlp', `Contents')") +CreateButton("Up", "&Up", "JumpId(`Wx.hlp', `Contents')") BrowseButtons() [MAP] diff --git a/include/wx/gtk/menu.h b/include/wx/gtk/menu.h index b51e7e5230..07f1575111 100644 --- a/include/wx/gtk/menu.h +++ b/include/wx/gtk/menu.h @@ -51,10 +51,6 @@ public: long m_style; wxWindow *m_invokingWindow; -#if 0 // seems to be unused (VZ) - wxMenuList& GetMenus() { return m_menus; } -#endif // 0 - private: DECLARE_DYNAMIC_CLASS(wxMenuBar) }; @@ -63,92 +59,34 @@ private: // wxMenu //----------------------------------------------------------------------------- -class wxMenu : public wxEvtHandler +class wxMenu : public wxMenuBase { - DECLARE_DYNAMIC_CLASS(wxMenu) - public: - wxMenu( const wxString& title, const wxFunction func) - { - Init(title, 0, func); - } - wxMenu( long style ) - { - Init( wxEmptyString, style ); - } - wxMenu( const wxString& title = wxEmptyString, long style = 0 ) - { - Init(title, style); - } - - ~wxMenu(); - - // title - void SetTitle(const wxString& label); - const wxString GetTitle() const; - - // menu creation - void AppendSeparator(); - void Append(int id, const wxString &item, - const wxString &helpStr = "", bool checkable = FALSE); - void Append(int id, const wxString &item, - wxMenu *subMenu, const wxString &helpStr = "" ); - void Append(wxMenuItem *pItem); - void Break() { } - - // delete item. don't delete the wxMenu if it's a submenu - void Delete( int id ); - - // find item by name/id - int FindItem( const wxString itemString ) const; - wxMenuItem *FindItem( int id ) const; + // ctors & dtor + wxMenu(const wxString& title, long style = 0) + : wxMenuBase(title, style) { Init(); } - // get/set item's state - void Enable( int id, bool enable ); - bool IsEnabled( int id ) const; - void Check( int id, bool check ); - bool IsChecked( int id ) const; + wxMenu(long style = 0) : wxMenuBase(style) { Init(); } - void SetLabel( int id, const wxString &label ); - wxString GetLabel( int id ) const; + virtual ~wxMenu(); - // helpstring - virtual void SetHelpString(int id, const wxString& helpString); - virtual wxString GetHelpString(int id) const ; + // implement base class virtuals + virtual bool DoAppend(wxMenuItem *item); + virtual bool DoInsert(size_t pos, wxMenuItem *item); + virtual wxMenuItem *DoRemove(wxMenuItem *item); - // accessors - wxList& GetItems() { return m_items; } - - void SetEventHandler(wxEvtHandler *handler) { m_eventHandler = handler; } - wxEvtHandler *GetEventHandler() { return m_eventHandler; } - - void SetClientData( void* clientData ) { m_clientData = clientData; } - void* GetClientData() const { return m_clientData; } - - // Updates the UI for a menu and all submenus recursively. - // source is the object that has the update event handlers - // defined for it. If NULL, the menu or associated window - // will be used. - void UpdateUI(wxEvtHandler* source = (wxEvtHandler*) NULL); - - wxMenuItem *FindItemForId( int id ) const { return FindItem( id ); } - - wxFunction GetCallback() const { return m_callback; } - void Callback(const wxFunction func) { m_callback = func; } - wxFunction m_callback; + // TODO: virtual void SetTitle(const wxString& title); #ifdef WXWIN_COMPATIBILITY - - // compatibility: these functions are deprecated - bool Enabled(int id) const { return IsEnabled(id); } - bool Checked(int id) const { return IsChecked(id); } - + wxMenu(const wxString& title, const wxFunction func) + : wxMenuBase(title) + { + Callback(func); + } #endif // WXWIN_COMPATIBILITY // implementation int FindMenuIdByMenuItem( GtkWidget *menuItem ) const; - void SetInvokingWindow( wxWindow *win ); - wxWindow *GetInvokingWindow(); // implementation GTK only GtkWidget *m_menu; // GtkMenu @@ -156,21 +94,11 @@ public: GtkAccelGroup *m_accel; GtkItemFactory *m_factory; - // used by wxMenuBar - long GetStyle(void) const { return m_style; } - private: - // common code for both constructors: - void Init( const wxString& title, - long style, - const wxFunction func = (wxFunction) NULL ); - - wxString m_title; - wxList m_items; - wxWindow *m_invokingWindow; - wxEvtHandler *m_eventHandler; - void *m_clientData; - long m_style; + // common code for all constructors: + void Init(); + + DECLARE_DYNAMIC_CLASS(wxMenu) }; #endif // __GTKMENUH__ diff --git a/include/wx/gtk/menuitem.h b/include/wx/gtk/menuitem.h index 58b65fc25d..ba846a4b9c 100644 --- a/include/wx/gtk/menuitem.h +++ b/include/wx/gtk/menuitem.h @@ -31,10 +31,15 @@ public: // implement base class virtuals virtual void SetText( const wxString& str ); + virtual wxString GetLabel() const; virtual void Enable( bool enable = TRUE ); virtual void Check( bool check = TRUE ); virtual bool IsChecked() const; +#if wxUSE_ACCEL + virtual wxAcceleratorEntry *GetAccel() const; +#endif // wxUSE_ACCEL + // implementation void SetMenuItem(GtkWidget *menuItem) { m_menuItem = menuItem; } GtkWidget *GetMenuItem() const { return m_menuItem; } diff --git a/include/wx/gtk1/menu.h b/include/wx/gtk1/menu.h index b51e7e5230..07f1575111 100644 --- a/include/wx/gtk1/menu.h +++ b/include/wx/gtk1/menu.h @@ -51,10 +51,6 @@ public: long m_style; wxWindow *m_invokingWindow; -#if 0 // seems to be unused (VZ) - wxMenuList& GetMenus() { return m_menus; } -#endif // 0 - private: DECLARE_DYNAMIC_CLASS(wxMenuBar) }; @@ -63,92 +59,34 @@ private: // wxMenu //----------------------------------------------------------------------------- -class wxMenu : public wxEvtHandler +class wxMenu : public wxMenuBase { - DECLARE_DYNAMIC_CLASS(wxMenu) - public: - wxMenu( const wxString& title, const wxFunction func) - { - Init(title, 0, func); - } - wxMenu( long style ) - { - Init( wxEmptyString, style ); - } - wxMenu( const wxString& title = wxEmptyString, long style = 0 ) - { - Init(title, style); - } - - ~wxMenu(); - - // title - void SetTitle(const wxString& label); - const wxString GetTitle() const; - - // menu creation - void AppendSeparator(); - void Append(int id, const wxString &item, - const wxString &helpStr = "", bool checkable = FALSE); - void Append(int id, const wxString &item, - wxMenu *subMenu, const wxString &helpStr = "" ); - void Append(wxMenuItem *pItem); - void Break() { } - - // delete item. don't delete the wxMenu if it's a submenu - void Delete( int id ); - - // find item by name/id - int FindItem( const wxString itemString ) const; - wxMenuItem *FindItem( int id ) const; + // ctors & dtor + wxMenu(const wxString& title, long style = 0) + : wxMenuBase(title, style) { Init(); } - // get/set item's state - void Enable( int id, bool enable ); - bool IsEnabled( int id ) const; - void Check( int id, bool check ); - bool IsChecked( int id ) const; + wxMenu(long style = 0) : wxMenuBase(style) { Init(); } - void SetLabel( int id, const wxString &label ); - wxString GetLabel( int id ) const; + virtual ~wxMenu(); - // helpstring - virtual void SetHelpString(int id, const wxString& helpString); - virtual wxString GetHelpString(int id) const ; + // implement base class virtuals + virtual bool DoAppend(wxMenuItem *item); + virtual bool DoInsert(size_t pos, wxMenuItem *item); + virtual wxMenuItem *DoRemove(wxMenuItem *item); - // accessors - wxList& GetItems() { return m_items; } - - void SetEventHandler(wxEvtHandler *handler) { m_eventHandler = handler; } - wxEvtHandler *GetEventHandler() { return m_eventHandler; } - - void SetClientData( void* clientData ) { m_clientData = clientData; } - void* GetClientData() const { return m_clientData; } - - // Updates the UI for a menu and all submenus recursively. - // source is the object that has the update event handlers - // defined for it. If NULL, the menu or associated window - // will be used. - void UpdateUI(wxEvtHandler* source = (wxEvtHandler*) NULL); - - wxMenuItem *FindItemForId( int id ) const { return FindItem( id ); } - - wxFunction GetCallback() const { return m_callback; } - void Callback(const wxFunction func) { m_callback = func; } - wxFunction m_callback; + // TODO: virtual void SetTitle(const wxString& title); #ifdef WXWIN_COMPATIBILITY - - // compatibility: these functions are deprecated - bool Enabled(int id) const { return IsEnabled(id); } - bool Checked(int id) const { return IsChecked(id); } - + wxMenu(const wxString& title, const wxFunction func) + : wxMenuBase(title) + { + Callback(func); + } #endif // WXWIN_COMPATIBILITY // implementation int FindMenuIdByMenuItem( GtkWidget *menuItem ) const; - void SetInvokingWindow( wxWindow *win ); - wxWindow *GetInvokingWindow(); // implementation GTK only GtkWidget *m_menu; // GtkMenu @@ -156,21 +94,11 @@ public: GtkAccelGroup *m_accel; GtkItemFactory *m_factory; - // used by wxMenuBar - long GetStyle(void) const { return m_style; } - private: - // common code for both constructors: - void Init( const wxString& title, - long style, - const wxFunction func = (wxFunction) NULL ); - - wxString m_title; - wxList m_items; - wxWindow *m_invokingWindow; - wxEvtHandler *m_eventHandler; - void *m_clientData; - long m_style; + // common code for all constructors: + void Init(); + + DECLARE_DYNAMIC_CLASS(wxMenu) }; #endif // __GTKMENUH__ diff --git a/include/wx/gtk1/menuitem.h b/include/wx/gtk1/menuitem.h index 58b65fc25d..ba846a4b9c 100644 --- a/include/wx/gtk1/menuitem.h +++ b/include/wx/gtk1/menuitem.h @@ -31,10 +31,15 @@ public: // implement base class virtuals virtual void SetText( const wxString& str ); + virtual wxString GetLabel() const; virtual void Enable( bool enable = TRUE ); virtual void Check( bool check = TRUE ); virtual bool IsChecked() const; +#if wxUSE_ACCEL + virtual wxAcceleratorEntry *GetAccel() const; +#endif // wxUSE_ACCEL + // implementation void SetMenuItem(GtkWidget *menuItem) { m_menuItem = menuItem; } GtkWidget *GetMenuItem() const { return m_menuItem; } diff --git a/include/wx/menu.h b/include/wx/menu.h index fbaf8caedb..440747fe17 100644 --- a/include/wx/menu.h +++ b/include/wx/menu.h @@ -20,20 +20,204 @@ // headers // ---------------------------------------------------------------------------- -#include "wx/list.h" // for wxMenuList +#include "wx/list.h" // for "template" list classes #include "wx/window.h" // base class for wxMenuBar +// also include this one to ensure compatibility with old code which only +// included wx/menu.h +#include "wx/menuitem.h" + class WXDLLEXPORT wxMenu; class WXDLLEXPORT wxMenuBar; class WXDLLEXPORT wxMenuItem; +// pseudo template list classes +WX_DECLARE_LIST(wxMenu, wxMenuList); +WX_DECLARE_LIST(wxMenuItem, wxMenuItemList); + // ---------------------------------------------------------------------------- // wxMenu // ---------------------------------------------------------------------------- -// for now, it's in platform-specific file +class WXDLLEXPORT wxMenuBase : public wxEvtHandler +{ +public: + // create a menu + static wxMenu *New(const wxString& title = wxEmptyString, long style = 0); + + // ctors + wxMenuBase(const wxString& title, long style = 0) : m_title(title) + { Init(style); } + wxMenuBase(long style = 0) + { Init(style); } + + // dtor deletes all the menu items we own + virtual ~wxMenuBase(); + + // menu construction + // ----------------- + + // append a separator to the menu + void AppendSeparator() { Append(wxID_SEPARATOR, wxEmptyString); } + + // append a normal item to the menu + void Append(int id, + const wxString& text, + const wxString& help = wxEmptyString, + bool isCheckable = FALSE) + { + DoAppend(wxMenuItem::New((wxMenu *)this, id, text, help, isCheckable)); + } + + // append a submenu + void Append(int id, + const wxString& text, + wxMenu *submenu, + const wxString& help = wxEmptyString) + { + DoAppend(wxMenuItem::New((wxMenu *)this, id, text, help, FALSE, submenu)); + } + + // the most generic form of Append() - append anything + void Append(wxMenuItem *item) { DoAppend(item); } + + // insert a break in the menu (only works when appending the items, not + // inserting them) + virtual void Break() { } + + // insert an item before given position + bool Insert(size_t pos, wxMenuItem *item); + + // detach an item from the menu, but don't delete it so that it can be + // added back later (but if it's not, the caller is responsible for + // deleting it!) + wxMenuItem *Remove(int id) { return Remove(FindChildItem(id)); } + wxMenuItem *Remove(wxMenuItem *item); + + // delete an item from the menu (submenus are not destroyed by this + // function, see Destroy) + bool Delete(int id) { return Delete(FindChildItem(id)); } + bool Delete(wxMenuItem *item); + + // delete the item from menu and destroy it (if it's a submenu) + bool Destroy(int id) { return Destroy(FindChildItem(id)); } + bool Destroy(wxMenuItem *item); + + // menu items access + // ----------------- + + // get the items + size_t GetMenuItemCount() const { return m_items.GetCount(); } + + const wxMenuItemList& GetMenuItems() const { return m_items; } + wxMenuItemList& GetMenuItems() { return m_items; } + + // search + virtual int FindItem(const wxString& itemString) const; + wxMenuItem* FindItem(int id, wxMenu **menu = NULL) const; + + // get/set items attributes + void Enable(int id, bool enable); + bool IsEnabled(int id) const; -WX_DECLARE_LIST(wxMenu, wxMenuList); + void Check(int id, bool check); + bool IsChecked(int id) const; + + void SetLabel(int id, const wxString& label); + wxString GetLabel(int id) const; + + virtual void SetHelpString(int id, const wxString& helpString); + virtual wxString GetHelpString(int id) const; + + // misc accessors + // -------------- + + // the title + virtual void SetTitle(const wxString& title) { m_title = title; } + const wxString GetTitle() const { return m_title; } + + // client data + void SetClientData(void* clientData) { m_clientData = clientData; } + void* GetClientData() const { return m_clientData; } + + // event handler + void SetEventHandler(wxEvtHandler *handler) { m_eventHandler = handler; } + wxEvtHandler *GetEventHandler() const { return m_eventHandler; } + + // invoking window + void SetInvokingWindow(wxWindow *win) { m_invokingWindow = win; } + wxWindow *GetInvokingWindow() const { return m_invokingWindow; } + + // style + long GetStyle() const { return m_style; } + + // implementation helpers + // ---------------------- + + // Updates the UI for a menu and all submenus recursively. source is the + // object that has the update event handlers defined for it. If NULL, the + // menu or associated window will be used. + void UpdateUI(wxEvtHandler* source = (wxEvtHandler*)NULL); + + // is the menu attached to a menu bar (or is it a popup one)? + bool IsAttached() const { return m_menuBar != NULL; } + + // set/get the parent of this menu + void SetParent(wxMenu *parent) { m_menuParent = parent; } + wxMenu *GetParent() const { return m_menuParent; } + +#if WXWIN_COMPATIBILITY + // compatibility: these functions are deprecated, use the new ones instead + bool Enabled(int id) const { return IsEnabled(id); } + bool Checked(int id) const { return IsChecked(id); } + + wxMenuItem* FindItemForId(int itemId, wxMenu **itemMenu) const + { return FindItem(itemId, itemMenu); } + + wxList& GetItems() const { return (wxList &)m_items; } + + // wxWin 1.6x compatible menu event handling + wxFunction GetCallback() const { return m_callback; } + void Callback(const wxFunction func) { m_callback = func; } + wxFunction m_callback; +#endif // WXWIN_COMPATIBILITY + +protected: + // virtuals to override in derived classes + // --------------------------------------- + + virtual bool DoAppend(wxMenuItem *item); + virtual bool DoInsert(size_t pos, wxMenuItem *item); + + virtual wxMenuItem *DoRemove(wxMenuItem *item); + virtual bool DoDelete(wxMenuItem *item); + virtual bool DoDestroy(wxMenuItem *item); + + // helpers + // ------- + + // common part of all ctors + void Init(long style); + + // unlike FindItem(), this function doesn't recurse but only looks through + // our direct children and also may return the index of the found child if + // pos != NULL + wxMenuItem *FindChildItem(int id, size_t *pos = NULL) const; + +protected: + wxMenuBar *m_menuBar; // menubar we belong to or NULL + wxMenu *m_menuParent; // parent menu or NULL + + wxString m_title; // the menu title or label + wxMenuItemList m_items; // the list of menu items + + wxWindow *m_invokingWindow; // for popup menus + void *m_clientData; // associated with the menu + + long m_style; // combination of wxMENU_XXX flags + + wxEvtHandler *m_eventHandler; // a pluggable in event handler +}; // ---------------------------------------------------------------------------- // wxMenuBar @@ -122,7 +306,7 @@ public: // compatibility only: these functions are deprecated, use the new ones // instead -#ifdef WXWIN_COMPATIBILITY +#if WXWIN_COMPATIBILITY bool Enabled(int id) const { return IsEnabled(id); } bool Checked(int id) const { return IsChecked(id); } @@ -161,9 +345,5 @@ protected: #endif #endif // wxUSE_BASE_CLASSES_ONLY/!wxUSE_BASE_CLASSES_ONLY -// also include this one to ensure compatibility with old code which only -// included wx/menu.h -#include "wx/menuitem.h" - #endif // _WX_MENU_H_BASE_ diff --git a/include/wx/menuitem.h b/include/wx/menuitem.h index f1dacef380..7860cd1097 100644 --- a/include/wx/menuitem.h +++ b/include/wx/menuitem.h @@ -33,6 +33,7 @@ // forward declarations // ---------------------------------------------------------------------------- +class WXDLLEXPORT wxAcceleratorEntry; class WXDLLEXPORT wxMenuItem; class WXDLLEXPORT wxMenu; @@ -52,6 +53,9 @@ public: bool isCheckable = FALSE, wxMenu *subMenu = (wxMenu *)NULL); + // destruction: wxMenuItem will delete its submenu + virtual ~wxMenuItemBase(); + // the menu we're in wxMenu *GetMenu() const { return m_parentMenu; } @@ -60,8 +64,14 @@ public: int GetId() const { return m_id; } bool IsSeparator() const { return m_id == wxID_SEPARATOR; } - // the item's text (or name, or label...) + // the item's text (or name) + // + // NB: the item's text includes the accelerators and mnemonics info (if + // any), i.e. it may contain '&' or '_' or "\t..." and thus is + // different from the item's label which only contains the text shown + // in the menu virtual void SetText(const wxString& str) { m_text = str; } + virtual wxString GetLabel() const { return m_text; } const wxString& GetText() const { return m_text; } // what kind of menu item we are @@ -75,13 +85,24 @@ public: // state virtual void Enable(bool enable = TRUE) { m_isEnabled = enable; } virtual bool IsEnabled() const { return m_isEnabled; } + virtual void Check(bool check = TRUE) { m_isChecked = check; } virtual bool IsChecked() const { return m_isChecked; } + void Toggle() { Check(!m_isChecked); } // help string (displayed in the status bar by default) void SetHelp(const wxString& str) { m_help = str; } const wxString& GetHelp() const { return m_help; } +#if wxUSE_ACCEL + // get our accelerator or NULL (caller must delete the pointer) + virtual wxAcceleratorEntry *GetAccel() const { return NULL; } + + // set the accel for this item - this may also be done indirectly with + // SetText() + virtual void SetAccel(wxAcceleratorEntry *accel); +#endif // wxUSE_ACCEL + // compatibility only, use new functions in the new code void SetName(const wxString& str) { SetText(str); } const wxString& GetName() const { return GetText(); } diff --git a/include/wx/msw/menu.h b/include/wx/msw/menu.h index 93dc89e822..31e2488996 100644 --- a/include/wx/msw/menu.h +++ b/include/wx/msw/menu.h @@ -16,179 +16,97 @@ #pragma interface "menu.h" #endif -#include "wx/defs.h" -#include "wx/event.h" -#include "wx/dynarray.h" -#include "wx/string.h" - #if wxUSE_ACCEL #include "wx/accel.h" + #include "wx/dynarray.h" + + WX_DEFINE_EXPORTED_ARRAY(wxAcceleratorEntry *, wxAcceleratorArray); #endif // wxUSE_ACCEL -class WXDLLEXPORT wxMenuItem; -class WXDLLEXPORT wxMenuBar; -class WXDLLEXPORT wxMenu; class WXDLLEXPORT wxFrame; -WXDLLEXPORT_DATA(extern const wxChar*) wxEmptyString; - -WX_DEFINE_EXPORTED_ARRAY(wxAcceleratorEntry *, wxAcceleratorArray); - // ---------------------------------------------------------------------------- // Menu // ---------------------------------------------------------------------------- -class WXDLLEXPORT wxMenu : public wxEvtHandler +class WXDLLEXPORT wxMenu : public wxMenuBase { - DECLARE_DYNAMIC_CLASS(wxMenu) - public: // ctors & dtor - wxMenu(const wxString& title, - const wxFunction func) - { - Init(title, func); - } + wxMenu(const wxString& title, long style = 0) + : wxMenuBase(title, style) { Init(); } - wxMenu( long WXUNUSED(style) ) - { - Init( wxEmptyString ); - } - - wxMenu(const wxString& title = wxEmptyString, long WXUNUSED(style) = 0) - { - Init(title); - } + wxMenu(long style = 0) : wxMenuBase(style) { Init(); } virtual ~wxMenu(); - // construct menu - // append a separator to the menu - void AppendSeparator(); - // append a normal item to the menu - void Append(int id, const wxString& label, - const wxString& helpString = wxEmptyString, - bool checkable = FALSE); - // append a submenu - void Append(int id, const wxString& label, - wxMenu *submenu, - const wxString& helpString = wxEmptyString); - // append anything (create wxMenuItem first) - void Append(wxMenuItem *pItem); - - // insert a break in the menu - void Break(); - - // delete an item - // If it's a submenu, menu is not destroyed. - // VZ: why? shouldn't it return "wxMenu *" then? - void Delete(int id); - - // client data - void SetClientData(void* clientData) { m_clientData = clientData; } - void* GetClientData() const { return m_clientData; } - - // menu item control - // enable/disable item - void Enable(int id, bool enable); - // TRUE if enabled - bool IsEnabled(int id) const; - - // check/uncheck item - only for checkable items, of course - void Check(int id, bool check); - // TRUE if checked - bool IsChecked(int id) const; - - // other properties - // the menu title - void SetTitle(const wxString& label); - const wxString GetTitle() const; - // the item label - void SetLabel(int id, const wxString& label); - wxString GetLabel(int id) const; - // help string - virtual void SetHelpString(int id, const wxString& helpString); - virtual wxString GetHelpString(int id) const; - - // get the list of items - wxList& GetItems() const { return (wxList &)m_menuItems; } - - // find item - // returns id of the item matching the given string or wxNOT_FOUND - virtual int FindItem(const wxString& itemString) const; - // returns NULL if not found - wxMenuItem* FindItem(int id) const { return FindItemForId(id); } - // find wxMenuItem by ID, and item's menu too if itemMenu is !NULL - wxMenuItem *FindItemForId(int itemId, wxMenu **itemMenu = NULL) const; - - // Updates the UI for a menu and all submenus recursively. source is the - // object that has the update event handlers defined for it. If NULL, the - // menu or associated window will be used. - void UpdateUI(wxEvtHandler* source = (wxEvtHandler*)NULL); + // implement base class virtuals + virtual bool DoAppend(wxMenuItem *item); + virtual bool DoInsert(size_t pos, wxMenuItem *item); + virtual wxMenuItem *DoRemove(wxMenuItem *item); + + virtual void Break(); + + virtual void SetTitle(const wxString& title); + // MSW-specific bool ProcessCommand(wxCommandEvent& event); - void SetEventHandler(wxEvtHandler *handler) { m_eventHandler = handler; } - wxEvtHandler *GetEventHandler() const { return m_eventHandler; } +#ifdef WXWIN_COMPATIBILITY + wxMenu(const wxString& title, const wxFunction func) + : wxMenuBase(title) + { + Callback(func); + } +#endif // WXWIN_COMPATIBILITY - // IMPLEMENTATION - bool MSWCommand(WXUINT param, WXWORD id); + // implementation only from now on + // ------------------------------- - void SetInvokingWindow(wxWindow *pWin) { m_pInvokingWindow = pWin; } - wxWindow *GetInvokingWindow() const { return m_pInvokingWindow; } + bool MSWCommand(WXUINT param, WXWORD id); // semi-private accessors // get the window which contains this menu wxWindow *GetWindow() const; // get the menu handle - WXHMENU GetHMenu() const; + WXHMENU GetHMenu() const { return m_hMenu; } - // only for wxMenuBar + // attach/detach menu to/from wxMenuBar void Attach(wxMenuBar *menubar); void Detach(); #if wxUSE_ACCEL + // called by wxMenuBar to build its accel table from the accels of all menus + bool HasAccels() const { return !m_accels.IsEmpty(); } size_t GetAccelCount() const { return m_accels.GetCount(); } size_t CopyAccels(wxAcceleratorEntry *accels) const; -#endif // wxUSE_ACCEL - wxFunction GetCallback() const { return m_callback; } - void Callback(const wxFunction func) { m_callback = func; } - wxFunction m_callback; - -#ifdef WXWIN_COMPATIBILITY - // compatibility: these functions are deprecated - bool Enabled(int id) const { return IsEnabled(id); } - bool Checked(int id) const { return IsChecked(id); } + // called by wxMenuItem when its accels changes + void UpdateAccel(wxMenuItem *item); -#endif // WXWIN_COMPATIBILITY + // helper used by wxMenu itself (returns the index in m_accels) + int FindAccel(int id) const; +#endif // wxUSE_ACCEL private: // common part of all ctors - void Init(const wxString& title, const wxFunction func = NULL ); - - bool m_doBreak; - - // This is used when m_hMenu is NULL because we don't want to - // delete it in ~wxMenu (it's been added to a parent menu). - // But we'll still need the handle for other purposes. - // Might be better to have a flag saying whether it's deleteable or not. - WXHMENU m_savehMenu ; // Used for Enable() on popup - WXHMENU m_hMenu; - - int m_noItems; - wxString m_title; - wxMenu * m_topLevelMenu; - wxMenuBar * m_menuBar; - wxList m_menuItems; - wxEvtHandler * m_eventHandler; - wxWindow *m_pInvokingWindow; - void* m_clientData; + void Init(); + + // common part of Append/Insert (behaves as Append is pos == (size_t)-1) + bool DoInsertOrAppend(wxMenuItem *item, size_t pos = (size_t)-1); + + // if TRUE, insert a breal before appending the next item + bool m_doBreak; + + // the menu handle of this menu + WXHMENU m_hMenu; #if wxUSE_ACCEL // the accelerators for our menu items wxAcceleratorArray m_accels; #endif // wxUSE_ACCEL + + DECLARE_DYNAMIC_CLASS(wxMenu) }; // ---------------------------------------------------------------------------- @@ -243,8 +161,11 @@ public: void Attach(wxFrame *frame); #if wxUSE_ACCEL - // get the accel table for the menus + // get the accel table for all the menus const wxAcceleratorTable& GetAccelTable() const { return m_accelTable; } + + // update the accel table (must be called after adding/deletign a menu) + void RebuildAccelTable(); #endif // wxUSE_ACCEL // get the menu handle diff --git a/include/wx/msw/menuitem.h b/include/wx/msw/menuitem.h index e07225ee6a..df414512df 100644 --- a/include/wx/msw/menuitem.h +++ b/include/wx/msw/menuitem.h @@ -45,12 +45,17 @@ public: // override base class virtuals virtual void SetText(const wxString& strName); + virtual wxString GetLabel() const; virtual void SetCheckable(bool checkable); virtual void Enable(bool bDoEnable = TRUE); virtual void Check(bool bDoCheck = TRUE); virtual bool IsChecked() const; +#if wxUSE_ACCEL + virtual wxAcceleratorEntry *GetAccel() const; +#endif // wxUSE_ACCEL + // unfortunately needed to resolve ambiguity between // wxMenuItemBase::IsCheckable() and wxOwnerDrawn::IsCheckable() bool IsCheckable() const { return wxMenuItemBase::IsCheckable(); } @@ -60,9 +65,6 @@ public: // menu handle depending on what we're int GetRealId() const; - // delete the submenu - void DeleteSubMenu(); - private: DECLARE_DYNAMIC_CLASS(wxMenuItem) }; diff --git a/samples/font/font.cpp b/samples/font/font.cpp index 7aee6fac4a..963b004a32 100644 --- a/samples/font/font.cpp +++ b/samples/font/font.cpp @@ -400,6 +400,8 @@ void MyFrame::OnSize(wxSizeEvent& event) wxSize size = event.GetSize(); Resize(size); + + event.Skip(); } void MyFrame::Resize(const wxSize& size, const wxFont& font) diff --git a/samples/menu/menu.cpp b/samples/menu/menu.cpp new file mode 100644 index 0000000000..2e44aa4747 --- /dev/null +++ b/samples/menu/menu.cpp @@ -0,0 +1,482 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: samples/menu.cpp +// Purpose: wxMenu/wxMenuBar sample +// Author: Vadim Zeitlin +// Modified by: +// Created: 01.11.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx/wx.h". +#include + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include + + #include +#endif + +// ---------------------------------------------------------------------------- +// classes +// ---------------------------------------------------------------------------- + +// Define a new application +class MyApp: public wxApp +{ +public: + bool OnInit(); +}; + +// Define a new frame +class MyFrame: public wxFrame +{ +public: + MyFrame(); + + virtual ~MyFrame() { delete m_menu; } + + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + + void OnDummy(wxCommandEvent& event); + + void OnAppendMenuItem(wxCommandEvent& event); + void OnAppendSubMenu(wxCommandEvent& event); + void OnDeleteMenuItem(wxCommandEvent& event); + void OnInsertMenuItem(wxCommandEvent& event); + void OnCheckMenuItem(wxCommandEvent& event); + void OnEnableMenuItem(wxCommandEvent& event); + void OnGetLabelMenuItem(wxCommandEvent& event); + void OnSetLabelMenuItem(wxCommandEvent& event); + + void OnAppendMenu(wxCommandEvent& event); + void OnDeleteMenu(wxCommandEvent& event); + void OnToggleMenu(wxCommandEvent& event); + void OnEnableMenu(wxCommandEvent& event); + void OnGetLabelMenu(wxCommandEvent& event); + void OnSetLabelMenu(wxCommandEvent& event); + + void OnRightDown(wxMouseEvent& event); + + void OnUpdateCheckMenuItemUI(wxUpdateUIEvent& event); + +private: + wxMenu *CreateDummyMenu(); + + wxMenuItem *GetLastMenuItem() const; + + wxMenu *m_menu; + + DECLARE_EVENT_TABLE() +}; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +enum +{ + Menu_File_Quit = 100, + + Menu_MenuBar_Toggle = 200, + Menu_MenuBar_Append, + Menu_MenuBar_Delete, + Menu_MenuBar_Enable, + Menu_MenuBar_GetLabel, + Menu_MenuBar_SetLabel, + + Menu_Menu_Append = 300, + Menu_Menu_AppendSub, + Menu_Menu_Insert, + Menu_Menu_Delete, + Menu_Menu_Enable, + Menu_Menu_Check, + Menu_Menu_GetLabel, + Menu_Menu_SetLabel, + + Menu_Dummy_First = 400, + Menu_Dummy_Second, + Menu_Dummy_Third, + Menu_Dummy_Fourth, + Menu_Dummy_Last, + + Menu_Help_About = 1000, + + Menu_Popup_ToBeDeleted = 2000, + Menu_Popup_ToBeGreyed, + Menu_Popup_ToBeChecked, + Menu_Popup_Submenu, + + Menu_Max +}; + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Menu_File_Quit, MyFrame::OnQuit) + + EVT_MENU(Menu_Help_About, MyFrame::OnAbout) + + EVT_MENU(Menu_MenuBar_Toggle, MyFrame::OnToggleMenu) + EVT_MENU(Menu_MenuBar_Append, MyFrame::OnAppendMenu) + EVT_MENU(Menu_MenuBar_Delete, MyFrame::OnDeleteMenu) + EVT_MENU(Menu_MenuBar_Enable, MyFrame::OnEnableMenu) + EVT_MENU(Menu_MenuBar_GetLabel, MyFrame::OnGetLabelMenu) + EVT_MENU(Menu_MenuBar_SetLabel, MyFrame::OnSetLabelMenu) + + EVT_MENU(Menu_Menu_Append, MyFrame::OnAppendMenuItem) + EVT_MENU(Menu_Menu_AppendSub, MyFrame::OnAppendSubMenu) + EVT_MENU(Menu_Menu_Insert, MyFrame::OnInsertMenuItem) + EVT_MENU(Menu_Menu_Delete, MyFrame::OnDeleteMenuItem) + EVT_MENU(Menu_Menu_Enable, MyFrame::OnEnableMenuItem) + EVT_MENU(Menu_Menu_Check, MyFrame::OnCheckMenuItem) + EVT_MENU(Menu_Menu_GetLabel, MyFrame::OnGetLabelMenuItem) + EVT_MENU(Menu_Menu_SetLabel, MyFrame::OnSetLabelMenuItem) + + EVT_MENU_RANGE(Menu_Dummy_First, Menu_Dummy_Last, MyFrame::OnDummy) + + EVT_UPDATE_UI(Menu_Menu_Check, MyFrame::OnUpdateCheckMenuItemUI) + + EVT_RIGHT_DOWN(MyFrame::OnRightDown) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// MyApp +// ---------------------------------------------------------------------------- + +IMPLEMENT_APP(MyApp) + +// The `main program' equivalent, creating the windows and returning the +// main frame +bool MyApp::OnInit() +{ + // Create the main frame window + MyFrame* frame = new MyFrame; + + frame->Show(TRUE); + + frame->SetStatusText("Hello, wxWindows"); + + SetTopWindow(frame); + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// MyFrame +// ---------------------------------------------------------------------------- + +// Define my frame constructor +MyFrame::MyFrame() + : wxFrame((wxFrame *)NULL, -1, "wxWindows menu sample", + wxDefaultPosition, wxSize(300, 200)) +{ + m_menu = NULL; + + CreateStatusBar(); + + // create the menubar + wxMenu *fileMenu = new wxMenu; + fileMenu->Append(Menu_File_Quit, "E&xit\tAlt-X", "Quit toolbar sample" ); + + wxMenu *menubarMenu = new wxMenu; + menubarMenu->Append(Menu_MenuBar_Append, "&Append menu\tCtrl-A", + "Append a menu to the menubar"); + menubarMenu->Append(Menu_MenuBar_Delete, "&Delete menu\tCtrl-D", + "Delete the last menu from the menubar"); + menubarMenu->Append(Menu_MenuBar_Toggle, "&Toggle menu\tCtrl-T", + "Toggle the first menu in the menubar", TRUE); + menubarMenu->AppendSeparator(); + menubarMenu->Append(Menu_MenuBar_Enable, "&Enable menu\tCtrl-E", + "Enable or disable the last menu", TRUE); + menubarMenu->AppendSeparator(); + menubarMenu->Append(Menu_MenuBar_GetLabel, "&Get menu label\tCtrl-G", + "Get the label of the last menu"); + menubarMenu->Append(Menu_MenuBar_SetLabel, "&Set menu label\tCtrl-S", + "Change the label of the last menu"); + + wxMenu *menuMenu = new wxMenu; + menuMenu->Append(Menu_Menu_Append, "&Append menu item\tAlt-A", + "Append a menu item to the last menu"); + menuMenu->Append(Menu_Menu_AppendSub, "&Append sub menu\tAlt-S", + "Append a sub menu to the last menu"); + menuMenu->Append(Menu_Menu_Insert, "&Insert menu item\tAlt-I", + "Insert a menu item in head of the last menu"); + menuMenu->Append(Menu_Menu_Delete, "&Delete menu item\tAlt-D", + "Delete the last menu item from the last menu"); + menuMenu->AppendSeparator(); + menuMenu->Append(Menu_Menu_Enable, "&Enable menu item\tAlt-E", + "Enable or disable the last menu item", TRUE); + menuMenu->Append(Menu_Menu_Check, "&Check menu item\tAlt-C", + "Check or uncheck the last menu item", TRUE); + menuMenu->AppendSeparator(); + menuMenu->Append(Menu_Menu_GetLabel, "&Get menu item label\tAlt-G", + "Get the label of the last menu item"); + menuMenu->Append(Menu_Menu_SetLabel, "&Set menu item label\tAlt-S", + "Change the label of the last menu item"); + + wxMenu *helpMenu = new wxMenu; + helpMenu->Append(Menu_Help_About, "&About\tF1", "About menu sample"); + + wxMenuBar* menuBar = new wxMenuBar( wxMB_DOCKABLE ); + + menuBar->Append(fileMenu, "&File"); + menuBar->Append(menubarMenu, "Menu&bar"); + menuBar->Append(menuMenu, "&Menu"); + menuBar->Append(helpMenu, "&Help"); + + // these items should be initially checked + menuBar->Check(Menu_MenuBar_Toggle, TRUE); + menuBar->Check(Menu_MenuBar_Enable, TRUE); + menuBar->Check(Menu_Menu_Enable, TRUE); + menuBar->Check(Menu_Menu_Check, FALSE); + + // associate the menu bar with the frame + SetMenuBar(menuBar); +} + +wxMenu *MyFrame::CreateDummyMenu() +{ + wxMenu *menu = new wxMenu; + menu->Append(Menu_Dummy_First, "First item\tCtrl-F1"); + menu->AppendSeparator(); + menu->Append(Menu_Dummy_Second, "Second item\tCtrl-F2", "", TRUE); + + return menu; +} + +wxMenuItem *MyFrame::GetLastMenuItem() const +{ + wxMenuBar *menubar = GetMenuBar(); + wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1); + + wxMenuItemList::Node *node = menu->GetMenuItems().GetLast(); + if ( !node ) + { + wxLogWarning("No last item in the last menu!"); + + return NULL; + } + else + { + return node->GetData(); + } +} + +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(TRUE); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + (void)wxMessageBox("wxWindows toolbar sample", + "About wxWindows menu sample", + wxICON_INFORMATION); +} + +void MyFrame::OnDeleteMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *mbar = GetMenuBar(); + + size_t count = mbar->GetMenuCount(); + if ( count == 2 ) + { + // don't let delete the first 2 menus + wxLogError("Can't delete any more menus"); + } + else + { + delete mbar->Remove(count - 1); + } +} + +void MyFrame::OnAppendMenu(wxCommandEvent& WXUNUSED(event)) +{ + static s_count = 0; + + wxString title; + title.Printf("Dummy menu &%d", ++s_count); + + GetMenuBar()->Append(CreateDummyMenu(), title); +} + +void MyFrame::OnToggleMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *mbar = GetMenuBar(); + if ( !m_menu ) + { + // hide the menu + m_menu = mbar->Remove(0); + } + else + { + // restore it + mbar->Insert(0, m_menu, "&File"); + m_menu = NULL; + } +} + +void MyFrame::OnEnableMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *mbar = GetMenuBar(); + size_t count = mbar->GetMenuCount(); + + static bool s_enabled = TRUE; + + s_enabled = !s_enabled; + mbar->EnableTop(count - 1, s_enabled); +} + +void MyFrame::OnGetLabelMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *mbar = GetMenuBar(); + size_t count = mbar->GetMenuCount(); + + wxLogMessage("The label of the last menu item is '%s'", + mbar->GetLabelTop(count - 1)); +} + +void MyFrame::OnSetLabelMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *mbar = GetMenuBar(); + size_t count = mbar->GetMenuCount(); + + mbar->SetLabelTop(count - 1, "Dummy label &0"); +} + +void MyFrame::OnDummy(wxCommandEvent& event) +{ + wxString s; + s.Printf("Dummy item #%d", event.GetId() - Menu_Dummy_First + 1); + wxMessageBox(s, "Menu sample", wxICON_INFORMATION); +} + +void MyFrame::OnAppendMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *menubar = GetMenuBar(); + wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1); + + menu->AppendSeparator(); + menu->Append(Menu_Dummy_Third, "Third dummy item\tCtrl-F3", + "Checkable item", TRUE); +} + +void MyFrame::OnAppendSubMenu(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *menubar = GetMenuBar(); + wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1); + + menu->Append(Menu_Dummy_Last, "Dummy sub menu\tCtrl-F12", + CreateDummyMenu()); +} + +void MyFrame::OnDeleteMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *menubar = GetMenuBar(); + wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1); + + size_t count = menu->GetMenuItemCount(); + if ( !count ) + { + wxLogWarning("No items to delete!"); + } + else + { + menu->Destroy(menu->GetMenuItems().Item(count - 1)->GetData()); + } +} + +void MyFrame::OnInsertMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuBar *menubar = GetMenuBar(); + wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1); + + menu->Insert(0, wxMenuItem::New(menu, Menu_Dummy_Fourth, + "Fourth dummy item\tCtrl-F4")); + menu->Insert(1, wxMenuItem::New(menu, wxID_SEPARATOR, "")); +} + +void MyFrame::OnEnableMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuItem *item = GetLastMenuItem(); + + if ( item ) + { + item->Enable(!item->IsEnabled()); + } +} + +void MyFrame::OnCheckMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuItem *item = GetLastMenuItem(); + + item->Toggle(); +} + +void MyFrame::OnUpdateCheckMenuItemUI(wxUpdateUIEvent& event) +{ + wxMenuItem *item = GetLastMenuItem(); + + event.Enable(item && item->IsCheckable()); +} + +void MyFrame::OnGetLabelMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuItem *item = GetLastMenuItem(); + + if ( item ) + { + wxLogMessage("The label of the last menu item is '%s'", + item->GetLabel()); + } +} + +void MyFrame::OnSetLabelMenuItem(wxCommandEvent& WXUNUSED(event)) +{ + wxMenuItem *item = GetLastMenuItem(); + + if ( item ) + { + item->SetText("Dummy menu item text"); + } +} + +void MyFrame::OnRightDown(wxMouseEvent &event ) +{ + wxMenu menu("Test popup"); + + menu.Append(Menu_Help_About, "&About"); + menu.Append(Menu_Popup_Submenu, "Submenu", CreateDummyMenu()); + menu.Append(Menu_Popup_ToBeDeleted, "To be deleted"); + menu.Append(Menu_Popup_ToBeChecked, "To be checked", "", TRUE); + menu.Append(Menu_Popup_ToBeGreyed, "To be greyed"); + menu.AppendSeparator(); + menu.Append(Menu_File_Quit, "E&xit"); + + menu.Delete(Menu_Popup_ToBeDeleted); + menu.Check(Menu_Popup_ToBeChecked, TRUE); + menu.Enable(Menu_Popup_ToBeGreyed, FALSE); + + PopupMenu( &menu, event.GetX(), event.GetY() ); +} diff --git a/samples/toolbar/test.cpp b/samples/toolbar/test.cpp index 2c35512d9d..ee3af9a57d 100644 --- a/samples/toolbar/test.cpp +++ b/samples/toolbar/test.cpp @@ -71,8 +71,6 @@ public: const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE); - virtual ~MyFrame() { delete m_menu; } - void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -94,8 +92,6 @@ private: bool m_smallToolbar; wxTextCtrl* m_textWindow; - wxMenu *m_menu; - DECLARE_EVENT_TABLE() }; @@ -109,10 +105,7 @@ enum { IDM_TOOLBAR_TOGGLETOOLBAR = 200, IDM_TOOLBAR_ENABLEPRINT, - IDM_TOOLBAR_TOGGLEHELP, - IDM_MENU_TOGGLE, - IDM_MENU_APPEND, - IDM_MENU_DELETE + IDM_TOOLBAR_TOGGLEHELP }; // ---------------------------------------------------------------------------- @@ -130,10 +123,6 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(IDM_TOOLBAR_ENABLEPRINT, MyFrame::OnEnablePrint) EVT_MENU(IDM_TOOLBAR_TOGGLEHELP, MyFrame::OnToggleHelp) - EVT_MENU(IDM_MENU_TOGGLE, MyFrame::OnToggleMenu) - EVT_MENU(IDM_MENU_APPEND, MyFrame::OnAppendMenu) - EVT_MENU(IDM_MENU_DELETE, MyFrame::OnDeleteMenu) - EVT_MENU(-1, MyFrame::OnToolLeftClick) EVT_TOOL_ENTER(ID_TOOLBAR, MyFrame::OnToolEnter) @@ -261,7 +250,6 @@ MyFrame::MyFrame(wxFrame* parent, long style) : wxFrame(parent, id, title, pos, size, style) { - m_menu = NULL; m_textWindow = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(-1, -1), wxTE_MULTILINE); m_smallToolbar = FALSE; @@ -280,11 +268,6 @@ MyFrame::MyFrame(wxFrame* parent, wxMenu *fileMenu = new wxMenu; fileMenu->Append(wxID_EXIT, "E&xit", "Quit toolbar sample" ); - wxMenu *menuMenu = new wxMenu; - menuMenu->Append(IDM_MENU_APPEND, "&Append menu"); - menuMenu->Append(IDM_MENU_DELETE, "&Delete menu"); - menuMenu->Append(IDM_MENU_TOGGLE, "&Toggle menu", "", TRUE); - wxMenu *helpMenu = new wxMenu; helpMenu->Append(wxID_HELP, "&About", "About toolbar sample"); @@ -292,7 +275,6 @@ MyFrame::MyFrame(wxFrame* parent, menuBar->Append(fileMenu, "&File"); menuBar->Append(tbarMenu, "&Toolbar"); - menuBar->Append(menuMenu, "&Menubar"); menuBar->Append(helpMenu, "&Help"); // Associate the menu bar with the frame @@ -333,53 +315,6 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) (void)wxMessageBox("wxWindows toolbar sample", "About wxToolBar"); } -void MyFrame::OnDeleteMenu(wxCommandEvent& WXUNUSED(event)) -{ - wxMenuBar *mbar = GetMenuBar(); - - size_t count = mbar->GetMenuCount(); - if ( count == 3 ) - { - // don't let delete the first 3 menus - wxLogError("Can't delete any more menus"); - } - else - { - delete mbar->Remove(count - 1); - } -} - -void MyFrame::OnAppendMenu(wxCommandEvent& WXUNUSED(event)) -{ - static s_count = 0; - - wxMenu *menu = new wxMenu; - menu->Append(0, "First item"); - menu->AppendSeparator(); - menu->Append(0, "Second item"); - - wxString title; - title.Printf("Dummy menu &%d", ++s_count); - - GetMenuBar()->Append(menu, title); -} - -void MyFrame::OnToggleMenu(wxCommandEvent& WXUNUSED(event)) -{ - wxMenuBar *mbar = GetMenuBar(); - if ( !m_menu ) - { - // hide the menu - m_menu = mbar->Remove(1); - } - else - { - // restore it - mbar->Insert(1, m_menu, "&Toolbar"); - m_menu = NULL; - } -} - void MyFrame::OnToolLeftClick(wxCommandEvent& event) { wxString str; diff --git a/src/common/docview.cpp b/src/common/docview.cpp index 317dbfbc7f..544e8468d3 100644 --- a/src/common/docview.cpp +++ b/src/common/docview.cpp @@ -1931,11 +1931,21 @@ void wxFileHistory::RemoveFileFromHistory(int i) // delete the last menu item which is unused now menu->Delete(wxID_FILE1 + m_fileHistoryN - 1); - // unfortunately, we can't delete separator (there is no function to - // delete item by position, only by id - and what if there are several - // separators in this menu?) - so we will be always left with at least - // one and, even worse, we will add another one if this was the last - // file... (FIXME) + // delete the last separator too if no more files are left + if ( m_fileHistoryN == 1 ) + { + wxMenuItemList::Node *node = menu->GetMenuItems().GetLast(); + if ( node ) + { + wxMenuItem *menuItem = node->GetData(); + if ( menuItem->IsSeparator() ) + { + menu->Delete(menuItem); + } + //else: should we search backwards for the last separator? + } + //else: menu is empty somehow + } } m_fileHistoryN--; diff --git a/src/common/menucmn.cpp b/src/common/menucmn.cpp index de656a0a3c..b5e8cd4266 100644 --- a/src/common/menucmn.cpp +++ b/src/common/menucmn.cpp @@ -37,14 +37,410 @@ // ---------------------------------------------------------------------------- #include "wx/listimpl.cpp" + WX_DEFINE_LIST(wxMenuList); +WX_DEFINE_LIST(wxMenuItemList); // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- -// ctor and dtor +// wxMenuItem +// ---------------------------------------------------------------------------- + +wxMenuItemBase::~wxMenuItemBase() +{ + delete m_subMenu; +} + +#if wxUSE_ACCEL + +void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel) +{ + wxString text = m_text.BeforeFirst(wxT('\t')); + if ( accel ) + { + text += wxT('\t'); + + int flags = accel->GetFlags(); + if ( flags & wxACCEL_ALT ) + text += wxT("Alt-"); + if ( flags & wxACCEL_CTRL ) + text += wxT("Ctrl-"); + if ( flags & wxACCEL_SHIFT ) + text += wxT("Shift-"); + + int code = accel->GetKeyCode(); + switch ( code ) + { + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + text << wxT('F') << code - WXK_F1 + 1; + break; + + // if there are any other keys wxGetAccelFromString() may return, + // we should process them here + + default: + if ( wxIsalnum(code) ) + { + text << (wxChar)code; + + break; + } + + wxFAIL_MSG( wxT("unknown keyboard accel") ); + } + } + + SetText(text); +} + +#endif // wxUSE_ACCEL + +// ---------------------------------------------------------------------------- +// wxMenu ctor and dtor +// ---------------------------------------------------------------------------- + +void wxMenuBase::Init(long style) +{ + m_items.DeleteContents(TRUE); + + m_menuBar = (wxMenuBar *)NULL; + m_menuParent = (wxMenu *)NULL; + + m_invokingWindow = (wxWindow *)NULL; + m_style = style; + m_clientData = (void *)NULL; + m_eventHandler = this; +} + +wxMenuBase::~wxMenuBase() +{ + // nothing to do, wxMenuItemList dtor will delete the menu items +} + +// ---------------------------------------------------------------------------- +// wxMenu item adding/removing +// ---------------------------------------------------------------------------- + +bool wxMenuBase::DoAppend(wxMenuItem *item) +{ + wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") ); + + m_items.Append(item); + + return TRUE; +} + +bool wxMenuBase::Insert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert") ); + wxCHECK_MSG( pos < GetMenuItemCount(), FALSE, + wxT("invalid index in wxMenu::Insert") ); + + return DoInsert(pos, item); +} + +bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") ); + + wxMenuItemList::Node *node = m_items.Item(pos); + wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") ); + + m_items.Insert(node, item); + + return TRUE; +} + +wxMenuItem *wxMenuBase::Remove(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") ); + + return DoRemove(item); +} + +wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item) +{ + wxMenuItemList::Node *node = m_items.Find(item); + + // if we get here, the item is valid or one of Remove() functions is broken + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); + + // we detach the item, but we do delete the list node (i.e. don't call + // DetachNode() here!) + node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item + m_items.DeleteNode(node); + + // item isn't attached to anything any more + wxMenu *submenu = item->GetSubMenu(); + if ( submenu ) + { + submenu->SetParent((wxMenu *)NULL); + } + + return item; +} + +bool wxMenuBase::Delete(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Delete") ); + + return DoDelete(item); +} + +bool wxMenuBase::DoDelete(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") ); + + // don't delete the submenu + item2->SetSubMenu((wxMenu *)NULL); + + delete item2; + + return TRUE; +} + +bool wxMenuBase::Destroy(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Destroy") ); + + return DoDestroy(item); +} + +bool wxMenuBase::DoDestroy(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") ); + + delete item2; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxMenu searching for items +// ---------------------------------------------------------------------------- + +// Finds the item id matching the given string, -1 if not found. +int wxMenuBase::FindItem(const wxString& text) const +{ + wxString label = wxMenuItem(NULL, wxID_SEPARATOR, text).GetLabel(); + for ( wxMenuItemList::Node *node = m_items.GetFirst(); + node; + node = node->GetNext() ) + { + wxMenuItem *item = node->GetData(); + if ( item->IsSubMenu() ) + { + int rc = item->GetSubMenu()->FindItem(label); + if ( rc != wxNOT_FOUND ) + return rc; + } + else if ( !item->IsSeparator() ) + { + if ( item->GetLabel() == label ) + return item->GetId(); + } + } + + return wxNOT_FOUND; +} + +// recursive search for item by id +wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const +{ + if ( itemMenu ) + *itemMenu = NULL; + + wxMenuItem *item = NULL; + for ( wxMenuItemList::Node *node = m_items.GetFirst(); + node && !item; + node = node->GetNext() ) + { + item = node->GetData(); + + if ( item->GetId() == itemId ) + { + if ( itemMenu ) + *itemMenu = (wxMenu *)this; + } + else if ( item->IsSubMenu() ) + { + item = item->GetSubMenu()->FindItem(itemId, itemMenu); + } + else + { + // don't exit the loop + item = NULL; + } + } + + return item; +} + +// non recursive search +wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const +{ + wxMenuItem *item = (wxMenuItem *)NULL; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + + size_t pos; + for ( pos = 0; node; pos++ ) + { + item = node->GetData(); + if ( item->GetId() == id ) + break; + + node = node->GetNext(); + } + + if ( ppos ) + { + *ppos = item ? pos : wxNOT_FOUND; + } + + return item; +} + +// ---------------------------------------------------------------------------- +// wxMenu helpers +// ---------------------------------------------------------------------------- + +// Update a menu and all submenus recursively. source is the object that has +// the update event handlers defined for it. If NULL, the menu or associated +// window will be used. +void wxMenuBase::UpdateUI(wxEvtHandler* source) +{ + if ( !source && GetInvokingWindow() ) + source = GetInvokingWindow()->GetEventHandler(); + if ( !source ) + source = GetEventHandler(); + if ( !source ) + source = this; + + wxMenuItemList::Node* node = GetMenuItems().GetFirst(); + while ( node ) + { + wxMenuItem* item = node->GetData(); + if ( !item->IsSeparator() ) + { + wxWindowID id = item->GetId(); + wxUpdateUIEvent event(id); + event.SetEventObject( source ); + + if ( source->ProcessEvent(event) ) + { + // if anything changed, update the chanegd attribute + if (event.GetSetText()) + SetLabel(id, event.GetText()); + if (event.GetSetChecked()) + Check(id, event.GetChecked()); + if (event.GetSetEnabled()) + Enable(id, event.GetEnabled()); + } + + // recurse to the submenus + if ( item->GetSubMenu() ) + item->GetSubMenu()->UpdateUI(source); + } + //else: item is a separator (which don't process update UI events) + + node = node->GetNext(); + } +} + +// ---------------------------------------------------------------------------- +// wxMenu functions forwarded to wxMenuItem +// ---------------------------------------------------------------------------- + +void wxMenuBase::Enable( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); + + item->Enable(enable); +} + +bool wxMenuBase::IsEnabled( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") ); + + return item->IsEnabled(); +} + +void wxMenuBase::Check( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); + + item->Check(enable); +} + +bool wxMenuBase::IsChecked( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") ); + + return item->IsChecked(); +} + +void wxMenuBase::SetLabel( int id, const wxString &label ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); + + item->SetText(label); +} + +wxString wxMenuBase::GetLabel( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") ); + + return item->GetText(); +} + +void wxMenuBase::SetHelpString( int id, const wxString& helpString ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); + + item->SetHelp( helpString ); +} + +wxString wxMenuBase::GetHelpString( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") ); + + return item->GetHelp(); +} + +// ---------------------------------------------------------------------------- +// wxMenuBarBase ctor and dtor // ---------------------------------------------------------------------------- wxMenuBarBase::wxMenuBarBase() diff --git a/src/common/resource.cpp b/src/common/resource.cpp index b3391f9ac7..83def5dbb7 100644 --- a/src/common/resource.cpp +++ b/src/common/resource.cpp @@ -2890,7 +2890,7 @@ bool wxWindowBase::LoadFromResource(wxWindow *parent, const wxString& resourceNa else if (IsKindOf(CLASSINFO(wxPanel))) { wxPanel* panel = (wxPanel *)this; - if (!panel->Create(parent, -1, wxPoint(x, y), wxSize(width, height), theWindowStyle, name)) + if (!panel->Create(parent, -1, wxPoint(x, y), wxSize(width, height), theWindowStyle | wxTAB_TRAVERSAL, name)) return FALSE; } else diff --git a/src/gtk/menu.cpp b/src/gtk/menu.cpp index 69b01eda04..b1906645a9 100644 --- a/src/gtk/menu.cpp +++ b/src/gtk/menu.cpp @@ -31,6 +31,10 @@ extern void wxapp_install_idle_handler(); extern bool g_isIdle; +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ); +#endif + //----------------------------------------------------------------------------- // wxMenuBar //----------------------------------------------------------------------------- @@ -355,7 +359,7 @@ int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemStr // Find a wxMenuItem using its id. Recurses down into sub-menus static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id) { - wxMenuItem* result = menu->FindItem(id); + wxMenuItem* result = menu->FindChildItem(id); wxNode *node = ((wxMenu *)menu)->GetItems().First(); // const_cast while ( node && result == NULL ) @@ -440,7 +444,7 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (!menu->IsEnabled(id)) return; - wxMenuItem* item = menu->FindItem( id ); + wxMenuItem* item = menu->FindChildItem( id ); wxCHECK_RET( item, wxT("error in menu item callback") ); if (item->IsCheckable()) @@ -569,18 +573,40 @@ wxMenuItem::~wxMenuItem() // don't delete menu items, the menus take care of that } -void wxMenuItem::SetText( const wxString& str ) -{ - DoSetText(str); +// return the menu item text without any menu accels +wxString wxMenuItem::GetLabel() const +{ + wxString label; +#if (GTK_MINOR_VERSION > 0) + for ( const wxChar *pc = m_text.c_str(); *pc; pc++ ) + { + if ( *pc == wxT('_') ) + { + // this is the escape character for GTK+ - skip it + continue; + } + + label += *pc; + } +#else // GTK+ 1.0 + label = m_text; +#endif // GTK+ 1.2/1.0 + + return label; +} + +void wxMenuItem::SetText( const wxString& str ) +{ + DoSetText(str); if (m_menuItem) { GtkLabel *label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); - - /* set new text */ + + /* set new text */ gtk_label_set( label, m_text.mb_str()); - - /* reparse key accel */ + + /* reparse key accel */ guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), m_text.mb_str() ); gtk_accel_label_refetch( GTK_ACCEL_LABEL(label) ); } @@ -623,6 +649,25 @@ void wxMenuItem::DoSetText( const wxString& str ) #endif } +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItem::GetAccel() const +{ + if ( !item.GetHotKey() ) + { + // nothing + return (wxAcceleratorEntry *)NULL; + } + + // as wxGetAccelFromString() looks for TAB, insert a dummy one here + wxString label; + label << wxT('\t') << item.GetHotKey(); + + return wxGetAccelFromString(label); +} + +#endif // wxUSE_ACCEL + void wxMenuItem::Check( bool check ) { wxCHECK_RET( m_menuItem, wxT("invalid menu item") ); @@ -658,12 +703,8 @@ wxString wxMenuItem::GetFactoryPath() const { /* in order to get the pointer to the item we need the item text _without_ underscores */ wxString path( wxT("
/") ); - for ( const wxChar *pc = m_text; *pc != wxT('\0'); pc++ ) - { - while (*pc == wxT('_')) pc++; /* skip it */ - path << *pc; - } - + path += GetLabel(); + return path; } @@ -673,17 +714,8 @@ wxString wxMenuItem::GetFactoryPath() const IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler) -void -wxMenu::Init( const wxString& title, - long style, - const wxFunction func - ) +void wxMenu::Init() { - m_title = title; - m_items.DeleteContents( TRUE ); - m_invokingWindow = (wxWindow *) NULL; - m_style = style; - #if (GTK_MINOR_VERSION > 0) m_accel = gtk_accel_group_new(); m_factory = gtk_item_factory_new( GTK_TYPE_MENU, "
", m_accel ); @@ -692,18 +724,6 @@ wxMenu::Init( const wxString& title, m_menu = gtk_menu_new(); // Do not show! #endif - m_callback = func; - - m_eventHandler = this; - m_clientData = (void*) NULL; - - if (m_title.IsNull()) m_title = wxT(""); - if (m_title != wxT("")) - { - Append(-2, m_title); - AppendSeparator(); - } - m_owner = (GtkWidget*) NULL; #if (GTK_MINOR_VERSION > 0) @@ -722,242 +742,145 @@ wxMenu::Init( const wxString& title, //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "
/tearoff" ); } #endif -} -wxMenu::~wxMenu() -{ - wxNode *node = m_items.First(); - while (node) + // append the title as the very first entry if we have it + if ( !!m_title ) { - wxMenuItem *item = (wxMenuItem*)node->Data(); - wxMenu *submenu = item->GetSubMenu(); - if (submenu) - delete submenu; - node = node->Next(); + Append(-2, m_title); + AppendSeparator(); } +} +wxMenu::~wxMenu() +{ gtk_widget_destroy( m_menu ); gtk_object_unref( GTK_OBJECT(m_factory) ); -} -void wxMenu::SetTitle( const wxString& title ) -{ - // TODO Waiting for something better - m_title = title; + // the menu items are deleted by the base class dtor } -const wxString wxMenu::GetTitle() const +virtual bool wxMenu::DoAppend(wxMenuItem *mitem) { - return m_title; -} - -void wxMenu::AppendSeparator() -{ - wxMenuItem *mitem = new wxMenuItem(this, wxID_SEPARATOR); + GtkWidget *menuItem; + if ( mitem->IsSeparator() ) + { #if (GTK_MINOR_VERSION > 0) - GtkItemFactoryEntry entry; - entry.path = "/sep"; - entry.callback = (GtkItemFactoryCallback) NULL; - entry.callback_action = 0; - entry.item_type = ""; - entry.accelerator = (gchar*) NULL; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - /* this will be wrong for more than one separator. do we care? */ - GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); -#else - GtkWidget *menuItem = gtk_menu_item_new(); - gtk_menu_append( GTK_MENU(m_menu), menuItem ); - gtk_widget_show( menuItem ); -#endif - - mitem->SetMenuItem(menuItem); - m_items.Append( mitem ); -} - -#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL -static wxString GetHotKey( const wxMenuItem& item ) -{ - wxString hotkey; - - // as wxGetAccelFromString() looks for TAB, insert a dummy one here - wxString label; - label << wxT('\t') << item.GetHotKey(); - - // but if the hotkey is empty don't do anything - if ( label.length() > 1 ) + GtkItemFactoryEntry entry; + entry.path = "/sep"; + entry.callback = (GtkItemFactoryCallback) NULL; + entry.callback_action = 0; + entry.item_type = ""; + entry.accelerator = (gchar*) NULL; + + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ + + /* this will be wrong for more than one separator. do we care? */ + menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); +#else // GTK+ 1.0 + menuItem = gtk_menu_item_new(); +#endif // GTK 1.2/1.0 + } + else if ( mitem->IsSubMenu() ) { - wxAcceleratorEntry *accel = wxGetAccelFromString(label); - if ( accel ) - { - int flags = accel->GetFlags(); - if ( flags & wxACCEL_ALT ) - hotkey += wxT(""); - if ( flags & wxACCEL_CTRL ) - hotkey += wxT(""); - if ( flags & wxACCEL_SHIFT ) - hotkey += wxT(""); - - int code = accel->GetKeyCode(); - switch ( code ) - { - case WXK_F1: - case WXK_F2: - case WXK_F3: - case WXK_F4: - case WXK_F5: - case WXK_F6: - case WXK_F7: - case WXK_F8: - case WXK_F9: - case WXK_F10: - case WXK_F11: - case WXK_F12: - hotkey << wxT('F') << code - WXK_F1 + 1; - break; +#if (GTK_MINOR_VERSION > 0) + /* text has "_" instead of "&" after mitem->SetText() */ + wxString text( mitem->GetText() ); - // if there are any other keys wxGetAccelFromString() may return, - // we should process them here + /* local buffer in multibyte form */ + char buf[200]; + strcpy( buf, "/" ); + strcat( buf, text.mb_str() ); - default: - if ( wxIsalnum(code) ) - { - hotkey << (wxChar)code; + GtkItemFactoryEntry entry; + entry.path = buf; + entry.callback = (GtkItemFactoryCallback) 0; + entry.callback_action = 0; + entry.item_type = ""; - break; - } + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - wxFAIL_MSG( wxT("unknown keyboard accel") ); - } + wxString path( mitem->GetFactoryPath() ); + GtkWidget *menuItem = gtk_item_factory_get_item( m_factory, path.mb_str() ); +#else // GTK+ 1.0 + GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText().mbc_str()); +#endif // GTK 1.2/1.0 - delete accel; - } + gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); } - - return hotkey; -} -#endif // wxUSE_ACCEL - -void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable ) -{ - wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, checkable); - + else // a normal item + { #if (GTK_MINOR_VERSION > 0) - /* text has "_" instead of "&" after mitem->SetText() */ - wxString text( mitem->GetText() ); - - /* local buffer in multibyte form */ - char buf[200]; - strcpy( buf, "/" ); - strcat( buf, text.mb_str() ); - - GtkItemFactoryEntry entry; - entry.path = buf; - entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; - entry.callback_action = 0; - if (checkable) - entry.item_type = ""; - else - entry.item_type = ""; + /* text has "_" instead of "&" after mitem->SetText() */ + wxString text( mitem->GetText() ); + + /* local buffer in multibyte form */ + char buf[200]; + strcpy( buf, "/" ); + strcat( buf, text.mb_str() ); + + GtkItemFactoryEntry entry; + entry.path = buf; + entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; + entry.callback_action = 0; + if (checkable) + entry.item_type = ""; + else + entry.item_type = ""; #if wxUSE_ACCEL - // due to an apparent bug in GTK+, we have to use a static buffer here - - // otherwise GTK+ 1.2.2 manages to override the memory we pass to it - // somehow! (VZ) - static char s_accel[32]; // must be big enough for F12 - strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); - entry.accelerator = s_accel; -#else - entry.accelerator = (char*) NULL; -#endif - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - wxString path( mitem->GetFactoryPath() ); - GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, path.mb_str() ); - -#else - - GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label( mitem->GetText().mb_str() ) - : gtk_menu_item_new_with_label( mitem->GetText().mb_str() ); - - gtk_signal_connect( GTK_OBJECT(menuItem), "activate", - GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), - (gpointer)this ); - - gtk_menu_append( GTK_MENU(m_menu), menuItem ); - gtk_widget_show( menuItem ); - -#endif + // due to an apparent bug in GTK+, we have to use a static buffer here - + // otherwise GTK+ 1.2.2 manages to override the memory we pass to it + // somehow! (VZ) + static char s_accel[32]; // must be big enough for F12 + strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); + entry.accelerator = s_accel; +#else // !wxUSE_ACCEL + entry.accelerator = (char*) NULL; +#endif // wxUSE_ACCEL/!wxUSE_ACCEL - gtk_signal_connect( GTK_OBJECT(menuItem), "select", - GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), - (gpointer)this ); + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", - GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), - (gpointer)this ); + wxString path( mitem->GetFactoryPath() ); + GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, path.mb_str() ); +#else // GTK+ 1.0 + GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label( mitem->GetText().mb_str() ) + : gtk_menu_item_new_with_label( mitem->GetText().mb_str() ); - mitem->SetMenuItem(menuItem); - - m_items.Append( mitem ); -} - -void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxString &helpStr ) -{ - wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, FALSE, subMenu); - -#if (GTK_MINOR_VERSION > 0) - /* text has "_" instead of "&" after mitem->SetText() */ - wxString text( mitem->GetText() ); - - /* local buffer in multibyte form */ - char buf[200]; - strcpy( buf, "/" ); - strcat( buf, text.mb_str() ); - - GtkItemFactoryEntry entry; - entry.path = buf; - entry.callback = (GtkItemFactoryCallback) 0; - entry.callback_action = 0; - entry.item_type = ""; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - wxString path( mitem->GetFactoryPath() ); - GtkWidget *menuItem = gtk_item_factory_get_item( m_factory, path.mb_str() ); + gtk_signal_connect( GTK_OBJECT(menuItem), "activate", + GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), + (gpointer)this ); +#endif // GTK+ 1.2/1.0 + } -#else + if ( !mitem->IsSeparator() ) + { + gtk_signal_connect( GTK_OBJECT(menuItem), "select", + GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), + (gpointer)this ); - GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText().mbc_str()); + gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", + GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), + (gpointer)this ); + } +#if GTK_MINOR_VERSION == 0 gtk_menu_append( GTK_MENU(m_menu), menuItem ); gtk_widget_show( menuItem ); - -#endif - - gtk_signal_connect( GTK_OBJECT(menuItem), "select", - GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), - (gpointer*)this ); - - gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", - GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), - (gpointer*)this ); - - gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); +#endif // GTK+ 1.0 mitem->SetMenuItem(menuItem); - m_items.Append( mitem ); + return wxMenuBase::DoAppend(mitem); } +// VZ: this seems to be GTK+ 1.0 only code, I don't understand why there were +// both specialized versions of Append() and this one before my changes, +// but it seems that the others are better... +#if 0 void wxMenu::Append( wxMenuItem *item ) { - m_items.Append( item ); - GtkWidget *menuItem = (GtkWidget*) NULL; if (item->IsSeparator()) @@ -988,126 +911,31 @@ void wxMenu::Append( wxMenuItem *item ) gtk_menu_append( GTK_MENU(m_menu), menuItem ); gtk_widget_show( menuItem ); - item->SetMenuItem(menuItem); -} - -void wxMenu::Delete( int id ) -{ - wxNode *node = m_items.First(); - while (node) - { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetId() == id) - { - /* TODO: this code doesn't delete the item factory item and - this seems impossible as of GTK 1.2.6. */ - gtk_widget_destroy( item->GetMenuItem() ); - m_items.DeleteNode( node ); - return; - } - node = node->Next(); - } -} - -int wxMenu::FindItem( const wxString itemString ) const -{ - wxString s = wxT(""); - for ( const wxChar *pc = itemString; *pc != wxT('\0'); pc++ ) - { - if (*pc == wxT('&')) - { - pc++; /* skip it */ -#if (GTK_MINOR_VERSION > 0) - s << wxT('_'); -#endif - } - s << *pc; - } - - wxNode *node = m_items.First(); - while (node) - { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetText() == s) - { - return item->GetId(); - } - node = node->Next(); - } - return wxNOT_FOUND; -} - -void wxMenu::Enable( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); - - item->Enable(enable); -} - -bool wxMenu::IsEnabled( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") ); - - return item->IsEnabled(); -} - -void wxMenu::Check( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); - - item->Check(enable); -} - -bool wxMenu::IsChecked( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") ); - - return item->IsChecked(); -} - -void wxMenu::SetLabel( int id, const wxString &label ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetText(label); -} - -wxString wxMenu::GetLabel( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") ); - - return item->GetText(); + item->SetMenuItem(menuItem); } +#endif // 0 -void wxMenu::SetHelpString( int id, const wxString& helpString ) +bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) { - wxMenuItem *item = FindItem(id); + if ( !wxMenuBase::DoInsert(pos, item) ) + return FALSE; - wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); + wxFAIL_MSG(wxT("not implemented")); - item->SetHelp( helpString ); + return FALSE; } -wxString wxMenu::GetHelpString( int id ) const +wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { - wxMenuItem *item = FindItem(id); + if ( !wxMenuBase::DoRemove(item) ) + return (wxMenuItem *)NULL; - wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") ); + // TODO: this code doesn't delete the item factory item and this seems + // impossible as of GTK 1.2.6. + gtk_widget_destroy( item->GetMenuItem() ); - return item->GetHelp(); + return item; } int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const @@ -1124,72 +952,62 @@ int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const return wxNOT_FOUND; } -wxMenuItem *wxMenu::FindItem(int id) const +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ) { - wxNode *node = m_items.First(); - while (node) + wxString hotkey; + + wxAcceleratorEntry *accel = item.GetAccel(); + if ( accel ) { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetId() == id) + int flags = accel->GetFlags(); + if ( flags & wxACCEL_ALT ) + hotkey += wxT(""); + if ( flags & wxACCEL_CTRL ) + hotkey += wxT(""); + if ( flags & wxACCEL_SHIFT ) + hotkey += wxT(""); + + int code = accel->GetKeyCode(); + switch ( code ) { - return item; - } - node = node->Next(); - } + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + hotkey << wxT('F') << code - WXK_F1 + 1; + break; - /* Not finding anything here can be correct - * when search the entire menu system for - * an entry -> no error message. */ + // if there are any other keys wxGetAccelFromString() may return, + // we should process them here - return (wxMenuItem *) NULL; -} + default: + if ( wxIsalnum(code) ) + { + hotkey << (wxChar)code; -void wxMenu::SetInvokingWindow( wxWindow *win ) -{ - m_invokingWindow = win; -} + break; + } -wxWindow *wxMenu::GetInvokingWindow() -{ - return m_invokingWindow; -} + wxFAIL_MSG( wxT("unknown keyboard accel") ); + } -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenu::UpdateUI(wxEvtHandler* source) -{ - if (!source && GetInvokingWindow()) - source = GetInvokingWindow()->GetEventHandler(); - if (!source) - source = GetEventHandler(); - if (!source) - source = this; - - wxNode* node = GetItems().First(); - while (node) - { - wxMenuItem* item = (wxMenuItem*) node->Data(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if (source->ProcessEvent(event)) - { - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - if (item->GetSubMenu()) - item->GetSubMenu()->UpdateUI(source); + delete accel; } - node = node->Next(); - } + + return hotkey; } +#endif // wxUSE_ACCEL diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp index 69b01eda04..b1906645a9 100644 --- a/src/gtk1/menu.cpp +++ b/src/gtk1/menu.cpp @@ -31,6 +31,10 @@ extern void wxapp_install_idle_handler(); extern bool g_isIdle; +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ); +#endif + //----------------------------------------------------------------------------- // wxMenuBar //----------------------------------------------------------------------------- @@ -355,7 +359,7 @@ int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemStr // Find a wxMenuItem using its id. Recurses down into sub-menus static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id) { - wxMenuItem* result = menu->FindItem(id); + wxMenuItem* result = menu->FindChildItem(id); wxNode *node = ((wxMenu *)menu)->GetItems().First(); // const_cast while ( node && result == NULL ) @@ -440,7 +444,7 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (!menu->IsEnabled(id)) return; - wxMenuItem* item = menu->FindItem( id ); + wxMenuItem* item = menu->FindChildItem( id ); wxCHECK_RET( item, wxT("error in menu item callback") ); if (item->IsCheckable()) @@ -569,18 +573,40 @@ wxMenuItem::~wxMenuItem() // don't delete menu items, the menus take care of that } -void wxMenuItem::SetText( const wxString& str ) -{ - DoSetText(str); +// return the menu item text without any menu accels +wxString wxMenuItem::GetLabel() const +{ + wxString label; +#if (GTK_MINOR_VERSION > 0) + for ( const wxChar *pc = m_text.c_str(); *pc; pc++ ) + { + if ( *pc == wxT('_') ) + { + // this is the escape character for GTK+ - skip it + continue; + } + + label += *pc; + } +#else // GTK+ 1.0 + label = m_text; +#endif // GTK+ 1.2/1.0 + + return label; +} + +void wxMenuItem::SetText( const wxString& str ) +{ + DoSetText(str); if (m_menuItem) { GtkLabel *label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); - - /* set new text */ + + /* set new text */ gtk_label_set( label, m_text.mb_str()); - - /* reparse key accel */ + + /* reparse key accel */ guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), m_text.mb_str() ); gtk_accel_label_refetch( GTK_ACCEL_LABEL(label) ); } @@ -623,6 +649,25 @@ void wxMenuItem::DoSetText( const wxString& str ) #endif } +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItem::GetAccel() const +{ + if ( !item.GetHotKey() ) + { + // nothing + return (wxAcceleratorEntry *)NULL; + } + + // as wxGetAccelFromString() looks for TAB, insert a dummy one here + wxString label; + label << wxT('\t') << item.GetHotKey(); + + return wxGetAccelFromString(label); +} + +#endif // wxUSE_ACCEL + void wxMenuItem::Check( bool check ) { wxCHECK_RET( m_menuItem, wxT("invalid menu item") ); @@ -658,12 +703,8 @@ wxString wxMenuItem::GetFactoryPath() const { /* in order to get the pointer to the item we need the item text _without_ underscores */ wxString path( wxT("
/") ); - for ( const wxChar *pc = m_text; *pc != wxT('\0'); pc++ ) - { - while (*pc == wxT('_')) pc++; /* skip it */ - path << *pc; - } - + path += GetLabel(); + return path; } @@ -673,17 +714,8 @@ wxString wxMenuItem::GetFactoryPath() const IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler) -void -wxMenu::Init( const wxString& title, - long style, - const wxFunction func - ) +void wxMenu::Init() { - m_title = title; - m_items.DeleteContents( TRUE ); - m_invokingWindow = (wxWindow *) NULL; - m_style = style; - #if (GTK_MINOR_VERSION > 0) m_accel = gtk_accel_group_new(); m_factory = gtk_item_factory_new( GTK_TYPE_MENU, "
", m_accel ); @@ -692,18 +724,6 @@ wxMenu::Init( const wxString& title, m_menu = gtk_menu_new(); // Do not show! #endif - m_callback = func; - - m_eventHandler = this; - m_clientData = (void*) NULL; - - if (m_title.IsNull()) m_title = wxT(""); - if (m_title != wxT("")) - { - Append(-2, m_title); - AppendSeparator(); - } - m_owner = (GtkWidget*) NULL; #if (GTK_MINOR_VERSION > 0) @@ -722,242 +742,145 @@ wxMenu::Init( const wxString& title, //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "
/tearoff" ); } #endif -} -wxMenu::~wxMenu() -{ - wxNode *node = m_items.First(); - while (node) + // append the title as the very first entry if we have it + if ( !!m_title ) { - wxMenuItem *item = (wxMenuItem*)node->Data(); - wxMenu *submenu = item->GetSubMenu(); - if (submenu) - delete submenu; - node = node->Next(); + Append(-2, m_title); + AppendSeparator(); } +} +wxMenu::~wxMenu() +{ gtk_widget_destroy( m_menu ); gtk_object_unref( GTK_OBJECT(m_factory) ); -} -void wxMenu::SetTitle( const wxString& title ) -{ - // TODO Waiting for something better - m_title = title; + // the menu items are deleted by the base class dtor } -const wxString wxMenu::GetTitle() const +virtual bool wxMenu::DoAppend(wxMenuItem *mitem) { - return m_title; -} - -void wxMenu::AppendSeparator() -{ - wxMenuItem *mitem = new wxMenuItem(this, wxID_SEPARATOR); + GtkWidget *menuItem; + if ( mitem->IsSeparator() ) + { #if (GTK_MINOR_VERSION > 0) - GtkItemFactoryEntry entry; - entry.path = "/sep"; - entry.callback = (GtkItemFactoryCallback) NULL; - entry.callback_action = 0; - entry.item_type = ""; - entry.accelerator = (gchar*) NULL; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - /* this will be wrong for more than one separator. do we care? */ - GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); -#else - GtkWidget *menuItem = gtk_menu_item_new(); - gtk_menu_append( GTK_MENU(m_menu), menuItem ); - gtk_widget_show( menuItem ); -#endif - - mitem->SetMenuItem(menuItem); - m_items.Append( mitem ); -} - -#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL -static wxString GetHotKey( const wxMenuItem& item ) -{ - wxString hotkey; - - // as wxGetAccelFromString() looks for TAB, insert a dummy one here - wxString label; - label << wxT('\t') << item.GetHotKey(); - - // but if the hotkey is empty don't do anything - if ( label.length() > 1 ) + GtkItemFactoryEntry entry; + entry.path = "/sep"; + entry.callback = (GtkItemFactoryCallback) NULL; + entry.callback_action = 0; + entry.item_type = ""; + entry.accelerator = (gchar*) NULL; + + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ + + /* this will be wrong for more than one separator. do we care? */ + menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); +#else // GTK+ 1.0 + menuItem = gtk_menu_item_new(); +#endif // GTK 1.2/1.0 + } + else if ( mitem->IsSubMenu() ) { - wxAcceleratorEntry *accel = wxGetAccelFromString(label); - if ( accel ) - { - int flags = accel->GetFlags(); - if ( flags & wxACCEL_ALT ) - hotkey += wxT(""); - if ( flags & wxACCEL_CTRL ) - hotkey += wxT(""); - if ( flags & wxACCEL_SHIFT ) - hotkey += wxT(""); - - int code = accel->GetKeyCode(); - switch ( code ) - { - case WXK_F1: - case WXK_F2: - case WXK_F3: - case WXK_F4: - case WXK_F5: - case WXK_F6: - case WXK_F7: - case WXK_F8: - case WXK_F9: - case WXK_F10: - case WXK_F11: - case WXK_F12: - hotkey << wxT('F') << code - WXK_F1 + 1; - break; +#if (GTK_MINOR_VERSION > 0) + /* text has "_" instead of "&" after mitem->SetText() */ + wxString text( mitem->GetText() ); - // if there are any other keys wxGetAccelFromString() may return, - // we should process them here + /* local buffer in multibyte form */ + char buf[200]; + strcpy( buf, "/" ); + strcat( buf, text.mb_str() ); - default: - if ( wxIsalnum(code) ) - { - hotkey << (wxChar)code; + GtkItemFactoryEntry entry; + entry.path = buf; + entry.callback = (GtkItemFactoryCallback) 0; + entry.callback_action = 0; + entry.item_type = ""; - break; - } + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - wxFAIL_MSG( wxT("unknown keyboard accel") ); - } + wxString path( mitem->GetFactoryPath() ); + GtkWidget *menuItem = gtk_item_factory_get_item( m_factory, path.mb_str() ); +#else // GTK+ 1.0 + GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText().mbc_str()); +#endif // GTK 1.2/1.0 - delete accel; - } + gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); } - - return hotkey; -} -#endif // wxUSE_ACCEL - -void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable ) -{ - wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, checkable); - + else // a normal item + { #if (GTK_MINOR_VERSION > 0) - /* text has "_" instead of "&" after mitem->SetText() */ - wxString text( mitem->GetText() ); - - /* local buffer in multibyte form */ - char buf[200]; - strcpy( buf, "/" ); - strcat( buf, text.mb_str() ); - - GtkItemFactoryEntry entry; - entry.path = buf; - entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; - entry.callback_action = 0; - if (checkable) - entry.item_type = ""; - else - entry.item_type = ""; + /* text has "_" instead of "&" after mitem->SetText() */ + wxString text( mitem->GetText() ); + + /* local buffer in multibyte form */ + char buf[200]; + strcpy( buf, "/" ); + strcat( buf, text.mb_str() ); + + GtkItemFactoryEntry entry; + entry.path = buf; + entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; + entry.callback_action = 0; + if (checkable) + entry.item_type = ""; + else + entry.item_type = ""; #if wxUSE_ACCEL - // due to an apparent bug in GTK+, we have to use a static buffer here - - // otherwise GTK+ 1.2.2 manages to override the memory we pass to it - // somehow! (VZ) - static char s_accel[32]; // must be big enough for F12 - strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); - entry.accelerator = s_accel; -#else - entry.accelerator = (char*) NULL; -#endif - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - wxString path( mitem->GetFactoryPath() ); - GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, path.mb_str() ); - -#else - - GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label( mitem->GetText().mb_str() ) - : gtk_menu_item_new_with_label( mitem->GetText().mb_str() ); - - gtk_signal_connect( GTK_OBJECT(menuItem), "activate", - GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), - (gpointer)this ); - - gtk_menu_append( GTK_MENU(m_menu), menuItem ); - gtk_widget_show( menuItem ); - -#endif + // due to an apparent bug in GTK+, we have to use a static buffer here - + // otherwise GTK+ 1.2.2 manages to override the memory we pass to it + // somehow! (VZ) + static char s_accel[32]; // must be big enough for F12 + strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); + entry.accelerator = s_accel; +#else // !wxUSE_ACCEL + entry.accelerator = (char*) NULL; +#endif // wxUSE_ACCEL/!wxUSE_ACCEL - gtk_signal_connect( GTK_OBJECT(menuItem), "select", - GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), - (gpointer)this ); + gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", - GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), - (gpointer)this ); + wxString path( mitem->GetFactoryPath() ); + GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, path.mb_str() ); +#else // GTK+ 1.0 + GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label( mitem->GetText().mb_str() ) + : gtk_menu_item_new_with_label( mitem->GetText().mb_str() ); - mitem->SetMenuItem(menuItem); - - m_items.Append( mitem ); -} - -void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxString &helpStr ) -{ - wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, FALSE, subMenu); - -#if (GTK_MINOR_VERSION > 0) - /* text has "_" instead of "&" after mitem->SetText() */ - wxString text( mitem->GetText() ); - - /* local buffer in multibyte form */ - char buf[200]; - strcpy( buf, "/" ); - strcat( buf, text.mb_str() ); - - GtkItemFactoryEntry entry; - entry.path = buf; - entry.callback = (GtkItemFactoryCallback) 0; - entry.callback_action = 0; - entry.item_type = ""; - - gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ - - wxString path( mitem->GetFactoryPath() ); - GtkWidget *menuItem = gtk_item_factory_get_item( m_factory, path.mb_str() ); + gtk_signal_connect( GTK_OBJECT(menuItem), "activate", + GTK_SIGNAL_FUNC(gtk_menu_clicked_callback), + (gpointer)this ); +#endif // GTK+ 1.2/1.0 + } -#else + if ( !mitem->IsSeparator() ) + { + gtk_signal_connect( GTK_OBJECT(menuItem), "select", + GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), + (gpointer)this ); - GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText().mbc_str()); + gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", + GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), + (gpointer)this ); + } +#if GTK_MINOR_VERSION == 0 gtk_menu_append( GTK_MENU(m_menu), menuItem ); gtk_widget_show( menuItem ); - -#endif - - gtk_signal_connect( GTK_OBJECT(menuItem), "select", - GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), - (gpointer*)this ); - - gtk_signal_connect( GTK_OBJECT(menuItem), "deselect", - GTK_SIGNAL_FUNC(gtk_menu_nolight_callback), - (gpointer*)this ); - - gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); +#endif // GTK+ 1.0 mitem->SetMenuItem(menuItem); - m_items.Append( mitem ); + return wxMenuBase::DoAppend(mitem); } +// VZ: this seems to be GTK+ 1.0 only code, I don't understand why there were +// both specialized versions of Append() and this one before my changes, +// but it seems that the others are better... +#if 0 void wxMenu::Append( wxMenuItem *item ) { - m_items.Append( item ); - GtkWidget *menuItem = (GtkWidget*) NULL; if (item->IsSeparator()) @@ -988,126 +911,31 @@ void wxMenu::Append( wxMenuItem *item ) gtk_menu_append( GTK_MENU(m_menu), menuItem ); gtk_widget_show( menuItem ); - item->SetMenuItem(menuItem); -} - -void wxMenu::Delete( int id ) -{ - wxNode *node = m_items.First(); - while (node) - { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetId() == id) - { - /* TODO: this code doesn't delete the item factory item and - this seems impossible as of GTK 1.2.6. */ - gtk_widget_destroy( item->GetMenuItem() ); - m_items.DeleteNode( node ); - return; - } - node = node->Next(); - } -} - -int wxMenu::FindItem( const wxString itemString ) const -{ - wxString s = wxT(""); - for ( const wxChar *pc = itemString; *pc != wxT('\0'); pc++ ) - { - if (*pc == wxT('&')) - { - pc++; /* skip it */ -#if (GTK_MINOR_VERSION > 0) - s << wxT('_'); -#endif - } - s << *pc; - } - - wxNode *node = m_items.First(); - while (node) - { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetText() == s) - { - return item->GetId(); - } - node = node->Next(); - } - return wxNOT_FOUND; -} - -void wxMenu::Enable( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); - - item->Enable(enable); -} - -bool wxMenu::IsEnabled( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") ); - - return item->IsEnabled(); -} - -void wxMenu::Check( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); - - item->Check(enable); -} - -bool wxMenu::IsChecked( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") ); - - return item->IsChecked(); -} - -void wxMenu::SetLabel( int id, const wxString &label ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetText(label); -} - -wxString wxMenu::GetLabel( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") ); - - return item->GetText(); + item->SetMenuItem(menuItem); } +#endif // 0 -void wxMenu::SetHelpString( int id, const wxString& helpString ) +bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) { - wxMenuItem *item = FindItem(id); + if ( !wxMenuBase::DoInsert(pos, item) ) + return FALSE; - wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); + wxFAIL_MSG(wxT("not implemented")); - item->SetHelp( helpString ); + return FALSE; } -wxString wxMenu::GetHelpString( int id ) const +wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { - wxMenuItem *item = FindItem(id); + if ( !wxMenuBase::DoRemove(item) ) + return (wxMenuItem *)NULL; - wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") ); + // TODO: this code doesn't delete the item factory item and this seems + // impossible as of GTK 1.2.6. + gtk_widget_destroy( item->GetMenuItem() ); - return item->GetHelp(); + return item; } int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const @@ -1124,72 +952,62 @@ int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const return wxNOT_FOUND; } -wxMenuItem *wxMenu::FindItem(int id) const +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ) { - wxNode *node = m_items.First(); - while (node) + wxString hotkey; + + wxAcceleratorEntry *accel = item.GetAccel(); + if ( accel ) { - wxMenuItem *item = (wxMenuItem*)node->Data(); - if (item->GetId() == id) + int flags = accel->GetFlags(); + if ( flags & wxACCEL_ALT ) + hotkey += wxT(""); + if ( flags & wxACCEL_CTRL ) + hotkey += wxT(""); + if ( flags & wxACCEL_SHIFT ) + hotkey += wxT(""); + + int code = accel->GetKeyCode(); + switch ( code ) { - return item; - } - node = node->Next(); - } + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + hotkey << wxT('F') << code - WXK_F1 + 1; + break; - /* Not finding anything here can be correct - * when search the entire menu system for - * an entry -> no error message. */ + // if there are any other keys wxGetAccelFromString() may return, + // we should process them here - return (wxMenuItem *) NULL; -} + default: + if ( wxIsalnum(code) ) + { + hotkey << (wxChar)code; -void wxMenu::SetInvokingWindow( wxWindow *win ) -{ - m_invokingWindow = win; -} + break; + } -wxWindow *wxMenu::GetInvokingWindow() -{ - return m_invokingWindow; -} + wxFAIL_MSG( wxT("unknown keyboard accel") ); + } -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenu::UpdateUI(wxEvtHandler* source) -{ - if (!source && GetInvokingWindow()) - source = GetInvokingWindow()->GetEventHandler(); - if (!source) - source = GetEventHandler(); - if (!source) - source = this; - - wxNode* node = GetItems().First(); - while (node) - { - wxMenuItem* item = (wxMenuItem*) node->Data(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if (source->ProcessEvent(event)) - { - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - if (item->GetSubMenu()) - item->GetSubMenu()->UpdateUI(source); + delete accel; } - node = node->Next(); - } + + return hotkey; } +#endif // wxUSE_ACCEL diff --git a/src/msw/dialog.cpp b/src/msw/dialog.cpp index 764e4518a1..0ded488a51 100644 --- a/src/msw/dialog.cpp +++ b/src/msw/dialog.cpp @@ -474,7 +474,9 @@ bool wxDialog::Show(bool show) if (hWndParent) ::BringWindowToTop(hWndParent); } - ShowWindow((HWND) GetHWND(), SW_HIDE); + + if ( m_hWnd ) + ShowWindow((HWND) GetHWND(), SW_HIDE); } } return TRUE; diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index aded67d34f..35f3e15db3 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -671,10 +671,9 @@ bool wxFrame::ProcessCommand(int id) return FALSE; wxMenuItem *item = bar->FindItemForId(id); - - if ( item && item->IsCheckable() ) + if ( item && item->IsCheckable() ) { - bar->Check(id, !bar->IsChecked(id)) ; + item->Toggle(); } wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index 22b89e7b4e..139accd657 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -33,6 +33,7 @@ #include "wx/menu.h" #include "wx/utils.h" #include "wx/intl.h" + #include "wx/log.h" #endif #if wxUSE_OWNER_DRAWN @@ -40,9 +41,6 @@ #endif #include "wx/msw/private.h" -#include "wx/msw/menu.h" -#include "wx/menuitem.h" -#include "wx/log.h" // other standard headers #include @@ -78,33 +76,32 @@ static const int idMenuTitle = -2; // --------------------------------------------------------------------------- // Construct a menu with optional title (then use append) -void wxMenu::Init(const wxString& title, const wxFunction func ) +void wxMenu::Init() { - m_title = title; - m_eventHandler = this; - m_pInvokingWindow = NULL; m_doBreak = FALSE; - m_noItems = 0; - m_menuBar = NULL; - m_hMenu = (WXHMENU) CreatePopupMenu(); - m_savehMenu = 0; - m_topLevelMenu = this; - m_clientData = (void*) NULL; + // create the menu + m_hMenu = (WXHMENU)CreatePopupMenu(); + if ( !m_hMenu ) + { + wxLogLastError("CreatePopupMenu"); + } + + // if we have a title, insert it in the beginning of the menu if ( !!m_title ) { Append(idMenuTitle, m_title); AppendSeparator(); } - - Callback(func); } // The wxWindow destructor will take care of deleting the submenus. wxMenu::~wxMenu() { - // free Windows resources - if ( m_hMenu ) + // we should free Windows resources only if Windows doesn't do it for us + // which happens if we're attached to a menubar or a submenu of another + // menu + if ( !IsAttached() && !GetParent() ) { if ( !::DestroyMenu(GetHmenu()) ) { @@ -112,24 +109,6 @@ wxMenu::~wxMenu() } } - // delete submenus - wxNode *node = m_menuItems.First(); - while ( node ) - { - wxMenuItem *item = (wxMenuItem *)node->Data(); - - // Delete child menus. - // Beware: they must not be appended to children list!!! - // (because order of delete is significant) - if ( item->IsSubMenu() ) - item->DeleteSubMenu(); - - wxNode *next = node->Next(); - delete item; - delete node; - node = next; - } - #if wxUSE_ACCEL // delete accels WX_CLEAR_ARRAY(m_accels); @@ -138,20 +117,64 @@ wxMenu::~wxMenu() void wxMenu::Break() { + // this will take effect during the next call to Append() m_doBreak = TRUE; } -// function appends a new item or submenu to the menu -void wxMenu::Append(wxMenuItem *pItem) +#if wxUSE_ACCEL + +int wxMenu::FindAccel(int id) const +{ + size_t n, count = m_accels.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( m_accels[n]->m_command == id ) + return n; + } + + return wxNOT_FOUND; +} + +void wxMenu::UpdateAccel(wxMenuItem *item) { - wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") ); + // find the (new) accel for this item + wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText()); + if ( accel ) + accel->m_command = item->GetId(); -#if wxUSE_ACCEL - wxAcceleratorEntry *accel = wxGetAccelFromString(pItem->GetText()); - if ( accel ) { - m_accels.Add(accel); - accel->m_command = pItem->GetId(); + // find the old one + int n = FindAccel(item->GetId()); + if ( n == wxNOT_FOUND ) + { + // no old, add new if any + if ( accel ) + m_accels.Add(accel); + else + return; // skipping RebuildAccelTable() below + } + else + { + // replace old with new or just remove the old one if no new + delete m_accels[n]; + if ( accel ) + m_accels[n] = accel; + else + m_accels.Remove(n); + } + + if ( IsAttached() ) + { + m_menuBar->RebuildAccelTable(); } +} + +#endif // wxUSE_ACCEL + +// append a new item or submenu to the menu +bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) +{ +#if wxUSE_ACCEL + UpdateAccel(pItem); #endif // wxUSE_ACCEL UINT flags = 0; @@ -172,12 +195,11 @@ void wxMenu::Append(wxMenuItem *pItem) UINT id; wxMenu *submenu = pItem->GetSubMenu(); if ( submenu != NULL ) { - wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL ); + wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); + + submenu->SetParent(this); id = (UINT)submenu->GetHMenu(); - submenu->m_topLevelMenu = m_topLevelMenu; - submenu->m_savehMenu = (WXHMENU)id; - submenu->m_hMenu = 0; flags |= MF_POPUP; } @@ -202,12 +224,25 @@ void wxMenu::Append(wxMenuItem *pItem) pData = (char*)pItem->GetText().c_str(); } - if ( !::AppendMenu(GetHmenu(), flags, id, pData) ) + BOOL ok; + if ( pos == (size_t)-1 ) + { + ok = ::AppendMenu(GetHmenu(), flags, id, pData); + } + else + { + ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData); + } + + if ( !ok ) { - wxLogLastError("AppendMenu"); + wxLogLastError("Insert or AppendMenu"); + + return FALSE; } else { + // if we just appended the title, highlight it #ifdef __WIN32__ if ( (int)id == idMenuTitle ) { @@ -224,78 +259,76 @@ void wxMenu::Append(wxMenuItem *pItem) } #endif // __WIN32__ - m_menuItems.Append(pItem); - m_noItems++; - } -} + // if we're already attached to the menubar, we must update it + if ( IsAttached() ) + { + m_menuBar->Refresh(); + } -void wxMenu::AppendSeparator() -{ - Append(new wxMenuItem(this, ID_SEPARATOR)); + return TRUE; + } } -// Pullright item -void wxMenu::Append(int id, - const wxString& label, - wxMenu *SubMenu, - const wxString& helpString) +bool wxMenu::DoAppend(wxMenuItem *item) { - Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu)); + return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item); } -// Ordinary menu item -void wxMenu::Append(int id, - const wxString& label, - const wxString& helpString, - bool checkable) +bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) { - // 'checkable' parameter is useless for Windows. - Append(new wxMenuItem(this, id, label, helpString, checkable)); + return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos); } -// delete item by id -void wxMenu::Delete(int id) +wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { - wxMenuItem *item = NULL; - int pos; - wxNode *node; - for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) + // we need to find the items position in the child list + size_t pos; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + for ( pos = 0; node; pos++ ) { - item = (wxMenuItem *)node->Data(); - if ( item->GetId() == id ) + if ( node->GetData() == item ) break; + + node = node->GetNext(); } - wxCHECK_RET( node, wxT("wxMenu::Delete(): item doesn't exist") ); + // DoRemove() (unlike Remove) can only be called for existing item! + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); - HMENU menu = GetHmenu(); +#if wxUSE_ACCEL + // remove the corresponding accel from the accel table + int n = FindAccel(item->GetId()); + if ( n != wxNOT_FOUND ) + { + delete m_accels[n]; - wxMenu *pSubMenu = item->GetSubMenu(); - if ( pSubMenu != NULL ) { - RemoveMenu(menu, (UINT)pos, MF_BYPOSITION); - pSubMenu->m_hMenu = pSubMenu->m_savehMenu; - pSubMenu->m_savehMenu = 0; - // RemoveChild(item->subMenu); - pSubMenu->m_topLevelMenu = NULL; - // TODO: Why isn't subMenu deleted here??? - // Will put this in for now. Assuming this is supposed - // to delete the menu, not just remove it. - item->DeleteSubMenu(); + m_accels.Remove(n); } - else { - DeleteMenu(menu, (UINT)pos, MF_BYPOSITION); + //else: this item doesn't have an accel, nothing to do +#endif // wxUSE_ACCEL + + // remove the item from the menu + if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) + { + wxLogLastError("RemoveMenu"); } - m_menuItems.DeleteNode(node); - delete item; -} + if ( IsAttached() ) + { + // otherwise, the chane won't be visible + m_menuBar->Refresh(); + } -#if wxUSE_ACCEL + // and from internal data structures + return wxMenuBase::DoRemove(item); +} // --------------------------------------------------------------------------- // accelerator helpers // --------------------------------------------------------------------------- +#if wxUSE_ACCEL + // create the wxAcceleratorEntries for our accels and put them into provided // array - return the number of accels we have size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const @@ -312,84 +345,7 @@ size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const #endif // wxUSE_ACCEL // --------------------------------------------------------------------------- -// wxMenu functions implemented in wxMenuItem -// --------------------------------------------------------------------------- - -void wxMenu::Enable(int id, bool Flag) -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_RET( item != NULL, wxT("can't enable non-existing menu item") ); - - item->Enable(Flag); -} - -bool wxMenu::IsEnabled(int id) const -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") ); - - return item->IsEnabled(); -} - -void wxMenu::Check(int id, bool Flag) -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_RET( item != NULL, wxT("can't get status of non-existing menu item") ); - - item->Check(Flag); -} - -bool wxMenu::IsChecked(int id) const -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") ); - - return item->IsChecked(); -} - -void wxMenu::SetLabel(int id, const wxString& label) -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetText(label); -} - -wxString wxMenu::GetLabel(int id) const -{ - wxString label; - wxMenuItem *pItem = FindItemForId(id); - if (pItem) - label = pItem->GetText(); - else - wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist")); - - return label; -} - -void wxMenu::SetHelpString(int itemId, const wxString& helpString) -{ - wxMenuItem *item = FindItemForId (itemId); - if (item) - item->SetHelp(helpString); - else - wxFAIL_MSG(wxT("wxMenu::SetHelpString: item doesn't exist")); -} - -wxString wxMenu::GetHelpString (int itemId) const -{ - wxString help; - wxMenuItem *item = FindItemForId (itemId); - if (item) - help = item->GetHelp(); - else - wxFAIL_MSG(wxT("wxMenu::GetHelpString: item doesn't exist")); - - return help; -} - -// --------------------------------------------------------------------------- -// wxMenu title +// set wxMenu title // --------------------------------------------------------------------------- void wxMenu::SetTitle(const wxString& label) @@ -403,11 +359,11 @@ void wxMenu::SetTitle(const wxString& label) { if ( !label.IsEmpty() ) { - if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title) || - !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) ) + if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, + (unsigned)idMenuTitle, m_title) || + !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) ) { - wxLogLastError(wxT("InsertMenu")); + wxLogLastError("InsertMenu"); } } } @@ -426,8 +382,8 @@ void wxMenu::SetTitle(const wxString& label) { // modify the title if ( !ModifyMenu(hMenu, 0u, - MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title) ) + MF_BYPOSITION | MF_STRING, + (unsigned)idMenuTitle, m_title) ) { wxLogLastError("ModifyMenu"); } @@ -448,12 +404,7 @@ void wxMenu::SetTitle(const wxString& label) wxLogLastError("SetMenuItemInfo"); } } -#endif -} - -const wxString wxMenu::GetTitle() const -{ - return m_title; +#endif // Win32 } // --------------------------------------------------------------------------- @@ -481,12 +432,14 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event) { bool processed = FALSE; +#if WXWIN_COMPATIBILITY // Try a callback if (m_callback) { (void)(*(m_callback))(*this, event); processed = TRUE; } +#endif WXWIN_COMPATIBILITY // Try the menu's event handler if ( !processed && GetEventHandler()) @@ -503,63 +456,6 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event) return processed; } -// --------------------------------------------------------------------------- -// Item search -// --------------------------------------------------------------------------- - -// Finds the item id matching the given string, -1 if not found. -int wxMenu::FindItem (const wxString& itemString) const -{ - wxString itemLabel = wxStripMenuCodes(itemString); - for ( wxNode *node = m_menuItems.First(); node; node = node->Next() ) - { - wxMenuItem *item = (wxMenuItem *)node->Data(); - if ( item->IsSubMenu() ) - { - int ans = item->GetSubMenu()->FindItem(itemString); - if ( ans != wxNOT_FOUND ) - return ans; - } - else if ( !item->IsSeparator() ) - { - wxString label = wxStripMenuCodes(item->GetText()); - if ( itemLabel == label ) - return item->GetId(); - } - } - - return wxNOT_FOUND; -} - -wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const -{ - if ( itemMenu ) - *itemMenu = NULL; - - wxMenuItem *item = NULL; - for ( wxNode *node = m_menuItems.First(); node && !item; node = node->Next() ) - { - item = (wxMenuItem *)node->Data(); - - if ( item->GetId() == itemId ) - { - if (itemMenu) - *itemMenu = (wxMenu *)this; - } - else if ( item->IsSubMenu() ) - { - item = item->GetSubMenu()->FindItemForId(itemId, itemMenu); - } - else - { - // don't exit the loop - item = NULL; - } - } - - return item; -} - // --------------------------------------------------------------------------- // other // --------------------------------------------------------------------------- @@ -571,8 +467,6 @@ void wxMenu::Attach(wxMenuBar *menubar) wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") ); m_menuBar = menubar; - m_savehMenu = m_hMenu; - m_hMenu = 0; } void wxMenu::Detach() @@ -580,8 +474,16 @@ void wxMenu::Detach() wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") ); m_menuBar = NULL; - m_hMenu = m_savehMenu; - m_savehMenu = 0; +} + +wxWindow *wxMenu::GetWindow() const +{ + if ( m_invokingWindow != NULL ) + return m_invokingWindow; + else if ( m_menuBar != NULL) + return m_menuBar->GetFrame(); + + return NULL; } // --------------------------------------------------------------------------- @@ -638,7 +540,7 @@ void wxMenuBar::Refresh() WXHMENU wxMenuBar::Create() { if (m_hMenu != 0 ) - return m_hMenu; + return m_hMenu; wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") ); @@ -674,7 +576,9 @@ WXHMENU wxMenuBar::Create() void wxMenuBar::EnableTop(size_t pos, bool enable) { - int flag = enable ? MF_ENABLED : MF_GRAYED;; + wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); + + int flag = enable ? MF_ENABLED : MF_GRAYED; EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag); @@ -683,6 +587,16 @@ void wxMenuBar::EnableTop(size_t pos, bool enable) void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) { + wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") ); + + m_titles[pos] = label; + + if ( !IsAttached() ) + { + return; + } + //else: have to modify the existing menu + UINT id; UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION); if ( flagsOld == 0xFFFFFFFF ) @@ -708,18 +622,16 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) { wxLogLastError("ModifyMenu"); } + + Refresh(); } wxString wxMenuBar::GetLabelTop(size_t pos) const { - int len = ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND); - - len++; // for the NUL character - wxString label; - ::GetMenuString(GetHmenu(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND); - label.UngetWriteBuf(); + wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString, + wxT("invalid menu index in wxMenuBar::GetLabelTop") ); - return label; + return m_titles[pos]; } int wxMenuBar::FindMenu(const wxString& title) @@ -764,6 +676,14 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) wxLogLastError("InsertMenu"); } +#if wxUSE_ACCEL + if ( menuOld->HasAccels() || menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL + Refresh(); } @@ -788,6 +708,14 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) wxLogLastError("InsertMenu"); } +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL + Refresh(); } @@ -799,8 +727,13 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title) WXHMENU submenu = menu ? menu->GetHMenu() : 0; wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") ); + if ( !wxMenuBarBase::Append(menu, title) ) + return FALSE; + menu->Attach(this); + m_titles.Add(title); + if ( IsAttached() ) { if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, @@ -809,13 +742,17 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title) wxLogLastError(wxT("AppendMenu")); } +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL + Refresh(); } - wxMenuBarBase::Append(menu, title); - - m_titles.Add(title); - return TRUE; } @@ -834,6 +771,14 @@ wxMenu *wxMenuBar::Remove(size_t pos) menu->Detach(); +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL + Refresh(); } @@ -842,15 +787,11 @@ wxMenu *wxMenuBar::Remove(size_t pos) return menu; } -void wxMenuBar::Attach(wxFrame *frame) -{ - wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); - - m_menuBarFrame = frame; - #if wxUSE_ACCEL - // create the accel table - we consider that the menubar construction is - // finished + +void wxMenuBar::RebuildAccelTable() +{ + // merge the accelerators of all menus into one accel table size_t nAccelCount = 0; size_t i, count = GetMenuCount(); for ( i = 0; i < count; i++ ) @@ -872,6 +813,18 @@ void wxMenuBar::Attach(wxFrame *frame) delete [] accelEntries; } +} + +#endif // wxUSE_ACCEL + +void wxMenuBar::Attach(wxFrame *frame) +{ + wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); + + m_menuBarFrame = frame; + +#if wxUSE_ACCEL + RebuildAccelTable(); #endif // wxUSE_ACCEL } @@ -918,68 +871,3 @@ wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const return item; } - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -wxWindow *wxMenu::GetWindow() const -{ - if ( m_pInvokingWindow != NULL ) - return m_pInvokingWindow; - else if ( m_menuBar != NULL) - return m_menuBar->GetFrame(); - - return NULL; -} - -WXHMENU wxMenu::GetHMenu() const -{ - if ( m_hMenu != 0 ) - return m_hMenu; - else if ( m_savehMenu != 0 ) - return m_savehMenu; - - wxFAIL_MSG(wxT("wxMenu without HMENU")); - - return 0; -} - -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenu::UpdateUI(wxEvtHandler* source) -{ - if (!source && GetInvokingWindow()) - source = GetInvokingWindow()->GetEventHandler(); - if (!source) - source = GetEventHandler(); - if (!source) - source = this; - - wxNode* node = GetItems().First(); - while (node) - { - wxMenuItem* item = (wxMenuItem*) node->Data(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if (source->ProcessEvent(event)) - { - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - if (item->GetSubMenu()) - item->GetSubMenu()->UpdateUI(source); - } - node = node->Next(); - } -} diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index 822bd0bfd6..2e981bba71 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -42,6 +42,10 @@ #include "wx/menuitem.h" #include "wx/log.h" +#if wxUSE_ACCEL + #include "wx/accel.h" +#endif // wxUSE_ACCEL + #include "wx/msw/private.h" // --------------------------------------------------------------------------- @@ -129,14 +133,6 @@ int wxMenuItem::GetRealId() const return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId(); } -// delete the sub menu -// ------------------- -void wxMenuItem::DeleteSubMenu() -{ - delete m_subMenu; - m_subMenu = NULL; -} - // get item state // -------------- @@ -148,41 +144,60 @@ bool wxMenuItem::IsChecked() const return (flag & MF_DISABLED) == 0; } +wxString wxMenuItem::GetLabel() const +{ + return wxStripMenuCodes(m_text); +} + +// accelerators +// ------------ + +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItem::GetAccel() const +{ + return wxGetAccelFromString(GetText()); +} + +#endif // wxUSE_ACCEL + // change item state // ----------------- -void wxMenuItem::Enable(bool bDoEnable) +void wxMenuItem::Enable(bool enable) { - if ( m_isEnabled != bDoEnable ) { - long rc = EnableMenuItem(GetHMenuOf(m_parentMenu), - GetRealId(), - MF_BYCOMMAND | - (bDoEnable ? MF_ENABLED : MF_GRAYED)); - - if ( rc == -1 ) { - wxLogLastError("EnableMenuItem"); - } + if ( m_isEnabled == enable ) + return; + + long rc = EnableMenuItem(GetHMenuOf(m_parentMenu), + GetRealId(), + MF_BYCOMMAND | + (enable ? MF_ENABLED : MF_GRAYED)); - wxMenuItemBase::Enable(m_isEnabled); + if ( rc == -1 ) { + wxLogLastError("EnableMenuItem"); } + + wxMenuItemBase::Enable(enable); } -void wxMenuItem::Check(bool bDoCheck) +void wxMenuItem::Check(bool check) { wxCHECK_RET( m_isCheckable, wxT("only checkable items may be checked") ); - if ( m_isChecked != bDoCheck ) { - long rc = CheckMenuItem(GetHMenuOf(m_parentMenu), - GetId(), - MF_BYCOMMAND | - (bDoCheck ? MF_CHECKED : MF_UNCHECKED)); + if ( m_isChecked == check ) + return; - if ( rc == -1 ) { - wxLogLastError("CheckMenuItem"); - } + long rc = CheckMenuItem(GetHMenuOf(m_parentMenu), + GetRealId(), + MF_BYCOMMAND | + (check ? MF_CHECKED : MF_UNCHECKED)); - wxMenuItemBase::Check(m_isChecked); + if ( rc == -1 ) { + wxLogLastError("CheckMenuItem"); } + + wxMenuItemBase::Check(check); } void wxMenuItem::SetText(const wxString& text) @@ -195,6 +210,11 @@ void wxMenuItem::SetText(const wxString& text) OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) ); HMENU hMenu = GetHMenuOf(m_parentMenu); + wxCHECK_RET( hMenu, wxT("menuitem without menu") ); + +#if wxUSE_ACCEL + m_parentMenu->UpdateAccel(this); +#endif // wxUSE_ACCEL UINT id = GetRealId(); UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND); -- 2.45.2