From 5526e819eca4465ed5520d49bccfebc6a28045e0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= <vslavik@fastmail.fm> Date: Wed, 7 Jul 1999 22:04:58 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2963 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- acconfig.h | 5 + configure.in | 16 + include/wx/busyinfo.h | 58 + include/wx/filesys.h | 194 ++ include/wx/fs_inet.h | 55 + include/wx/fs_zip.h | 41 + include/wx/html/forcelink.h | 59 + include/wx/html/htmlcell.h | 292 +++ include/wx/html/htmldefs.h | 94 + include/wx/html/htmlfilter.h | 70 + include/wx/html/htmlhelp.h | 223 ++ include/wx/html/htmlparser.h | 176 ++ include/wx/html/htmltag.h | 135 ++ include/wx/html/htmlwin.h | 220 ++ include/wx/html/htmlwinparser.h | 219 ++ include/wx/html/mod_templ.h | 102 + include/wx/html/msw/back.bmp | Bin 0 -> 202 bytes include/wx/html/msw/book.ico | Bin 0 -> 318 bytes include/wx/html/msw/folder.ico | Bin 0 -> 318 bytes include/wx/html/msw/forward.bmp | Bin 0 -> 202 bytes include/wx/html/msw/page.ico | Bin 0 -> 318 bytes include/wx/html/msw/panel.bmp | Bin 0 -> 710 bytes include/wx/html/msw/wxhtml.rc | 16 + include/wx/html/version.h | 7 + include/wx/msw/setup0.h | 2 + include/wx/wxhtml.h | 27 + include/wx/zipstream.h | 70 + samples/html/Makefile.am | 8 + samples/html/about/Makefile.am | 9 + samples/html/about/about.cpp | 174 ++ samples/html/about/about.rc | 2 + samples/html/about/data/about.htm | 17 + samples/html/about/data/logo.png | Bin 0 -> 7637 bytes samples/html/help/Makefile.am | 9 + samples/html/help/help.cpp | 85 + samples/html/help/help.rc | 2 + samples/html/help/helpfiles/Index.hhk | 24 + samples/html/help/helpfiles/book1.htm | 4 + samples/html/help/helpfiles/book2.htm | 5 + samples/html/help/helpfiles/contents.hhc | 33 + samples/html/help/helpfiles/main.htm | 5 + samples/html/help/helpfiles/page2-b.htm | 5 + samples/html/help/helpfiles/testing.hhp | 15 + samples/html/printing/Makefile.am | 9 + samples/html/printing/mondrian.ico | Bin 0 -> 766 bytes samples/html/printing/mondrian.xpm | 44 + samples/html/printing/pic.png | Bin 0 -> 31315 bytes samples/html/printing/printing.cpp | 312 +++ samples/html/printing/printing.h | 76 + samples/html/printing/printing.rc | 3 + samples/html/printing/test.htm | 126 ++ samples/html/test/Makefile.am | 9 + samples/html/test/f.html | 2474 ++++++++++++++++++++++ samples/html/test/fft.html | 144 ++ samples/html/test/pic.png | Bin 0 -> 31315 bytes samples/html/test/pic2.bmp | Bin 0 -> 23244 bytes samples/html/test/tables.htm | 116 + samples/html/test/test.cpp | 203 ++ samples/html/test/test.htm | 266 +++ samples/html/test/test.rc | 2 + samples/html/virtual/Makefile.am | 9 + samples/html/virtual/start.htm | 12 + samples/html/virtual/virtual.cpp | 231 ++ samples/html/virtual/virtual.rc | 2 + samples/html/widget/Makefile.am | 9 + samples/html/widget/start.htm | 20 + samples/html/widget/widget.cpp | 244 +++ samples/html/widget/widget.rc | 2 + samples/html/zip/Makefile.am | 9 + samples/html/zip/pages.zip | Bin 0 -> 62123 bytes samples/html/zip/start.htm | 9 + samples/html/zip/zip.cpp | 195 ++ samples/html/zip/zip.rc | 2 + src/common/filesys.cpp | 294 +++ src/common/fs_inet.cpp | 130 ++ src/common/fs_zip.cpp | 75 + src/common/unzip.c | 1294 +++++++++++ src/common/unzip.h | 275 +++ src/common/zipstream.cpp | 110 + src/generic/busyinfo.cpp | 69 + src/gtk/Makefile.am | 29 +- src/gtk1/Makefile.am | 29 +- src/html/bitmaps/back.xpm | 24 + src/html/bitmaps/book.xpm | 40 + src/html/bitmaps/folder.xpm | 50 + src/html/bitmaps/forward.xpm | 24 + src/html/bitmaps/page.xpm | 25 + src/html/bitmaps/panel.xpm | 122 ++ src/html/htmlcell.cpp | 507 +++++ src/html/htmlfilter.cpp | 170 ++ src/html/htmlhelp.cpp | 864 ++++++++ src/html/htmlhelp_io.cpp | 250 +++ src/html/htmlparser.cpp | 169 ++ src/html/htmltag.cpp | 248 +++ src/html/htmlwin.cpp | 542 +++++ src/html/htmlwinparser.cpp | 288 +++ src/html/mod_fonts.cpp | 175 ++ src/html/mod_hline.cpp | 88 + src/html/mod_image.cpp | 147 ++ src/html/mod_layout.cpp | 223 ++ src/html/mod_links.cpp | 80 + src/html/mod_list.cpp | 142 ++ src/html/mod_pre.cpp | 157 ++ src/html/mod_tables.cpp | 480 +++++ src/html/search.cpp | 73 + src/html/search.h | 50 + src/motif/Makefile.am | 26 +- 107 files changed, 14270 insertions(+), 5 deletions(-) create mode 100644 include/wx/busyinfo.h create mode 100644 include/wx/filesys.h create mode 100644 include/wx/fs_inet.h create mode 100644 include/wx/fs_zip.h create mode 100644 include/wx/html/forcelink.h create mode 100644 include/wx/html/htmlcell.h create mode 100644 include/wx/html/htmldefs.h create mode 100644 include/wx/html/htmlfilter.h create mode 100644 include/wx/html/htmlhelp.h create mode 100644 include/wx/html/htmlparser.h create mode 100644 include/wx/html/htmltag.h create mode 100644 include/wx/html/htmlwin.h create mode 100644 include/wx/html/htmlwinparser.h create mode 100644 include/wx/html/mod_templ.h create mode 100644 include/wx/html/msw/back.bmp create mode 100644 include/wx/html/msw/book.ico create mode 100644 include/wx/html/msw/folder.ico create mode 100644 include/wx/html/msw/forward.bmp create mode 100644 include/wx/html/msw/page.ico create mode 100644 include/wx/html/msw/panel.bmp create mode 100644 include/wx/html/msw/wxhtml.rc create mode 100644 include/wx/html/version.h create mode 100644 include/wx/wxhtml.h create mode 100644 include/wx/zipstream.h create mode 100644 samples/html/Makefile.am create mode 100644 samples/html/about/Makefile.am create mode 100644 samples/html/about/about.cpp create mode 100644 samples/html/about/about.rc create mode 100644 samples/html/about/data/about.htm create mode 100644 samples/html/about/data/logo.png create mode 100644 samples/html/help/Makefile.am create mode 100644 samples/html/help/help.cpp create mode 100644 samples/html/help/help.rc create mode 100644 samples/html/help/helpfiles/Index.hhk create mode 100644 samples/html/help/helpfiles/book1.htm create mode 100644 samples/html/help/helpfiles/book2.htm create mode 100644 samples/html/help/helpfiles/contents.hhc create mode 100644 samples/html/help/helpfiles/main.htm create mode 100644 samples/html/help/helpfiles/page2-b.htm create mode 100644 samples/html/help/helpfiles/testing.hhp create mode 100644 samples/html/printing/Makefile.am create mode 100644 samples/html/printing/mondrian.ico create mode 100644 samples/html/printing/mondrian.xpm create mode 100644 samples/html/printing/pic.png create mode 100644 samples/html/printing/printing.cpp create mode 100644 samples/html/printing/printing.h create mode 100644 samples/html/printing/printing.rc create mode 100644 samples/html/printing/test.htm create mode 100644 samples/html/test/Makefile.am create mode 100644 samples/html/test/f.html create mode 100644 samples/html/test/fft.html create mode 100644 samples/html/test/pic.png create mode 100644 samples/html/test/pic2.bmp create mode 100644 samples/html/test/tables.htm create mode 100644 samples/html/test/test.cpp create mode 100644 samples/html/test/test.htm create mode 100644 samples/html/test/test.rc create mode 100644 samples/html/virtual/Makefile.am create mode 100644 samples/html/virtual/start.htm create mode 100644 samples/html/virtual/virtual.cpp create mode 100644 samples/html/virtual/virtual.rc create mode 100644 samples/html/widget/Makefile.am create mode 100644 samples/html/widget/start.htm create mode 100644 samples/html/widget/widget.cpp create mode 100644 samples/html/widget/widget.rc create mode 100644 samples/html/zip/Makefile.am create mode 100644 samples/html/zip/pages.zip create mode 100644 samples/html/zip/start.htm create mode 100644 samples/html/zip/zip.cpp create mode 100644 samples/html/zip/zip.rc create mode 100644 src/common/filesys.cpp create mode 100644 src/common/fs_inet.cpp create mode 100644 src/common/fs_zip.cpp create mode 100644 src/common/unzip.c create mode 100644 src/common/unzip.h create mode 100644 src/common/zipstream.cpp create mode 100644 src/generic/busyinfo.cpp create mode 100644 src/html/bitmaps/back.xpm create mode 100644 src/html/bitmaps/book.xpm create mode 100644 src/html/bitmaps/folder.xpm create mode 100644 src/html/bitmaps/forward.xpm create mode 100644 src/html/bitmaps/page.xpm create mode 100644 src/html/bitmaps/panel.xpm create mode 100644 src/html/htmlcell.cpp create mode 100644 src/html/htmlfilter.cpp create mode 100644 src/html/htmlhelp.cpp create mode 100644 src/html/htmlhelp_io.cpp create mode 100644 src/html/htmlparser.cpp create mode 100644 src/html/htmltag.cpp create mode 100644 src/html/htmlwin.cpp create mode 100644 src/html/htmlwinparser.cpp create mode 100644 src/html/mod_fonts.cpp create mode 100644 src/html/mod_hline.cpp create mode 100644 src/html/mod_image.cpp create mode 100644 src/html/mod_layout.cpp create mode 100644 src/html/mod_links.cpp create mode 100644 src/html/mod_list.cpp create mode 100644 src/html/mod_pre.cpp create mode 100644 src/html/mod_tables.cpp create mode 100644 src/html/search.cpp create mode 100644 src/html/search.h diff --git a/acconfig.h b/acconfig.h index f0b87b500b..e0f7d38429 100644 --- a/acconfig.h +++ b/acconfig.h @@ -533,6 +533,11 @@ */ #define wxUSE_MINIFRAME 0 +/* + * wxHTML + */ +#define wxUSE_HTML 0 + /* * Disable this if your compiler can't cope * with omission of prototype parameters. diff --git a/configure.in b/configure.in index 5e6a6fa14a..3aceaf4cdf 100644 --- a/configure.in +++ b/configure.in @@ -292,6 +292,7 @@ if test $DEBUG_CONFIGURE = 1; then DEFAULT_wxUSE_STARTUP_TIPS=no DEFAULT_wxUSE_PROGRESSDLG=no DEFAULT_wxUSE_MINIFRAME=no + DEFAULT_wxUSE_HTML=no DEFAULT_wxUSE_VALIDATORS=yes DEFAULT_wxUSE_ACCEL=no @@ -391,6 +392,7 @@ else DEFAULT_wxUSE_STARTUP_TIPS=yes DEFAULT_wxUSE_PROGRESSDLG=yes DEFAULT_wxUSE_MINIFRAME=yes + DEFAULT_wxUSE_HTML=no DEFAULT_wxUSE_VALIDATORS=yes DEFAULT_wxUSE_ACCEL=yes @@ -675,6 +677,7 @@ WX_ARG_ENABLE(textdlg, [ --enable-textdlg use wxTextDialog], wxUSE_T WX_ARG_ENABLE(tipdlg, [ --enable-tipdlg use startup tips], wxUSE_STARTUP_TIPS) WX_ARG_ENABLE(progressdlg, [ --enable-progressdlg use wxProgressDialog], wxUSE_PROGRESSDLG) WX_ARG_ENABLE(miniframe, [ --enable-miniframe use wxMiniFrame class], wxUSE_MINIFRAME) +WX_ARG_ENABLE(html, [ --enable-html use wxHTML sub-library], wxUSE_HTML) WX_ARG_ENABLE(tooltips, [ --enable-tooltips use wxToolTip class], wxUSE_TOOLTIPS) WX_ARG_ENABLE(splines, [ --enable-splines use spline drawing code], wxUSE_SPLINES) WX_ARG_ENABLE(validators, [ --enable-validators use wxValidator and derived classes], wxUSE_VALIDATORS) @@ -1993,6 +1996,11 @@ if test "$wxUSE_MINIFRAME" = "yes"; then SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS minifram" fi +if test "$wxUSE_HTML" = "yes"; then + AC_DEFINE(wxUSE_HTML) + SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS html" +fi + if test "$wxUSE_VALIDATORS" = "yes"; then AC_DEFINE(wxUSE_VALIDATORS) SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS validate" @@ -2178,6 +2186,14 @@ dnl samples/Makefile samples/minimal/Makefile samples/validate/Makefile samples/wxpoem/Makefile samples/wxsocket/Makefile + samples/html/Makefile + samples/html/about/Makefile + samples/html/help/Makefile + samples/html/test/Makefile + samples/html/printing/Makefile + samples/html/widget/Makefile + samples/html/virtual/Makefile + samples/html/zip/Makefile ], [ chmod +x wx-config diff --git a/include/wx/busyinfo.h b/include/wx/busyinfo.h new file mode 100644 index 0000000000..b4266a935a --- /dev/null +++ b/include/wx/busyinfo.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: busyinfo.h +// Purpose: Information window (when app is busy) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef __INFOWIN_H__ +#define __INFOWIN_H__ + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + + +#include <wx/dialog.h> + + + + +class wxInfoFrame : public wxFrame +{ + public: + wxInfoFrame(wxWindow *parent, const wxString& message); +}; + + +//-------------------------------------------------------------------------------- +// wxBusyInfo +// Displays progress information +// Can be used in exactly same way as wxBusyCursor +//-------------------------------------------------------------------------------- + +class wxBusyInfo : public wxObject +{ + public: + wxBusyInfo(const wxString& message); + ~wxBusyInfo(); + + private: + wxInfoFrame *m_InfoFrame; +}; + + +#endif + + diff --git a/include/wx/filesys.h b/include/wx/filesys.h new file mode 100644 index 0000000000..5ff10cb25e --- /dev/null +++ b/include/wx/filesys.h @@ -0,0 +1,194 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: filesys.h +// Purpose: class for opening files - virtual file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef __FILESYS_H__ +#define __FILESYS_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include <wx/stream.h> +#include <wx/mimetype.h> +#include <wx/url.h> + + +class wxFSFile; +class wxFileSystemHandler; +class wxFileSystem; + +//-------------------------------------------------------------------------------- +// wxFSFile +// This class is a file opened using wxFileSystem. It consists of +// input stream, location, mime type & optional anchor +// (in 'index.htm#chapter2', 'chapter2' is anchor) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxFSFile : public wxObject +{ + private: + wxInputStream *m_Stream; + wxString m_Location; + wxString m_MimeType; + wxString m_Anchor; + + public: + wxFSFile(wxInputStream *stream, const wxString& loc, const wxString& mimetype, const wxString& anchor) + { + m_Stream = stream; + m_Location = loc; + m_MimeType = mimetype; m_MimeType.MakeLower(); + m_Anchor = anchor; + } + virtual ~wxFSFile() + { + if (m_Stream) delete m_Stream; + } + + wxInputStream *GetStream() const {return m_Stream;} + // returns stream. This doesn't _create_ stream, it only returns + // pointer to it!! + + const wxString& GetMimeType() const {return m_MimeType;} + // returns file's mime type + + const wxString& GetLocation() const {return m_Location;} + // returns the original location (aka filename) of the file + + const wxString& GetAnchor() const {return m_Anchor;} +}; + + + + + +//-------------------------------------------------------------------------------- +// wxFileSystemHandler +// This class is FS handler for wxFileSystem. It provides +// interface to access certain +// kinds of files (HTPP, FTP, local, tar.gz etc..) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxFileSystemHandler : public wxObject +{ + DECLARE_ABSTRACT_CLASS(wxFileSystemHandler) + + public: + wxFileSystemHandler() : wxObject() {} + + virtual bool CanOpen(const wxString& location) = 0; + // returns TRUE if this handler is able to open given location + + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location) = 0; + // opens given file and returns pointer to input stream. + // Returns NULL if opening failed. + // The location is always absolute path. + + protected: + wxString GetProtocol(const wxString& location) const; + // returns protocol ("file", "http", "tar" etc.) The last (most right) + // protocol is used: + // {it returns "tar" for "file:subdir/archive.tar.gz#tar:/README.txt"} + + wxString GetLeftLocation(const wxString& location) const; + // returns left part of address: + // {it returns "file:subdir/archive.tar.gz" for "file:subdir/archive.tar.gz#tar:/README.txt"} + + wxString GetAnchor(const wxString& location) const; + // returns anchor part of address: + // {it returns "anchor" for "file:subdir/archive.tar.gz#tar:/README.txt#anchor"} + // NOTE: anchor is NOT a part of GetLeftLocation()'s return value + + wxString GetRightLocation(const wxString& location) const; + // returns right part of address: + // {it returns "/README.txt" for "file:subdir/archive.tar.gz#tar:/README.txt"} + + wxString GetMimeTypeFromExt(const wxString& location); + // Returns MIME type of the file - w/o need to open it + // (default behaviour is that it returns type based on extension) + + private: + static wxMimeTypesManager m_MimeMng; + // MIME manager + // (it's static and thus shared by all instances and derived classes) +}; + + + + +//-------------------------------------------------------------------------------- +// wxFileSystem +// This class provides simple interface for opening various +// kinds of files (HTPP, FTP, local, tar.gz etc..) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxFileSystem : public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxFileSystem) + + private: + wxString m_Path; + // the path (location) we are currently in + // this is path, not file! + // (so if you opened test/demo.htm, it is + // "test/", not "test/demo.htm") + wxString m_LastName; + // name of last opened file (full path) + static wxList m_Handlers; + // list of FS handlers + + public: + wxFileSystem() : wxObject() {m_Path = m_LastName = wxEmptyString; m_Handlers.DeleteContents(TRUE);} + + void ChangePathTo(const wxString& location, bool is_dir = FALSE); + // sets the current location. Every call to OpenFile is + // relative to this location. + // NOTE !! + // unless is_dir = TRUE 'location' is *not* the directory but + // file contained in this directory + // (so ChangePathTo("dir/subdir/xh.htm") sets m_Path to "dir/subdir/") + + wxString GetPath() const {return m_Path;} + + wxFSFile* OpenFile(const wxString& location); + // opens given file and returns pointer to input stream. + // Returns NULL if opening failed. + // It first tries to open the file in relative scope + // (based on ChangePathTo()'s value) and then as an absolute + // path. + + static void AddHandler(wxFileSystemHandler *handler); + // Adds FS handler. + // In fact, this class is only front-end to the FS hanlers :-) +}; + + +/* + +'location' syntax: + +To determine FS type, we're using standard KDE notation: +file:/absolute/path/file.htm +file:relative_path/xxxxx.html +/some/path/x.file ('file:' is default) +http://www.gnome.org +file:subdir/archive.tar.gz#tar:/README.txt + +special characters : + ':' - FS identificator is before this char + '#' - separator. It can be either HTML anchor ("index.html#news") + (in case there is no ':' in the string to the right from it) + or FS separator + (example : http://www.wxhtml.org/wxhtml-0.1.tar.gz#tar:/include/wxhtml/filesys.h" + this would access tgz archive stored on web) + '/' - directory (path) separator. It is used to determine upper-level path. + HEY! Don't use \ even if you're on Windows! + +*/ + +#endif // __FILESYS_H__ diff --git a/include/wx/fs_inet.h b/include/wx/fs_inet.h new file mode 100644 index 0000000000..695bdb425f --- /dev/null +++ b/include/wx/fs_inet.h @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_inet.h +// Purpose: HTTP and FTP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +/* + +REMARKS : + +This FS creates local cache (in /tmp directory). The cache is freed +on program exit. + +Size of cache is limited to cca 1000 items (due to GetTempFileName +limitation) + + +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/filesys.h> + + + +//-------------------------------------------------------------------------------- +// wxInternetFSHandler +//-------------------------------------------------------------------------------- + +class wxInternetFSHandler : public wxFileSystemHandler +{ + private: + wxHashTable m_Cache; + + public: + virtual bool CanOpen(const wxString& location); + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location); + ~wxInternetFSHandler(); +}; + + diff --git a/include/wx/fs_zip.h b/include/wx/fs_zip.h new file mode 100644 index 0000000000..f0b481d78f --- /dev/null +++ b/include/wx/fs_zip.h @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_zip.h +// Purpose: ZIP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/filesys.h> + + + +//-------------------------------------------------------------------------------- +// wxZipFSHandler +//-------------------------------------------------------------------------------- + +class wxZipFSHandler : public wxFileSystemHandler +{ + public: + virtual bool CanOpen(const wxString& location); + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location); + ~wxZipFSHandler(); +}; + + + diff --git a/include/wx/html/forcelink.h b/include/wx/html/forcelink.h new file mode 100644 index 0000000000..2be0bc0cf6 --- /dev/null +++ b/include/wx/html/forcelink.h @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: forcelink.h +// Purpose: see bellow +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +/* + +DESCRPITON: + +mod_*.cpp files contain handlers for tags. These files are modules - they contain +one wxTagModule class and it's OnInit() method is called from wxApp's init method. +The module is called even if you only link it into the executable, so everything +seems wonderful. + +The problem is that we have these modules in LIBRARY and mod_*.cpp files contain +no method nor class which is known out of the module. So the linker won't +link these .o/.obj files into executable because it detected that it is not used +by the program. + +To workaround this I introduced set of macros FORCE_LINK_ME and FORCE_LINK. These +macros are generic and are not limited to mod_*.cpp files. You may find them quite +useful somewhere else... + +How to use them: +let's suppose you want to always link file foo.cpp and that you have module +always.cpp that is certainly always linked (e.g. the one with main() function +or htmlwin.cpp in wxHtml library). + +Place FORCE_LINK_ME(foo) somewhere in foo.cpp and FORCE_LINK(foo) somewhere +in always.cpp +See mod_*.cpp and htmlwin.cpp for example :-) + +*/ + + +#ifndef __FORCELINK_H__ +#define __FORCELINK_H__ + + + +// This must be part of the module you want to force: +#define FORCE_LINK_ME(module_name) \ + int _link_dummy_func_##module_name () \ + { \ + return 1; \ + } + + +// And this must be somewhere where it certainly will be linked: +#define FORCE_LINK(module_name) \ + extern int _link_dummy_func_##module_name (); \ + static int _link_dummy_var_##module_name = \ + _link_dummy_func_##module_name (); + + +#endif // __FORCELINK_H__ diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h new file mode 100644 index 0000000000..23293c93b0 --- /dev/null +++ b/include/wx/html/htmlcell.h @@ -0,0 +1,292 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlcell.h +// Purpose: wxHtmlCell class is used by wxHtmlWindow/wxHtmlWinParser +// as a basic visual element of HTML page +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLCELL_H__ +#define __HTMLCELL_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + + +#include <wx/html/htmltag.h> +#include <wx/html/htmldefs.h> +#include <wx/window.h> + +class wxHtmlCell; +class wxHtmlContainerCell; + +//-------------------------------------------------------------------------------- +// wxHtmlCell +// Internal data structure. It represents fragments of parsed HTML +// page - a word, picture, table, horizontal line and so on. +// It is used by wxHtmlWindow to represent HTML page in memory. +//-------------------------------------------------------------------------------- + + +class WXDLLEXPORT wxHtmlCell : public wxObject +{ + protected: + wxHtmlCell *m_Next; + // pointer to the next cell + wxHtmlContainerCell *m_Parent; + // pointer to parent cell + long m_Width, m_Height, m_Descent; + // dimensions of fragment + // m_Descent is used to position text&images.. + long m_PosX, m_PosY; + // position where the fragment is drawn + wxString m_Link; + // destination address if this fragment is hypertext link, "" otherwise + + public: + wxHtmlCell() : wxObject() {m_Next = NULL; m_Parent = NULL; m_Width = m_Height = m_Descent = 0;}; + virtual ~wxHtmlCell() {if (m_Next) delete m_Next;}; + + void SetParent(wxHtmlContainerCell *p) {m_Parent = p;} + wxHtmlContainerCell *GetParent() const {return m_Parent;} + + int GetPosX() const {return m_PosX;} + int GetPosY() const {return m_PosY;} + int GetWidth() const {return m_Width;} + int GetHeight() const {return m_Height;} + int GetDescent() const {return m_Descent;} + virtual wxString GetLink(int x = 0, int y = 0) const {return m_Link;} + // returns the link associated with this cell. The position is position within + // the cell so it varies from 0 to m_Width, from 0 to m_Height + wxHtmlCell *GetNext() const {return m_Next;} + // members access methods + + virtual void SetPos(int x, int y) {m_PosX = x, m_PosY = y;} + void SetLink(const wxString& link) {m_Link = link;} + void SetNext(wxHtmlCell *cell) {m_Next = cell;} + // members writin methods + + virtual void Layout(int w) {SetPos(0, 0); if (m_Next) m_Next -> Layout(w);}; + // 1. adjust cell's width according to the fact that maximal possible width is w. + // (this has sense when working with horizontal lines, tables etc.) + // 2. prepare layout (=fill-in m_PosX, m_PosY (and sometime m_Height) members) + // = place items to fit window, according to the width w + + virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) {if (m_Next) m_Next -> Draw(dc, x, y, view_y1, view_y2);} + // renders the cell + + virtual void DrawInvisible(wxDC& dc, int x, int y) {if (m_Next) m_Next -> DrawInvisible(dc, x, y);}; + // proceed drawing actions in case the cell is not visible (scrolled out of screen). + // This is needed to change fonts, colors and so on + + virtual const wxHtmlCell* Find(int condition, const void* param) const {if (m_Next) return m_Next -> Find(condition, param); else return NULL;} + // This method returns pointer to the FIRST cell for that + // the condition + // is true. It first checks if the condition is true for this + // cell and then calls m_Next -> Find(). (Note: it checks + // all subcells if the cell is container) + // Condition is unique condition identifier (see htmldefs.h) + // (user-defined condition IDs should start from 10000) + // and param is optional parameter + // Example : m_Cell -> Find(HTML_COND_ISANCHOR, "news"); + // returns pointer to anchor news + + virtual void OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right); + // This function is called when mouse button is clicked over the cell. + // left, middle, right are flags indicating whether the button was or wasn't + // pressed. + // Parent is pointer to wxHtmlWindow that generated the event + // HINT: if this handling is not enough for you you should use + // wxHtmlBinderCell +}; + + + + +//-------------------------------------------------------------------------------- +// Inherited cells: +//-------------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------------- +// wxHtmlWordCell +// Single word in input stream. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlWordCell : public wxHtmlCell +{ + protected: + wxString m_Word; + + public: + wxHtmlWordCell(const wxString& word, wxDC& dc); + void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); +}; + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlContainerCell +// Container - it contains other cells. Basic of layout algorithm. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlContainerCell : public wxHtmlCell +{ + protected: + int m_IndentLeft, m_IndentRight, m_IndentTop, m_IndentBottom; + // indentation of subcells. There is always m_Indent pixels + // big space between given border of the container and the subcells + // it m_Indent < 0 it is in PERCENTS, otherwise it is in pixels + int m_MinHeight, m_MinHeightAlign; + // minimal height. + int m_MaxLineWidth; + // maximal widht of line. Filled during Layout() + wxHtmlCell *m_Cells, *m_LastCell; + // internal cells, m_Cells points to the first of them, m_LastCell to the last one. + // (LastCell is needed only to speed-up InsertCell) + int m_AlignHor, m_AlignVer; + // alignment horizontal and vertical (left, center, right) + int m_WidthFloat, m_WidthFloatUnits; + // width float is used in adjustWidth + bool m_UseBkColour; + wxColour m_BkColour; + // background color of this container + bool m_UseBorder; + wxColour m_BorderColour1, m_BorderColour2; + // borders color of this container + + public: + wxHtmlContainerCell(wxHtmlContainerCell *parent); + ~wxHtmlContainerCell() {if (m_Cells) delete m_Cells;} + + virtual void Layout(int w); + virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); + virtual void DrawInvisible(wxDC& dc, int x, int y); + + void InsertCell(wxHtmlCell *cell); + // insert cell at the end of m_Cells list + void SetAlignHor(int al) {m_AlignHor = al;} + int GetAlignHor() const {return m_AlignHor;} + void SetAlignVer(int al) {m_AlignVer = al;} + // sets horizontal/vertical alignment + int GetAlignVer() const {return m_AlignVer;} + void SetIndent(int i, int what, int units = HTML_UNITS_PIXELS); + // sets left-border indentation. units is one of HTML_UNITS_* constants + // what is combination of HTML_INDENT_* + int GetIndent(int ind) const; + // returns the indentation. ind is one of HTML_INDENT_* constants + int GetIndentUnits(int ind) const; + // returns type of value returned by GetIndent(ind) + void SetAlign(const wxHtmlTag& tag); + // sets alignment info based on given tag's params + void SetWidthFloat(int w, int units) {m_WidthFloat = w; m_WidthFloatUnits = units;} + void SetWidthFloat(const wxHtmlTag& tag); + // sets floating width adjustment + // (examples : 32 percent of parent container, + // -15 pixels percent (this means 100 % - 15 pixels) + void SetMinHeight(int h, int align = HTML_ALIGN_TOP) {m_MinHeight = h; m_MinHeightAlign = align;} + // sets minimal height of this container. + int GetMaxLineWidth() const {return m_MaxLineWidth;} + // returns maximal line width in this container. + // Call to this method is valid only after calling + // Layout() + void SetBackgroundColour(const wxColour& clr) {m_UseBkColour = TRUE; m_BkColour = clr;} + void SetBorder(const wxColour& clr1, const wxColour& clr2) {m_UseBorder = TRUE; m_BorderColour1 = clr1, m_BorderColour2 = clr2;} + virtual wxString GetLink(int x = 0, int y = 0) const; + virtual const wxHtmlCell* Find(int condition, const void* param) const; + virtual void OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right); + + wxHtmlCell* GetFirstCell() {return m_Cells;} + // returns pointer to the first cell in container or NULL +}; + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlColourCell +// Color changer. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlColourCell : public wxHtmlCell +{ + public: + wxColour m_Colour; + unsigned m_Flags; + + wxHtmlColourCell(wxColour clr, int flags = HTML_CLR_FOREGROUND) : wxHtmlCell() {m_Colour = clr; m_Flags = flags;} + virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); + virtual void DrawInvisible(wxDC& dc, int x, int y); +}; + + + + +//-------------------------------------------------------------------------------- +// wxHtmlFontCell +// Sets actual font used for text rendering +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlFontCell : public wxHtmlCell +{ + public: + wxFont *m_Font; + + wxHtmlFontCell(wxFont *font) : wxHtmlCell() {m_Font = font;}; + virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); + virtual void DrawInvisible(wxDC& dc, int x, int y); +}; + + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlwidgetCell +// This cell is connected with wxWindow object +// You can use it to insert windows into HTML page +// (buttons, input boxes etc.) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlWidgetCell : public wxHtmlCell +{ + protected: + wxWindow* m_Wnd; + int m_WidthFloat; + // width float is used in adjustWidth (it is in percents) + + public: + wxHtmlWidgetCell(wxWindow *wnd, int w = 0); + // !!! wnd must have correct parent! + // if w != 0 then the m_Wnd has 'floating' width - it adjust + // it's width according to parent container's width + // (w is percent of parent's width) + virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); + virtual void DrawInvisible(wxDC& dc, int x, int y); + virtual void Layout(int w); +}; + + + + +#endif // __HTMLCELL_H__ + +#endif + + + + + + + + diff --git a/include/wx/html/htmldefs.h b/include/wx/html/htmldefs.h new file mode 100644 index 0000000000..88d5602683 --- /dev/null +++ b/include/wx/html/htmldefs.h @@ -0,0 +1,94 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmldefs.h +// Purpose: constants for wxhtml library +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLDEFS_H__ +#define __HTMLDEFS_H__ + +#include "wx/defs.h" +#if wxUSE_HTML + + +//-------------------------------------------------------------------------------- +// ALIGNMENTS +// Describes alignment of text etc. in containers +//-------------------------------------------------------------------------------- + +#define HTML_ALIGN_LEFT 0x0000 +#define HTML_ALIGN_RIGHT 0x0002 + +#define HTML_ALIGN_TOP 0x0004 +#define HTML_ALIGN_BOTTOM 0x0008 + +#define HTML_ALIGN_CENTER 0x0001 + + + +//-------------------------------------------------------------------------------- +// COLOR MODES +// Used by wxHtmlColourCell to determine clr of what is changing +//-------------------------------------------------------------------------------- + +#define HTML_CLR_FOREGROUND 0x0001 +#define HTML_CLR_BACKGROUND 0x0002 + + + +//-------------------------------------------------------------------------------- +// UNITS +// Used to specify units +//-------------------------------------------------------------------------------- + +#define HTML_UNITS_PIXELS 0x0001 +#define HTML_UNITS_PERCENT 0x0002 + + + +//-------------------------------------------------------------------------------- +// INDENTS +// Used to specify indetation relatives +//-------------------------------------------------------------------------------- + +#define HTML_INDENT_LEFT 0x0010 +#define HTML_INDENT_RIGHT 0x0020 +#define HTML_INDENT_TOP 0x0040 +#define HTML_INDENT_BOTTOM 0x0080 + +#define HTML_INDENT_HORIZONTAL HTML_INDENT_LEFT | HTML_INDENT_RIGHT +#define HTML_INDENT_VERTICAL HTML_INDENT_TOP | HTML_INDENT_BOTTOM +#define HTML_INDENT_ALL HTML_INDENT_VERTICAL | HTML_INDENT_HORIZONTAL + + + + +//-------------------------------------------------------------------------------- +// FIND CONDITIONS +// Identifiers of wxHtmlCell's Find() conditions +//-------------------------------------------------------------------------------- + +#define HTML_COND_ISANCHOR 1 + // Finds the anchor of 'param' name (pointer to wxString). + +#define HTML_COND_USER 10000 + // User-defined conditions should start from this number + + +//-------------------------------------------------------------------------------- +// INTERNALS +// wxHTML internal constants +//-------------------------------------------------------------------------------- + +#define HTML_SCROLL_STEP 16 + /* size of one scroll step of wxHtmlWindow in pixels */ +#define HTML_BUFLEN 1024 + /* size of temporary buffer used during parsing */ +#define HTML_REALLOC_STEP 32 + /* steps of array reallocation */ + +#endif +#endif \ No newline at end of file diff --git a/include/wx/html/htmlfilter.h b/include/wx/html/htmlfilter.h new file mode 100644 index 0000000000..99b00d8de6 --- /dev/null +++ b/include/wx/html/htmlfilter.h @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlfilter.h +// Purpose: filters +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLFILTER_H__ +#define __HTMLFILTER_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/filesys.h> + + +//-------------------------------------------------------------------------------- +// wxHtmlFilter +// This class is input filter. It can "translate" files +// in non-HTML format to HTML format +// interface to access certain +// kinds of files (HTPP, FTP, local, tar.gz etc..) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlFilter : public wxObject +{ + DECLARE_ABSTRACT_CLASS(wxHtmlFilter) + + public: + wxHtmlFilter() : wxObject() {} + + virtual bool CanRead(const wxFSFile& file) = 0; + // returns TRUE if this filter is able to open&read given file + + virtual wxString ReadFile(const wxFSFile& file) = 0; + // reads given file and returns HTML document. + // Returns empty string if opening failed +}; + + + +//-------------------------------------------------------------------------------- +// wxHtmlFilterPlainText +// This filter is used as default filter if no other can +// be used (= uknown type of file). It is used by +// wxHtmlWindow itself. +//-------------------------------------------------------------------------------- + + +class WXDLLEXPORT wxHtmlFilterPlainText : public wxHtmlFilter +{ + DECLARE_DYNAMIC_CLASS(wxHtmlFilterPlainText) + + public: + virtual bool CanRead(const wxFSFile& file); + virtual wxString ReadFile(const wxFSFile& file); +}; + + + + +#endif // __HTMLFILTER_H__ + +#endif \ No newline at end of file diff --git a/include/wx/html/htmlhelp.h b/include/wx/html/htmlhelp.h new file mode 100644 index 0000000000..6e56bc5815 --- /dev/null +++ b/include/wx/html/htmlhelp.h @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlhelp.h +// Purpose: Help controller +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLHELP_H__ +#define __HTMLHELP_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/window.h> +#include <wx/config.h> +#include <wx/splitter.h> +#include <wx/notebook.h> +#include <wx/listctrl.h> +#include <wx/html/htmlwin.h> + + + +//-------------------------------------------------------------------------------- +// helper classes & structs - please ignore 'em +//-------------------------------------------------------------------------------- + + + +class WXDLLEXPORT HtmlBookRecord : public wxObject +{ + public: + wxString m_BasePath; + wxString m_Title; + wxString m_Start; + + HtmlBookRecord(const wxString& basepath, const wxString& title, const wxString& start) {m_BasePath = basepath; m_Title = title; m_Start = start;} + wxString GetTitle() const {return m_Title;} + wxString GetStart() const {return m_Start;} + wxString GetBasePath() const {return m_BasePath;} +}; + + +#undef WXDLLEXPORTLOCAL +#define WXDLLEXPORTLOCAL WXDLLEXPORT + // ?? Don't know why - but Allen Van Sickel reported it to fix problems with DLL +WX_DECLARE_OBJARRAY(HtmlBookRecord, HtmlBookRecArray); + +#undef WXDLLEXPORTLOCAL +#define WXDLLEXPORTLOCAL + + +typedef struct + { + short int m_Level; + int m_ID; + char* m_Name; + char* m_Page; + HtmlBookRecord *m_Book; + } HtmlContentsItem; + + + + +//-------------------------------------------------------------------------------- +// wxHtmlHelpController +// This class ensures dislaying help. +// See documentation for details on its philosophy. +// +// WARNING!! +// This class is not derived from wxHelpController and is not +// compatible with it! +//-------------------------------------------------------------------------------- + + +class WXDLLEXPORT wxHtmlHelpController : public wxEvtHandler +{ + DECLARE_DYNAMIC_CLASS(wxHtmlHelpController) + + protected: + wxConfigBase *m_Config; + wxString m_ConfigRoot; + // configuration file/registry used to store custom settings + wxString m_TitleFormat; + // title of the help frame + wxString m_TempPath; + + wxFrame *m_Frame; + wxHtmlWindow *m_HtmlWin; + wxSplitterWindow *m_Splitter; + wxNotebook *m_NavigPan; + wxTreeCtrl *m_ContentsBox; + wxImageList *m_ContentsImageList; + wxListBox *m_IndexBox; + wxTextCtrl *m_SearchText; + wxButton *m_SearchButton; + wxListBox *m_SearchList; + // ...pointers to parts of help window + + struct { + long x, y, w, h; + long sashpos; + bool navig_on; + } m_Cfg; + // settings (window size, position, sash pos etc..) + + HtmlBookRecArray m_BookRecords; + // each book has one record in this array + HtmlContentsItem* m_Contents; + int m_ContentsCnt; + // list of all available books and pages. + HtmlContentsItem* m_Index; + int m_IndexCnt; + // list of index items + + public: + wxHtmlHelpController(); + ~wxHtmlHelpController(); + + void SetTitleFormat(const wxString& format) {m_TitleFormat = format;} + // Sets format of title of the frame. Must contain exactly one "%s" + // (for title of displayed HTML page) + + void SetTempDir(const wxString& path); + // Sets directory where temporary files are stored. + // These temp files are index & contents file in binary (much faster to read) + // form. These files are NOT deleted on program's exit. + + bool AddBook(const wxString& book, bool show_wait_msg = FALSE); + // Adds new book. 'book' is location of .htb file (stands for "html book"). + // See documentation for details on its format. + // Returns success. + // If show_wait_msg == true then message window with "loading book..." is displayed + + void Display(const wxString& x); + // Displays page x. If not found it will offect the user a choice of searching + // books. + // Looking for the page runs in these steps: + // 1. try to locate file named x (if x is for example "doc/howto.htm") + // 2. try to open starting page of book x + // 3. try to find x in contents (if x is for example "How To ...") + // 4. try to find x in index (if x is for example "How To ...") + // 5. offer searching and if the user agree, run KeywordSearch + void Display(const int id); + // Alternative version that works with numeric ID. + // (uses extension to MS format, <param name="ID" value=id>, see docs) + + void DisplayContents(); + // Displays help window and focuses contents. + + void DisplayIndex(); + // Displays help window and focuses index. + + bool KeywordSearch(const wxString& keyword); + // Searches for keyword. Returns TRUE and display page if found, return + // FALSE otherwise + // Syntax of keyword is Altavista-like: + // * words are separated by spaces + // (but "\"hello world\"" is only one world "hello world") + // * word may be pretended by + or - + // (+ : page must contain the word ; - : page can't contain the word) + // * if there is no + or - before the word, + is default + + void UseConfig(wxConfigBase *config, const wxString& rootpath = wxEmptyString) {m_Config = config; m_ConfigRoot = rootpath;} + // Assigns config object to the controller. This config is then + // used in subsequent calls to Read/WriteCustomization of both help + // controller and it's wxHtmlWindow + + void ReadCustomization(wxConfigBase *cfg, wxString path = wxEmptyString); + // saves custom settings into cfg config. it will use the path 'path' + // if given, otherwise it will save info into currently selected path. + // saved values : things set by SetFonts, SetBorders. + void WriteCustomization(wxConfigBase *cfg, wxString path = wxEmptyString); + // ... + + protected: + virtual void CreateHelpWindow(); + // Creates frame & html window and sets m_Frame and other variables; + // Do nothing if the window already exists + void RefreshLists(); + // Refreshes Contents and Index tabs + void CreateContents(); + // Adds items to m_Contents tree control + void CreateIndex(); + // Adds items to m_IndexList + + void LoadMSProject(HtmlBookRecord *book, wxFileSystem& fsys, const wxString& indexfile, const wxString& contentsfile, bool show_wait_msg); + // Imports .hhp files (MS HTML Help Workshop) + void LoadCachedBook(HtmlBookRecord *book, wxInputStream *f); + // Reads binary book + void SaveCachedBook(HtmlBookRecord *book, wxOutputStream *f); + // Writes binary book + + void OnToolbar(wxCommandEvent& event); + void OnContentsSel(wxTreeEvent& event); + void OnIndexSel(wxCommandEvent& event); + void OnSearchSel(wxCommandEvent& event); + void OnSearch(wxCommandEvent& event); + void OnCloseWindow(wxCloseEvent& event); + + DECLARE_EVENT_TABLE() +}; + + + +#endif // __HTMLHELP_H__ + +#endif + + + + + + + + + + diff --git a/include/wx/html/htmlparser.h b/include/wx/html/htmlparser.h new file mode 100644 index 0000000000..d1c6a65070 --- /dev/null +++ b/include/wx/html/htmlparser.h @@ -0,0 +1,176 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlparser.h +// Purpose: wxHtmlParser class (generic parser) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLPARSER_H__ +#define __HTMLPARSER_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/htmltag.h> +#include <wx/filesys.h> + +class wxHtmlParser; +class wxHtmlTagHandler; + +//-------------------------------------------------------------------------------- +// wxHtmlParser +// This class handles generic parsing of HTML document : it scans +// the document and divide it into blocks of tags (where one block +// consists of starting and ending tag and of text between these +// 2 tags. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlParser : public wxObject +{ + DECLARE_ABSTRACT_CLASS(wxHtmlParser) + + protected: + wxString m_Source; + // source being parsed + wxHtmlTagsCache *m_Cache; + // tags cache, used during parsing. + wxHashTable m_HandlersHash; + wxList m_HandlersList; + // handlers that handle particular tags. The table is accessed by + // key = tag's name. + // This attribute MUST be filled by derived class otherwise it would + // be empty and no tags would be recognized + // (see wxHtmlWinParser for details about filling it) + // m_HandlersHash is for random access based on knowledge of tag name (BR, P, etc.) + // it may (and often does) contain more references to one object + // m_HandlersList is list of all handlers and it is guaranteed to contain + // only one reference to each handler instance. + wxFileSystem *m_FS; + // class for opening files (file system) + + public: + wxHtmlParser() : wxObject(), m_HandlersHash(wxKEY_STRING) {m_FS = NULL; m_Cache = NULL;} + virtual ~wxHtmlParser(); + + void SetFS(wxFileSystem *fs) {m_FS = fs;} + // Sets the class which will be used for opening files + wxFileSystem* GetFS() const {return m_FS;} + + wxObject* Parse(const wxString& source); + // You can simply call this method when you need parsed output. + // This method does these things: + // 1. call InitParser(source); + // 2. call DoParsing(); + // 3. call GetProduct(); (it's return value is then returned) + // 4. call DoneParser(); + + virtual void InitParser(const wxString& source); + // Sets the source. This must be called before running Parse() method. + virtual void DoneParser(); + // This must be called after Parse(). + + void DoParsing(int begin_pos, int end_pos); + inline void DoParsing() {DoParsing(0, m_Source.Length());}; + // Parses the m_Source from begin_pos to end_pos-1. + // (in noparams version it parses whole m_Source) + + virtual wxObject* GetProduct() = 0; + // Returns product of parsing + // Returned value is result of parsing of the part. The type of this result + // depends on internal representation in derived parser + // (see wxHtmlWinParser for details). + + virtual void AddTagHandler(wxHtmlTagHandler *handler); + // adds handler to the list & hash table of handlers. + + wxString* GetSource() {return &m_Source;} + + virtual wxList* GetTempData() {return NULL;} + // this method returns list of wxObjects that represents + // all data allocated by the parser. These can't be freeded + // by destructor because they must be valid as long as + // GetProduct's return value is valid - the caller must + // explicitly call delete MyParser -> GetTempData() to free + // the memory + // (this method always sets the list to delete its contents) + + protected: + + virtual void AddText(const char* txt) = 0; + // Adds text to the output. + // This is called from Parse() and must be overriden in derived classes. + // txt is not guaranteed to be only one word. It is largest continuous part of text + // (= not broken by tags) + // NOTE : using char* because of speed improvements + + virtual void AddTag(const wxHtmlTag& tag); + // Adds tag and proceeds it. Parse() may (and usually is) called from this method. + // This is called from Parse() and may be overriden. + // Default behavior is that it looks for proper handler in m_Handlers. The tag is + // ignored if no hander is found. + // Derived class is *responsible* for filling in m_Handlers table. +}; + + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlTagHandler +// This class (and derived classes) cooperates with wxHtmlParser. +// Each recognized tag is passed to handler which is capable +// of handling it. Each tag is handled in 3 steps: +// 1. Handler will modifies state of parser +// (using it's public methods) +// 2. Parser parses source between starting and ending tag +// 3. Handler restores original state of the parser +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlTagHandler : public wxObject +{ + DECLARE_ABSTRACT_CLASS(wxHtmlTagHandler) + + protected: + wxHtmlParser *m_Parser; + + public: + wxHtmlTagHandler() : wxObject () {m_Parser = NULL;}; + + virtual void SetParser(wxHtmlParser *parser) {m_Parser = parser;} + // Sets the parser. + // NOTE : each _instance_ of handler is guaranteed to be called + // only by one parser. This means you don't have to care about + // reentrancy. + + virtual wxString GetSupportedTags() = 0; + // Returns list of supported tags. The list is in uppercase and + // tags are delimited by ','. + // Example : "I,B,FONT,P" + // is capable of handling italic, bold, font and paragraph tags + + virtual bool HandleTag(const wxHtmlTag& tag) = 0; + // This is hadling core method. It does all the Steps 1-3. + // To process step 2, you can call ParseInner() + // returned value : TRUE if it called ParseInner(), + // FALSE etherwise + + protected: + void ParseInner(const wxHtmlTag& tag) {m_Parser -> DoParsing(tag.GetBeginPos(), tag.GetEndPos1());} + // parses input between beginning and ending tag. + // m_Parser must be set. +}; + + + + + +#endif // __HTMLPARSER_H__ + +#endif diff --git a/include/wx/html/htmltag.h b/include/wx/html/htmltag.h new file mode 100644 index 0000000000..2f6a443e58 --- /dev/null +++ b/include/wx/html/htmltag.h @@ -0,0 +1,135 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmltag.h +// Purpose: wxHtmlTag class (represents single tag) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLTAG_H__ +#define __HTMLTAG_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + + +//-------------------------------------------------------------------------------- +// wxHtmlTagsCache +// !! INTERNAL STRUCTURE !! Do not use in your program! +// This structure contains information on positions of tags +// in the string being parsed +//-------------------------------------------------------------------------------- + +typedef struct { + int Key; + // this is "pos" value passed to wxHtmlTag's constructor. + // it is position of '<' character of the tag + int End1, End2; + // end positions for the tag: + // end1 is '<' of ending tag, + // end2 is '>' or both are + // -1 if there is no ending tag for this one... + // or -2 if this is ending tag </...> + char *Name; + // name of this tag + } sCacheItem; + + + +class wxHtmlTagsCache : public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxHtmlTagsCache) + + private: + sCacheItem *m_Cache; + int m_CacheSize; + int m_CachePos; + + public: + wxHtmlTagsCache() : wxObject() {m_CacheSize = 0; m_Cache = NULL;} + wxHtmlTagsCache(const wxString& source); + ~wxHtmlTagsCache() {free(m_Cache);} + + void QueryTag(int at, int* end1, int* end2); + // Finds parameters for tag starting at at and fills the variables +}; + + + +//-------------------------------------------------------------------------------- +// wxHtmlTag +// This represents single tag. It is used as internal structure +// by wxHtmlParser. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlTag : public wxObject +{ + DECLARE_CLASS(wxHtmlTag) + + private: + wxString m_Name, m_Params; + int m_Begin, m_End1, m_End2; + bool m_Ending; + + public: + wxHtmlTag(const wxString& source, int pos, int end_pos, wxHtmlTagsCache* cache); + // constructs wxHtmlTag object based on HTML tag. + // The tag begins (with '<' character) at position pos in source + // end_pos is position where parsing ends (usually end of document) + + inline wxString GetName() const {return m_Name;}; + // Returns tag's name in uppercase. + + bool HasParam(const wxString& par) const; + // Returns TRUE if the tag has given parameter. Parameter + // should always be in uppercase. + // Example : <IMG SRC="test.jpg"> HasParam("SRC") returns TRUE + + wxString GetParam(const wxString& par, bool with_commas = FALSE) const; + // Returns value of the param. Value is in uppercase unless it is + // enclosed with " + // Example : <P align=right> GetParam("ALIGN") returns (RIGHT) + // <P IMG SRC="WhaT.jpg"> GetParam("SRC") returns (WhaT.jpg) + // (or ("WhaT.jpg") if with_commas == TRUE) + + void ScanParam(const wxString& par, char *format, ...) const; + // Scans param like scanf() functions family do. + // Example : ScanParam("COLOR", "\"#%X\"", &clr); + // This is always with with_commas=FALSE + + inline const wxString& GetAllParams() const {return m_Params;}; + // Returns string containing all params. + + inline bool IsEnding() const {return m_Ending;}; + // return TRUE if this is ending tag (</something>) or FALSE + // if it isn't (<something>) + + inline bool HasEnding() const {return m_End1 >= 0;}; + // return TRUE if this is ending tag (</something>) or FALSE + // if it isn't (<something>) + + inline int GetBeginPos() const {return m_Begin;}; + // returns beginning position of _internal_ block of text + // See explanation (returned value is marked with *): + // bla bla bla <MYTAG>* bla bla intenal text</MYTAG> bla bla + inline int GetEndPos1() const {return m_End1;}; + // returns ending position of _internal_ block of text. + // bla bla bla <MYTAG> bla bla intenal text*</MYTAG> bla bla + inline int GetEndPos2() const {return m_End2;}; + // returns end position 2 : + // bla bla bla <MYTAG> bla bla internal text</MYTAG>* bla bla +}; + + + + + + +#endif // __HTMLTAG_H__ + +#endif diff --git a/include/wx/html/htmlwin.h b/include/wx/html/htmlwin.h new file mode 100644 index 0000000000..351e000d0c --- /dev/null +++ b/include/wx/html/htmlwin.h @@ -0,0 +1,220 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlwin.h +// Purpose: wxHtmlWindow class for parsing & displaying HTML +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLWIN_H__ +#define __HTMLWIN_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/window.h> +#include <wx/config.h> +#include <wx/treectrl.h> +#include <wx/html/htmlwinparser.h> +#include <wx/html/htmlcell.h> +#include <wx/filesys.h> +#include <wx/html/htmlfilter.h> + + +//-------------------------------------------------------------------------------- +// wxHtmlWindow +// (This is probably the only class you will directly use.) +// Purpose of this class is to display HTML page (either local +// file or downloaded via HTTP protocol) in a window. Width +// of window is constant - given in constructor - virtual height +// is changed dynamicly depending on page size. +// Once the window is created you can set it's content by calling +// SetPage(text) or LoadPage(filename). +//-------------------------------------------------------------------------------- + + +// item of history list +class WXDLLEXPORT HtmlHistoryItem : public wxObject +{ + private: + wxString m_Page; + wxString m_Anchor; + int m_Pos; + + public: + HtmlHistoryItem(const wxString& p, const wxString& a) {m_Page = p, m_Anchor = a, m_Pos = 0;} + int GetPos() const {return m_Pos;} + void SetPos(int p) {m_Pos = p;} + const wxString& GetPage() const {return m_Page;} + const wxString& GetAnchor() const {return m_Anchor;} +}; + +#undef WXDLLEXPORTLOCAL +#define WXDLLEXPORTLOCAL WXDLLEXPORT + // ?? Don't know why - but Allen Van Sickel reported it to fix problems with DLL + +WX_DECLARE_OBJARRAY(HtmlHistoryItem, HtmlHistoryArray); + +#undef WXDLLEXPORTLOCAL +#define WXDLLEXPORTLOCAL + + +class WXDLLEXPORT wxHtmlWindow : public wxScrolledWindow +{ + DECLARE_DYNAMIC_CLASS(wxHtmlWindow) + + protected: + wxHtmlContainerCell *m_Cell; + // This is pointer to the first cell in parsed data. + // (Note: the first cell is usually top one = all other cells are sub-cells of this one) + wxHtmlWinParser *m_Parser; + // parser which is used to parse HTML input. + // Each wxHtmlWindow has it's own parser because sharing one global + // parser would be problematic (because of reentrancy) + wxString m_OpenedPage; + // contains name of actualy opened page or empty string if no page opened + wxString m_OpenedAnchor; + // contains name of current anchor within m_OpenedPage + wxFileSystem* m_FS; + // class for opening files (file system) + + wxFrame *m_RelatedFrame; + wxString m_TitleFormat; + int m_RelatedStatusBar; + // frame in which page title should be displayed & number of it's statusbar + // reserved for usage with this html window + + int m_Borders; + // borders (free space between text and window borders) + // defaults to 10 pixels. + + bool m_Scrollable; + // TRUE if you can scroll the window. + // If it is FALSE you can't scroll the window even if it's contents is larger + // than window. + + + private: + bool m_tmpMouseMoved; + // a flag indicated if mouse moved + // (if TRUE we will try to change cursor in last call to OnIdle) + bool m_tmpCanDraw; + // if FALSE contents of the window is not redrawn + // (in order to avoid ugly bliking) + + static wxList m_Filters; + // list of HTML filters + static wxHtmlFilterPlainText m_DefaultFilter; + // this filter is used when no filter is able to read some file + + HtmlHistoryArray m_History; + int m_HistoryPos; + // browser history + bool m_HistoryOn; + // if this FLAG is false, items are not added to history + + public: + wxHtmlWindow() : wxScrolledWindow() {}; + wxHtmlWindow(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + const wxString& name = "htmlWindow", bool scrollable = TRUE); + ~wxHtmlWindow(); + + bool SetPage(const wxString& source); + // Set HTML page and display it. !! source is HTML document itself, + // it is NOT address/filename of HTML document. If you want to + // specify document location, use LoadPage() istead + // Return value : FALSE if an error occured, TRUE otherwise + + bool LoadPage(const wxString& location); + // Load HTML page from given location. Location can be either + // a) /usr/wxGTK2/docs/html/wx.htm + // b) http://www.somewhere.uk/document.htm + // c) ftp://ftp.somesite.cz/pub/something.htm + // In case there is no prefix (http:,ftp:), the method + // will try to find it itself (1. local file, then http or ftp) + // After the page is loaded, the method calls SetPage() to display it. + // Note : you can also use path relative to previously loaded page + // Return value : same as SetPage + + wxString GetOpenedPage() const {return m_OpenedPage;} + // Returns full location of opened page + + void SetRelatedFrame(wxFrame* frame, const wxString& format); + // sets frame in which page title will be displayed. Format is format of + // frame title, e.g. "HtmlHelp : %s". It must contain exactly one %s + wxFrame* GetRelatedFrame() const {return m_RelatedFrame;} + + void SetRelatedStatusBar(int bar); + // after(!) calling SetRelatedFrame, this sets statusbar slot where messages + // will be displayed. Default is -1 = no messages. + + void SetFonts(wxString normal_face, int normal_italic_mode, wxString fixed_face, int fixed_italic_mode, int *sizes); + // sets fonts to be used when displaying HTML page. + // *_italic_mode can be either wxSLANT or wxITALIC + + void SetTitle(const wxString& title); + // Sets the title of the window + // (depending on the information passed to SetRelatedFrame() method) + + void SetBorders(int b) {m_Borders = b;} + // Sets space between text and window borders. + + virtual void ReadCustomization(wxConfigBase *cfg, wxString path = wxEmptyString); + // saves custom settings into cfg config. it will use the path 'path' + // if given, otherwise it will save info into currently selected path. + // saved values : things set by SetFonts, SetBorders. + virtual void WriteCustomization(wxConfigBase *cfg, wxString path = wxEmptyString); + // ... + + bool HistoryBack(); + bool HistoryForward(); + // Goes to previous/next page (in browsing history) + // Returns TRUE if successful, FALSE otherwise + void HistoryClear(); + // Resets history + + wxHtmlContainerCell* GetInternalRepresentation() const {return m_Cell;} + // Returns pointer to conteiners/cells structure. + // It should be used ONLY when printing + + static void AddFilter(wxHtmlFilter *filter); + // Adds input filter + + virtual void OnLinkClicked(const wxString& link); + // called when users clicked on hypertext link. Default behavior is to + // call LoadPage(loc) + + protected: + bool ScrollToAnchor(const wxString& anchor); + // Scrolls to anchor of this name. (Anchor is #news + // or #features etc. it is part of address sometimes: + // http://www.ms.mff.cuni.cz/~vsla8348/wxhtml/index.html#news) + // Return value : TRUE if anchor exists, FALSE otherwise + + void CreateLayout(); + // prepare layout (= fill m_PosX, m_PosY for fragments) based on actual size of + // window. This method also setup scrollbars + + void OnDraw(wxDC& dc); + void OnSize(wxSizeEvent& event); + void OnMouseEvent(wxMouseEvent& event); + void OnIdle(wxIdleEvent& event); + void OnKeyDown(wxKeyEvent& event); + + DECLARE_EVENT_TABLE() +}; + + + +#endif // __HTMLWIN_H__ + +#endif + + + diff --git a/include/wx/html/htmlwinparser.h b/include/wx/html/htmlwinparser.h new file mode 100644 index 0000000000..fa1769c5ba --- /dev/null +++ b/include/wx/html/htmlwinparser.h @@ -0,0 +1,219 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlwinparser.h +// Purpose: wxHtmlWinParser class (parser to be used with wxHtmlWindow) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifndef __HTMLWINPARSER_H__ +#define __HTMLWINPARSER_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/module.h> +#include <wx/html/htmlparser.h> +#include <wx/html/htmlcell.h> + +class wxHtmlWinParser; +class wxHtmlWinTagHandler; +class wxHtmlTagsModule; + +//-------------------------------------------------------------------------------- +// wxHtmlWinParser +// This class is derived from wxHtmlParser and its mail goal +// is to parse HTML input so that it can be displayed in +// wxHtmlWindow. It uses special wxHtmlWinTagHandler. +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlWinParser : public wxHtmlParser +{ + DECLARE_DYNAMIC_CLASS(wxHtmlWinParser) + + friend class wxHtmlWindow; + + private: + wxWindow *m_Window; + // window we're parsing for + wxDC *m_DC; + // Device Context we're parsing for + static wxList m_Modules; + // list of tags modules (see wxHtmlTagsModule for details) + // This list is used to initialize m_Handlers member. + + wxHtmlContainerCell *m_Container; + // actual container. See Open/CloseContainer for details. + + int m_FontBold, m_FontItalic, m_FontUnderlined, m_FontFixed; // this is not TRUE,FALSE but 1,0, we need it for indexing + int m_FontSize; /* -2 to +4, 0 is default */ + wxColour m_LinkColor; + wxColour m_ActualColor; + // basic font parameters. + wxString m_Link; + // actual hypertext link or empty string + bool m_UseLink; + // TRUE if m_Link is not empty + long m_CharHeight, m_CharWidth; + // average height of normal-sized text + int m_Align; + // actual alignment + + wxFont *m_FontsTable[2][2][2][2][7]; + // table of loaded fonts. 1st four indexes are 0 or 1, depending on on/off + // state of these flags (from left to right): + // [bold][italic][underlined][fixed_size] + // last index is font size : from 0 to 7 (remapped from html sizes -2 to +4) + // Note : this table covers all possible combinations of fonts, but not + // all of them are used, so many items in table are usually NULL. + int m_FontsSizes[7]; + wxString m_FontFaceFixed, m_FontFaceNormal; + int m_ItalicModeFixed, m_ItalicModeNormal; + // html font sizes and faces of fixed and proportional fonts + + public: + wxHtmlWinParser() : wxHtmlParser() {wxHtmlWinParser(NULL);} + wxHtmlWinParser(wxWindow *wnd); + + virtual void InitParser(const wxString& source); + virtual void DoneParser(); + virtual wxObject* GetProduct(); + + virtual void SetDC(wxDC *dc) {m_DC = dc;} + // Set's the DC used for parsing. If SetDC() is not called, + // parsing won't proceed + wxDC *GetDC() {return m_DC;} + int GetCharHeight() const {return m_CharHeight;} + int GetCharWidth() const {return m_CharWidth;} + // NOTE : these functions do _not_ return _actual_ + // height/width. They return h/w of default font + // for this DC. If you want actual values, call + // GetDC() -> GetChar...() + wxWindow *GetWindow() {return m_Window;} + // returns associated wxWindow + + void SetFonts(wxString normal_face, int normal_italic_mode, wxString fixed_face, int fixed_italic_mode, int *sizes); + // sets fonts to be used when displaying HTML page. + // *_italic_mode can be either wxSLANT or wxITALIC + + virtual wxList* GetTempData(); + + static void AddModule(wxHtmlTagsModule *module); + // Adds tags module. see wxHtmlTagsModule for details. + + // parsing-related methods. These methods are called by tag handlers: + wxHtmlContainerCell *GetContainer() const {return m_Container;} + // Returns pointer to actual container. Common use in tag handler is : + // m_WParser -> GetContainer() -> InsertCell(new ...); + wxHtmlContainerCell *OpenContainer(); + // opens new container. This container is sub-container of opened + // container. Sets GetContainer to newly created container + // and returns it. + wxHtmlContainerCell *SetContainer(wxHtmlContainerCell *c); + // works like OpenContainer except that new container is not created + // but c is used. You can use this to directly set actual container + wxHtmlContainerCell *CloseContainer(); + // closes the container and sets actual Container to upper-level + // container + + int GetFontSize() const {return m_FontSize;} + void SetFontSize(int s) {m_FontSize = s;} + int GetFontBold() const {return m_FontBold;} + void SetFontBold(int x) {m_FontBold = x;} + int GetFontItalic() const {return m_FontItalic;} + void SetFontItalic(int x) {m_FontItalic = x;} + int GetFontUnderlined() const {return m_FontUnderlined;} + void SetFontUnderlined(int x) {m_FontUnderlined = x;} + int GetFontFixed() const {return m_FontFixed;} + void SetFontFixed(int x) {m_FontFixed = x;} + + int GetAlign() const {return m_Align;} + void SetAlign(int a) {m_Align = a;} + const wxColour& GetLinkColor() const {return m_LinkColor;} + void SetLinkColor(const wxColour& clr) {m_LinkColor = clr;} + const wxColour& GetActualColor() const {return m_ActualColor;} + void SetActualColor(const wxColour& clr) {m_ActualColor = clr;} + const wxString& GetLink() const {return m_Link;} + void SetLink(const wxString& link) {m_Link = link; m_UseLink = link.Length() > 0;} + + virtual wxFont* CreateCurrentFont(); + // creates font depending on m_Font* members. + // (note : it calls wxHtmlWindow's CreateCurrentFont...) + + protected: + virtual void AddText(const char *txt); + + private: + bool m_tmpLastWasSpace; + // temporary variable used by AddText +}; + + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlWinTagHandler +// This is basicly wxHtmlTagHandler except +// it is extended with protected member m_Parser pointing to +// the wxHtmlWinParser object +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlWinTagHandler : public wxHtmlTagHandler +{ + DECLARE_ABSTRACT_CLASS(wxHtmlWinTagHandler) + + protected: + wxHtmlWinParser *m_WParser; + // same as m_Parser, but overcasted + + public: + wxHtmlWinTagHandler() : wxHtmlTagHandler() {}; + + virtual void SetParser(wxHtmlParser *parser) {wxHtmlTagHandler::SetParser(parser); m_WParser = (wxHtmlWinParser*) parser;}; +}; + + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlTagsModule +// This is basic of dynamic tag handlers binding. +// The class provides methods for filling parser's handlers +// hash table. +// (See documentation for details) +//-------------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlTagsModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxHtmlTagsModule) + + public: + wxHtmlTagsModule() : wxModule() {}; + + virtual bool OnInit(); + virtual void OnExit(); + + virtual void FillHandlersTable(wxHtmlWinParser *parser) {} + // This is called by wxHtmlWinParser. + // The method must simply call parser->AddTagHandler(new <handler_class_name>); + // for each handler + +}; + + + +#endif // __HTMLWINPARSER_H__ + +#endif + + + diff --git a/include/wx/html/mod_templ.h b/include/wx/html/mod_templ.h new file mode 100644 index 0000000000..cb9f3fadb6 --- /dev/null +++ b/include/wx/html/mod_templ.h @@ -0,0 +1,102 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_templ.h +// Purpose: wxHtml tags module generic "template" +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +/* + +DESCRIPTION: +This is set of macros for easier writing of tag handlers. How to use it? +See mod_fonts.cpp for example... + +Attention! This is quite strange C++ bastard. Before using it, +I STRONGLY recommend reading and understanding these macros!! + +*/ + + +#ifndef __MOD_TEMPL_H__ +#define __MOD_TEMPL_H__ + +#include "wx/defs.h" +#if wxUSE_HTML + + +#ifdef __GNUG__ +#pragma interface +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + + + + +#include <wx/html/htmlwinparser.h> + + +#define TAG_HANDLER_BEGIN(name,tags) \ + class HTML_Handler_##name : public wxHtmlWinTagHandler \ + { \ + public: \ + wxString GetSupportedTags() {return tags;} + + + +#define TAG_HANDLER_VARS \ + private: + +#define TAG_HANDLER_CONSTR(name) \ + public: \ + HTML_Handler_##name () : wxHtmlWinTagHandler() + + +#define TAG_HANDLER_PROC(varib) \ + public: \ + bool HandleTag(const wxHtmlTag& varib) + + + +#define TAG_HANDLER_END(name) \ + }; + + + + +#define TAGS_MODULE_BEGIN(name) \ + class HTML_Module##name : public wxHtmlTagsModule \ + { \ + DECLARE_DYNAMIC_CLASS(HTML_Module##name ) \ + public: \ + void FillHandlersTable(wxHtmlWinParser *parser) \ + { + + + + +#define TAGS_MODULE_ADD(handler) \ + parser -> AddTagHandler(new HTML_Handler_##handler); + + + + +#define TAGS_MODULE_END(name) \ + } \ + }; \ + IMPLEMENT_DYNAMIC_CLASS(HTML_Module##name , wxHtmlTagsModule) + + + +#endif +#endif \ No newline at end of file diff --git a/include/wx/html/msw/back.bmp b/include/wx/html/msw/back.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a81d37879afb304478cb1bf15359fb7f2ee74f15 GIT binary patch literal 202 zcmZ?rJ;eY4UO-9%hy|dSk%0v)(EubFp_mm&gYba^2Y@64!|5jn7$zJkXJ}|>0P|sl z1BAf>r5zzOiy(w{RCIB1abRE(G87aP6kuRfHU<I#1|cZTsAQz1qy%(^kRn)~fl(1+ N9D^W~1~~@<001D55l;XB literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/book.ico b/include/wx/html/msw/book.ico new file mode 100644 index 0000000000000000000000000000000000000000..2b3279313515e2af29b90826af9a773d91677f21 GIT binary patch literal 318 zcmbtOIS#`x45NWOz+QrMD>`NK^Sb&6L6E6azv3@>YbKS9?Ip+-N+M;-7vLD)dkC`w zMk!0qljSgwfqd{4C4h;Ps*u?t=S<bWj)a*y7DJZS9rQISlZ;=iYOw@ikL5$GXMH#S Zd(zG7{-vo|dGLJT)h{CUNA-()_yeugXZ8R9 literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/folder.ico b/include/wx/html/msw/folder.ico new file mode 100644 index 0000000000000000000000000000000000000000..ead2829adaeb2ece9bd1d8660adbb9a385ee9fff GIT binary patch literal 318 zcmbu(p$-Bu5CqU^LISQ;R3Jbin_&7`mmqqw38w#q=_j2-E;B9i9NX@^?VdTn@q`ed zx;x-3+1lLL4hJUCNA5)hcv0(w$q~JGst-0U%rvoiw9;EOMv{WpD_4o!>UAKu+?qTQ md0c;%sV`h`??2^*i#KoU<NY+c#FFR|6EQ@k**4Md{8e9rY+LOB literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/forward.bmp b/include/wx/html/msw/forward.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ec26993fd29464b61c9040cf179d5d67a895139a GIT binary patch literal 202 zcmZ?rJ;eY4UO-9%hy|dSk%0v)(EubFp_mm&gYba^2Y@64!|5jn7$zJkXJ}|>0P|sl z1C-$cr5&LHjv_z-7Z(>tMWBEn5EuakgpGkf5lSlwFbF9rDH#FzAbB7c1Q>x_Fb&~? J-2)LpkN_gv5l;XB literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/page.ico b/include/wx/html/msw/page.ico new file mode 100644 index 0000000000000000000000000000000000000000..46114c9e2a884d19957b5b02c51265857b91a635 GIT binary patch literal 318 zcmbtMF%E!02<s*8+~n-&GkF?M;s@ArPR7Mppil?}24l_%;T*uO&eG;!4Qyl}n%~F) wCfrveb3{b2>rkDj(!^qDCH(~NfK@S@tno>&zp88>v&?0c@|3--Z%F>Z1<F}xaR2}S literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/panel.bmp b/include/wx/html/msw/panel.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e735d3584b054c7d330d0594fb710820aa2b331b GIT binary patch literal 710 zcmY*XOH30{6g}VvEh?a(hzKHJQK?0gkF5%J6v1h!SZmS#fLbwukRUaI*y+H6kk}TQ zG(bZG8y4Nc&V?*!(!_LE6Np`ugk`rT1rioyyi=hGH#wPe-rW1%x%WMl=2te-@h1zY zA(l_bBV^%Bdi`&jiyHWRh;TRzr<2F@^mo+P|Ax!;6W!f<Sglsr?RJ>WX3Wj`AqWDZ z(H-n;ZDC_$16^I6l<UIM(h@?U5KJZ$@gRidWe96)NF)+)yT@U%STH;}33g=#GM|su z+>p}QLOc#35`jRqLNJIpX@_GN9QOqk1_Su@b<AvUqlcj6dGK;MQmd;-CX-0c&m%Q8 zg$U^;trmg6G^*O$k*m?b<ME)8;~;Z5pwsDKv)P~~Zygg8P>+tHRRsBNbB%)MzoMeI z7cA}NiAM2bZx4aZP1FqzLZwona&Zyg4i3Om?=9rP=^R1x_&BTs185i<L*LL480yFC z^@3$fQ8_z{k^Oxzl*@4=VElfXm6m)ILrOUVySreh*I3K|qp=WWG#7^E6$&XqM$sRO zp+A+v!h#PuEQ@M}f&J65=zrI7Ec8_wY5Pc2&mQTX-ab(u{WqB{R#6|;8@k_rF#gY1 zYdW>ByWZ&Dik147)@Lf_`HQxf?V{{>b-(_>!-mGD=0^&JLizZ~)2ixQ(wf`lckb5K z%I?YQaHaTaNy)X+>t&Miq8k-AD{&z&zo6hEE=eSXMUu;O)2B}7h|lk=B=_8T`eq{g M#K{a#6Y*K%AIQzvR{#J2 literal 0 HcmV?d00001 diff --git a/include/wx/html/msw/wxhtml.rc b/include/wx/html/msw/wxhtml.rc new file mode 100644 index 0000000000..99c310f430 --- /dev/null +++ b/include/wx/html/msw/wxhtml.rc @@ -0,0 +1,16 @@ + +// +// This file contains bitmaps used +// by wxHtmlHelpController +// Include it in your .rc file if you're using wxHTML help system +// (#include "wx/html/msw/wxhtml.rc") +// + +back BITMAP "wx/html/msw/back.bmp" +forward BITMAP "wx/html/msw/forward.bmp" +panel BITMAP "wx/html/msw/panel.bmp" + +book ICON "wx/html/msw/book.ico" +folder ICON "wx/html/msw/folder.ico" +page ICON "wx/html/msw/page.ico" + diff --git a/include/wx/html/version.h b/include/wx/html/version.h new file mode 100644 index 0000000000..49ff8aeae8 --- /dev/null +++ b/include/wx/html/version.h @@ -0,0 +1,7 @@ + +#define wxHTML_VERSION_MAJOR 0 +#define wxHTML_VERSION_MINOR 2 +#define wxHTML_VERSION_REL 3 + +#define wxHTML_VERSION (wxHTML_VERSION_MAJOR * 1000 + wxHTML_VERSION_MINOR * 100 + wxHTML_VERSION_REL) + diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index d7a89dba0a..b67a81cd27 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -198,6 +198,8 @@ // wxWindow::SetToolTip() method #define wxUSE_SOCKETS 0 // Set to 1 to use socket classes +#define wxUSE_HTML 0 + // Set to 1 to use wxHTML sub-library /* * Finer detail diff --git a/include/wx/wxhtml.h b/include/wx/wxhtml.h new file mode 100644 index 0000000000..f8082a7aaa --- /dev/null +++ b/include/wx/wxhtml.h @@ -0,0 +1,27 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wxhtml.h +// Purpose: wxHTML library for wxWindows +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef __WXHTML_H__ +#define __WXHTML_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + + +#include <wx/html/version.h> +#include <wx/html/htmldefs.h> +#include <wx/html/htmltag.h> +#include <wx/html/htmlcell.h> +#include <wx/html/htmlparser.h> +#include <wx/html/htmlwin.h> +#include <wx/html/htmlwinparser.h> +#include <wx/filesys.h> +#include <wx/html/htmlhelp.h> + +#endif // __WXHTML_H__ diff --git a/include/wx/zipstream.h b/include/wx/zipstream.h new file mode 100644 index 0000000000..6da057c473 --- /dev/null +++ b/include/wx/zipstream.h @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: zipstream.h +// Purpose: wxZipInputStream for reading files from ZIP archive +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef __ZIPSTREAM_H__ +#define __ZIPSTREAM_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#if wxUSE_ZLIB && wxUSE_STREAMS + +#include <wx/stream.h> + +//-------------------------------------------------------------------------------- +// wxZipInputStream +// This class is input stream from ZIP archive. The archive +// must be local file (accessible via FILE*) +//-------------------------------------------------------------------------------- + + +class WXDLLEXPORT wxZipInputStream : public wxInputStream +{ + private: + size_t m_Size; + off_t m_Pos; + void *m_Archive; + // this void* is handle of archive . + // I'm sorry it is void and not proper type but I don't want + // to make unzip.h header public. + + public: + wxZipInputStream(const wxString& archive, const wxString& file); + // archive is name of .zip archive, file is name of file to be extracted. + // Remember that archive must be local file accesible via fopen, fread functions! + ~wxZipInputStream(); + + protected: + virtual size_t StreamSize() const {return m_Size;} + virtual size_t OnSysRead(void *buffer, size_t bufsize); + virtual off_t OnSysSeek(off_t seek, wxSeekMode mode); + virtual off_t OnSysTell() const {return m_Pos;} +}; + + +#endif // if use_zlib && use_streams + +#endif // __ZIPSTREAM_H__ + + + + + + + + + + + + + + + + + diff --git a/samples/html/Makefile.am b/samples/html/Makefile.am new file mode 100644 index 0000000000..6eee574d1b --- /dev/null +++ b/samples/html/Makefile.am @@ -0,0 +1,8 @@ +## Purpose: The automake makefile for wxHTML samples +## Author: VS +## Version: $Id$ +## +## Process this file with automake to produce Makefile.in + +SUBDIRS = about help printing test virtual widget zip + diff --git a/samples/html/about/Makefile.am b/samples/html/about/Makefile.am new file mode 100644 index 0000000000..56e4183fdc --- /dev/null +++ b/samples/html/about/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = about + +about_SOURCES = about.cpp diff --git a/samples/html/about/about.cpp b/samples/html/about/about.cpp new file mode 100644 index 0000000000..7bfb813b2e --- /dev/null +++ b/samples/html/about/about.cpp @@ -0,0 +1,174 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "test.cpp" + #pragma interface "test.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + +#include <wx/image.h> +#include <wx/wxhtml.h> + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + virtual bool OnInit(); + }; + +// Define a new frame type: this is going to be our main frame + class MyFrame : public wxFrame + { + public: + // ctor(s) + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + + private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + }; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands + enum + { + // menu items + Minimal_Quit = 1, + Minimal_About, + Minimal_Back, + Minimal_Forward, + + // controls start here (the numbers are, of course, arbitrary) + Minimal_Text = 1000, + }; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// ---------------------------------------------------------------------------- + +// the event tables connect the wxWindows events with the functions (event +// handlers) which process them. It can be also done at run-time, but for the +// simple menu events like this the static method is much simpler. + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + END_EVENT_TABLE() + + // Create a new application object: this macro will allow wxWindows to create + // the application object during program execution (it's better than using a + // static object for many reasons) and also declares the accessor function + // wxGetApp() which will return the reference of the right type (i.e. MyApp and + // not wxApp) + IMPLEMENT_APP(MyApp) + + // ============================================================================ + // implementation + // ============================================================================ + + // ---------------------------------------------------------------------------- + // the application class + // ---------------------------------------------------------------------------- + // `Main program' equivalent: the program execution "starts" here + bool MyApp::OnInit() + { + wxImage::AddHandler(new wxPNGHandler); + // Create the main application window + MyFrame *frame = new MyFrame("wxHtmlWindow testing application", + wxPoint(50, 50), wxSize(150, 50)); + + // Show it and tell the application that it's our main window + // @@@ what does it do exactly, in fact? is it necessary here? + frame->Show(TRUE); + SetTopWindow(frame); + + + // success: wxApp::OnRun() will be called which will enter the main message + // loop and the application will run. If we returned FALSE here, the + // application would exit immediately. + return TRUE; + } + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + + +// frame constructor + MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) + { + // create a menu bar + wxMenu *menuFile = new wxMenu; + + menuFile->Append(Minimal_About, "&About"); + menuFile->Append(Minimal_Quit, "E&xit"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, "&File"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + } + + +// event handlers + + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) + { + // TRUE is to force the frame to close + Close(TRUE); + } + + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) + { + wxHtmlWindow *html; + wxDialog dlg(this, -1, "About", wxDefaultPosition, wxSize(400, 230), wxDIALOG_MODAL | wxDEFAULT_DIALOG_STYLE); + + html = new wxHtmlWindow(&dlg, -1, wxPoint(10, 10), wxSize(380, 160), "htmlWindow", FALSE); + html -> SetBorders(0); + html -> LoadPage("data/about.htm"); + wxButton *bu1 = new wxButton(&dlg, wxID_OK, "OK", wxPoint(250, 185), wxSize(100, 30)); + bu1 -> SetDefault(); + dlg.ShowModal(); + } + + + + + + + diff --git a/samples/html/about/about.rc b/samples/html/about/about.rc new file mode 100644 index 0000000000..82bdf07561 --- /dev/null +++ b/samples/html/about/about.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" + diff --git a/samples/html/about/data/about.htm b/samples/html/about/data/about.htm new file mode 100644 index 0000000000..b3bfa67dfc --- /dev/null +++ b/samples/html/about/data/about.htm @@ -0,0 +1,17 @@ +<html><body bgcolor="#FFFFFF"><table cellspacing=3 cellpadding=4 width="100%"> +<tr><td bgcolor="#101010"> +<center><font size=+2 color="#FFFFFF"><b> +<br>wxHTML Library Sample 0.2.0<br> +</b></font></center> +<tr><td bgcolor="#73A183"> +<b><font size=+1>Copyright (C) 1999 Vaclav Slavik</font></b><p> +<font size=-1> +<table cellpadding=0 cellspacing=0 width="100%"> +<tr><td width="65%"> +Vaclav Slavik (slavik2@czn.cz)<br>Someone Else (selse@hell.org)<p> +<td valign=top><img src="logo.png"> +</table> +<font size=-2> +The wxHTML library is available at <font color="#0000FF">http://www.ms.mff.cuni.cz/~vsla8348/wxhtml</font><br> +The library is licenced under wxWindows Library Licence, Version 3. +</font></font></table></body></html> diff --git a/samples/html/about/data/logo.png b/samples/html/about/data/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6c5e312049f30e07bdcfdbcc00aa7a87ae5379ff GIT binary patch literal 7637 zcmV;`9V+69P)<h;3K|Lk000e1NJLTq003?P0015c1^@s6&3P+200004XF*Lt00D-e zG3b_G0013~Nkl<Zc-rlnS*&Kqao_*d-Dmms``vx^;VhgPl0#CWNSdNd*^*)^mKQjL zm&9<8M1YL=Ar24&NnY|2#K=PyIS3pn$wOiW2$a~cC0P>WRg_4Hl&F!!Wysl=J9qu= z{noSgQk92G39=~0q8}1xDd6A$=k)1roFD4nUDZYSOJF~7tc8#L@G_b|ogq5yAQe&l z^%P;KND3k_5tIm}0=>u*-(QRBFnFS1Urs0t6{IABC4vA@00a;L0MJ_uE8qKo6oBZB z$BqDg<3%i>R75SX#OJK&#Q+I_yBfpaFvK&pKXw3M02mQUL`VZt6Nv{9h@eHNA<*;8 z@jEN1rigf8^3gf`w`&>x!B=*F;D2WDm&FLAR|C{Mqx{nb@q{!HBI>eXCJHRV0p4xH zH@+E%#<3uNLxaaklR|{H7zv_$0C9jogaSY$AP9X29t+@t5DUITH8v2X!2&S*eV{6Z zA`$`!Lc*?wQ=4$9k3#b#2{HwL%P6sAR6~rUVtf$t0{9>SIr&JD=vb6)i)MxrfJ1-} z1Ng?p*mvJwLd^yFi~KJ0FCSa{-_Gnv+W-RiTM^vli2Q9GQ9~Ni<emk0D=$fHB}_|X z!;wt)E^)SS!MOWY6gB3!DGB!+q+2<p)(SZRi-5F&(FO(r4F(DJy-)xW`Hq)~C9nYA zS+Rl0Y6ZkGVyzLefLxF|uP_^pWwLiwvgQS<A6Pb+Ya^i+cdX`~V`)2<sB#FUm$Iml zM?|3$BTh7$h!9yPJ}Z&!4P~<RDrd>7WZ(0*5aRFS{eLdFpFi38F6|H^qCX=h0ucfM z^!+7AMC7}^*_SGMLx{fL{ksMe2);9*0Pcn%Skjbo<Eo9`@#=c~!+SP9es(#ltDJ4j z_Iic-#hVkpb90wxX;bux1zP#jo4ub2vvTE2n~V2;@Z{ifLgnmE+3QYc(*L1j*`yAL zU)^Z+2k}Cq2-+wg<Yc-xIWbojjfA}qkk4!%KXP|6y8Z5>qnAb*HNJ46d;h^z;j!+e z<LxqRj!pg(r#63UBj-ES77ZgIzOSQtf%)z)UQ9nQ@$uocS=u+Lvd6pm^?Q2buUsD| z>C0P7?>W7Yg+)wxW~0z=*h@9Sh1)Y;yZ%fV{lO()eptJJw+YWI{Kf!W5!tV&a5s#S zoJcGI3Q#Q;>Wb*)AW{*9O-)i0NlBmxpp-=|u&6$ZOcjM4MN+DLO&1Ud0(nE<34j)% zrU*4eR9i?aAQ_Pqio_8~NkkE1XSn+xUOV!U&uks}Ysv+M^@JL?cWk#4rho73SO3Ls z#TRTL8zZa837z{l7w`U+a_Hxz-_l=x_P}H3?akS>{?QiKqW=9_OP$O%{9cvlo#RIg zGAkqu=#yyZAgjY|zjtU=PtuN=du7wM>^JYTHOHU2eb=dMt7WPJ=oOPNneT;@+q-3u z@{gtt*QZ|9HpZdPznuKyZ(hCsryE%wPjyq-`L@C~!aqIv%<9?>^Jg}epPa6p>7LrV zZLh8#kN!^j{I|{=9YwoUFze%h(UAGy(zrU;kHgynCjeE?Hpt&F8jJ{ph>a-g1z|+q zZNVqkBA;kQDi#AH5gSp?i})dVx21hThSQXYA~8@Bv4(O16#Td4NQhZL3=R``zfCTJ z;zSdoh8Qt0!LYF`%2tR(^J1@_0QCV1X{0c&X_~f@!iR<5eX;X1bIHio1<a__?#4i! zQyQJo;njoypwY(H2WI}*)&{?R>Wn6%aj|#GfCS<LBm${c3aJ@+n&M{Tm=0P4rIljr zqhJ5l{pTr-RleBO9BaS{M%*?@S@4am#`}&h7kMBwyq3x5UQVC<udg2dP}YcBlcRHl z+JlUSDlKgk=>xyNw%E&RY55|jONZ}DbrNB?g}cU!{H{^K`MBb8Tyga+U;9B7`0aR| zvENAGuWL<Onww6JWL_3y6Qm9z5-^$N7}rxOmiwf7i_{qxvNG2Z3JN~2F&j-~ikhm` zMP=H3bag6S79`dQyh31rwx--ZIIpY(_|hZKD@<HYWxq|-Z=rQ%s7|f)gVhNFE8*bK z&+bh7kI!ByUx^R4r%?mm3Wed6^pY&qUe4J-b!jnK=%8yxBj!#6GV@S#DNL{!99U3d zt-vb6tN^+VaN&TMz!rcFFl#$-r5DqQ5h8=a0DTUsWh@o76&6Jh0$YZUBYJUo^vK=O z=$*}`a3wPP%(q%UwkeIai#@?sAVm<*nA_RLpi4{l954N?ms(m@n*`<IYlq8o2b*`x z-m$Eflckl-%3-(mQmp6R0|-AjxYuF@jriG3_3*ELYT=(Rp;GTSFx{P+rdnwfH_k5A zf6`>R=ACK%@_%3XCvNJOf9mY;#_|G97F+IetoZ9BwB0q*_{wGTqgMy<1C6;jKCGsb zldFE?+LoDn`Ib3+_^__eE!w@oRL_=r;p-~qb=x5IA1^Na+-INH@2!K1e&l?8^PMZ% zwWEEv(d&jdj59znTth?35~i-P(y1G^rlSp_vC-K5^0nw>R&d0o1PI_Npj`~*NBbN0 zbGHtgS~M+}V>DGtuc%ceq#(|Nlm-+_hjQtRc4eh+!?m)j-m|=I8;+vSkB&!nc>!WQ z;z5pju0feH@y57$`q+Gt=@_;(uRC=fX><(`Jh=9N0g6@x<wJBV9x%m=#IsTaOb|h_ zH8Z!3T6A8PT#$Jmq$vSL(_4luZy}XAk!XpJ_3O~9%hrZ#9h+W?)UeUkvG{lY@*{Uz z%W3)Stf0lsy!8$iYW&vg?bAkBRyyVALuYn=|M;B$+U?97{8tx_{>peqx?!bd4u?to z)Zshp&tB>DZ*#Xj7<7y&EvMq#V+V%sdFqkukDu9S9{CSf4*aZccp(UVYQr3T`L*qb zf8pWX=UWZm*yczVj=^;e1dAi>0?TvMOtfB&i1Gu=wD_ef>8Y~WFaU$$L0*BK!+fVG zpE`YUwmmWwr^b~1h3+ets;20ez<{umLyeI<_0XN!^$jkAx7F#DEnZpB>E|vUS{cqY zL1h8GTcEZA5shD1*^tBS&~4AtiI08t(CV6B=t|EJoP~q{5r)n^DiGZXE!_)o9BcqL ziO72(BFy5H2GgkFxo!nUD=-ofQI6j(I7{S==+}4S6L;p9j|ZjVJP1i(bjk`Y@OcY_ z7ha3+KI*3W>e7<&Iwi0m-_wiFU(4Tj^pUap#OwWs2XSjb7A=T8wsW1laHF}h+^zg; z)pEpbL$zY%gVJ9ZFW-M^!#B5l)Mg^Z4NZ~<tQ46%y0~kThHdN&qJFmpYD^}W82||Z z9O#?letRvC&#h2(Y?No&q?B$yAJUlHpos@38a8-bUQ^5*MtSLHN0yb^9?qW$dC`<a zphq<tRSmVuVz|mC)37(3%4DHKey*(+uju|NoD=q*BzUNq6`7A{r%qHpZZ)ErI=q}z z(Iss(&vFnkpa@V3<UCG{Hf6P6$V$umR(ly)N)Q{+o|d>@Hl>pW+1d~FV*!i^6wBKL z2Zq=Ja__Re_ESf9zW&+U^N&^_-K<NrMl*F~!yGw$zOGNKxZb3w%$48>WFWRi$LDmi zSI)&L?)&Ce;{*~03`4^HMxZfg<&g*S$*r#q8ZT!{2@D|+s5vY3r(aA@@3h*Abx9O} zcvMJFO?j)WLTkhci;MO+rJX1tu@0y`E~81W4WkG|(XDZuytv)&hsb~!<Qo>~6JQ<2 zm7>T5yEWo0D`b6nPPxN#ML(o-^T<kYTLT`*c5Cb%fZLt&cs!G}ZbN6&+UTWh<Tufe zxUz@}E7AZ3m*cm08hBTktB0DZ+0IG?st{FPoKXZVfEU=vV5SXvjUb&k$T$Q-mH{ky z!0o_$Mk5Xaff9iRpalCd=63~7e?B<X67f3}3Xk&V?;X6byHVZyg<`RnX+j5#8`q?D z?ub6@EXUVu60xoTyC1nuVnYmSqzMk*8@BQ6IDnG`r~)3IABJ;Bi+pdwWhW{#Gb&<^ zG=;>Vt^;P3C<{lN2wEeH6FkHH=Um=u<io9@Fbe=%Lua|zG$I%vcm|aL;utpCj~O*v zbcY4TD_xM*KtyOatjtO%&r$`(UL(fLkUd3t4F(_#SVds#Q8@(9$XKw^N@%#y#zLrT z0#5-$Xt)AR3fL+;U;!TK=C~_j_0nF1UKmQEfW?I%ui6%gV^FOyH42gOczM{0#d?UV z1qSq-YvNH=AU1DgX9&;)iZszes`1YrS-@T0=uMEmv0LLGzp(c`;1+}UHSKCarkb?T z($!R)@4*GEM-i>06&+a$%`e`J5(<`@QxArqHW4@?T)1W88^h+}D^<%l??8nE9AkAQ z^CG^uzAm!|4^78sR{ilSn`ZF~vz{rMh6=9$Fi<<3kA~9hh>J`)ySWvzSktuG;l|5( z5>?8R_yF>RIQNJXg-Z69sRV-Ns6rJKNo~QzKoKylYATup5qJXfMog32GabVh!bwDM z00*XwnPwG{2x>)`b`l!iwG;*;78S&kkisO5uoOx;ff25h3H`ggjl0W0uTzYcw(?+- zqt#V-c`M%ERk{FGWVkgnN@?pmMJ6*cloU0pxi&ImBsMHW5KTa&h!Rb7v}@@6ftc=^ zH=rhe$Ln}kV^s5-J<c5QqF&P87nH?KTA%O9PH$s!aO_C40Wt;p+Urqzb)B^&9%qor zUeo|4L-H!dYPSX>G9yb$f&*EPlti2azcG|zXUwC9q3NUd*8UH#MGIV(AP-2S0MGbP zJdxF7VABm{mWSzhCgY_Z?XKtMz)i1|kOx6yHJf5J^%BLJ`@P_^9O5kLrMm=s12!*a zOg=VH-eU=woLX`A;%x{Ke5A>qo~wu6Clu!;>L`LlgauPcx4{AXX>1oqRA1Rpy>8Rl ztda&ip;<b#8YLdTPr}u2#Kr;iYM~I@8aW7^Bh0#^z}E^*MuEIwpfv7UtU0R{uT&EW zra@CfI5->P@KT9JL`V&(cA|7ULA2CT@jH)3v0t@fPKA&@XgPkc29(I~*OtD&RO-cm zv<>D7m7&Jqfg|qfm22a37bZy~Z>Mx)EHrst>uDA!^A5p~Jb7;!E_^fSR~*r79KlQj zMY=?#6c)-1i%m#w;k@U<c^M@UMzup{Yv>dQ24W2bLnwn(-lCBxoH-iYi<jVHP19CF zd(Lx_WQCNPfS~A*WH_>*__2p%x;f<OER(v?Q2O8kb$;gyY7ub6-UBXRmlU}Gd1Jj` zMc_IJX?Q6UBB?8+7Sf+9zbpN`-|qMlCd2_;2Sl}pXGYp*dEtgav&>``6sgD{u1Xw@ z9MTv;l~$Qt#EPO=JUAjecL}DI5D8mUC5gllwN(iOs8K=DLR%$Ts59483#XP$c5>N7 zrI+kmuZ1$XrK{!bI2?b{;;q&^6LvJ3i^B0bRYgssZ`~lfo~w{SAXN$H92i1VXh>Zm zNrOCbFX}&eRX3unq$D_O>4c&(L!=3;NRA(3e{9)}U%i2{*HYD~Lt6drH*judoi^;? zp}}<!9VvXJB)a;NSDlVD=Q`9l<P^`hRK1e8(QwyRFAU=*0^_O(cogtpiR#*V7!Rj1 zT<r^Ir8zMZny<W5rnWdJ4)b%GI}KqXFueg}SRt*-k|+p-1(jAPJVWniSD64&ium}l z%<hV2^+pk;v9r`t07&EE<GyT*jn_9grkYS{LU#`SzT;H<=P#R%jf6mqItZfRaORK% z7Vj_K0!r@*j<G?&Iqh)wVZ;Kp8XymyJF4PViZiMmHrI+UY%02R=MwL(UkKTmtHC~L z<@>@j_SIP8lTMni8J9bnzVBZ8^7Vm#0^4Qlc1~0ULT&>jP7nnzrxxI+g|4;O#MMwa zF##3@31SbJh;izGt|q0FMx#1@Kq<%J^yU^X$EBd91VbbsP3V)8T@jjAiazmtNPqq@ z)jzbX=2Jz3UPtQl2ZMiYSjo_Vh9r3JJWF8ZCZ$ZKg{-agQ65_oy*Y5JFYQ=EEbtU0 zi3q%({%6qswK=HU$`T+1As~36N*G#0AR+>Y2(XuNG|asLfXpbQVsU&CVWlU<muvW( zlzQZ(*xgK&Nu(|+%5QB}U9lx#3;@DvOK|TYgqQ9pY}G;{9@;S|Sp44WN^KOOUs>wC zw1IopN8y2KA?D^tb&k#PrC)j?{>{x&Uc9myHZJ^^FxhC#>T})r&EVXn80mXUnd?P< zXPdHii*En;JLSTE`h##V1*uXrh9Xd9j;0YnMSf$K%DnU)D}pRA6bA?kj3#I;(1xm6 zA!WBkc6;hiZ|};9wGk(k5K2~PawR`@uja2^cB&nKiB*`2sOK)yT!`fSyU!*iDl`)< z=#j(F3zQ;!`9@GlH&QN05kv;D!Kie6@W#*+Sivj8dLYVnYV{~Z92m@k5E$XHGwSvq zyjtInAP@l(CCExpX(Qo%Cu9~0dpY#V9PGt`Yl{FCd8z|TRh#nU65r{jK!_0*7lbNH zYB*D|61N&NqpTca66|`=*RIEEW`#plQ>0U|Of&`HLcl9GolXpC7Zg2nNmjc?#2AIO zT{-*8y8o-SMLEcWjBECv^jVl5Y`X9DI>VWQ%oIAyV6#nCU1P8^r(U~0az9yn5(1L~ zLlMjA6~)~qitUk1A38}g_=Y>=MQAw+*sB4@K(DRBFqg8hQYa-&SM#CQ*Ta0_6*`7t z1Is%PlY8R+ID6q*-K$v?IM7x}nB5e8YFV|F@PR*k+4aAAIkX)ML4cE8lKCF-ogu5* zqxOs$5r%s+uI>!Ij)F+=`zPT2F8IbyP_-9t1AOJAo{R%Ya9{y62)#t4n-DfeOtnXF zETMAZI*E*n%5h90&N1agu%38tCiU7b?@bHY+#X4(2&$W^_~1PC?>T_OFI?w709XN< z2C~v6_r<T;v<?9K3N1s(1HnKr6QP+GQE#xAd4Ud0^9^Vp^r77hXU8RvCl!x#M)~}9 z<-Zr40twvZ80jf5&6sLiV;F%hF3+h!Cy~&Py|fJDNSEY^Gf^IE8s6Rsqs5N8y3(gv zBZ5pkpcLehBg#K`+|0(gO!7)*N9WYuBM0=Xn;<kzKqp~7JTLz7v+?eYb=h0#>2Wg! zCmPakh^)4OV;zDorFq{WvwM7z@_qvxYe*ghD?Md<4VuhKv4xYeurj{)ka_8^Kcuf8 zXbGp9r5&>zU!b}f(KM^Y7FOy>$@!5vedz<I_2yy&+>AxE29lU;Wl`joUFpP4N+}x= z-8no@+c5<ph%_UXdk*M)XTtej#(O){aD8jc-`JbUS86BEukG>rja{#nnh5tSQZNLZ zT2Mg?%ER+|+Dzc@nj<;0L`=d+jX)7F-vAT|R@x%{6j*3L4)rL^N@?uPcqO;8U;|op z5Hq#>rmTt~0o<iX+K-o*Uryca>zI@QS3YoG@;gf{+{2K=fzjR^GwoSSu5N|hX)YTA z41e++@eV{zzj)Ih*%)#2?6GKEIt*_O!oWFfO)DClIHIS&^dsrUYun-Qtdv%#p~{PQ zcs82J>|j@4OCub9;D}B)C)_=;sC+M`a(yD>nrZh(?uoMH4)sfqZeEF=lv3W<mBF~+ zi3^zSPI;JBsDJo;@_WY*na4!1v^nOc3zT2D<@Y89kC`#u8u9S{W9F+L`6~^5XUGp< z-wg)_Gf9V;<l7S-PD`1EfP81l)Ae0(#}Al4eZQh|cgCw{R(05_WOidG?2QZFDV*F6 zf*V?6rWKi^eZ6+--HqbXrvJc?-yfOJzT}pf;a}h4y`{FAJ@ru1ID0@fZ9x0%c1SlT z9E$*F4`|m-NoJMMp*iJ0|B8*;iJDDIjCN<tr4{8wloG(PycwKjAlfp3C#*ai*j_=g zIpoc@R=+dI`C4IdPhn+cS|Hk+1v{Ma(0Qy0uo-Dhy*6DwwiF%hHhKBdHk;v$i%B8d z3b=lKKpRo4kS4g|SRE@pFWp|_csS#-b{MuY8m-K!3)@pHYOR*845X2j%vmWj0`?X< zsvMPQ1VKM5rL{ZdFqraqR>>^^wst1GbL9?WFeP6&j7No>7-h1sGYJ?>c{r=&76DtE zBi?!KcGz2MQOKN(Mj7rJ<(S)<iVUVa%xk#=V0SPL!^?L9`d#(ul{s8DMxDLB%S$^G z#_p7NvRZCAmJO}3Nt&hvNS<RvME1~v*?8_cpH*6|%qlh;qfkRIUFfK4W;u-`>OoX{ zxuaqcn7s_NmjMFs=9IaaYQH<<dN7sIw2&<uWGo7mBH~2Tn>Qzac&EUJjyB=0M$&$w z#9gmP_G_Qy@y0aV9GA?Qm0{^*xpI=0R($1T!h&sp2a3oiW8A7eZkAS-3(JktiL)NN zT48N#!UISUB5dciY-cquWR=8~lbQv?%G1aN@L-BA3l<$q$9j<SQYyk^QlMxIp;^!^ zowN!oD6C{Q$fi<Qo7B8}eJA*IL}g|<pO&&Yt9d@JMHg0PHpr&dxHBqw_v%*QIHGD= zaXzbfJ*%ak)uIY3nG3S6G}b4UN7r|PPsijY6}wTvqpXsp+=?o#j2+7w6V@Yxv1v-4 zw87(o>+P9@X)P|Rc~n?gtehmZgC`)HRgw=Tq!ppVf({E(7Q`Y@-;N(ygdHPPPHbUi zX1#0#!X2YAYZCc(q~2VS_SA_sKKl3)qLUWAUmKyC5&il<3i|o4a5|W9FRP?)y>uK) z;u#V|N>Z4m5oPUIc@3nMldkpXI+oP4Faw#^7<FQmwG$EvXcSI5HlSsLm>}W>$P-O@ zYA9$z>H=DxrO5&v1WpmENTZGvQD7vVC9w?hEHwjDV=(TuDL>fJK|Ce1f;)LFb9Inb z9iTl+Erf|SnDpCJEVneXqa-W2n_HQyy|iqA3L<sVXxP8;i+}S+=eq4WHN+$mS?3#- zb#3cH8dwOVtTLuBM(1&)>nK(})=D&>*mGo^Z&uc|oeQaF)*=w4lrvg+tpH((LI`nS zF(RTx<lEqci1xz~P!N#YAID^IY>HTE%R)RWN<97a)1MiS#{&StJilG;S6E$-F#U}_ zpaoBLIb7G%YT#|~UUC;C4h$^<5Xc*Wi-a5nuxDuJG4Vm-ATS~%3UEeHD<;Q|#CplB z$Jnt%B2W-wO>kPsDIpF)bYMh*5e0c8Lrw@m5QG30(Ltbv0R;-Nf@>R9uNv(S7|q*d z@XnHTUS>WZ5`oe}!6?|aR(92Bzo;}1d~n{udWUIXL|~8tg{Fzpk9_3so__AR=eQ^e z+1lEqg9nf3vMBZCD_7Lt|J7ebzu%XC{n3wxPG^ok_`whI8+B5`%+%}kND--LzW9tj zc<`V)aNvO2-rAN2-|?W_zI|KbD28>Gu3WjIu3ovSlve2VdUWE%39PKF;E(_4kMYpE z9+FPGBXJV5F{W1(MR@el9|})D{j{7ve_rP2=kbY8eBw5M3jl^@Jr8(hqrk(<De$rZ z0O<qxhvyc;ZznVUlRKpw*`RFLUm#;m(vFm@HVmKbM{;pwX|o7*?pRrt{hCrm+)p$g z?HHMhm0X!PyH^EO1yP=bB1MvD;(nr~6_MmlXlw&jUiSMSNTf(Kkq`lag@Wvt)M*9j z#ftBnPxxo<YD+g(xHWV9>05cYJa)G9OoIJ<?_8|;fyIP>>R3xUvBH&!<4@nr!i|}$ zD=$j+GxX9<OfbfT;c$quEM;}|08X7c?Qh(;5hjx{ed*aR;b(vL=WzM*CAsgu^YZbJ ze;iLf`J{aQ^Pk6k_uVIDS<2&&KQ2j<@@P1sn>TMkD}^WC`vgArv5(8b!UD8X^uG7M zAD{i~=O~UM965RvRaxPapZpX~o;-<XzVHl^G{xH5nw&d#PF{cgHF?*&9>z;Ay(AAm z{P4FG@*sfA0EYAfm#h9cRlq+$o4-gO_(7|X-=dEns9m$!Y<~E|AO72En)U(2Z(|++ zfNR&T;lzm(_%o%AZ#8lGpC7lqRUcJV$<t3ieQ7)%e-Xgi+nV72#YO<;0h|EPdb{BM z7nuOa09=1N9{2x(DFDeE_rI(buz!rr{~y=?q4qxj5M7ypaImHB00000NkvXXu0mjf Dp@n$J literal 0 HcmV?d00001 diff --git a/samples/html/help/Makefile.am b/samples/html/help/Makefile.am new file mode 100644 index 0000000000..99eba9fb57 --- /dev/null +++ b/samples/html/help/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = help + +help_SOURCES = help.cpp diff --git a/samples/html/help/help.cpp b/samples/html/help/help.cpp new file mode 100644 index 0000000000..22677fee69 --- /dev/null +++ b/samples/html/help/help.cpp @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation + #pragma interface +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + +#include <wx/image.h> +#include <wx/wxhtml.h> +#if (( wxVERSION_NUMBER < 2100 ) || (( wxVERSION_NUMBER == 2100 ) && (wxBETA_NUMBER <= 4))) +#include <wx/imaggif.h> +#endif +#include <wx/config.h> + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + private: + wxHtmlHelpController help; + wxConfig* config; + + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + bool OnInit(); + int OnExit(); + }; + + IMPLEMENT_APP(MyApp) + + + bool MyApp::OnInit() + { + config = new wxConfig("wxHTMLhelp"); + #if wxUSE_LIBPNG + wxImage::AddHandler(new wxPNGHandler); + #endif + #if wxUSE_LIBJPEG + wxImage::AddHandler(new wxJPEGHandler); + #endif + + help.UseConfig(config); + help.SetTempDir("tmp"); + help.AddBook("helpfiles/testing.hhp"); + help.Display("Main page"); + return TRUE; + } + + int MyApp::OnExit() + { + delete config; + return 0; + } + + + + + + + + diff --git a/samples/html/help/help.rc b/samples/html/help/help.rc new file mode 100644 index 0000000000..7fa90c817b --- /dev/null +++ b/samples/html/help/help.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" +#include "wx/html/msw/wxhtml.rc" diff --git a/samples/html/help/helpfiles/Index.hhk b/samples/html/help/helpfiles/Index.hhk new file mode 100644 index 0000000000..a9ab87b4a0 --- /dev/null +++ b/samples/html/help/helpfiles/Index.hhk @@ -0,0 +1,24 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML> +<HEAD> +<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> +<!-- Sitemap 1.0 --> +</HEAD><BODY> +<UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="1"> + <param name="Name" value="Book 1"> + <param name="Local" value="book1.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="main"> + <param name="Name" value="Untitled: d:\HELPS\testing\main.htm"> + <param name="Local" value="main.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="2"> + <param name="Name" value="Book 1"> + <param name="Local" value="book2.htm"> + </OBJECT> +</UL> +</BODY></HTML> diff --git a/samples/html/help/helpfiles/book1.htm b/samples/html/help/helpfiles/book1.htm new file mode 100644 index 0000000000..fa470e3ec5 --- /dev/null +++ b/samples/html/help/helpfiles/book1.htm @@ -0,0 +1,4 @@ +<html><title>Book 1</title><body> +<h2>Book 1.</h2> +How do you enjoy <i> book one</i>?? +</body></html> diff --git a/samples/html/help/helpfiles/book2.htm b/samples/html/help/helpfiles/book2.htm new file mode 100644 index 0000000000..828723fc65 --- /dev/null +++ b/samples/html/help/helpfiles/book2.htm @@ -0,0 +1,5 @@ +<html><title>Book 1</title><body> +<h2>Book 2.</h2> +How do you enjoy <i> book two</i>?? +<p>Please click <a href="page2-b.htm">HERE</a> +</body></html> diff --git a/samples/html/help/helpfiles/contents.hhc b/samples/html/help/helpfiles/contents.hhc new file mode 100644 index 0000000000..3eb7c2c974 --- /dev/null +++ b/samples/html/help/helpfiles/contents.hhc @@ -0,0 +1,33 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML> +<HEAD> +<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> +<!-- Sitemap 1.0 --> +</HEAD><BODY> +<OBJECT type="text/site properties"> + <param name="ImageType" value="Folder"> +</OBJECT> +<UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Main page"> + <param name="Local" value="main.htm"> + </OBJECT> + <UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Book 1"> + <param name="Local" value="book1.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Book 2"> + <param name="ID" value=34> + <param name="Local" value="book2.htm"> + </OBJECT> + <UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="sub book"> + <param name="Local" value="page2-b.htm"> + </OBJECT> + </UL> + </UL> +</UL> +</BODY></HTML> diff --git a/samples/html/help/helpfiles/main.htm b/samples/html/help/helpfiles/main.htm new file mode 100644 index 0000000000..ca5275bfd7 --- /dev/null +++ b/samples/html/help/helpfiles/main.htm @@ -0,0 +1,5 @@ +<html><body> +<h2>This is main page.</h2> +<a href="book1.htm">Book 1</a><br> +<a href="book2.htm">Book 2</a><br> +</body></html> diff --git a/samples/html/help/helpfiles/page2-b.htm b/samples/html/help/helpfiles/page2-b.htm new file mode 100644 index 0000000000..f51dd6d6d6 --- /dev/null +++ b/samples/html/help/helpfiles/page2-b.htm @@ -0,0 +1,5 @@ +<html><body> +<font color="#FF0000" size=+4 face="Tahoma"> +Hello, you're on sub page of page 2 !!! +</font> +</body></html> diff --git a/samples/html/help/helpfiles/testing.hhp b/samples/html/help/helpfiles/testing.hhp new file mode 100644 index 0000000000..5cd4d4e87f --- /dev/null +++ b/samples/html/help/helpfiles/testing.hhp @@ -0,0 +1,15 @@ +[OPTIONS] +Compatibility=1.1 +Compiled file=testing.chm +Contents file=contents.hhc +Display compile progress=No +Index file=Index.hhk +Language=0x405 Èesky +Title=Testing HELPFILE :-) +Default topic=main.htm + +[FILES] +main.htm +book1.htm +book2.htm +page2-b.htm diff --git a/samples/html/printing/Makefile.am b/samples/html/printing/Makefile.am new file mode 100644 index 0000000000..73aa8ade60 --- /dev/null +++ b/samples/html/printing/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = printing + +printing_SOURCES = printing.cpp diff --git a/samples/html/printing/mondrian.ico b/samples/html/printing/mondrian.ico new file mode 100644 index 0000000000000000000000000000000000000000..2310c5d275a87af295d5ea8dc79ea417a5e74c53 GIT binary patch literal 766 zcmZQzU<5)11px*Sc)`TLAO@s0fLH;D9e|jTfdxnc0Z<M**w4TKL=5})Lnt5#WHKB$ zaDbtqp#doIAB-6O{|B*v7zjZ^AOa2W|NsACHyAJ}De?dRKnp(HN~rljcR;{k;{zQE i@;}UZ|9Q?Fpp*~yJCwmWbLIrN`9Qm9%}2L?p!oo$cZ4ed literal 0 HcmV?d00001 diff --git a/samples/html/printing/mondrian.xpm b/samples/html/printing/mondrian.xpm new file mode 100644 index 0000000000..409f27a843 --- /dev/null +++ b/samples/html/printing/mondrian.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *mondrian_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 6 1", +" c Black", +". c Blue", +"X c #00bf00", +"o c Red", +"O c Yellow", +"+ c Gray100", +/* pixels */ +" ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" oooooo +++++++++++++++++++++++ ", +" ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ .... ", +" ++++++ ++++++++++++++++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++++++++++++++++ ++++ ", +" ++++++ ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" ++++++ OOOOOOOOOOOO XXXXX ++++ ", +" " +}; diff --git a/samples/html/printing/pic.png b/samples/html/printing/pic.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc18c1296d650b9ad75f9dc61b15d6cb0d09b03 GIT binary patch literal 31315 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 literal 0 HcmV?d00001 diff --git a/samples/html/printing/printing.cpp b/samples/html/printing/printing.cpp new file mode 100644 index 0000000000..2febc3bd6c --- /dev/null +++ b/samples/html/printing/printing.cpp @@ -0,0 +1,312 @@ +/* + * File: printing.cc + * Purpose: Printing demo for wxWindows class library + * Author: Julian Smart + * modified by Vaclav Slavik (wxHTML stuffs) + * Created: 1995 + * Updated: + * Copyright: (c) 1995, AIAI, University of Edinburgh + */ + +/* static const char sccsid[] = "%W% %G%"; */ + +#ifdef __GNUG__ +#pragma implementation +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#if !wxUSE_PRINTING_ARCHITECTURE +#error You must set wxUSE_PRINTING_ARCHITECTURE to 1 in setup.h to compile this demo. +#endif + +// Set this to 1 if you want to test PostScript printing under MSW. +// However, you'll also need to edit src/msw/makefile.nt. + +//!!! DON'T DO THAT! This is wxHTML sample now +#define wxTEST_POSTSCRIPT_IN_MSW 0 + +#include <ctype.h> +#include "wx/metafile.h" +#include "wx/print.h" +#include "wx/printdlg.h" + +#include "wx/accel.h" + +#if wxTEST_POSTSCRIPT_IN_MSW +#include "wx/generic/printps.h" +#include "wx/generic/prntdlgg.h" +#endif + +#include <wx/wxhtml.h> +#include <wx/wfstream.h> +#include "printing.h" + +#ifndef __WXMSW__ +#include "mondrian.xpm" +#endif + +// Global print data, to remember settings during the session +wxPrintData *g_printData = (wxPrintData*) NULL ; + +// Global page setup data +wxPageSetupData* g_pageSetupData = (wxPageSetupData*) NULL; + + +// Declare a frame +MyFrame *frame = (MyFrame *) NULL; +wxHtmlWindow *html = NULL; +int orientation = wxPORTRAIT; + +// Main proc +IMPLEMENT_APP(MyApp) + + +MyApp::MyApp() +{ +} + +// The `main program' equivalent, creating the windows and returning the +// main frame +bool MyApp::OnInit(void) +{ + g_printData = new wxPrintData; + g_pageSetupData = new wxPageSetupDialogData; + + // Create the main frame window + frame = new MyFrame((wxFrame *) NULL, (char *) "wxWindows Printing Demo", wxPoint(0, 0), wxSize(600, 400)); + + // Give it a status line + frame->CreateStatusBar(2); + + // Load icon and bitmap + frame->SetIcon( wxICON( mondrian) ); + + // Make a menubar + wxMenu *file_menu = new wxMenu; + + file_menu->Append(WXPRINT_PRINT, "&Print...", "Print"); + file_menu->Append(WXPRINT_PRINT_SETUP, "Print &Setup...", "Setup printer properties"); + file_menu->Append(WXPRINT_PAGE_SETUP, "Page Set&up...", "Page setup"); + file_menu->Append(WXPRINT_PREVIEW, "Print Pre&view", "Preview"); + + // Accelerators + wxAcceleratorEntry entries[1]; + entries[0].Set(wxACCEL_CTRL, (int) 'V', WXPRINT_PREVIEW); + wxAcceleratorTable accel(1, entries); + frame->SetAcceleratorTable(accel); + + file_menu->AppendSeparator(); + file_menu->Append(WXPRINT_QUIT, "E&xit", "Exit program"); + + wxMenu *help_menu = new wxMenu; + help_menu->Append(WXPRINT_ABOUT, "&About", "About this demo"); + + wxMenuBar *menu_bar = new wxMenuBar; + + menu_bar->Append(file_menu, "&File"); + menu_bar->Append(help_menu, "&Help"); + + // Associate the menu bar with the frame + frame->SetMenuBar(menu_bar); + + frame->Centre(wxBOTH); + frame->Show(TRUE); + + frame->SetStatusText("Printing demo"); + + SetTopWindow(frame); + + return TRUE; +} + +int MyApp::OnExit() +{ + delete g_printData; + delete g_pageSetupData; + return 1; +} + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(WXPRINT_QUIT, MyFrame::OnExit) + EVT_MENU(WXPRINT_PRINT, MyFrame::OnPrint) + EVT_MENU(WXPRINT_PREVIEW, MyFrame::OnPrintPreview) + EVT_MENU(WXPRINT_PRINT_SETUP, MyFrame::OnPrintSetup) + EVT_MENU(WXPRINT_PAGE_SETUP, MyFrame::OnPageSetup) + EVT_MENU(WXPRINT_ABOUT, MyFrame::OnPrintAbout) +END_EVENT_TABLE() + +// Define my frame constructor +MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size): + wxFrame(frame, -1, title, pos, size) +{ + html = new wxHtmlWindow(this); + html -> LoadPage("test.htm"); +} + +void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(TRUE); +} + +void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event)) +{ + wxPrinter printer; + MyPrintout printout("My printout"); + if (!printer.Print(this, &printout, TRUE)) + wxMessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wxOK); +} + +void MyFrame::OnPrintPreview(wxCommandEvent& WXUNUSED(event)) +{ + wxPrintData printData; + printData.SetOrientation(orientation); + + // Pass two printout objects: for preview, and possible printing. + wxPrintPreview *preview = new wxPrintPreview(new MyPrintout, new MyPrintout, & printData); + if (!preview->Ok()) + { + delete preview; + wxMessageBox("There was a problem previewing.\nPerhaps your current printer is not set correctly?", "Previewing", wxOK); + return; + } + + wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650)); + frame->Centre(wxBOTH); + frame->Initialize(); + frame->Show(TRUE); +} + +void MyFrame::OnPrintSetup(wxCommandEvent& WXUNUSED(event)) +{ + wxPrintDialogData printDialogData(* g_printData); + wxPrintDialog printerDialog(this, & printDialogData); + + printerDialog.GetPrintDialogData().SetSetupDialog(TRUE); + printerDialog.ShowModal(); + + (*g_printData) = printerDialog.GetPrintDialogData().GetPrintData(); +} + +void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event)) +{ + (*g_pageSetupData) = * g_printData; + + wxPageSetupDialog pageSetupDialog(this, g_pageSetupData); + pageSetupDialog.ShowModal(); + + (*g_printData) = pageSetupDialog.GetPageSetupData().GetPrintData(); + (*g_pageSetupData) = pageSetupDialog.GetPageSetupData(); +} + + + +void MyFrame::OnPrintAbout(wxCommandEvent& WXUNUSED(event)) +{ + (void)wxMessageBox("wxWindows printing demo\nAuthor: Julian Smart julian.smart@ukonline.co.uk\n\nModified by Vaclav Slavik to show wxHtml features", + "About wxWindows printing demo", wxOK|wxCENTRE); +} + + +bool MyPrintout::OnPrintPage(int page) +{ + wxDC *dc = GetDC(); + if (dc) + { + if (page == 1) + DrawPageOne(dc); + + return TRUE; + } + else + return FALSE; +} + +bool MyPrintout::OnBeginDocument(int startPage, int endPage) +{ + if (!wxPrintout::OnBeginDocument(startPage, endPage)) + return FALSE; + + return TRUE; +} + +void MyPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) +{ + *minPage = 1; + *maxPage = 1; + *selPageFrom = 1; + *selPageTo = 1; +} + +bool MyPrintout::HasPage(int pageNum) +{ + return (pageNum == 1); +} + + +void MyPrintout::DrawPageOne(wxDC *dc) +{ + int leftMargin = 20; + int topMargin = 40; + +/* You might use THIS code to set the printer DC to ROUGHLY reflect + * the screen text size. This page also draws lines of actual length 5cm + * on the page. + */ + // Get the logical pixels per inch of screen and printer + int ppiScreenX, ppiScreenY; + GetPPIScreen(&ppiScreenX, &ppiScreenY); + int ppiPrinterX, ppiPrinterY; + GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); + + // Here we obtain internal cell representation of HTML document: + wxHtmlContainerCell *cell = html -> GetInternalRepresentation(); + + // Now we have to check in case our real page size is reduced + // (e.g. because we're drawing to a print preview memory DC) + int pageWidth, pageHeight; + int w, h; + dc->GetSize(&w, &h); + GetPageSizePixels(&pageWidth, &pageHeight); + + // Now we must scale it somehow. The best would be to suppose that html window + // width is equal to page width: + + float scale = (float)((float)(pageWidth - 0 * leftMargin)/((float)cell -> GetMaxLineWidth() + 2 * leftMargin)); + + // If printer pageWidth == current DC width, then this doesn't + // change. But w might be the preview bitmap width, so scale down. + float overallScale = scale * (float)(w/(float)pageWidth); + dc->SetUserScale(overallScale, overallScale); + + // Calculate conversion factor for converting millimetres into + // logical units. + // There are approx. 25.1 mm to the inch. There are ppi + // device units to the inch. Therefore 1 mm corresponds to + // ppi/25.1 device units. We also divide by the + // screen-to-printer scaling factor, because we need to + // unscale to pass logical units to DrawLine. + + dc->SetBackgroundMode(wxTRANSPARENT); + + // TESTING + + int pageWidthMM, pageHeightMM; + GetPageSizeMM(&pageWidthMM, &pageHeightMM); + + + // This is all the printing : + cell -> Draw(*dc, leftMargin, topMargin, 0, cell -> GetHeight()); +} + + + diff --git a/samples/html/printing/printing.h b/samples/html/printing/printing.h new file mode 100644 index 0000000000..ba50b4e216 --- /dev/null +++ b/samples/html/printing/printing.h @@ -0,0 +1,76 @@ +/* + * File: printing.h + * Purpose: Printing demo for wxWindows class library + * Author: Julian Smart + * Created: 1995 + * Updated: + * Copyright: (c) 1995, AIAI, University of Edinburgh + */ + +/* sccsid[] = "%W% %G%" */ + +#ifdef __GNUG__ +#pragma interface +#endif + +// Define a new application +class MyApp: public wxApp +{ + public: + MyApp() ; + bool OnInit(); + int OnExit(); +}; + +DECLARE_APP(MyApp) + +class MyCanvas; + +// Define a new canvas and frame +class MyFrame: public wxFrame +{ + public: + MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size); + + void OnPrint(wxCommandEvent& event); + void OnPrintPreview(wxCommandEvent& event); + void OnPrintSetup(wxCommandEvent& event); + void OnPageSetup(wxCommandEvent& event); +#if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW + void OnPrintPS(wxCommandEvent& event); + void OnPrintPreviewPS(wxCommandEvent& event); + void OnPrintSetupPS(wxCommandEvent& event); + void OnPageSetupPS(wxCommandEvent& event); +#endif + + void OnExit(wxCommandEvent& event); + void OnPrintAbout(wxCommandEvent& event); +DECLARE_EVENT_TABLE() +}; + + +class MyPrintout: public wxPrintout +{ + public: + MyPrintout(char *title = "My printout"):wxPrintout(title) {} + bool OnPrintPage(int page); + bool HasPage(int page); + bool OnBeginDocument(int startPage, int endPage); + void GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo); + + void DrawPageOne(wxDC *dc); +}; + +#define WXPRINT_QUIT 100 +#define WXPRINT_PRINT 101 +#define WXPRINT_PRINT_SETUP 102 +#define WXPRINT_PAGE_SETUP 103 +#define WXPRINT_PREVIEW 104 + +#define WXPRINT_PRINT_PS 105 +#define WXPRINT_PRINT_SETUP_PS 106 +#define WXPRINT_PAGE_SETUP_PS 107 +#define WXPRINT_PREVIEW_PS 108 + +#define WXPRINT_ABOUT 109 + diff --git a/samples/html/printing/printing.rc b/samples/html/printing/printing.rc new file mode 100644 index 0000000000..7655c62a4c --- /dev/null +++ b/samples/html/printing/printing.rc @@ -0,0 +1,3 @@ +mondrian ICON "mondrian.ico" +#include "wx/msw/wx.rc" + diff --git a/samples/html/printing/test.htm b/samples/html/printing/test.htm new file mode 100644 index 0000000000..ca2d7dfba1 --- /dev/null +++ b/samples/html/printing/test.htm @@ -0,0 +1,126 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="GENERATOR" CONTENT="Mozilla/4.06 [en] (X11; I; Linux 2.0.35 i686) [Netscape]"> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088"> +This is - - default text, now switching to +<CENTER> +<P>center, now still ctr, now exiting</CENTER> + +<P>exited!.<A HREF="#downtown">[link to down]</A> +<P>Hello, this *is* default charset (helvetica, probably) and it is displayed +with one <FONT COLOR="#FF0000">COLOR CHANGE</FONT>. Of course we +can have as many color changes as we can, what about this <FONT COLOR="#FF0000">M</FONT><FONT COLOR="#FFFF00">A</FONT><FONT COLOR="#33FF33">D</FONT><B><FONT COLOR="#FFFFFF"><FONT SIZE=+1>N</FONT></FONT></B>E<FONT COLOR="#999999">S</FONT><FONT COLOR="#CC33CC">S?</FONT> +<P><FONT COLOR="#000000">There was a space above.</FONT> +<BR> +<HR WIDTH="100%">This was a line. <TT>(BTW we are in <B>fixed</B> font +/ <I><U>typewriter</U> font</I> right now :-)</TT> +<BR>This is in <B>BOLD</B> face. This is <I>ITALIC.</I> This is <B><I><U>E +V E R Y T H I N G</U></I></B>. +<BR> +<BR> +<BR> +<BR> +<BR> +<CENTER> +<P>Right now, <FONT COLOR="#0000FF"><FONT SIZE=+4>centered REALLY Big Text</FONT></FONT>, +how do you like (space) it?</CENTER> + +<DIV ALIGN=right>RIGHT: <FONT SIZE=-2>text-2, </FONT><FONT SIZE=-1>text-1, +</FONT>text+0, +<FONT SIZE=+1>text+1, +</FONT><FONT COLOR="#FF0000"><FONT SIZE=+2>text+2, +</FONT></FONT><FONT SIZE=+3>text+3, +</FONT><FONT SIZE=+4>text+4</FONT> +<BR><U><FONT SIZE=+1>we are right now</FONT></U></DIV> + +<CENTER><U><FONT SIZE=+1>we are center now</FONT></U></CENTER> +<U><FONT SIZE=+1>we are left now.</FONT></U> +<P><I><FONT COLOR="#3366FF">Blue italic text is displayed there....</FONT></I> +<H1> + +<HR ALIGN=LEFT SIZE=10 WIDTH="50%">This is heading one.</H1> +this is normal +<CENTER> +<H1> +This is <FONT COLOR="#33FF33">CENTERED</FONT> heading one</H1></CENTER> +<IMG SRC="pic.png" ALT="Testing image image" >and this is text...... +<BR> +<UL> +<LI> +item 1</LI> + +<LI> +item 2</LI> + +<UL> +<LI> +nested item</LI> + +<LI> +nested item 2</LI> +</UL> + +<LI> +item 3</LI> +</UL> + +<OL> +<LI> +item one</LI> + +<LI> +item two</LI> + +<OL> +<LI> +nsted item</LI> +</OL> + +<LI> +last numbered item</LI> +</OL> + +<H1> +Heading 1</H1> +<I>Italic text now...</I> +<H2> +<I>Heading 2</I></H2> +<I>and now?</I> +<H3> +Heading 3</H3> + +<H4> +Heading 4</H4> + +<H5> +Heading 5</H5> + +<H6> +Heading 6</H6> +And this is normal text, once again :-) +<P>And yes, we're in <FONT SIZE=+4>HTML DOCUMENT, </FONT><FONT SIZE=+1>so +what about some nice <A HREF="fft.html">hypertext link</A>??</FONT> +<P>hello? +<CENTER> +<P>This is <A NAME="downtown"></A>centered paragraph</CENTER> + +<P>Now, you will see some PRE text: +<PRE>// This is sample C++ code: + +void main(int argc, char *argv[]) +{ + printf("Go away, man!\n"); + i = 666; + printf("\n\n\nCRASH\n DOWN NOW. . . \n"); +}</PRE> + +<H3> +WWW</H3> +<A HREF="http://www.kde.org">This is WWW link to KDE site!</A> +<BR><A HREF="http://www.ms.mff.cuni.cz/~vsla8348/wxhtml/index.html">(one +folder up)</A> +</BODY> +</HTML> diff --git a/samples/html/test/Makefile.am b/samples/html/test/Makefile.am new file mode 100644 index 0000000000..3631656b63 --- /dev/null +++ b/samples/html/test/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = test + +test_SOURCES = test.cpp diff --git a/samples/html/test/f.html b/samples/html/test/f.html new file mode 100644 index 0000000000..625ec44f81 --- /dev/null +++ b/samples/html/test/f.html @@ -0,0 +1,2474 @@ +<HTML> +<head><title>wxWindow</title></head> +<BODY BGCOLOR="#FFFFFF"> +<A NAME="wxwindow"></A><CENTER> +<A HREF="http://www.wx.org/wx.zip#zip:wx.htm#anchor">Contents</A> <A HREF="wx22.htm#classref">Up</A> <A HREF="wx259.htm#wxwave"><<</A> <A HREF="wx261.htm#wxwindowdc">>></A> </CENTER><HR> + +<H2>wxWindow</H2> +<P> +wxWindow is the base class for all windows. Any +children of the window will be deleted automatically by the destructor +before the window itself is deleted.<P> +<B><FONT COLOR="#FF0000">Derived from</FONT></B><P> +<A HREF="wx85.htm#wxevthandler">wxEvtHandler</A><BR> + +<A HREF="wx158.htm#wxobject">wxObject</A><P> +<B><FONT COLOR="#FF0000">Include files</FONT></B><P> +<wx/window.h><P> +<B><FONT COLOR="#FF0000">Window styles</FONT></B><P> +The following styles can apply to all windows, although they will not always make sense for a particular +window class.<P> + +<TABLE BORDER> + + +<TR><TD VALIGN=TOP> +<B>wxSIMPLE_BORDER</B> +</TD> + +<TD VALIGN=TOP> +Displays a thin border around the window. wxBORDER is the old name +for this style. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxDOUBLE_BORDER</B> +</TD> + +<TD VALIGN=TOP> +Displays a double border. Windows only. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxSUNKEN_BORDER</B> +</TD> + +<TD VALIGN=TOP> +Displays a sunken border. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxRAISED_BORDER</B> +</TD> + +<TD VALIGN=TOP> +Displays a raised border. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxSTATIC_BORDER</B> +</TD> + +<TD VALIGN=TOP> +Displays a border suitable for a static control. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxTRANSPARENT_WINDOW</B> +</TD> + +<TD VALIGN=TOP> +The window is transparent, that is, it will not receive paint +events. Windows only. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxNO_3D</B> +</TD> + +<TD VALIGN=TOP> +Prevents the children of this window taking on 3D styles, even though +the application-wide policy is for 3D controls. Windows only. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxTAB_TRAVERSAL</B> +</TD> + +<TD VALIGN=TOP> +Use this to enable tab traversal for non-dialog windows. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxVSCROLL</B> +</TD> + +<TD VALIGN=TOP> +Use this style to enable a vertical scrollbar. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxHSCROLL</B> +</TD> + +<TD VALIGN=TOP> +Use this style to enable a horizontal scrollbar. +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxCLIP_CHILDREN</B> +</TD> + +<TD VALIGN=TOP> +Use this style to eliminate flicker caused by the background being +repainted, then children being painted over them. Windows-only. +</TD></TR> + + +</TABLE> +<P> +See also <A HREF="wx305.htm#windowstyles">window styles overview</A>.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> +<B><FONT COLOR="#FF0000">Members</FONT></B><P> +<A HREF="#topic1026">wxWindow::wxWindow</A><BR> +<A HREF="#topic1027">wxWindow::~wxWindow</A><BR> +<A HREF="#topic1028">wxWindow::AddChild</A><BR> +<A HREF="#wxwindowcapturemouse">wxWindow::CaptureMouse</A><BR> +<A HREF="#wxwindowcenter">wxWindow::Center</A><BR> +<A HREF="#wxwindowcentre">wxWindow::Centre</A><BR> +<A HREF="#wxwindowclear">wxWindow::Clear</A><BR> +<A HREF="#topic1029">wxWindow::ClientToScreen</A><BR> +<A HREF="#wxwindowclose">wxWindow::Close</A><BR> +<A HREF="#wxwindowconvertdialogtopixels">wxWindow::ConvertDialogToPixels</A><BR> +<A HREF="#wxwindowconvertpixelstodialog">wxWindow::ConvertPixelsToDialog</A><BR> +<A HREF="#wxwindowdestroy">wxWindow::Destroy</A><BR> +<A HREF="#topic1030">wxWindow::DestroyChildren</A><BR> +<A HREF="#wxwindowdragacceptfiles">wxWindow::DragAcceptFiles</A><BR> +<A HREF="#wxwindowenable">wxWindow::Enable</A><BR> +<A HREF="#wxwindowfindfocus">wxWindow::FindFocus</A><BR> +<A HREF="#wxwindowfindwindow">wxWindow::FindWindow</A><BR> +<A HREF="#wxwindowfit">wxWindow::Fit</A><BR> +<A HREF="#wxwindowgetbackgroundcolour">wxWindow::GetBackgroundColour</A><BR> +<A HREF="#topic1031">wxWindow::GetCharHeight</A><BR> +<A HREF="#topic1032">wxWindow::GetCharWidth</A><BR> +<A HREF="#topic1033">wxWindow::GetChildren</A><BR> +<A HREF="#wxwindowgetclientsize">wxWindow::GetClientSize</A><BR> +<A HREF="#wxwindowgetconstraints">wxWindow::GetConstraints</A><BR> +<A HREF="#wxwindowgetdefaultitem">wxWindow::GetDefaultItem</A><BR> +<A HREF="#wxwindowgetdroptarget">wxWindow::GetDropTarget</A><BR> +<A HREF="#wxwindowgeteventhandler">wxWindow::GetEventHandler</A><BR> +<A HREF="#wxwindowgetfont">wxWindow::GetFont</A><BR> +<A HREF="#wxwindowgetforegroundcolour">wxWindow::GetForegroundColour</A><BR> +<A HREF="#topic1034">wxWindow::GetGrandParent</A><BR> +<A HREF="#topic1035">wxWindow::GetHandle</A><BR> +<A HREF="#wxwindowgetid">wxWindow::GetId</A><BR> +<A HREF="#topic1036">wxWindow::GetPosition</A><BR> +<A HREF="#topic1037">wxWindow::GetLabel</A><BR> +<A HREF="#wxwindowgetname">wxWindow::GetName</A><BR> +<A HREF="#topic1038">wxWindow::GetParent</A><BR> +<A HREF="#wxwindowgetrect">wxWindow::GetRect</A><BR> +<A HREF="#wxwindowgetreturncode">wxWindow::GetReturnCode</A><BR> +<A HREF="#wxwindowgetscrollthumb">wxWindow::GetScrollThumb</A><BR> +<A HREF="#wxwindowgetscrollpos">wxWindow::GetScrollPos</A><BR> +<A HREF="#wxwindowgetscrollrange">wxWindow::GetScrollRange</A><BR> +<A HREF="#wxwindowgetsize">wxWindow::GetSize</A><BR> +<A HREF="#topic1039">wxWindow::GetTextExtent</A><BR> +<A HREF="#wxwindowgettitle">wxWindow::GetTitle</A><BR> +<A HREF="#wxwindowgetupdateregion">wxWindow::GetUpdateRegion</A><BR> +<A HREF="#topic1040">wxWindow::GetWindowStyleFlag</A><BR> +<A HREF="#wxwindowinitdialog">wxWindow::InitDialog</A><BR> +<A HREF="#wxwindowisenabled">wxWindow::IsEnabled</A><BR> +<A HREF="#wxwindowisretained">wxWindow::IsRetained</A><BR> +<A HREF="#wxwindowisshown">wxWindow::IsShown</A><BR> +<A HREF="#wxwindowlayout">wxWindow::Layout</A><BR> +<A HREF="#wxwindowloadfromresource">wxWindow::LoadFromResource</A><BR> +<A HREF="#wxwindowlower">wxWindow::Lower</A><BR> +<A HREF="#wxwindowmakemodal">wxWindow::MakeModal</A><BR> +<A HREF="#wxwindowmove">wxWindow::Move</A><BR> +<A HREF="#wxwindowonactivate">wxWindow::OnActivate</A><BR> +<A HREF="#wxwindowonchar">wxWindow::OnChar</A><BR> +<A HREF="#wxwindowoncharhook">wxWindow::OnCharHook</A><BR> +<A HREF="#wxwindowoncommand">wxWindow::OnCommand</A><BR> +<A HREF="#wxwindowonclose">wxWindow::OnClose</A><BR> +<A HREF="#wxwindowonclosewindow">wxWindow::OnCloseWindow</A><BR> +<A HREF="#wxwindowondropfiles">wxWindow::OnDropFiles</A><BR> +<A HREF="#wxwindowonerasebackground">wxWindow::OnEraseBackground</A><BR> +<A HREF="#wxwindowonkeydown">wxWindow::OnKeyDown</A><BR> +<A HREF="#wxwindowonkeyup">wxWindow::OnKeyUp</A><BR> +<A HREF="#wxwindowonkillfocus">wxWindow::OnKillFocus</A><BR> +<A HREF="#wxwindowonidle">wxWindow::OnIdle</A><BR> +<A HREF="#wxwindowoninitdialog">wxWindow::OnInitDialog</A><BR> +<A HREF="#wxwindowonmenucommand">wxWindow::OnMenuCommand</A><BR> +<A HREF="#wxwindowonmenuhighlight">wxWindow::OnMenuHighlight</A><BR> +<A HREF="#wxwindowonmouseevent">wxWindow::OnMouseEvent</A><BR> +<A HREF="#wxwindowonmove">wxWindow::OnMove</A><BR> +<A HREF="#wxwindowonpaint">wxWindow::OnPaint</A><BR> +<A HREF="#wxwindowonscroll">wxWindow::OnScroll</A><BR> +<A HREF="#wxwindowonsetfocus">wxWindow::OnSetFocus</A><BR> +<A HREF="#wxwindowonsize">wxWindow::OnSize</A><BR> +<A HREF="#wxwindowonsyscolourchanged">wxWindow::OnSysColourChanged</A><BR> +<A HREF="#wxwindowpopeventhandler">wxWindow::PopEventHandler</A><BR> +<A HREF="#wxwindowpopupmenu">wxWindow::PopupMenu</A><BR> +<A HREF="#wxwindowpusheventhandler">wxWindow::PushEventHandler</A><BR> +<A HREF="#wxwindowraise">wxWindow::Raise</A><BR> +<A HREF="#wxwindowrefresh">wxWindow::Refresh</A><BR> +<A HREF="#wxwindowreleasemouse">wxWindow::ReleaseMouse</A><BR> +<A HREF="#wxwindowremovechild">wxWindow::RemoveChild</A><BR> +<A HREF="#wxwindowscreentoclient">wxWindow::ScreenToClient</A><BR> +<A HREF="#wxwindowscrollwindow">wxWindow::ScrollWindow</A><BR> +<A HREF="#wxwindowsetacceleratortable">wxWindow::SetAcceleratorTable</A><BR> +<A HREF="#wxwindowsetautolayout">wxWindow::SetAutoLayout</A><BR> +<A HREF="#wxwindowsetbackgroundcolour">wxWindow::SetBackgroundColour</A><BR> +<A HREF="#wxwindowsetclientsize">wxWindow::SetClientSize</A><BR> +<A HREF="#wxwindowsetcursor">wxWindow::SetCursor</A><BR> +<A HREF="#wxwindowseteventhandler">wxWindow::SetEventHandler</A><BR> +<A HREF="#wxwindowsetconstraints">wxWindow::SetConstraints</A><BR> +<A HREF="#wxwindowsetdroptarget">wxWindow::SetDropTarget</A><BR> +<A HREF="#wxwindowsetfocus">wxWindow::SetFocus</A><BR> +<A HREF="#wxwindowsetfont">wxWindow::SetFont</A><BR> +<A HREF="#wxwindowsetforegroundcolour">wxWindow::SetForegroundColour</A><BR> +<A HREF="#wxwindowsetid">wxWindow::SetId</A><BR> +<A HREF="#wxwindowsetname">wxWindow::SetName</A><BR> +<A HREF="#wxwindowsetpalette">wxWindow::SetPalette</A><BR> +<A HREF="#wxwindowsetreturncode">wxWindow::SetReturnCode</A><BR> +<A HREF="#wxwindowsetscrollbar">wxWindow::SetScrollbar</A><BR> +<A HREF="#wxwindowsetscrollpos">wxWindow::SetScrollPos</A><BR> +<A HREF="#wxwindowsetsize">wxWindow::SetSize</A><BR> +<A HREF="#wxwindowsetsizehints">wxWindow::SetSizeHints</A><BR> +<A HREF="#wxwindowsettitle">wxWindow::SetTitle</A><BR> +<A HREF="#topic1041">wxWindow::Show</A><BR> +<A HREF="#wxwindowtransferdatafromwindow">wxWindow::TransferDataFromWindow</A><BR> +<A HREF="#wxwindowtransferdatatowindow">wxWindow::TransferDataToWindow</A><BR> +<A HREF="#wxwindowvalidate">wxWindow::Validate</A><BR> +<A HREF="#wxwindowwarppointer">wxWindow::WarpPointer</A><BR> +<P> + +<HR> +<A NAME="topic1026"></A> +<H3>wxWindow::wxWindow</H3> +<P> +<B></B> <B>wxWindow</B>()<P> +Default constructor.<P> +<B></B> <B>wxWindow</B>(<B>wxWindow*</B><I> parent</I>, <B>wxWindowID </B><I>id</I>, + <B>const wxPoint& </B><I>pos = wxDefaultPosition</I>, + <B>const wxSize& </B><I>size = wxDefaultSize</I>, + <B>long </B><I>style = 0</I>, + <B>const wxString& </B><I>name = wxPanelNameStr</I>)<P> +Constructs a window, which can be a child of a frame, dialog or any other non-control window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>parent</I><UL><UL> +Pointer to a parent window.</UL></UL> +<P> +<I>id</I><UL><UL> +Window identifier. If -1, will automatically create an identifier.</UL></UL> +<P> +<I>pos</I><UL><UL> +Window position. wxDefaultPosition is (-1, -1) which indicates that wxWindows +should generate a default position for the window. If using the wxWindow class directly, supply +an actual position.</UL></UL> +<P> +<I>size</I><UL><UL> +Window size. wxDefaultSize is (-1, -1) which indicates that wxWindows +should generate a default size for the window.</UL></UL> +<P> +<I>style</I><UL><UL> +Window style. For generic window styles, please see <A HREF="wx260.htm#wxwindow">wxWindow</A>.</UL></UL> +<P> +<I>name</I><UL><UL> +Window name.</UL></UL> +<P> + +<HR> +<A NAME="topic1027"></A> +<H3>wxWindow::~wxWindow</H3> +<P> +<B></B> <B>~wxWindow</B>()<P> +Destructor. Deletes all subwindows, then deletes itself. Instead of using +the <B>delete</B> operator explicitly, you should normally +use <A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A> so that wxWindows +can delete a window only when it is safe to do so, in idle time.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx296.htm#windowdeletionoverview">Window deletion overview</A>, +<A HREF="wx260.htm#wxwindowonclosewindow">wxWindow::OnCloseWindow</A>, +<A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A>, +<A HREF="wx45.htm#wxcloseevent">wxCloseEvent</A><P> + +<HR> +<A NAME="topic1028"></A> +<H3>wxWindow::AddChild</H3> +<P> +<B>virtual void</B> <B>AddChild</B>(<B>wxWindow* </B><I>child</I>)<P> +Adds a child window. This is called automatically by window creation +functions so should not be required by the application programmer.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>child</I><UL><UL> +Child window to add.</UL></UL> +<P> + +<HR> +<A NAME="wxwindowcapturemouse"></A> +<H3>wxWindow::CaptureMouse</H3> +<P> +<B>virtual void</B> <B>CaptureMouse</B>()<P> +Directs all mouse input to this window. Call <A HREF="wx260.htm#wxwindowreleasemouse">wxWindow::ReleaseMouse</A> to +release the capture.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowreleasemouse">wxWindow::ReleaseMouse</A><P> + +<HR> +<A NAME="wxwindowcenter"></A> +<H3>wxWindow::Center</H3> +<P> +<B>void</B> <B>Center</B>(<B>int</B><I> direction</I>)<P> +A synonym for <A HREF="wx260.htm#wxwindowcentre">Centre</A>.<P> + +<HR> +<A NAME="wxwindowcentre"></A> +<H3>wxWindow::Centre</H3> +<P> +<B>virtual void</B> <B>Centre</B>(<B>int</B><I> direction = wxHORIZONTAL</I>)<P> +Centres the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>direction</I><UL><UL> +Specifies the direction for the centering. May be <TT>wxHORIZONTAL</TT>, <TT>wxVERTICAL</TT> +or <TT>wxBOTH</TT>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The actual behaviour depends on the derived window. For a frame or dialog box, +centring is relative to the whole display. For a panel item, centring is +relative to the panel.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowcenter">wxWindow::Center</A><P> + +<HR> +<A NAME="wxwindowclear"></A> +<H3>wxWindow::Clear</H3> +<P> +<B>void</B> <B>Clear</B>()<P> +Clears the window by filling it with the current background colour. Does not +cause an erase background event to be generated.<P> + +<HR> +<A NAME="topic1029"></A> +<H3>wxWindow::ClientToScreen</H3> +<P> +<B>virtual void</B> <B>ClientToScreen</B>(<B>int* </B><I>x</I>, <B>int* </B><I>y</I>) <B>const</B><P> +<B>virtual wxPoint</B> <B>ClientToScreen</B>(<B>const wxPoint&</B><I> pt</I>) <B>const</B><P> +Converts to screen coordinates from coordinates relative to this window.<P> +<I>x</I><UL><UL> +A pointer to a integer value for the x coordinate. Pass the client coordinate in, and +a screen coordinate will be passed out.</UL></UL> +<P> +<I>y</I><UL><UL> +A pointer to a integer value for the y coordinate. Pass the client coordinate in, and +a screen coordinate will be passed out.</UL></UL> +<P> +<I>pt</I><UL><UL> +The client position for the second form of the function.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>ClientToScreen(point)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>ClientToScreenXY(x, y)</B> +</TD> + +<TD VALIGN=TOP> +Returns a 2-tuple, (x, y) +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + + +<HR> +<A NAME="wxwindowclose"></A> +<H3>wxWindow::Close</H3> +<P> +<B>virtual bool</B> <B>Close</B>(<B>const bool</B><I> force = FALSE</I>)<P> +The purpose of this call is to provide a safer way of destroying a window than using +the <I>delete</I> operator.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>force</I><UL><UL> +FALSE if the window's close handler should be able to veto the destruction +of this window, TRUE if it cannot.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Close calls the <A HREF="wx45.htm#wxcloseevent">close handler</A> for the window, providing an opportunity for the window to +choose whether to destroy the window.<P> +The close handler should check whether the window is being deleted forcibly, +using <A HREF="wx45.htm#wxcloseeventgetforce">wxCloseEvent::GetForce</A>, in which case it should +destroy the window using <A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A>.<P> +Applies to managed windows (wxFrame and wxDialog classes) only.<P> +<I>Note</I> that calling Close does not guarantee that the window will be destroyed; but it +provides a way to simulate a manual close of a window, which may or may not be implemented by +destroying the window. The default implementation of wxDialog::OnCloseWindow does not +necessarily delete the dialog, since it will simply simulate an wxID_CANCEL event which +itself only hides the dialog.<P> +To guarantee that the window will be destroyed, call <A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A> instead.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx296.htm#windowdeletionoverview">Window deletion overview</A>, +<A HREF="wx260.htm#wxwindowonclosewindow">wxWindow::OnCloseWindow</A>, +<A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A>, +<A HREF="wx45.htm#wxcloseevent">wxCloseEvent</A><P> + +<HR> +<A NAME="wxwindowconvertdialogtopixels"></A> +<H3>wxWindow::ConvertDialogToPixels</H3> +<P> +<B>wxPoint</B> <B>ConvertDialogToPixels</B>(<B>const wxPoint&</B><I> pt</I>)<P> +<B>wxSize</B> <B>ConvertDialogToPixels</B>(<B>const wxSize&</B><I> sz</I>)<P> +Converts a point or size from dialog units to pixels.<P> +For the x dimension, the dialog units are multiplied by the average character width +and then divided by 4.<P> +For the y dimension, the dialog units are multiplied by the average character height +and then divided by 8.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Dialog units are used for maintaining a dialog's proportions even if the font changes. +Dialogs created using Dialog Editor optionally use dialog units.<P> +You can also use these functions programmatically. A convenience macro is defined:<P> +<FONT SIZE=2> +<PRE> +#define wxDLG_UNIT(parent, pt) parent->ConvertDialogToPixels(pt) +</PRE> +</FONT><P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowconvertpixelstodialog">wxWindow::ConvertPixelsToDialog</A><P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>ConvertDialogPointToPixels(point)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>ConvertDialogSizeToPixels(size)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxSize +</TD></TR> + + +</TABLE> +</UL></UL> +<P> +Additionally, the following helper functions are defined:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>wxDLG_PNT(win, point)</B> +</TD> + +<TD VALIGN=TOP> +Converts a wxPoint from dialog +units to pixels +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxDLG_SZE(win, size)</B> +</TD> + +<TD VALIGN=TOP> +Converts a wxSize from dialog +units to pixels +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + + +<HR> +<A NAME="wxwindowconvertpixelstodialog"></A> +<H3>wxWindow::ConvertPixelsToDialog</H3> +<P> +<B>wxPoint</B> <B>ConvertPixelsToDialog</B>(<B>const wxPoint&</B><I> pt</I>)<P> +<B>wxSize</B> <B>ConvertPixelsToDialog</B>(<B>const wxSize&</B><I> sz</I>)<P> +Converts a point or size from pixels to dialog units.<P> +For the x dimension, the pixels are multiplied by 4 and then divided by the average +character width.<P> +For the y dimension, the pixels are multipled by 8 and then divided by the average +character height.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Dialog units are used for maintaining a dialog's proportions even if the font changes. +Dialogs created using Dialog Editor optionally use dialog units.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowconvertdialogtopixels">wxWindow::ConvertDialogToPixels</A><P> + +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>ConvertDialogPointToPixels(point)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>ConvertDialogSizeToPixels(size)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxSize +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowdestroy"></A> +<H3>wxWindow::Destroy</H3> +<P> +<B>virtual bool</B> <B>Destroy</B>()<P> +Destroys the window safely. Use this function instead of the delete operator, since +different window classes can be destroyed differently. Frames and dialogs +are not destroyed immediately when this function is called - they are added +to a list of windows to be deleted on idle time, when all the window's events +have been processed. This prevents problems with events being sent to non-existant +windows.<P> +<B><FONT COLOR="#FF0000">Return value</FONT></B><P> +TRUE if the window has either been successfully deleted, or it has been added +to the list of windows pending real deletion.<P> + +<HR> +<A NAME="topic1030"></A> +<H3>wxWindow::DestroyChildren</H3> +<P> +<B>virtual void</B> <B>DestroyChildren</B>()<P> +Destroys all children of a window. Called automatically by the destructor.<P> + +<HR> +<A NAME="wxwindowdragacceptfiles"></A> +<H3>wxWindow::DragAcceptFiles</H3> +<P> +<B>virtual void</B> <B>DragAcceptFiles</B>(<B>const bool</B><I> accept</I>)<P> +Enables or disables elibility for drop file events (OnDropFiles).<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>accept</I><UL><UL> +If TRUE, the window is eligible for drop file events. If FALSE, the window +will not accept drop file events.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Windows only.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowondropfiles">wxWindow::OnDropFiles</A><P> + +<HR> +<A NAME="wxwindowenable"></A> +<H3>wxWindow::Enable</H3> +<P> +<B>virtual void</B> <B>Enable</B>(<B>const bool</B><I> enable</I>)<P> +Enable or disable the window for user input.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>enable</I><UL><UL> +If TRUE, enables the window for input. If FALSE, disables the window.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowisenabled">wxWindow::IsEnabled</A><P> + +<HR> +<A NAME="wxwindowfindfocus"></A> +<H3>wxWindow::FindFocus</H3> +<P> +<B>static wxWindow*</B> <B>FindFocus</B>()<P> +Finds the window or control which currently has the keyboard focus.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Note that this is a static function, so it can be called without needing a wxWindow pointer.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetfocus">wxWindow::SetFocus</A><P> + +<HR> +<A NAME="wxwindowfindwindow"></A> +<H3>wxWindow::FindWindow</H3> +<P> +<B>wxWindow*</B> <B>FindWindow</B>(<B>long</B><I> id</I>)<P> +Find a child of this window, by identifier.<P> +<B>wxWindow*</B> <B>FindWindow</B>(<B>const wxString&</B><I> name</I>)<P> +Find a child of this window, by name.<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>FindWindowById(id)</B> +</TD> + +<TD VALIGN=TOP> +Accepts an integer +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>FindWindowByName(name)</B> +</TD> + +<TD VALIGN=TOP> +Accepts a string +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowfit"></A> +<H3>wxWindow::Fit</H3> +<P> +<B>virtual void</B> <B>Fit</B>()<P> +Sizes the window so that it fits around its subwindows.<P> + +<HR> +<A NAME="wxwindowgetbackgroundcolour"></A> +<H3>wxWindow::GetBackgroundColour</H3> +<P> +<B>virtual wxColour</B> <B>GetBackgroundColour</B>() <B>const</B><P> +Returns the background colour of the window.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetbackgroundcolour">wxWindow::SetBackgroundColour</A>, +<A HREF="wx260.htm#wxwindowsetforegroundcolour">wxWindow::SetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowgetforegroundcolour">wxWindow::GetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowonerasebackground">wxWindow::OnEraseBackground</A><P> + +<HR> +<A NAME="topic1031"></A> +<H3>wxWindow::GetCharHeight</H3> +<P> +<B>virtual int</B> <B>GetCharHeight</B>() <B>const</B><P> +Returns the character height for this window.<P> + +<HR> +<A NAME="topic1032"></A> +<H3>wxWindow::GetCharWidth</H3> +<P> +<B>virtual int</B> <B>GetCharWidth</B>() <B>const</B><P> +Returns the average character width for this window.<P> + +<HR> +<A NAME="topic1033"></A> +<H3>wxWindow::GetChildren</H3> +<P> +<B>wxList&</B> <B>GetChildren</B>()<P> +Returns a reference to the list of the window's children.<P> + +<HR> +<A NAME="wxwindowgetclientsize"></A> +<H3>wxWindow::GetClientSize</H3> +<P> +<B>virtual void</B> <B>GetClientSize</B>(<B>int* </B><I>width</I>, <B>int* </B><I>height</I>) <B>const</B><P> +<B>virtual wxSize</B> <B>GetClientSize</B>() <B>const</B><P> +This gets the size of the window 'client area' in pixels. The client area is the +area which may be drawn on by the programmer, excluding title bar, border etc.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>width</I><UL><UL> +Receives the client width in pixels.</UL></UL> +<P> +<I>height</I><UL><UL> +Receives the client height in pixels.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>wxGetClientSizeTuple()</B> +</TD> + +<TD VALIGN=TOP> +Returns a 2-tuple of (width, height) +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>wxGetClientSize()</B> +</TD> + +<TD VALIGN=TOP> +Returns a wxSize object +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowgetconstraints"></A> +<H3>wxWindow::GetConstraints</H3> +<P> +<B>wxLayoutConstraints*</B> <B>GetConstraints</B>() <B>const</B><P> +Returns a pointer to the window's layout constraints, or NULL if there are none.<P> + +<HR> +<A NAME="wxwindowgetdefaultitem"></A> +<H3>wxWindow::GetDefaultItem</H3> +<P> +<B>wxButton*</B> <B>GetDefaultItem</B>() <B>const</B><P> +Returns a pointer to the button which is the default for this window, or NULL.<P> + +<HR> +<A NAME="wxwindowgetdroptarget"></A> +<H3>wxWindow::GetDropTarget</H3> +<P> +<B>wxDropTarget*</B> <B>GetDropTarget</B>() <B>const</B><P> +Returns the associated drop target, which may be NULL.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetdroptarget">wxWindow::SetDropTarget</A>, +<A HREF="wx312.htm#wxdndoverview">Drag and drop overview</A><P> + +<HR> +<A NAME="wxwindowgeteventhandler"></A> +<H3>wxWindow::GetEventHandler</H3> +<P> +<B>wxEvtHandler*</B> <B>GetEventHandler</B>() <B>const</B><P> +Returns the event handler for this window. By default, the window is its +own event handler.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowseteventhandler">wxWindow::SetEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PushEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PopEventHandler</A>, +<A HREF="wx85.htm#wxevthandlerprocessevent">wxEvtHandler::ProcessEvent</A>, +<A HREF="wx85.htm#wxevthandler">wxEvtHandler</A><P> + +<HR> +<A NAME="wxwindowgetfont"></A> +<H3>wxWindow::GetFont</H3> +<P> +<B>wxFont&</B> <B>GetFont</B>() <B>const</B><P> +Returns a reference to the font for this window.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetfont">wxWindow::SetFont</A><P> + +<HR> +<A NAME="wxwindowgetforegroundcolour"></A> +<H3>wxWindow::GetForegroundColour</H3> +<P> +<B>virtual wxColour</B> <B>GetForegroundColour</B>()<P> +Returns the foreground colour of the window.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The interpretation of foreground colour is open to interpretation according +to the window class; it may be the text colour or other colour, or it may not +be used at all.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetforegroundcolour">wxWindow::SetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowsetbackgroundcolour">wxWindow::SetBackgroundColour</A>, +<A HREF="wx260.htm#wxwindowgetbackgroundcolour">wxWindow::GetBackgroundColour</A><P> + +<HR> +<A NAME="topic1034"></A> +<H3>wxWindow::GetGrandParent</H3> +<P> +<B>wxWindow*</B> <B>GetGrandParent</B>() <B>const</B><P> +Returns the grandparent of a window, or NULL if there isn't one.<P> + +<HR> +<A NAME="topic1035"></A> +<H3>wxWindow::GetHandle</H3> +<P> +<B>void*</B> <B>GetHandle</B>() <B>const</B><P> +Returns the platform-specific handle of the physical window. Cast it to an appropriate +handle, such as <B>HWND</B> for Windows or <B>Widget</B> for Motif.<P> + +<HR> +<A NAME="wxwindowgetid"></A> +<H3>wxWindow::GetId</H3> +<P> +<B>int</B> <B>GetId</B>() <B>const</B><P> +Returns the identifier of the window.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Each window has an integer identifier. If the application has not provided one, +an identifier will be generated.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetid">wxWindow::SetId</A> +<A HREF="wx299.htm#windowids">Window identifiers</A><P> + +<HR> +<A NAME="topic1036"></A> +<H3>wxWindow::GetPosition</H3> +<P> +<B>virtual void</B> <B>GetPosition</B>(<B>int* </B><I>x</I>, <B>int* </B><I>y</I>) <B>const</B><P> +This gets the position of the window in pixels, relative to the parent window or +if no parent, relative to the whole display.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>x</I><UL><UL> +Receives the x position of the window.</UL></UL> +<P> +<I>y</I><UL><UL> +Receives the y position of the window.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>GetPosition()</B> +</TD> + +<TD VALIGN=TOP> +Returns a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>GetPositionTuple()</B> +</TD> + +<TD VALIGN=TOP> +Returns a tuple (x, y) +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="topic1037"></A> +<H3>wxWindow::GetLabel</H3> +<P> +<B>virtual wxString& </B> <B>GetLabel</B>() <B>const</B><P> +Generic way of getting a label from any window, for +identification purposes.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The interpretation of this function differs from class to class. +For frames and dialogs, the value returned is the title. For buttons or static text controls, it is +the button text. This function can be useful for meta-programs (such as testing +tools or special-needs access programs) which need to identify windows +by name.<P> + +<HR> +<A NAME="wxwindowgetname"></A> +<H3>wxWindow::GetName</H3> +<P> +<B>virtual wxString& </B> <B>GetName</B>() <B>const</B><P> +Returns the window's name.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This name is not guaranteed to be unique; it is up to the programmer to supply an appropriate +name in the window constructor or via <A HREF="wx260.htm#wxwindowsetname">wxWindow::SetName</A>.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetname">wxWindow::SetName</A><P> + +<HR> +<A NAME="topic1038"></A> +<H3>wxWindow::GetParent</H3> +<P> +<B>virtual wxWindow*</B> <B>GetParent</B>() <B>const</B><P> +Returns the parent of the window, or NULL if there is no parent.<P> + +<HR> +<A NAME="wxwindowgetrect"></A> +<H3>wxWindow::GetRect</H3> +<P> +<B>virtual wxRect</B> <B>GetRect</B>() <B>const</B><P> +Returns the size and position of the window as a <A HREF="wx193.htm#wxrect">wxRect</A> object.<P> + +<HR> +<A NAME="wxwindowgetreturncode"></A> +<H3>wxWindow::GetReturnCode</H3> +<P> +<B>int</B> <B>GetReturnCode</B>()<P> +Gets the return code for this window.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +A return code is normally associated with a modal dialog, where <A HREF="wx71.htm#wxdialogshowmodal">wxDialog::ShowModal</A> returns +a code to the application.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetreturncode">wxWindow::SetReturnCode</A>, <A HREF="wx71.htm#wxdialogshowmodal">wxDialog::ShowModal</A>, +<A HREF="wx71.htm#wxdialogendmodal">wxDialog::EndModal</A><P> + +<HR> +<A NAME="wxwindowgetscrollthumb"></A> +<H3>wxWindow::GetScrollThumb</H3> +<P> +<B>virtual int</B> <B>GetScrollThumb</B>(<B>int </B><I>orientation</I>)<P> +Returns the built-in scrollbar thumb size.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetscrollbar">wxWindow::SetScrollbar</A><P> + +<HR> +<A NAME="wxwindowgetscrollpos"></A> +<H3>wxWindow::GetScrollPos</H3> +<P> +<B>virtual int</B> <B>GetScrollPos</B>(<B>int </B><I>orientation</I>)<P> +Returns the built-in scrollbar position.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +See <A HREF="wx260.htm#wxwindowsetscrollbar">wxWindow::SetScrollbar</A><P> + +<HR> +<A NAME="wxwindowgetscrollrange"></A> +<H3>wxWindow::GetScrollRange</H3> +<P> +<B>virtual int</B> <B>GetScrollRange</B>(<B>int </B><I>orientation</I>)<P> +Returns the built-in scrollbar range.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetscrollbar">wxWindow::SetScrollbar</A><P> + +<HR> +<A NAME="wxwindowgetsize"></A> +<H3>wxWindow::GetSize</H3> +<P> +<B>virtual void</B> <B>GetSize</B>(<B>int* </B><I>width</I>, <B>int* </B><I>height</I>) <B>const</B><P> +<B>virtual wxSize</B> <B>GetSize</B>() <B>const</B><P> +This gets the size of the entire window in pixels.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>width</I><UL><UL> +Receives the window width.</UL></UL> +<P> +<I>height</I><UL><UL> +Receives the window height.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>GetSize()</B> +</TD> + +<TD VALIGN=TOP> +Returns a wxSize +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>GetSizeTuple()</B> +</TD> + +<TD VALIGN=TOP> +Returns a 2-tuple (width, height) +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="topic1039"></A> +<H3>wxWindow::GetTextExtent</H3> +<P> +<B>virtual void</B> <B>GetTextExtent</B>(<B>const wxString& </B><I>string</I>, <B>int* </B><I>x</I>, <B>int* </B><I>y</I>, + <B>int* </B><I>descent = NULL</I>, <B>int* </B><I>externalLeading = NULL</I>, + <B>const wxFont* </B><I>font = NULL</I>, <B>const bool</B><I> use16 = FALSE</I>) <B>const</B><P> +Gets the dimensions of the string as it would be drawn on the +window with the currently selected font.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>string</I><UL><UL> +String whose extent is to be measured.</UL></UL> +<P> +<I>x</I><UL><UL> +Return value for width.</UL></UL> +<P> +<I>y</I><UL><UL> +Return value for height.</UL></UL> +<P> +<I>descent</I><UL><UL> +Return value for descent (optional).</UL></UL> +<P> +<I>externalLeading</I><UL><UL> +Return value for external leading (optional).</UL></UL> +<P> +<I>font</I><UL><UL> +Font to use instead of the current window font (optional).</UL></UL> +<P> +<I>use16</I><UL><UL> +If TRUE, <I>string</I> contains 16-bit characters. The default is FALSE.</UL></UL> +<P> + +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>GetTextExtent(string)</B> +</TD> + +<TD VALIGN=TOP> +Returns a 2-tuple, (width, height) +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>GetFullTextExtent(string, font=NULL)</B> +</TD> + +<TD VALIGN=TOP> +Returns a +4-tuple, (width, height, descent, externalLeading) +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + + +<HR> +<A NAME="wxwindowgettitle"></A> +<H3>wxWindow::GetTitle</H3> +<P> +<B>virtual wxString</B> <B>GetTitle</B>()<P> +Gets the window's title. Applicable only to frames and dialogs.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsettitle">wxWindow::SetTitle</A><P> + +<HR> +<A NAME="wxwindowgetupdateregion"></A> +<H3>wxWindow::GetUpdateRegion</H3> +<P> +<B>virtual wxRegion</B> <B>GetUpdateRegion</B>() <B>const</B><P> +Returns the region specifying which parts of the window have been damaged. Should +only be called within an <A HREF="wx260.htm#wxwindowonpaint">OnPaint</A> event handler.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx195.htm#wxregion">wxRegion</A>, <A HREF="wx196.htm#wxregioniterator">wxRegionIterator</A>, <A HREF="wx260.htm#wxwindowonpaint">wxWindow::OnPaint</A><P> + +<HR> +<A NAME="topic1040"></A> +<H3>wxWindow::GetWindowStyleFlag</H3> +<P> +<B>long</B> <B>GetWindowStyleFlag</B>() <B>const</B><P> +Gets the window style that was passed to the consructor or <B>Create</B> member.<P> + +<HR> +<A NAME="wxwindowinitdialog"></A> +<H3>wxWindow::InitDialog</H3> +<P> +<B>void</B> <B>InitDialog</B>()<P> +Sends an <A HREF="wx260.htm#wxwindowoninitdialog">wxWindow::OnInitDialog</A> event, which +in turn transfers data to the dialog via validators.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowoninitdialog">wxWindow::OnInitDialog</A><P> + +<HR> +<A NAME="wxwindowisenabled"></A> +<H3>wxWindow::IsEnabled</H3> +<P> +<B>virtual bool</B> <B>IsEnabled</B>() <B>const</B><P> +Returns TRUE if the window is enabled for input, FALSE otherwise.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowenable">wxWindow::Enable</A><P> + +<HR> +<A NAME="wxwindowisretained"></A> +<H3>wxWindow::IsRetained</H3> +<P> +<B>virtual bool</B> <B>IsRetained</B>() <B>const</B><P> +Returns TRUE if the window is retained, FALSE otherwise.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Retained windows are only available on X platforms.<P> + +<HR> +<A NAME="wxwindowisshown"></A> +<H3>wxWindow::IsShown</H3> +<P> +<B>virtual bool</B> <B>IsShown</B>() <B>const</B><P> +Returns TRUE if the window is shown, FALSE if it has been hidden.<P> + +<HR> +<A NAME="wxwindowlayout"></A> +<H3>wxWindow::Layout</H3> +<P> +<B>void</B> <B>Layout</B>()<P> +Invokes the constraint-based layout algorithm for this window. It is called +automatically by the default <B>wxWindow::OnSize</B> member.<P> + +<HR> +<A NAME="wxwindowloadfromresource"></A> +<H3>wxWindow::LoadFromResource</H3> +<P> +<B>virtual bool</B> <B>LoadFromResource</B>(<B>wxWindow* </B><I>parent</I>, +<B>const wxString& </B><I>resourceName</I>, <B>const wxResourceTable* </B><I>resourceTable = NULL</I>)<P> +Loads a panel or dialog from a resource file.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>parent</I><UL><UL> +Parent window.</UL></UL> +<P> +<I>resourceName</I><UL><UL> +The name of the resource to load.</UL></UL> +<P> +<I>resourceTable</I><UL><UL> +The resource table to load it from. If this is NULL, the +default resource table will be used.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Return value</FONT></B><P> +TRUE if the operation succeeded, otherwise FALSE.<P> + +<HR> +<A NAME="wxwindowlower"></A> +<H3>wxWindow::Lower</H3> +<P> +<B>void</B> <B>Lower</B>()<P> +Lowers the window to the bottom of the window hierarchy if it is a managed window (dialog +or frame).<P> + +<HR> +<A NAME="wxwindowmakemodal"></A> +<H3>wxWindow::MakeModal</H3> +<P> +<B>virtual void</B> <B>MakeModal</B>(<B>const bool </B><I>flag</I>)<P> +Disables all other windows in the application so that +the user can only interact with this window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>flag</I><UL><UL> +If TRUE, this call disables all other windows in the application so that +the user can only interact with this window. If FALSE, the effect is reversed.</UL></UL> +<P> + +<HR> +<A NAME="wxwindowmove"></A> +<H3>wxWindow::Move</H3> +<P> +<B>void</B> <B>Move</B>(<B>int</B><I> x</I>, <B>int</B><I> y</I>)<P> +<B>void</B> <B>Move</B>(<B>const wxPoint&</B><I> pt</I>)<P> +Moves the window to the given position.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>x</I><UL><UL> +Required x position.</UL></UL> +<P> +<I>y</I><UL><UL> +Required y position.</UL></UL> +<P> +<I>pt</I><UL><UL> +<A HREF="wx171.htm#wxpoint">wxPoint</A> object representing the position.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Implementations of SetSize can also implicitly implement the +wxWindow::Move function, which is defined in the base wxWindow class +as the call:<P> +<PRE> + SetSize(x, y, -1, -1, wxSIZE_USE_EXISTING); +</PRE> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetsize">wxWindow::SetSize</A><P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>Move(point)</B> +</TD> + +<TD VALIGN=TOP> +Accepts a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>MoveXY(x, y)</B> +</TD> + +<TD VALIGN=TOP> +Accepts a pair of integers +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowonactivate"></A> +<H3>wxWindow::OnActivate</H3> +<P> +<B>void</B> <B>OnActivate</B>(<B>wxActivateEvent&</B><I> event</I>)<P> +Called when a window is activated or deactivated.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Object containing activation information.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +If the window is being activated, <A HREF="wx25.htm#wxactivateeventgetactive">wxActivateEvent::GetActive</A> returns TRUE, +otherwise it returns FALSE (it is being deactivated).<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx25.htm#wxactivateevent">wxActivateEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonchar"></A> +<H3>wxWindow::OnChar</H3> +<P> +<B>void</B> <B>OnChar</B>(<B>wxKeyEvent&</B><I> event</I>)<P> +Called when the user has pressed a key that is not a modifier (SHIFT, CONTROL or ALT).<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Object containing keypress information. See <A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A> for +details about this class.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This member function is called in response to a keypress. To intercept this event, +use the EVT_CHAR macro in an event table definition. Your <B>OnChar</B> handler may call this +default function to achieve default keypress functionality.<P> +Note that the ASCII values do not have explicit key codes: they are passed as ASCII +values.<P> +Note that not all keypresses can be intercepted this way. If you wish to intercept modifier +keypresses, then you will need to use <A HREF="wx260.htm#wxwindowonkeydown">wxWindow::OnKeyDown</A> or +<A HREF="wx260.htm#wxwindowonkeyup">wxWindow::OnKeyUp</A>.<P> +Most, but not all, windows allow keypresses to be intercepted.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowonkeydown">wxWindow::OnKeyDown</A>, <A HREF="wx260.htm#wxwindowonkeyup">wxWindow::OnKeyUp</A>, +<A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A>, <A HREF="wx260.htm#wxwindowoncharhook">wxWindow::OnCharHook</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowoncharhook"></A> +<H3>wxWindow::OnCharHook</H3> +<P> +<B>void</B> <B>OnCharHook</B>(<B>wxKeyEvent&</B><I> event</I>)<P> +This member is called to allow the window to intercept keyboard events +before they are processed by child windows.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Object containing keypress information. See <A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A> for +details about this class.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This member function is called in response to a keypress, if the window is active. To intercept this event, +use the EVT_CHAR_HOOK macro in an event table definition. If you do not process a particular +keypress, call <A HREF="wx84.htm#wxeventskip">wxEvent::Skip</A> to allow default processing.<P> +An example of using this function is in the implementation of escape-character processing for wxDialog, +where pressing ESC dismisses the dialog by <B>OnCharHook</B> 'forging' a cancel button press event.<P> +Note that the ASCII values do not have explicit key codes: they are passed as ASCII +values.<P> +This function is only relevant to top-level windows (frames and dialogs), and under +Windows only.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A>, <A HREF="wx260.htm#wxwindowoncharhook">wxWindow::OnCharHook</A>, +<A HREF="wx26.htm#wxapponcharhook">wxApp::OnCharHook</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowoncommand"></A> +<H3>wxWindow::OnCommand</H3> +<P> +<B>virtual void</B> <B>OnCommand</B>(<B>wxEvtHandler& </B><I>object</I>, <B>wxCommandEvent& </B><I>event</I>)<P> +This virtual member function is called if the control does not handle the command event.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>object</I><UL><UL> +Object receiving the command event.</UL></UL> +<P> +<I>event</I><UL><UL> +Command event</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This virtual function is provided mainly for backward compatibility. You can also intercept commands +from child controls by using an event table, with identifiers or identifier ranges to identify +the control(s) in question.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx52.htm#wxcommandevent">wxCommandEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonclose"></A> +<H3>wxWindow::OnClose</H3> +<P> +<B>virtual bool</B> <B>OnClose</B>()<P> +Called when the user has tried to close a a frame +or dialog box using the window manager (X) or system menu (Windows).<P> +<B>Note:</B> This is an obsolete function. +It is superceded by the <A HREF="wx260.htm#wxwindowonclosewindow">wxWindow::OnCloseWindow</A> event +handler.<P> +<B><FONT COLOR="#FF0000">Return value</FONT></B><P> +If TRUE is returned by OnClose, the window will be deleted by the system, otherwise the +attempt will be ignored. Do not delete the window from within this handler, although +you may delete other windows.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx296.htm#windowdeletionoverview">Window deletion overview</A>, +<A HREF="wx260.htm#wxwindowclose">wxWindow::Close</A>, +<A HREF="wx260.htm#wxwindowonclosewindow">wxWindow::OnCloseWindow</A>, +<A HREF="wx45.htm#wxcloseevent">wxCloseEvent</A><P> + +<HR> +<A NAME="wxwindowonclosewindow"></A> +<H3>wxWindow::OnCloseWindow</H3> +<P> +<B>void</B> <B>OnCloseWindow</B>(<B>wxCloseEvent& </B><I>event</I>)<P> +This is an event handler function called when the user has tried to close a a frame +or dialog box using the window manager (X) or system menu (Windows). It is +called via the <A HREF="wx260.htm#wxwindowclose">wxWindow::Close</A> function, so +that the application can also invoke the handler programmatically.<P> +Use the EVT_CLOSE event table macro to handle close events.<P> +You should check whether the application is forcing the deletion of the window +using <A HREF="wx45.htm#wxcloseeventgetforce">wxCloseEvent::GetForce</A>. If this is TRUE, +destroy the window using <A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A>. +If not, it is up to you whether you respond by destroying the window.<P> +(Note: GetForce is now superceded by CanVeto. So to test whether forced destruction of +the window is required, test for the negative of CanVeto. If CanVeto returns FALSE, +it is not possible to skip window deletion.)<P> +If you don't destroy the window, you should call <A HREF="wx45.htm#wxcloseeventveto">wxCloseEvent::Veto</A> to +let the calling code know that you did not destroy the window. This allows the <A HREF="wx260.htm#wxwindowclose">wxWindow::Close</A> function +to return TRUE or FALSE depending on whether the close instruction was honoured or not.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The <A HREF="wx260.htm#wxwindowonclose">wxWindow::OnClose</A> virtual function remains +for backward compatibility with earlier versions of wxWindows. The +default <B>OnCloseWindow</B> handler for wxFrame and wxDialog will call <B>OnClose</B>, +destroying the window if it returns TRUE or if the close is being forced.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx296.htm#windowdeletionoverview">Window deletion overview</A>, +<A HREF="wx260.htm#wxwindowclose">wxWindow::Close</A>, +<A HREF="wx260.htm#wxwindowonclose">wxWindow::OnClose</A>, +<A HREF="wx260.htm#wxwindowdestroy">wxWindow::Destroy</A>, +<A HREF="wx45.htm#wxcloseevent">wxCloseEvent</A>, +<A HREF="wx26.htm#wxapponqueryendsession">wxApp::OnQueryEndSession</A>, +<A HREF="wx26.htm#wxapponendsession">wxApp::OnEndSession</A><P> + +<HR> +<A NAME="wxwindowondropfiles"></A> +<H3>wxWindow::OnDropFiles</H3> +<P> +<B>void</B> <B>OnDropFiles</B>(<B>wxDropFilesEvent&</B><I> event</I>)<P> +Called when files have been dragged from the file manager to the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Drop files event. For more information, see <A HREF="wx80.htm#wxdropfilesevent">wxDropFilesEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The window must have previously been enabled for dropping by calling +<A HREF="wx260.htm#wxwindowdragacceptfiles">wxWindow::DragAcceptFiles</A>.<P> +This event is only generated under Windows.<P> +To intercept this event, use the EVT_DROP_FILES macro in an event table definition.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx80.htm#wxdropfilesevent">wxDropFilesEvent</A>, <A HREF="wx260.htm#wxwindowdragacceptfiles">wxWindow::DragAcceptFiles</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonerasebackground"></A> +<H3>wxWindow::OnEraseBackground</H3> +<P> +<B>void</B> <B>OnEraseBackground</B>(<B>wxEraseEvent&</B><I> event</I>)<P> +Called when the background of the window needs to be erased.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Erase background event. For more information, see <A HREF="wx83.htm#wxeraseevent">wxEraseEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This event is only generated under Windows.<P> +To intercept this event, use the EVT_ERASE_BACKGROUND macro in an event table definition.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx83.htm#wxeraseevent">wxEraseEvent</A>, <A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonkeydown"></A> +<H3>wxWindow::OnKeyDown</H3> +<P> +<B>void</B> <B>OnKeyDown</B>(<B>wxKeyEvent&</B><I> event</I>)<P> +Called when the user has pressed a key, before it is translated into an ASCII value using other +modifier keys that might be pressed at the same time.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Object containing keypress information. See <A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A> for +details about this class.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This member function is called in response to a key down event. To intercept this event, +use the EVT_KEY_DOWN macro in an event table definition. Your <B>OnKeyDown</B> handler may call this +default function to achieve default keypress functionality.<P> +Note that not all keypresses can be intercepted this way. If you wish to intercept special +keys, such as shift, control, and function keys, then you will need to use <A HREF="wx260.htm#wxwindowonkeydown">wxWindow::OnKeyDown</A> or +<A HREF="wx260.htm#wxwindowonkeyup">wxWindow::OnKeyUp</A>.<P> +Most, but not all, windows allow keypresses to be intercepted.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowonchar">wxWindow::OnChar</A>, <A HREF="wx260.htm#wxwindowonkeyup">wxWindow::OnKeyUp</A>, +<A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A>, <A HREF="wx260.htm#wxwindowoncharhook">wxWindow::OnCharHook</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonkeyup"></A> +<H3>wxWindow::OnKeyUp</H3> +<P> +<B>void</B> <B>OnKeyUp</B>(<B>wxKeyEvent&</B><I> event</I>)<P> +Called when the user has released a key.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Object containing keypress information. See <A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A> for +details about this class.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This member function is called in response to a key up event. To intercept this event, +use the EVT_KEY_UP macro in an event table definition. Your <B>OnKeyUp</B> handler may call this +default function to achieve default keypress functionality.<P> +Note that not all keypresses can be intercepted this way. If you wish to intercept special +keys, such as shift, control, and function keys, then you will need to use <A HREF="wx260.htm#wxwindowonkeydown">wxWindow::OnKeyDown</A> or +<A HREF="wx260.htm#wxwindowonkeyup">wxWindow::OnKeyUp</A>.<P> +Most, but not all, windows allow key up events to be intercepted.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowonchar">wxWindow::OnChar</A>, <A HREF="wx260.htm#wxwindowonkeydown">wxWindow::OnKeyDown</A>, +<A HREF="wx124.htm#wxkeyevent">wxKeyEvent</A>, <A HREF="wx260.htm#wxwindowoncharhook">wxWindow::OnCharHook</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonkillfocus"></A> +<H3>wxWindow::OnKillFocus</H3> +<P> +<B>void</B> <B>OnKillFocus</B>(<B>wxFocusEvent& </B><I>event</I>)<P> +Called when a window's focus is being killed.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The focus event. For more information, see <A HREF="wx99.htm#wxfocusevent">wxFocusEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +To intercept this event, use the macro EVT_KILL_FOCUS in an event table definition.<P> +Most, but not all, windows respond to this event.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx99.htm#wxfocusevent">wxFocusEvent</A>, <A HREF="wx260.htm#wxwindowonsetfocus">wxWindow::OnSetFocus</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonidle"></A> +<H3>wxWindow::OnIdle</H3> +<P> +<B>void</B> <B>OnIdle</B>(<B>wxIdleEvent& </B><I>event</I>)<P> +Provide this member function for any processing which needs to be done +when the application is idle.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx26.htm#wxapponidle">wxApp::OnIdle</A>, <A HREF="wx113.htm#wxidleevent">wxIdleEvent</A><P> + +<HR> +<A NAME="wxwindowoninitdialog"></A> +<H3>wxWindow::OnInitDialog</H3> +<P> +<B>void</B> <B>OnInitDialog</B>(<B>wxInitDialogEvent&</B><I> event</I>)<P> +Default handler for the wxEVT_INIT_DIALOG event. Calls <A HREF="wx260.htm#wxwindowtransferdatatowindow">wxWindow::TransferDataToWindow</A>.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Dialog initialisation event.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Gives the window the default behaviour of transferring data to child controls via +the validator that each control has.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx255.htm#wxvalidator">wxValidator</A>, <A HREF="wx260.htm#wxwindowtransferdatatowindow">wxWindow::TransferDataToWindow</A><P> + +<HR> +<A NAME="wxwindowonmenucommand"></A> +<H3>wxWindow::OnMenuCommand</H3> +<P> +<B>void</B> <B>OnMenuCommand</B>(<B>wxCommandEvent& </B><I>event</I>)<P> +Called when a menu command is received from a menu bar.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The menu command event. For more information, see <A HREF="wx52.htm#wxcommandevent">wxCommandEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +A function with this name doesn't actually exist; you can choose any member function to receive +menu command events, using the EVT_COMMAND macro for individual commands or EVT_COMMAND_RANGE for +a range of commands.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx52.htm#wxcommandevent">wxCommandEvent</A>, +<A HREF="wx260.htm#wxwindowonmenuhighlight">wxWindow::OnMenuHighlight</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonmenuhighlight"></A> +<H3>wxWindow::OnMenuHighlight</H3> +<P> +<B>void</B> <B>OnMenuHighlight</B>(<B>wxMenuEvent& </B><I>event</I>)<P> +Called when a menu select is received from a menu bar: that is, the +mouse cursor is over a menu item, but the left mouse button has not been +pressed.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The menu highlight event. For more information, see <A HREF="wx143.htm#wxmenuevent">wxMenuEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +You can choose any member function to receive +menu select events, using the EVT_MENU_HIGHLIGHT macro for individual menu items or EVT_MENU_HIGHLIGHT_ALL macro +for all menu items.<P> +The default implementation for <A HREF="wx104.htm#wxframeonmenuhighlight">wxFrame::OnMenuHighlight</A> displays help +text in the first field of the status bar.<P> +This function was known as <B>OnMenuSelect</B> in earlier versions of wxWindows, but this was confusing +since a selection is normally a left-click action.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx143.htm#wxmenuevent">wxMenuEvent</A>, +<A HREF="wx260.htm#wxwindowonmenucommand">wxWindow::OnMenuCommand</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + + +<HR> +<A NAME="wxwindowonmouseevent"></A> +<H3>wxWindow::OnMouseEvent</H3> +<P> +<B>void</B> <B>OnMouseEvent</B>(<B>wxMouseEvent&</B><I> event</I>)<P> +Called when the user has initiated an event with the +mouse.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The mouse event. See <A HREF="wx150.htm#wxmouseevent">wxMouseEvent</A> for +more details.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Most, but not all, windows respond to this event.<P> +To intercept this event, use the EVT_MOUSE_EVENTS macro in an event table definition, or individual +mouse event macros such as EVT_LEFT_DOWN.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx150.htm#wxmouseevent">wxMouseEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonmove"></A> +<H3>wxWindow::OnMove</H3> +<P> +<B>void</B> <B>OnMove</B>(<B>wxMoveEvent& </B><I>event</I>)<P> +Called when a window is moved.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The move event. For more information, see <A HREF="wx151.htm#wxmoveevent">wxMoveEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Use the EVT_MOVE macro to intercept move events.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Not currently implemented.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx151.htm#wxmoveevent">wxMoveEvent</A>, +<A HREF="wx104.htm#wxframeonsize">wxFrame::OnSize</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonpaint"></A> +<H3>wxWindow::OnPaint</H3> +<P> +<B>void</B> <B>OnPaint</B>(<B>wxPaintEvent& </B><I>event</I>)<P> +Sent to the event handler when the window must be refreshed.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Paint event. For more information, see <A HREF="wx164.htm#wxpaintevent">wxPaintEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Use the EVT_PAINT macro in an event table definition to intercept paint events.<P> +In a paint event handler, the application should always create a <A HREF="wx163.htm#wxpaintdc">wxPaintDC</A> object.<P> +For example:<P> +<FONT SIZE=2><PRE> + void MyWindow::OnPaint(wxPaintEvent& event) + { + wxPaintDC dc(this); + + DrawMyDocument(dc); + } +</PRE> +</FONT>You can optimize painting by retrieving the rectangles +that have been damaged and only repainting these. The rectangles are in +terms of the client area, and are unscrolled, so you will need to do +some calculations using the current view position to obtain logical, +scrolled units.<P> +Here is an example of using the <A HREF="wx196.htm#wxregioniterator">wxRegionIterator</A> class:<P> +<FONT SIZE=2><PRE> +// Called when window needs to be repainted. +void MyWindow::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this); + + // Find Out where the window is scrolled to + int vbX,vbY; // Top left corner of client + ViewStart(&vbX,&vbY); + + int vX,vY,vW,vH; // Dimensions of client area in pixels + wxRegionIterator upd(GetUpdateRegion()); // get the update rect list + + while (upd) + { + vX = upd.GetX(); + vY = upd.GetY(); + vW = upd.GetW(); + vH = upd.GetH(); + + // Alternatively we can do this: + // wxRect rect; + // upd.GetRect(&rect); + + // Repaint this rectangle + ...some code... + + upd ++ ; + } +} +</PRE> +</FONT><B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx164.htm#wxpaintevent">wxPaintEvent</A>, +<A HREF="wx163.htm#wxpaintdc">wxPaintDC</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonscroll"></A> +<H3>wxWindow::OnScroll</H3> +<P> +<B>void</B> <B>OnScroll</B>(<B>wxScrollEvent& </B><I>event</I>)<P> +Called when a scroll event is received from one of the window's built-in scrollbars.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Command event. Retrieve the new scroll position by +calling <A HREF="wx202.htm#wxscrolleventgetposition">wxScrollEvent::GetPosition</A>, and the +scrollbar orientation by calling <A HREF="wx202.htm#wxscrolleventgetorientation">wxScrollEvent::GetOrientation</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Note that it is not possible to distinguish between horizontal and vertical scrollbars +until the function is executing (you can't have one function for vertical, another +for horizontal events).<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx202.htm#wxscrollevent">wxScrollEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonsetfocus"></A> +<H3>wxWindow::OnSetFocus</H3> +<P> +<B>void</B> <B>OnSetFocus</B>(<B>wxFocusEvent& </B><I>event</I>)<P> +Called when a window's focus is being set.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +The focus event. For more information, see <A HREF="wx99.htm#wxfocusevent">wxFocusEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +To intercept this event, use the macro EVT_SET_FOCUS in an event table definition.<P> +Most, but not all, windows respond to this event.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx99.htm#wxfocusevent">wxFocusEvent</A>, <A HREF="wx260.htm#wxwindowonkillfocus">wxWindow::OnKillFocus</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonsize"></A> +<H3>wxWindow::OnSize</H3> +<P> +<B>void</B> <B>OnSize</B>(<B>wxSizeEvent& </B><I>event</I>)<P> +Called when the window has been resized.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +Size event. For more information, see <A HREF="wx206.htm#wxsizeevent">wxSizeEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +You may wish to use this for frames to resize their child windows as appropriate.<P> +Note that the size passed is of +the whole window: call <A HREF="wx260.htm#wxwindowgetclientsize">wxWindow::GetClientSize</A> for the area which may be +used by the application.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx206.htm#wxsizeevent">wxSizeEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowonsyscolourchanged"></A> +<H3>wxWindow::OnSysColourChanged</H3> +<P> +<B>void</B> <B>OnSysColourChanged</B>(<B>wxOnSysColourChangedEvent& </B><I>event</I>)<P> +Called when the user has changed the system colours.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>event</I><UL><UL> +System colour change event. For more information, see <A HREF="wx227.htm#wxsyscolourchangedevent">wxSysColourChangedEvent</A>.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx227.htm#wxsyscolourchangedevent">wxSysColourChangedEvent</A>, +<A HREF="wx299.htm#eventhandlingoverview">Event handling overview</A><P> + +<HR> +<A NAME="wxwindowpopeventhandler"></A> +<H3>wxWindow::PopEventHandler</H3> +<P> +<B>wxEvtHandler*</B> <B>PopEventHandler</B>(<B>bool </B><I>deleteHandler = FALSE</I>) <B>const</B><P> +Removes and returns the top-most event handler on the event handler stack.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>deleteHandler</I><UL><UL> +If this is TRUE, the handler will be deleted after it is removed. The +default value is FALSE.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowseteventhandler">wxWindow::SetEventHandler</A>, +<A HREF="wx260.htm#wxwindowgeteventhandler">wxWindow::GetEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PushEventHandler</A>, +<A HREF="wx85.htm#wxevthandlerprocessevent">wxEvtHandler::ProcessEvent</A>, +<A HREF="wx85.htm#wxevthandler">wxEvtHandler</A><P> + +<HR> +<A NAME="wxwindowpopupmenu"></A> +<H3>wxWindow::PopupMenu</H3> +<P> +<B>virtual bool</B> <B>PopupMenu</B>(<B>wxMenu* </B><I>menu</I>, <B>int </B><I>x</I>, <B>int </B><I>y</I>)<P> +Pops up the given menu at the specified coordinates, relative to this +window, and returns control when the user has dismissed the menu. If a +menu item is selected, the callback defined for the menu is called with +wxMenu and wxCommandEvent reference arguments. The callback should access +the commandInt member of the event to check the selected menu identifier.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>menu</I><UL><UL> +Menu to pop up.</UL></UL> +<P> +<I>x</I><UL><UL> +Required x position for the menu to appear.</UL></UL> +<P> +<I>y</I><UL><UL> +Required y position for the menu to appear.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx140.htm#wxmenu">wxMenu</A><P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Just before the menu is popped up, <A HREF="wx140.htm#wxmenuupdateui">wxMenu::UpdateUI</A> is called +to ensure that the menu items are in the correct state.<P> + +<HR> +<A NAME="wxwindowpusheventhandler"></A> +<H3>wxWindow::PushEventHandler</H3> +<P> +<B>void</B> <B>PushEventHandler</B>(<B>wxEvtHandler* </B><I>handler</I>)<P> +Pushes this event handler onto the event stack for the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>handler</I><UL><UL> +Specifies the handler to be pushed.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +An event handler is an object that is capable of processing the events +sent to a window. By default, the window is its own event handler, but +an application may wish to substitute another, for example to allow +central implementation of event-handling for a variety of different +window classes.<P> +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PushEventHandler</A> allows +an application to set up a chain of event handlers, where an event not handled by one event handler is +handed to the next one in the chain. Use <A HREF="wx260.htm#wxwindowpopeventhandler">wxWindow::PopEventHandler</A> to +remove the event handler.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowseteventhandler">wxWindow::SetEventHandler</A>, +<A HREF="wx260.htm#wxwindowgeteventhandler">wxWindow::GetEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PopEventHandler</A>, +<A HREF="wx85.htm#wxevthandlerprocessevent">wxEvtHandler::ProcessEvent</A>, +<A HREF="wx85.htm#wxevthandler">wxEvtHandler</A><P> + +<HR> +<A NAME="wxwindowraise"></A> +<H3>wxWindow::Raise</H3> +<P> +<B>void</B> <B>Raise</B>()<P> +Raises the window to the top of the window hierarchy if it is a managed window (dialog +or frame).<P> + +<HR> +<A NAME="wxwindowrefresh"></A> +<H3>wxWindow::Refresh</H3> +<P> +<B>virtual void</B> <B>Refresh</B>(<B>const bool</B><I> eraseBackground = TRUE</I>, <B>const wxRect* </B><I>rect += NULL</I>)<P> +Causes a message or event to be generated to repaint the +window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>eraseBackground</I><UL><UL> +If TRUE, the background will be +erased.</UL></UL> +<P> +<I>rect</I><UL><UL> +If non-NULL, only the given rectangle will +be treated as damaged.</UL></UL> +<P> + +<HR> +<A NAME="wxwindowreleasemouse"></A> +<H3>wxWindow::ReleaseMouse</H3> +<P> +<B>virtual void</B> <B>ReleaseMouse</B>()<P> +Releases mouse input captured with <A HREF="wx260.htm#wxwindowcapturemouse">wxWindow::CaptureMouse</A>.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowcapturemouse">wxWindow::CaptureMouse</A><P> + +<HR> +<A NAME="wxwindowremovechild"></A> +<H3>wxWindow::RemoveChild</H3> +<P> +<B>virtual void</B> <B>RemoveChild</B>(<B>wxWindow* </B><I>child</I>)<P> +Removes a child window. This is called automatically by window deletion +functions so should not be required by the application programmer.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>child</I><UL><UL> +Child window to remove.</UL></UL> +<P> + +<HR> +<A NAME="wxwindowscreentoclient"></A> +<H3>wxWindow::ScreenToClient</H3> +<P> +<B>virtual void</B> <B>ScreenToClient</B>(<B>int* </B><I>x</I>, <B>int* </B><I>y</I>) <B>const</B><P> +<B>virtual wxPoint</B> <B>ScreenToClient</B>(<B>const wxPoint& </B><I>pt</I>) <B>const</B><P> +Converts from screen to client window coordinates.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>x</I><UL><UL> +Stores the screen x coordinate and receives the client x coordinate.</UL></UL> +<P> +<I>y</I><UL><UL> +Stores the screen x coordinate and receives the client x coordinate.</UL></UL> +<P> +<I>pt</I><UL><UL> +The screen position for the second form of the function.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>ScreenToClient(point)</B> +</TD> + +<TD VALIGN=TOP> +Accepts and returns a wxPoint +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>ScreenToClientXY(x, y)</B> +</TD> + +<TD VALIGN=TOP> +Returns a 2-tuple, (x, y) +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + + +<HR> +<A NAME="wxwindowscrollwindow"></A> +<H3>wxWindow::ScrollWindow</H3> +<P> +<B>virtual void</B> <B>ScrollWindow</B>(<B>int </B><I>dx</I>, <B>int </B><I>dy</I>, <B>const wxRect*</B><I> rect = NULL</I>)<P> +Physically scrolls the pixels in the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>dx</I><UL><UL> +Amount to scroll horizontally.</UL></UL> +<P> +<I>dy</I><UL><UL> +Amount to scroll vertically.</UL></UL> +<P> +<I>rect</I><UL><UL> +Rectangle to invalidate. If this is NULL, the whole window is invalidated. If you +pass a rectangle corresponding to the area of the window exposed by the scroll, your painting handler +can optimise painting by checking for the invalidated region.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Available only under Windows.<P> +Use this function to optimise your scrolling implementations, to minimise the area that must be +redrawn.<P> + +<HR> +<A NAME="wxwindowsetacceleratortable"></A> +<H3>wxWindow::SetAcceleratorTable</H3> +<P> +<B>virtual void</B> <B>SetAcceleratorTable</B>(<B>const wxAcceleratorTable&</B><I> accel</I>)<P> +Sets the accelerator table for this window. See <A HREF="wx24.htm#wxacceleratortable">wxAcceleratorTable</A>.<P> + +<HR> +<A NAME="wxwindowsetautolayout"></A> +<H3>wxWindow::SetAutoLayout</H3> +<P> +<B>void</B> <B>SetAutoLayout</B>(<B>const bool</B><I> autoLayout</I>)<P> +Determines whether the <A HREF="wx260.htm#wxwindowlayout">wxWindow::Layout</A> function will +be called automatically when the window is resized.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>autoLayout</I><UL><UL> +Set this to TRUE if you wish the Layout function to be called +from within wxWindow::OnSize functions.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetconstraints">wxWindow::SetConstraints</A><P> + +<HR> +<A NAME="wxwindowsetbackgroundcolour"></A> +<H3>wxWindow::SetBackgroundColour</H3> +<P> +<B>virtual void</B> <B>SetBackgroundColour</B>(<B>const wxColour& </B><I>colour</I>)<P> +Sets the background colour of the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>colour</I><UL><UL> +The colour to be used as the background colour.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The background colour is usually painted by the default +<A HREF="wx260.htm#wxwindowonerasebackground">wxWindow::OnEraseBackground</A> event handler function.<P> +Note that setting the background colour does not cause an immediate refresh, so you +may wish to call <A HREF="wx260.htm#wxwindowclear">wxWindow::Clear</A> or <A HREF="wx260.htm#wxwindowrefresh">wxWindow::Refresh</A> after +calling this function.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetbackgroundcolour">wxWindow::GetBackgroundColour</A>, +<A HREF="wx260.htm#wxwindowsetforegroundcolour">wxWindow::SetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowgetforegroundcolour">wxWindow::GetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowclear">wxWindow::Clear</A>, +<A HREF="wx260.htm#wxwindowrefresh">wxWindow::Refresh</A>, +<A HREF="wx260.htm#wxwindowonerasebackground">wxWindow::OnEraseBackground</A><P> + +<HR> +<A NAME="wxwindowsetclientsize"></A> +<H3>wxWindow::SetClientSize</H3> +<P> +<B>virtual void</B> <B>SetClientSize</B>(<B>int</B><I> width</I>, <B>int</B><I> height</I>)<P> +<B>virtual void</B> <B>SetClientSize</B>(<B>const wxSize&</B><I> size</I>)<P> +This sets the size of the window client area in pixels. Using this function to size a window +tends to be more device-independent than <A HREF="wx260.htm#wxwindowsetsize">wxWindow::SetSize</A>, since the application need not +worry about what dimensions the border or title bar have when trying to fit the window +around panel items, for example.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>width</I><UL><UL> +The required client area width.</UL></UL> +<P> +<I>height</I><UL><UL> +The required client area height.</UL></UL> +<P> +<I>size</I><UL><UL> +The required client size.</UL></UL> +<P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>SetClientSize(size)</B> +</TD> + +<TD VALIGN=TOP> +Accepts a wxSize +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>SetClientSizeWH(width, height)</B> +</TD> + +<TD VALIGN=TOP> + +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowsetcursor"></A> +<H3>wxWindow::SetCursor</H3> +<P> +<B>virtual void</B> <B>SetCursor</B>(<B>const wxCursor&</B><I>cursor</I>)<P> +Sets the window's cursor. Notice that setting the cursor for this window does +not set it for its children so you'll need to explicitly call SetCursor() for +them too if you need it.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>cursor</I><UL><UL> +Specifies the cursor that the window should normally display.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx268.htm#wxsetcursor">::wxSetCursor</A>, <A HREF="wx59.htm#wxcursor">wxCursor</A><P> + +<HR> +<A NAME="wxwindowseteventhandler"></A> +<H3>wxWindow::SetEventHandler</H3> +<P> +<B>void</B> <B>SetEventHandler</B>(<B>wxEvtHandler* </B><I>handler</I>)<P> +Sets the event handler for this window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>handler</I><UL><UL> +Specifies the handler to be set.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +An event handler is an object that is capable of processing the events +sent to a window. By default, the window is its own event handler, but +an application may wish to substitute another, for example to allow +central implementation of event-handling for a variety of different +window classes.<P> +It is usually better to use <A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PushEventHandler</A> since +this sets up a chain of event handlers, where an event not handled by one event handler is +handed to the next one in the chain.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgeteventhandler">wxWindow::GetEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PushEventHandler</A>, +<A HREF="wx260.htm#wxwindowpusheventhandler">wxWindow::PopEventHandler</A>, +<A HREF="wx85.htm#wxevthandlerprocessevent">wxEvtHandler::ProcessEvent</A>, +<A HREF="wx85.htm#wxevthandler">wxEvtHandler</A><P> + +<HR> +<A NAME="wxwindowsetconstraints"></A> +<H3>wxWindow::SetConstraints</H3> +<P> +<B>void</B> <B>SetConstraints</B>(<B>wxLayoutConstraints* </B><I>constraints</I>)<P> +Sets the window to have the given layout constraints. The window +will then own the object, and will take care of its deletion. +If an existing layout constraints object is already owned by the +window, it will be deleted.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>constraints</I><UL><UL> +The constraints to set. Pass NULL to disassociate and delete the window's +constraints.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +You must call <A HREF="wx260.htm#wxwindowsetautolayout">wxWindow::SetAutoLayout</A> to tell a window to use +the constraints automatically in OnSize; otherwise, you must +override OnSize and call Layout explicitly.<P> + +<HR> +<A NAME="wxwindowsetdroptarget"></A> +<H3>wxWindow::SetDropTarget</H3> +<P> +<B>void</B> <B>SetDropTarget</B>(<B>wxDropTarget*</B><I> target</I>)<P> +Associates a drop target with this window.<P> +If the window already has a drop target, it is deleted.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetdroptarget">wxWindow::GetDropTarget</A>, +<A HREF="wx312.htm#wxdndoverview">Drag and drop overview</A><P> + +<HR> +<A NAME="wxwindowsetfocus"></A> +<H3>wxWindow::SetFocus</H3> +<P> +<B>virtual void</B> <B>SetFocus</B>()<P> +This sets the window to receive keyboard input.<P> + +<HR> +<A NAME="wxwindowsetfont"></A> +<H3>wxWindow::SetFont</H3> +<P> +<B>void</B> <B>SetFont</B>(<B>const wxFont& </B><I>font</I>)<P> +Sets the font for this window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>font</I><UL><UL> +Font to associate with this window.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetfont">wxWindow::GetFont</A><P> + +<HR> +<A NAME="wxwindowsetforegroundcolour"></A> +<H3>wxWindow::SetForegroundColour</H3> +<P> +<B>virtual void</B> <B>SetForegroundColour</B>(<B>const wxColour& </B><I>colour</I>)<P> +Sets the foreground colour of the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>colour</I><UL><UL> +The colour to be used as the foreground colour.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The interpretation of foreground colour is open to interpretation according +to the window class; it may be the text colour or other colour, or it may not +be used at all.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetforegroundcolour">wxWindow::GetForegroundColour</A>, +<A HREF="wx260.htm#wxwindowsetbackgroundcolour">wxWindow::SetBackgroundColour</A>, +<A HREF="wx260.htm#wxwindowgetbackgroundcolour">wxWindow::GetBackgroundColour</A><P> + +<HR> +<A NAME="wxwindowsetid"></A> +<H3>wxWindow::SetId</H3> +<P> +<B>void</B> <B>SetId</B>(<B>int</B><I> id</I>)<P> +Sets the identifier of the window.<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Each window has an integer identifier. If the application has not provided one, +an identifier will be generated. Normally, the identifier should be provided +on creation and should not be modified subsequently.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetid">wxWindow::GetId</A>, +<A HREF="wx299.htm#windowids">Window identifiers</A><P> + +<HR> +<A NAME="wxwindowsetname"></A> +<H3>wxWindow::SetName</H3> +<P> +<B>virtual void</B> <B>SetName</B>(<B>const wxString& </B><I>name</I>)<P> +Sets the window's name.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>name</I><UL><UL> +A name to set for the window.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetname">wxWindow::GetName</A><P> + +<HR> +<A NAME="wxwindowsetpalette"></A> +<H3>wxWindow::SetPalette</H3> +<P> +<B>virtual void</B> <B>SetPalette</B>(<B>wxPalette* </B><I>palette</I>)<P> +Obsolete - use <A HREF="wx65.htm#wxdcsetpalette">wxDC::SetPalette</A> instead.<P> + +<HR> +<A NAME="wxwindowsetreturncode"></A> +<H3>wxWindow::SetReturnCode</H3> +<P> +<B>void</B> <B>SetReturnCode</B>(<B>int </B><I>retCode</I>)<P> +Sets the return code for this window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>retCode</I><UL><UL> +The integer return code, usually a control identifier.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +A return code is normally associated with a modal dialog, where <A HREF="wx71.htm#wxdialogshowmodal">wxDialog::ShowModal</A> returns +a code to the application. The function <A HREF="wx71.htm#wxdialogendmodal">wxDialog::EndModal</A> calls <B>SetReturnCode</B>.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgetreturncode">wxWindow::GetReturnCode</A>, <A HREF="wx71.htm#wxdialogshowmodal">wxDialog::ShowModal</A>, +<A HREF="wx71.htm#wxdialogendmodal">wxDialog::EndModal</A><P> + +<HR> +<A NAME="wxwindowsetscrollbar"></A> +<H3>wxWindow::SetScrollbar</H3> +<P> +<B>virtual void</B> <B>SetScrollbar</B>(<B>int </B><I>orientation</I>, <B>int </B><I>position</I>, +<B>int </B><I>thumbSize</I>, <B>int </B><I>range</I>, +<B>const bool </B><I>refresh = TRUE</I>)<P> +Sets the scrollbar properties of a built-in scrollbar.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>orientation</I><UL><UL> +Determines the scrollbar whose page size is to be set. May be wxHORIZONTAL or wxVERTICAL.</UL></UL> +<P> +<I>position</I><UL><UL> +The position of the scrollbar in scroll units.</UL></UL> +<P> +<I>thumbSize</I><UL><UL> +The size of the thumb, or visible portion of the scrollbar, in scroll units.</UL></UL> +<P> +<I>range</I><UL><UL> +The maximum position of the scrollbar.</UL></UL> +<P> +<I>refresh</I><UL><UL> +TRUE to redraw the scrollbar, FALSE otherwise.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +Let's say you wish to display 50 lines of text, using the same font. +The window is sized so that you can only see 16 lines at a time.<P> +You would use:<P> +<FONT SIZE=2><PRE> + SetScrollbar(wxVERTICAL, 0, 16, 50); +</PRE> +</FONT><P> +Note that with the window at this size, the thumb position can never go +above 50 minus 16, or 34.<P> +You can determine how many lines are currently visible by dividing the current view +size by the character height in pixels.<P> +When defining your own scrollbar behaviour, you will always need to recalculate +the scrollbar settings when the window size changes. You could therefore put your +scrollbar calculations and SetScrollbar +call into a function named AdjustScrollbars, which can be called initially and also +from your <A HREF="wx260.htm#wxwindowonsize">wxWindow::OnSize</A> event handler function.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx297.htm#scrollingoverview">Scrolling overview</A>, +<A HREF="wx201.htm#wxscrollbar">wxScrollBar</A>, <A HREF="wx203.htm#wxscrolledwindow">wxScrolledWindow</A><P> + +<HR> +<A NAME="wxwindowsetscrollpos"></A> +<H3>wxWindow::SetScrollPos</H3> +<P> +<B>virtual void</B> <B>SetScrollPos</B>(<B>int </B><I>orientation</I>, <B>int </B><I>pos</I>, <B>const bool </B><I>refresh = TRUE</I>)<P> +Sets the position of one of the built-in scrollbars.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>orientation</I><UL><UL> +Determines the scrollbar whose position is to be set. May be wxHORIZONTAL or wxVERTICAL.</UL></UL> +<P> +<I>pos</I><UL><UL> +Position in scroll units.</UL></UL> +<P> +<I>refresh</I><UL><UL> +TRUE to redraw the scrollbar, FALSE otherwise.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +This function does not directly affect the contents of the window: it is up to the +application to take note of scrollbar attributes and redraw contents accordingly.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowsetscrollbar">wxWindow::SetScrollbar</A>, +<A HREF="wx260.htm#wxwindowsetscrollpos">wxWindow::GetScrollPos</A>, +<A HREF="wx260.htm#wxwindowgetscrollthumb">wxWindow::GetScrollThumb</A>, +<A HREF="wx201.htm#wxscrollbar">wxScrollBar</A>, <A HREF="wx203.htm#wxscrolledwindow">wxScrolledWindow</A><P> + +<HR> +<A NAME="wxwindowsetsize"></A> +<H3>wxWindow::SetSize</H3> +<P> +<B>virtual void</B> <B>SetSize</B>(<B>int</B><I> x</I>, <B>int</B><I> y</I>, <B>int</B><I> width</I>, <B>int</B><I> height</I>, + <B>int</B><I> sizeFlags = wxSIZE_AUTO</I>)<P> +<B>virtual void</B> <B>SetSize</B>(<B>const wxRect&</B><I> rect</I>)<P> +Sets the size and position of the window in pixels.<P> +<B>virtual void</B> <B>SetSize</B>(<B>int</B><I> width</I>, <B>int</B><I> height</I>)<P> +<B>virtual void</B> <B>SetSize</B>(<B>const wxSize&</B><I> size</I>)<P> +Sets the size of the window in pixels.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>x</I><UL><UL> +Required x position in pixels, or -1 to indicate that the existing +value should be used.</UL></UL> +<P> +<I>y</I><UL><UL> +Required y position in pixels, or -1 to indicate that the existing +value should be used.</UL></UL> +<P> +<I>width</I><UL><UL> +Required width in pixels, or -1 to indicate that the existing +value should be used.</UL></UL> +<P> +<I>height</I><UL><UL> +Required height position in pixels, or -1 to indicate that the existing +value should be used.</UL></UL> +<P> +<I>size</I><UL><UL> +<A HREF="wx205.htm#wxsize">wxSize</A> object for setting the size.</UL></UL> +<P> +<I>rect</I><UL><UL> +<A HREF="wx193.htm#wxrect">wxRect</A> object for setting the position and size.</UL></UL> +<P> +<I>sizeFlags</I><UL><UL> +Indicates the interpretation of other parameters. It is a bit list of the following:<P> +<B>wxSIZE_AUTO_WIDTH</B>: a -1 width value is taken to indicate +a wxWindows-supplied default width.<BR> + +<B>wxSIZE_AUTO_HEIGHT</B>: a -1 height value is taken to indicate +a wxWindows-supplied default width.<BR> + +<B>wxSIZE_AUTO</B>: -1 size values are taken to indicate +a wxWindows-supplied default size.<BR> + +<B>wxSIZE_USE_EXISTING</B>: existing dimensions should be used +if -1 values are supplied.<BR> + +<B>wxSIZE_ALLOW_MINUS_ONE</B>: allow dimensions of -1 and less to be interpreted +as real dimensions, not default values. +</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +The second form is a convenience for calling the first form with default +x and y parameters, and must be used with non-default width and height values.<P> +The first form sets the position and optionally size, of the window. +Parameters may be -1 to indicate either that a default should be supplied +by wxWindows, or that the current value of the dimension should be used.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowmove">wxWindow::Move</A><P> +<B><FONT COLOR="#0000C8">wxPython note:</FONT></B><BR> + In place of a single overloaded method name, wxPython +implements the following methods:<P> + +<UL><UL> + +<TABLE> + + +<TR><TD VALIGN=TOP> +<B>SetDimensions(x, y, width, height, sizeFlags=wxSIZE_AUTO)</B> +</TD> + +<TD VALIGN=TOP> + +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>SetSize(size)</B> +</TD> + +<TD VALIGN=TOP> + +</TD></TR> + + +<TR><TD VALIGN=TOP> +<B>SetPosition(point)</B> +</TD> + +<TD VALIGN=TOP> + +</TD></TR> + + +</TABLE> +</UL></UL> + +<P> + +<HR> +<A NAME="wxwindowsetsizehints"></A> +<H3>wxWindow::SetSizeHints</H3> +<P> +<B>virtual void</B> <B>SetSizeHints</B>(<B>int</B><I> minW=-1</I>, <B>int</B><I> minH=-1</I>, <B>int</B><I> maxW=-1</I>, <B>int</B><I> maxH=-1</I>, + <B>int</B><I> incW=-1</I>, <B>int</B><I> incH=-1</I>)<P> +Allows specification of minimum and maximum window sizes, and window size increments. +If a pair of values is not set (or set to -1), the default values will be used.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>minW</I><UL><UL> +Specifies the minimum width allowable.</UL></UL> +<P> +<I>minH</I><UL><UL> +Specifies the minimum height allowable.</UL></UL> +<P> +<I>maxW</I><UL><UL> +Specifies the maximum width allowable.</UL></UL> +<P> +<I>maxH</I><UL><UL> +Specifies the maximum height allowable.</UL></UL> +<P> +<I>incW</I><UL><UL> +Specifies the increment for sizing the width (Motif/Xt only).</UL></UL> +<P> +<I>incH</I><UL><UL> +Specifies the increment for sizing the height (Motif/Xt only).</UL></UL> +<P> +<B><FONT COLOR="#FF0000">Remarks</FONT></B><P> +If this function is called, the user will not be able to size the window outside the +given bounds.<P> +The resizing increments are only significant under Motif or Xt.<P> + +<HR> +<A NAME="wxwindowsettitle"></A> +<H3>wxWindow::SetTitle</H3> +<P> +<B>virtual void</B> <B>SetTitle</B>(<B>const wxString& </B><I>title</I>)<P> +Sets the window's title. Applicable only to frames and dialogs.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>title</I><UL><UL> +The window's title.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowgettitle">wxWindow::GetTitle</A><P> + +<HR> +<A NAME="topic1041"></A> +<H3>wxWindow::Show</H3> +<P> +<B>virtual bool</B> <B>Show</B>(<B>const bool</B><I> show</I>)<P> +Shows or hides the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>show</I><UL><UL> +If TRUE, displays the window and brings it to the front. Otherwise, +hides the window.</UL></UL> +<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowisshown">wxWindow::IsShown</A><P> + +<HR> +<A NAME="wxwindowtransferdatafromwindow"></A> +<H3>wxWindow::TransferDataFromWindow</H3> +<P> +<B>virtual bool</B> <B>TransferDataFromWindow</B>()<P> +Transfers values from child controls to data areas specified by their validators. Returns +FALSE if a transfer failed.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowtransferdatatowindow">wxWindow::TransferDataToWindow</A>, +<A HREF="wx255.htm#wxvalidator">wxValidator</A>, <A HREF="wx260.htm#wxwindowvalidate">wxWindow::Validate</A><P> + +<HR> +<A NAME="wxwindowtransferdatatowindow"></A> +<H3>wxWindow::TransferDataToWindow</H3> +<P> +<B>virtual bool</B> <B>TransferDataToWindow</B>()<P> +Transfers values to child controls from data areas specified by their validators.<P> +<B><FONT COLOR="#FF0000">Return value</FONT></B><P> +Returns FALSE if a transfer failed.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowtransferdatafromwindow">wxWindow::TransferDataFromWindow</A>, +<A HREF="wx255.htm#wxvalidator">wxValidator</A>, <A HREF="wx260.htm#wxwindowvalidate">wxWindow::Validate</A><P> + +<HR> +<A NAME="wxwindowvalidate"></A> +<H3>wxWindow::Validate</H3> +<P> +<B>virtual bool</B> <B>Validate</B>()<P> +Validates the current values of the child controls using their validators.<P> +<B><FONT COLOR="#FF0000">Return value</FONT></B><P> +Returns FALSE if any of the validations failed.<P> +<B><FONT COLOR="#FF0000">See also</FONT></B><P> +<A HREF="wx260.htm#wxwindowtransferdatafromwindow">wxWindow::TransferDataFromWindow</A>, +<A HREF="wx260.htm#wxwindowtransferdatafromwindow">wxWindow::TransferDataFromWindow</A>, +<A HREF="wx255.htm#wxvalidator">wxValidator</A><P> + +<HR> +<A NAME="wxwindowwarppointer"></A> +<H3>wxWindow::WarpPointer</H3> +<P> +<B>void</B> <B>WarpPointer</B>(<B>int</B><I> x</I>, <B>int</B><I> y</I>)<P> +Moves the pointer to the given position on the window.<P> +<B><FONT COLOR="#FF0000">Parameters</FONT></B><P> +<I>x</I><UL><UL> +The new x position for the cursor.</UL></UL> +<P> +<I>y</I><UL><UL> +The new y position for the cursor.</UL></UL> +<P> + +</BODY></HTML> diff --git a/samples/html/test/fft.html b/samples/html/test/fft.html new file mode 100644 index 0000000000..3cef164b9e --- /dev/null +++ b/samples/html/test/fft.html @@ -0,0 +1,144 @@ +<head> + <META > + <META NAME="Author" CONTENT="Vaclav Slavik"> + <META NAME="Keywords" CONTENT="wxWindows,HTML widget,HTML,free,Unix,Linux,Windows,cross-platform,wxHTML,LGPL"> + <TITLE>wxHTML : wxWindows HTML library</TITLE> +</head> + +<body TEXT="#000000" BGCOLOR="#8D99BC" LINK="#51188E" VLINK="#51188E" ALINK="#FF0000"> + +<!-- TITLE BAR --> + +<center> +<img src="pic/logo.png"> +<p> +[ Intro & News ] +<a href="features.html.iso-8859-1">[ Features ]</a> +<a href="downloads.html.iso-8859-1">[ Download ]</a> +<a href="licence.html.iso-8859-1">[ Licence ]</a> +<a href="screenshots.html.iso-8859-1">[ Screenshots ]</a> +<a href="links.html.iso-8859-1">[ Links & Apps ]</a> +</center> + + +<!-- PAGE --> + + +<!-- HEADLINE --> + +<p align=center><b><font color="#9B3030"> + +<center><table bgcolor="#00000" width="60%" cellpadding=1> +<tr><td> +<table width="100%" cellspacing=1 cellpadding=0><tr><td bgcolor="#7783A2" valign=center><font color="#FFFFFF" size=+2><center> + +Latest release 0.2.3 + +</center></font> +</table> +</table></center> + +</font></b></p> + +<center></center> +<div align=right><font size=-1> +<!-- begin include --> +2811<!-- end --> visitors since January 99 + + +<br>Last updated on : June 13, 1999 + + +</font></div> +<p> + +<table width="100%" cellspacing=0 cellpadding=6 border><tr><td width="30%" bgcolor="#7783A2" valign=top> + + +<!-- NEWS --> + +<h2><u>News</u></h2> + +<ul> +<li><b><font color="#9B3030">13/06/1999</font> - CVS available! </b><br> +Thanks to Russell Smith, development version of wxHTML is available through CVS. +See Download page for details! +</ul> + +<ul> +<li><b><font color="#9B3030">13/06/1999</font> - 0.2.3 release </b><br> +Only minor changes and bugfixes. +</ul> + +<ul> +<li><b><font color="#9B3030">16/05/1999</font> - New release </b><br> +Well, 0.2.1 is out. It contains some bug fixes (mainly related to Visual C++) +and new help controller that works with MS HTML Help Workshop projects as +it's native format. Patch from previous version is only 30kB so don't hesitate +to download it! +</ul> + +<ul> +<li><b><font color="#9B3030">02/05/1999</font> - Beta release 0.2 is out!</b><br> +Ok, it's here, download it! Help controller is included (and broken under +MSW/Mingw32 - I'll fix it asap. If anyone can help with it, please do so...) +</ul> + + + + + +<!-- INTRO --> + +<td valign=top> +<h2><u>Intro</u></h2> + +I started work on this library in January, 1999. +<br>The main goal was to provide light-weight HTML viewer for +<a href="http://web.ukonline.co.uk/julian.smart/wxwin">wxWindows 2</a> toolkit. +This viewer was expected to be used as help/documentation browser rather than full-featured web browser. + +<p>This library is released under <b><font color="#330000"><a href="licence.html.iso-8859-1"> +wxWindows Library Licence, Version 3</a></font>.</b> It is basically +GNU Library General Public Licence except that it makes using +wxHTML in commercial products much easier. + +<p>The library should work on all platforms supported by wxWindows - it +is written as poor wxWindows-only code, without line of platform-specific +code (as I hope :-). It is known to compile under these enviromnets: + +<ul> +<li>EGCS under Linux +<li>Cygwin b20 or Mingw32 under Windows 95 +</ul> + + + + + + +<!-- AUTHOR --> + +<h2><u>Author(s)</u></h2> +<i>wxHTML (and this page) is copyrighted by Vaclav Slavik. Parts of wxHTML are copyrighted by other +autors - all of them are listed in <a href="#contrib">contributors</a> section. +</i> +<p> +Feel free to send your suggestions, comments, bug reports to me. My +e-mail address is + +<br><A HREF="mailto:slavik2@czn.cz">slavik2@czn.cz</A> +<br>or +<br><A HREF="mailto:vsla8348@ss1000.ms.mff.cuni.cz">vsla8348@ss1000.ms.mff.cuni.cz</A> +<p align=right>Vaclav Slavik + + +<a name="contrib"><h2><u>Contributors</u></h2></a> +<ul> +<li><b><u>Guillermo Rodriguez Garcia</u></b> (<a href="mailto:guille@iies.es">guille@iies.es</a>) +<br>contributed GIF reading routines +</ul> + +</table> +</body> +</html> diff --git a/samples/html/test/pic.png b/samples/html/test/pic.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc18c1296d650b9ad75f9dc61b15d6cb0d09b03 GIT binary patch literal 31315 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 literal 0 HcmV?d00001 diff --git a/samples/html/test/pic2.bmp b/samples/html/test/pic2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e79b526fc39951accbbbf783da31d00d3809da98 GIT binary patch literal 23244 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 UdzA;qwXgsAR&VTVIZ(v^13ZQ8S^xk5 literal 0 HcmV?d00001 diff --git a/samples/html/test/tables.htm b/samples/html/test/tables.htm new file mode 100644 index 0000000000..b27eb5e3f5 --- /dev/null +++ b/samples/html/test/tables.htm @@ -0,0 +1,116 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="GENERATOR" CONTENT="Mozilla/4.06 [en] (X11; I; Linux 2.0.35 i686) [Netscape]"> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EF" VLINK="#51188E" ALINK="#FF0000"> + +<H3> +This is TABLES +tests page...</H3> + + +(yes, really, see bellow:) +<BR>Click <a href="test.htm">here</a> to go to original testing page... +<BR>Click <a href="../../docs/html/man.htm">here</a> to go to manuals... +<BR> +<CENTER><TABLE CELLSPACING=5 BORDER COLS=2 WIDTH="40%" NOSAVE > +<TR ALIGN=CENTER NOSAVE> +<TD WIDTH="40%" NOSAVE>Top left +<BR>(two lines expression) +<P>paragraph done</TD> + +<TD NOSAVE>Top right</TD> +</TR> + +<TR> +<TD>Bottom left</TD> + +<TD>Bottom right</TD> +</TR> +</TABLE></CENTER> + +<P>Subsampling is shown there: +<BR> +<TABLE BORDER COLS=2 WIDTH="100%" NOSAVE > +<TR NOSAVE> +<TD VALIGN=BOTTOM NOSAVE> +<TABLE BORDER COLS=2 WIDTH="50%" NOSAVE > +<TR ALIGN=CENTER BGCOLOR="#3366FF" NOSAVE> +<TD>a</TD> + +<TD WIDTH="10%" NOSAVE>b</TD> +</TR> + +<TR NOSAVE> +<TD>c</TD> + +<TD NOSAVE>d</TD> +</TR> + +</TABLE> +</TD> + +<TD VALIGN=BOTTOM NOSAVE>2</TD> +</TR> + +<TR NOSAVE> +<TD>3 dflkj lkjfl dkjldkfjl flk jflkf lkjflkj ljlf ajlfj alff h khg hgj +gjg jg gjhfg fg gjh gjf jgf jgj f gjfgj kfajg </TD> + +<TD ALIGN=CENTER VALIGN=BOTTOM BGCOLOR="#FFFF99" NOSAVE>4 +<BR>gh +<BR>gfh +<BR>gh +<BR>hg +<BR>5</TD> +</TR> +</TABLE> + +<P>This is "default" table - with no sizes givev: +<BR> +<TABLE BORDER COLS=4 WIDTH="100%" NOSAVE > +<TR NOSAVE> +<TD>Hello</TD> + +<TD NOSAVE>lkfdsjlk fj dlfj lkfj lkjflk jlfk lk fjlk elwkf lkejflek f jlekjflkj +ljlk lk jlkf lefjl j flkj ljl lf lfj lfjl lj lwe lekf;eh kfejh lkh kjh +kjhkj hkj hkj lkh kjh kjlh kj</TD> + +<TD>shortebn formo lr lk</TD> + +<TD>djsf lkjlf poer oi pjr po kpk </TD> +</TR> + +<TR> +<TD>a</TD> + +<TD>b</TD> + +<TD>c</TD> + +<TD>d</TD> +</TR> + +<TR NOSAVE> +<TD>1</TD> + +<TD>2</TD> + +<TD COLSPAN="2" ROWSPAN="2" NOSAVE>3</TD> +</TR> + +<TR> +<TD>A</TD> + +<TD>B</Td> +</TR> +</TABLE> + + + + + + + diff --git a/samples/html/test/test.cpp b/samples/html/test/test.cpp new file mode 100644 index 0000000000..fa61e56489 --- /dev/null +++ b/samples/html/test/test.cpp @@ -0,0 +1,203 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "test.cpp" + #pragma interface "test.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + +#include <wx/image.h> +#include <wx/html/htmlwin.h> + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + virtual bool OnInit(); + }; + +// Define a new frame type: this is going to be our main frame + class MyFrame : public wxFrame + { + public: + // ctor(s) + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnBack(wxCommandEvent& event); + void OnForward(wxCommandEvent& event); + + private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + }; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands + enum + { + // menu items + Minimal_Quit = 1, + Minimal_About, + Minimal_Back, + Minimal_Forward, + + // controls start here (the numbers are, of course, arbitrary) + Minimal_Text = 1000, + }; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// ---------------------------------------------------------------------------- + +// the event tables connect the wxWindows events with the functions (event +// handlers) which process them. It can be also done at run-time, but for the +// simple menu events like this the static method is much simpler. + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + EVT_MENU(Minimal_Back, MyFrame::OnBack) + EVT_MENU(Minimal_Forward, MyFrame::OnForward) + END_EVENT_TABLE() + + // Create a new application object: this macro will allow wxWindows to create + // the application object during program execution (it's better than using a + // static object for many reasons) and also declares the accessor function + // wxGetApp() which will return the reference of the right type (i.e. MyApp and + // not wxApp) + IMPLEMENT_APP(MyApp) + + // ============================================================================ + // implementation + // ============================================================================ + + // ---------------------------------------------------------------------------- + // the application class + // ---------------------------------------------------------------------------- + // `Main program' equivalent: the program execution "starts" here + bool MyApp::OnInit() + { + wxLogDebug("[starting testing app]"); + #if wxUSE_LIBPNG + wxImage::AddHandler(new wxPNGHandler); + #endif + #if wxUSE_LIBJPEG + wxImage::AddHandler(new wxJPEGHandler); + #endif + // Create the main application window + MyFrame *frame = new MyFrame("wxHtmlWindow testing application", + wxPoint(50, 50), wxSize(640, 480)); + + // Show it and tell the application that it's our main window + // @@@ what does it do exactly, in fact? is it necessary here? + frame->Show(TRUE); + SetTopWindow(frame); + + + // success: wxApp::OnRun() will be called which will enter the main message + // loop and the application will run. If we returned FALSE here, the + // application would exit immediately. + return TRUE; + } + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +wxHtmlWindow *html; + +// frame constructor + MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) + { + // create a menu bar + wxMenu *menuFile = new wxMenu; + wxMenu *menuNav = new wxMenu; + + menuFile->Append(Minimal_About, "&Load wxWindows manual page"); + menuFile->AppendSeparator(); + menuFile->Append(Minimal_Quit, "E&xit"); + menuNav->Append(Minimal_Back, "Go &BACK"); + menuNav->Append(Minimal_Forward, "Go &FORWARD"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, "&File"); + menuBar->Append(menuNav, "&Navigate"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + + CreateStatusBar(1); + + { + wxConfig *cfg = new wxConfig("wxHtmlTest"); + html = new wxHtmlWindow(this); + html -> SetRelatedFrame(this, "HTML : %s"); + html -> SetRelatedStatusBar(0); + html -> ReadCustomization(cfg); + delete cfg; + html -> LoadPage("test.htm"); + } + } + + +// event handlers + + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) + { + // TRUE is to force the frame to close + wxLogDebug("about to save config..."); + wxConfig *cfg = new wxConfig("wxHtmlTest"); + html -> WriteCustomization(cfg); + delete cfg; + Close(TRUE); + } + + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) + { + html -> LoadPage("fft.html"); + } + + + + void MyFrame::OnBack(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryBack()) wxMessageBox("You reached prehistory era!"); + } + + + void MyFrame::OnForward(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryForward()) wxMessageBox("No more items in history!"); + } diff --git a/samples/html/test/test.htm b/samples/html/test/test.htm new file mode 100644 index 0000000000..dc7ead5694 --- /dev/null +++ b/samples/html/test/test.htm @@ -0,0 +1,266 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="GENERATOR" CONTENT="Mozilla/4.06 [en] (X11; I; Linux 2.0.35 i686) [Netscape]"> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#006600" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088"> + +<b><a href="tables.htm">click here to go to tables test page!</a></b> + +<p> +This is - - default text, now switching to +<CENTER> +<P>center, now still ctr, now exiting</CENTER> +exited!.<A HREF="#downtown">[link to down]</A> +<P>Hello, this *is* default charset (helvetica, probably) and it is displayed +with one <FONT COLOR="#FF0000">COLOR CHANGE</FONT>. Of course we +can have as many color changes as we can, what about this <FONT COLOR="#FF0000">M</FONT><FONT COLOR="#FFFF00">A</FONT><FONT COLOR="#33FF33">D</FONT><B><FONT COLOR="#FFFFFF"><FONT SIZE=+1>N</FONT></FONT></B>E<FONT COLOR="#999999">S</FONT><FONT COLOR="#CC33CC">S?</FONT> +<P><FONT COLOR="#000000">There was a space above.</FONT> +<BR> +<HR WIDTH="100%">This was a line. <TT>(BTW we are in <B>fixed</B> font +/ <I><U>typewriter</U> font</I> right now :-)</TT> +<BR>This is in <B>BOLD</B> face. This is <I>ITALIC.</I> This is <B><I><U>E +V E R Y T H I N G</U></I></B>. +<BR> +<P><BR> +<CENTER> +<P>Right now, <FONT COLOR="#0000FF"><FONT SIZE=+4>centered REALLY Big Text</FONT></FONT>, +how do you like (space) it?</CENTER> + +<DIV ALIGN=right>RIGHT: <FONT SIZE=-2>text-2, </FONT><FONT SIZE=-1>text-1, +</FONT>text+0, +<FONT SIZE=+1>text+1, +</FONT><FONT COLOR="#FF0000"><FONT SIZE=+2>text+2, +</FONT></FONT><FONT SIZE=+3>text+3, +</FONT><FONT SIZE=+4>text+4</FONT> +<BR><U><FONT SIZE=+1>we are right now</FONT></U></DIV> + +<CENTER><U><FONT SIZE=+1>we are center now</FONT></U></CENTER> +<U><FONT SIZE=+1>we are left now.</FONT></U> +<P><I><FONT COLOR="#3366FF">Blue italic text is displayed there....</FONT></I> +<H1> + +<HR ALIGN=LEFT SIZE=10 WIDTH="50%">This is heading one.</H1> +this is normal +<CENTER> +<H1> +This is <FONT COLOR="#33FF33">CENTERED</FONT> heading one</H1></CENTER> +<FONT COLOR="#FFFF00">Yes, hmmmmmmmmm........, right now, <TT>we should +display some tiny nice image</TT>, he?</FONT> +<BR><IMG SRC="pic.png" ALT="Testing image image" ><IMG SRC="pic2.bmp">and this is text...... +<P><IMG SRC="pic.png" ALT="Testing image image" HEIGHT=200 WIDTH=327 ALIGN=CENTER>and +this is text...... +<BR><A HREF="pic.png"><IMG SRC="pic.png" ALT="Testing image image" HEIGHT=160 WIDTH=100 ALIGN=TEXTTOP></A> (try clicking on the image :-) and +this is text...... +<BR> +<BR> +<UL> +<LI> +item 1</LI> + +<LI> +item 2</LI> + +<UL> +<LI> +nested item</LI> + +<LI> +nested item 2</LI> +</UL> + +<LI> +item 3</LI> +</UL> + +<OL> +<LI> +item one</LI> + +<LI> +item two</LI> + +<OL> +<LI> +nsted item</LI> +</OL> + +<LI> +last numbered item</LI> +</OL> + +<H1> +Heading 1</H1> +<I>Italic text now...</I> +<H2> +<I>Heading 2</I></H2> +<I>and now?</I> +<H3> +Heading 3</H3> + +<H4> +Heading 4</H4> + +<H5> +Heading 5</H5> + +<H6> +Heading 6</H6> +And this is normal text, once again :-) +<BR> +<BR> +<BR> +<BR> +<BR> +<BR> +<P>And yes, we're in <FONT SIZE=+4>HTML DOCUMENT, </FONT><FONT SIZE=+1>so +what about some nice <A HREF="fft.html">hypertext link</A>??</FONT> +<P>hello? +<BR> +<P><BR> +<CENTER> +<P>This is <A NAME="downtown"></a>centered paragraph</CENTER> + +<P>This is new par? +<P><B>We switched to BOLD</B> +<P><B>This is new paragraph</B> Bold is off now. +<P>new par +<P> ----------- +<P><FONT SIZE=-2>Hello</FONT> +<OL><FONT SIZE=-2>this is standalone :-)</FONT> +<LI> +<FONT SIZE=-2>This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.</FONT></LI> + +<LI> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO</FONT></LI> + +<BLOCKQUOTE><FONT SIZE=+0><B>(blockquote)</B>two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO</FONT> +<BLOCKQUOTE><FONT SIZE=+0>two two two two two two twotwo TWO two two two</FONT></BLOCKQUOTE> +<FONT SIZE=+0>two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO</FONT></BLOCKQUOTE> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO</FONT> +<LI> +<FONT SIZE=-2>This is item nyumber 3.</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.</FONT></LI> + +<LI> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item nyumber 3.</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.</FONT></LI> + +<LI> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item nyumber 3.</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.</FONT></LI> + +<LI> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item nyumber 3.</FONT></LI> + +<LI> +<FONT SIZE=-2>This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.</FONT></LI> + +<LI> +<FONT SIZE=-2>two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO</FONT></LI> + +<P><BR><FONT SIZE=-2>two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO two two two two two +two twotwo TWO</FONT> +<P><FONT SIZE=-2>two two two two two two twotwo TWO two two two two two +two twotwo TWO two two two two two two twotwo TWO two two two two two two +twotwo TWO</FONT> +<LI> +<FONT SIZE=-2>This is item nyumber 3.</FONT></LI> +</OL> +Now, you will see some PRE text:<p> +<PRE>// This is sample C++ code: + +void main(int argc, char *argv[]) +{ + printf("Go away, man!\n"); + i = 666; + printf("\n\n\nCRASH\n DOWN NOW. . . \n"); +}</PRE> + +<H3>WWW</H3> +<A HREF="http://www.kde.org">This is WWW link to KDE site!</A> +<BR> + + + + + + +<A HREF="http://www.ms.mff.cuni.cz/~vsla8348/wxhtml/index.html">(one folder up)</A> +<BR> + +... +<BR> +... +<BR> +Link to normal text file : <a href="test.cpp">test.cpp</a> +<BR> +And link to BINARY : <a href="test">Unix</a> or <a href="test.exe">Windows</a> +<BR> +<a href="http://www.tue.nl">ANOTHER LINK(www.tue.nl)</a> + + +</BODY> +</HTML> diff --git a/samples/html/test/test.rc b/samples/html/test/test.rc new file mode 100644 index 0000000000..82bdf07561 --- /dev/null +++ b/samples/html/test/test.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" + diff --git a/samples/html/virtual/Makefile.am b/samples/html/virtual/Makefile.am new file mode 100644 index 0000000000..e5fe674b3e --- /dev/null +++ b/samples/html/virtual/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = virtual + +virtual_SOURCES = virtual.cpp diff --git a/samples/html/virtual/start.htm b/samples/html/virtual/start.htm new file mode 100644 index 0000000000..1dc3cdd353 --- /dev/null +++ b/samples/html/virtual/start.htm @@ -0,0 +1,12 @@ +<html> +<head><title>VFS Demo</title></head> +<body> +<h3>Virtual File Systems demonstration</h3> + +Hello. This sample demonstrates VFS. Try the link (and have a look +at status bar before clicking on them) +<p> +<a href="myVFS:node"><b>Enter top level Node...</b></a> + +</body> +</html> diff --git a/samples/html/virtual/virtual.cpp b/samples/html/virtual/virtual.cpp new file mode 100644 index 0000000000..99e848ee55 --- /dev/null +++ b/samples/html/virtual/virtual.cpp @@ -0,0 +1,231 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: virtua;.cpp +// Purpose: wxHtml testing example +// demonstrates virtual file systems feature +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "test.cpp" + #pragma interface "test.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + + +#include <wx/html/htmlwin.h> + + +// new handler class: + +#include <wx/wfstream.h> +#include <wx/mstream.h> + + + +class MyVFS : public wxFileSystemHandler +{ +public: + MyVFS() : wxFileSystemHandler() {} + + wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location); + bool CanOpen(const wxString& location); +}; + + +bool MyVFS::CanOpen(const wxString& location) +{ + return (GetProtocol(location) == "myVFS"); +} + + + +wxFSFile* MyVFS::OpenFile(wxFileSystem& fs, const wxString& location) +{ + wxFSFile *f; + wxInputStream *str; + char *buf = (char*)malloc(1024); + + sprintf(buf, "<html><body><h2><i>You're in Node <u>%s</u></i></h2><p>" + "Where do you want to go?<br><blockquote>" + "<a href=\"%s-1\">sub-1</a><br>" + "<a href=\"%s-2\">sub-2</a><br>" + "<a href=\"%s-3\">sub-3</a><br>" + "</blockquote></body></html>", + location.GetData(), location.GetData(), location.GetData(), location.GetData()); + str = new wxMemoryInputStream(buf, strlen(buf)); + f = new wxFSFile(str, location, "text/html", wxEmptyString); + return f; +} + + + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + virtual bool OnInit(); + }; + +// Define a new frame type: this is going to be our main frame + class MyFrame : public wxFrame + { + public: + // ctor(s) + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnBack(wxCommandEvent& event); + void OnForward(wxCommandEvent& event); + + private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + }; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands + enum + { + // menu items + Minimal_Quit = 1, + Minimal_About, + Minimal_Back, + Minimal_Forward, + + // controls start here (the numbers are, of course, arbitrary) + Minimal_Text = 1000, + }; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// ---------------------------------------------------------------------------- + +// the event tables connect the wxWindows events with the functions (event +// handlers) which process them. It can be also done at run-time, but for the +// simple menu events like this the static method is much simpler. + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + EVT_MENU(Minimal_Back, MyFrame::OnBack) + EVT_MENU(Minimal_Forward, MyFrame::OnForward) + END_EVENT_TABLE() + + // Create a new application object: this macro will allow wxWindows to create + // the application object during program execution (it's better than using a + // static object for many reasons) and also declares the accessor function + // wxGetApp() which will return the reference of the right type (i.e. MyApp and + // not wxApp) + IMPLEMENT_APP(MyApp) + + // ============================================================================ + // implementation + // ============================================================================ + + // ---------------------------------------------------------------------------- + // the application class + // ---------------------------------------------------------------------------- + + // `Main program' equivalent: the program execution "starts" here + bool MyApp::OnInit() + { + // Create the main application window + MyFrame *frame = new MyFrame("wxHtmlWindow testing application", + wxPoint(50, 50), wxSize(640, 480)); + + // Show it and tell the application that it's our main window + // @@@ what does it do exactly, in fact? is it necessary here? + frame->Show(TRUE); + SetTopWindow(frame); + wxFileSystem::AddHandler(new MyVFS); + + // success: wxApp::OnRun() will be called which will enter the main message + // loop and the application will run. If we returned FALSE here, the + // application would exit immediately. + return TRUE; + } + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +wxHtmlWindow *html; + +// frame constructor + MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) + { + // create a menu bar + wxMenu *menuFile = new wxMenu; + wxMenu *menuNav = new wxMenu; + + menuFile->Append(Minimal_Quit, "E&xit"); + menuNav->Append(Minimal_Back, "Go &BACK"); + menuNav->Append(Minimal_Forward, "Go &FORWARD"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, "&File"); + menuBar->Append(menuNav, "&Navigate"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + + CreateStatusBar(1); + + html = new wxHtmlWindow(this); + html -> SetRelatedFrame(this, "VFS Demo: '%s'"); + html -> SetRelatedStatusBar(1); + html -> LoadPage("start.htm"); + } + + +// event handlers + + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) + { + // TRUE is to force the frame to close + Close(TRUE); + } + + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) + { + } + + + + void MyFrame::OnBack(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryBack()) wxMessageBox("You reached prehistory era!"); + } + + + void MyFrame::OnForward(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryForward()) wxMessageBox("No more items in history!"); + } diff --git a/samples/html/virtual/virtual.rc b/samples/html/virtual/virtual.rc new file mode 100644 index 0000000000..82bdf07561 --- /dev/null +++ b/samples/html/virtual/virtual.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" + diff --git a/samples/html/widget/Makefile.am b/samples/html/widget/Makefile.am new file mode 100644 index 0000000000..5e03a4a779 --- /dev/null +++ b/samples/html/widget/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = widget + +widget_SOURCES = widget.cpp diff --git a/samples/html/widget/start.htm b/samples/html/widget/start.htm new file mode 100644 index 0000000000..23c528d04e --- /dev/null +++ b/samples/html/widget/start.htm @@ -0,0 +1,20 @@ +<html> +<head><title>Binder demo</title></head> +<body> +<h3>wxHtmlBinderCell demonstration</h3> + +There is binded window somewhere around. Enjoy it. + +<hr> +<center> +<mybind name="experimental binded window :-)" x=300 y=500> +</center> +<hr> + +<mybind name="(small one)" x=150 y=30> +<hr> + +<mybind name="a widget with floating width, hurray :-)" float=y x="50" y=50> + +</body> +</html> diff --git a/samples/html/widget/widget.cpp b/samples/html/widget/widget.cpp new file mode 100644 index 0000000000..74fa22ff81 --- /dev/null +++ b/samples/html/widget/widget.cpp @@ -0,0 +1,244 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: virtua;.cpp +// Purpose: wxHtml testing example +// demonstrates virtual file systems feature +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "test.cpp" + #pragma interface "test.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + + +#include <wx/html/htmlwin.h> + + + + +/* + + +TAG HANDER FOR 'MYBIND' TAG + + +*/ + +#include <wx/html/mod_templ.h> + + +TAG_HANDLER_BEGIN(MYBIND, "MYBIND") + + TAG_HANDLER_PROC(tag) + { + wxWindow *wnd; + int ax, ay; + int fl = 0; + + tag.ScanParam("X", "%i", &ax); + tag.ScanParam("Y", "%i", &ay); + if (tag.HasParam("FLOAT")) fl = ax; + + wnd = new wxTextCtrl( m_WParser -> GetWindow(), -1, tag.GetParam("NAME"), + wxPoint(0,0), wxSize(ax, ay), wxTE_MULTILINE ); + wnd -> Show(TRUE); + + m_WParser -> OpenContainer() -> InsertCell(new wxHtmlWidgetCell(wnd, fl)); + + return FALSE; + } + +TAG_HANDLER_END(MYBIND) + + + +TAGS_MODULE_BEGIN(MyBind) + + TAGS_MODULE_ADD(MYBIND) + +TAGS_MODULE_END(MyBind) + + + + + + + + + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + virtual bool OnInit(); + }; + +// Define a new frame type: this is going to be our main frame + class MyFrame : public wxFrame + { + public: + // ctor(s) + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnBack(wxCommandEvent& event); + void OnForward(wxCommandEvent& event); + + private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + }; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands + enum + { + // menu items + Minimal_Quit = 1, + Minimal_About, + Minimal_Back, + Minimal_Forward, + + // controls start here (the numbers are, of course, arbitrary) + Minimal_Text = 1000, + }; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// ---------------------------------------------------------------------------- + +// the event tables connect the wxWindows events with the functions (event +// handlers) which process them. It can be also done at run-time, but for the +// simple menu events like this the static method is much simpler. + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + EVT_MENU(Minimal_Back, MyFrame::OnBack) + EVT_MENU(Minimal_Forward, MyFrame::OnForward) + END_EVENT_TABLE() + + // Create a new application object: this macro will allow wxWindows to create + // the application object during program execution (it's better than using a + // static object for many reasons) and also declares the accessor function + // wxGetApp() which will return the reference of the right type (i.e. MyApp and + // not wxApp) + IMPLEMENT_APP(MyApp) + + // ============================================================================ + // implementation + // ============================================================================ + + // ---------------------------------------------------------------------------- + // the application class + // ---------------------------------------------------------------------------- + + // `Main program' equivalent: the program execution "starts" here + bool MyApp::OnInit() + { + // Create the main application window + MyFrame *frame = new MyFrame("wxHtmlWindow testing application", + wxPoint(50, 50), wxSize(640, 480)); + + // Show it and tell the application that it's our main window + // @@@ what does it do exactly, in fact? is it necessary here? + frame->Show(TRUE); + SetTopWindow(frame); + + // success: wxApp::OnRun() will be called which will enter the main message + // loop and the application will run. If we returned FALSE here, the + // application would exit immediately. + return TRUE; + } + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +wxHtmlWindow *html; + +// frame constructor + MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) + { + // create a menu bar + wxMenu *menuFile = new wxMenu; + wxMenu *menuNav = new wxMenu; + + menuFile->Append(Minimal_Quit, "E&xit"); + menuNav->Append(Minimal_Back, "Go &BACK"); + menuNav->Append(Minimal_Forward, "Go &FORWARD"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, "&File"); + menuBar->Append(menuNav, "&Navigate"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + + CreateStatusBar(1); + + html = new wxHtmlWindow(this); + html -> SetRelatedFrame(this, "VFS Demo: '%s'"); + html -> SetRelatedStatusBar(1); + html -> LoadPage("start.htm"); + } + + +// event handlers + + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) + { + // TRUE is to force the frame to close + Close(TRUE); + } + + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) + { + } + + + + void MyFrame::OnBack(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryBack()) wxMessageBox("You reached prehistory era!"); + } + + + void MyFrame::OnForward(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryForward()) wxMessageBox("No more items in history!"); + } + + + + + + diff --git a/samples/html/widget/widget.rc b/samples/html/widget/widget.rc new file mode 100644 index 0000000000..82bdf07561 --- /dev/null +++ b/samples/html/widget/widget.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" + diff --git a/samples/html/zip/Makefile.am b/samples/html/zip/Makefile.am new file mode 100644 index 0000000000..814476c5da --- /dev/null +++ b/samples/html/zip/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = 1.3 no-dependencies + +SUFFIXES = .cpp + +DEFS = @DEFS@ $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) + +noinst_PROGRAMS = zip + +zip_SOURCES = zip.cpp diff --git a/samples/html/zip/pages.zip b/samples/html/zip/pages.zip new file mode 100644 index 0000000000000000000000000000000000000000..f70ded12b5c613fae7f7d649f2f4ef9f67a93e6a GIT binary patch literal 62123 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%0DMyXSd;H2zsuZeA;PHVgN4mSzOGn0 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 Y4*(@uNT~m08|wQ=`A$CQ?SJn62LeMZp#T5? literal 0 HcmV?d00001 diff --git a/samples/html/zip/start.htm b/samples/html/zip/start.htm new file mode 100644 index 0000000000..cca461e6b0 --- /dev/null +++ b/samples/html/zip/start.htm @@ -0,0 +1,9 @@ +<html><body> +<h1>ZIP archive</h1> +<h3>feature demo</h3> +<p> +Click on this <a href="pages.zip#zip:test.htm">link</a> to load page stored in ZIP +archive (<a href="pages.zip">pages.zip</a>). Enjoy it! + + +</body></html> diff --git a/samples/html/zip/zip.cpp b/samples/html/zip/zip.cpp new file mode 100644 index 0000000000..3f518da664 --- /dev/null +++ b/samples/html/zip/zip.cpp @@ -0,0 +1,195 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "test.cpp" + #pragma interface "test.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include <wx/wxprec.h> + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include <wx/wx.h> +#endif + +#include <wx/image.h> +#include <wx/html/htmlwin.h> +#include <wx/fs_zip.h> + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp + class MyApp : public wxApp + { + public: + // override base class virtuals + // ---------------------------- + + // this one is called on application startup and is a good place for the app + // initialization (doing it here and not in the ctor allows to have an error + // return: if OnInit() returns false, the application terminates) + virtual bool OnInit(); + }; + +// Define a new frame type: this is going to be our main frame + class MyFrame : public wxFrame + { + public: + // ctor(s) + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnBack(wxCommandEvent& event); + void OnForward(wxCommandEvent& event); + + private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() + }; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands + enum + { + // menu items + Minimal_Quit = 1, + Minimal_About, + Minimal_Back, + Minimal_Forward, + + // controls start here (the numbers are, of course, arbitrary) + Minimal_Text = 1000, + }; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// ---------------------------------------------------------------------------- + +// the event tables connect the wxWindows events with the functions (event +// handlers) which process them. It can be also done at run-time, but for the +// simple menu events like this the static method is much simpler. + BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(Minimal_Quit, MyFrame::OnQuit) + EVT_MENU(Minimal_About, MyFrame::OnAbout) + EVT_MENU(Minimal_Back, MyFrame::OnBack) + EVT_MENU(Minimal_Forward, MyFrame::OnForward) + END_EVENT_TABLE() + + // Create a new application object: this macro will allow wxWindows to create + // the application object during program execution (it's better than using a + // static object for many reasons) and also declares the accessor function + // wxGetApp() which will return the reference of the right type (i.e. MyApp and + // not wxApp) + IMPLEMENT_APP(MyApp) + + // ============================================================================ + // implementation + // ============================================================================ + + // ---------------------------------------------------------------------------- + // the application class + // ---------------------------------------------------------------------------- + // `Main program' equivalent: the program execution "starts" here + bool MyApp::OnInit() + { + #if wxUSE_LIBPNG + wxImage::AddHandler(new wxPNGHandler); + #endif + #if wxUSE_LIBJPEG + wxImage::AddHandler(new wxJPEGHandler); + #endif + + wxFileSystem::AddHandler(new wxZipFSHandler); + + // Create the main application window + MyFrame *frame = new MyFrame("wxHtmlWindow testing application", + wxPoint(50, 50), wxSize(640, 480)); + + // Show it and tell the application that it's our main window + // @@@ what does it do exactly, in fact? is it necessary here? + frame->Show(TRUE); + SetTopWindow(frame); + + // success: wxApp::OnRun() will be called which will enter the main message + // loop and the application will run. If we returned FALSE here, the + // application would exit immediately. + return TRUE; + } + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +wxHtmlWindow *html; + +// frame constructor + MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) + { + // create a menu bar + wxMenu *menuFile = new wxMenu; + wxMenu *menuNav = new wxMenu; + + menuFile->Append(Minimal_Quit, "E&xit"); + menuNav->Append(Minimal_Back, "Go &BACK"); + menuNav->Append(Minimal_Forward, "Go &FORWARD"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, "&File"); + menuBar->Append(menuNav, "&Navigate"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + + CreateStatusBar(1); + + { + html = new wxHtmlWindow(this); + html -> SetRelatedFrame(this, "HTML : %s"); + html -> SetRelatedStatusBar(0); + html -> LoadPage("start.htm"); + } + } + + +// event handlers + + void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) + { + // TRUE is to force the frame to close + Close(TRUE); + } + + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) + { + } + + + + void MyFrame::OnBack(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryBack()) wxMessageBox("You reached prehistory era!"); + } + + + void MyFrame::OnForward(wxCommandEvent& WXUNUSED(event)) + { + if (!html -> HistoryForward()) wxMessageBox("No more items in history!"); + } diff --git a/samples/html/zip/zip.rc b/samples/html/zip/zip.rc new file mode 100644 index 0000000000..82bdf07561 --- /dev/null +++ b/samples/html/zip/zip.rc @@ -0,0 +1,2 @@ +#include "wx/msw/wx.rc" + diff --git a/src/common/filesys.cpp b/src/common/filesys.cpp new file mode 100644 index 0000000000..5712bf60ba --- /dev/null +++ b/src/common/filesys.cpp @@ -0,0 +1,294 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: filesys.cpp +// Purpose: wxFileSystem class - interface for opening files +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/wfstream.h> +#include <wx/url.h> +#include <wx/module.h> +#include <wx/filesys.h> + + + +//-------------------------------------------------------------------------------- +// wxFileSystemHandler +//-------------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) + +wxMimeTypesManager wxFileSystemHandler::m_MimeMng; + + +wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) +{ + wxString ext = wxEmptyString, mime = wxEmptyString; + wxString loc = GetRightLocation(location); + char c; + int l = loc.Length(), l2; + wxFileType *ft; + + l2 = l; + for (int i = l-1; i >= 0; i--) { + c = loc[i]; + if (c == '#') l2 = i + 1; + if (c == '.') {ext = loc.Right(l2-i-1); break;} + if ((c == '/') || (c == '\\') || (c == ':')) {return wxEmptyString;} + } + ft = m_MimeMng.GetFileTypeFromExtension(ext); + if (ft && (ft -> GetMimeType(&mime))) return mime; + else return wxEmptyString; +} + + + +wxString wxFileSystemHandler::GetProtocol(const wxString& location) const +{ + wxString s = wxEmptyString; + int i, l = location.Length(); + bool fnd; + + fnd = FALSE; + for (i = l-1; (i >= 0) && ((location[i] != '#') || (!fnd)); i--) { + if ((location[i] == ':') && (i != 1 /*win: C:\path*/)) fnd = TRUE; + } + if (!fnd) return "file"; + for (++i; (i < l) && (location[i] != ':'); i++) s << location[i]; + return s; +} + + + +wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const +{ + int i; + bool fnd; + + fnd = FALSE; + for (i = location.Length()-1; i >= 0; i--) { + if ((location[i] == ':') && (i != 1 /*win: C:\path*/)) fnd = TRUE; + else if (fnd && (location[i] == '#')) return location.Left(i); + } + return wxEmptyString; +} + + + +wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const +{ + int i, l = location.Length(); + int l2 = l + 1; + for (i = l-1; (i >= 0) && ((location[i] != ':') || (i == 1) || (location[i-2] == ':')); i--) {if (location[i] == '#') l2 = i + 1;} + if (i == 0) return wxEmptyString; + else return location.Mid(i + 1, l2 - i - 2); +} + + + +wxString wxFileSystemHandler::GetAnchor(const wxString& location) const +{ + char c; + int l = location.Length(); + + for (int i = l-1; i >= 0; i--) { + c = location[i]; + if (c == '#') return location.Right(l-i-1); + else if ((c == '.') || (c == '/') || (c == '\\') || (c == ':')) return wxEmptyString; + } + return wxEmptyString; +} + + + + + +//-------------------------------------------------------------------------------- +// wxLocalFSHandler +//-------------------------------------------------------------------------------- + +class wxLocalFSHandler : public wxFileSystemHandler +{ + public: + virtual bool CanOpen(const wxString& location); + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location); +}; + + + +bool wxLocalFSHandler::CanOpen(const wxString& location) +{ + return GetProtocol(location) == "file"; +} + + + +wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + wxString right = GetRightLocation(location); + if (wxFileExists(right)) + return new wxFSFile(new wxFileInputStream(right), + right, + GetMimeTypeFromExt(location), + GetAnchor(location)); + else return NULL; +} + + + + + + +//----------------------------------------------------------------------------- +// wxFileSystem +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) + + +wxList wxFileSystem::m_Handlers; + + + +void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) +{ + int i, pathpos = -1; + m_Path = location; + + for (i = m_Path.Length()-1; i >= 0; i--) + if (m_Path[i] == '\\') m_Path.GetWritableChar(i) = '/'; // wanna be windows-safe + + if (is_dir == FALSE) { + for (i = m_Path.Length()-1; i >= 0; i--) { + if (m_Path[i] == '/') { + if ((i > 1) && (m_Path[i-1] == '/') && (m_Path[i-2] == ':')) { + i -= 2; + continue; + } + else { + pathpos = i; + break; + } + } + else if (m_Path[i] == ':') { + pathpos = i; + break; + } + } + if (pathpos == -1) { + for (i = 0; i < (int) m_Path.Length(); i++) { + if (m_Path[i] == ':') { + //m_Path << '/'; + m_Path.Remove(i+1); + break; + } + } + if (i == (int) m_Path.Length()) m_Path = wxEmptyString; + } + else { + if (m_Path[m_Path.Length()-1] != '/') m_Path << '/'; + m_Path.Remove(pathpos+1); + } + } +} + + + +wxFSFile* wxFileSystem::OpenFile(const wxString& location) +{ + wxString loc = location; + int i, ln; + char meta; + wxFSFile *s = NULL; + wxNode *node; + + ln = loc.Length(); + meta = 0; + for (i = 0; i < ln; i++) { + if (loc[i] == '\\') loc.GetWritableChar(i) = '/'; // wanna be windows-safe + if (!meta) switch (loc[i]) { + case '/' : case ':' : case '#' : meta = loc[i]; + } + } + m_LastName = wxEmptyString; + + // try relative paths first : + if (meta != ':') { + node = m_Handlers.GetFirst(); + while (node){ + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(m_Path + location)) { + s = h -> OpenFile(*this, m_Path + location); + if (s) {m_LastName = m_Path + location; break;} + } + node = node -> GetNext(); + } + } + + // if failed, try absolute paths : + if (s == NULL) { + node = m_Handlers.GetFirst(); + while (node){ + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(location)) { + s = h -> OpenFile(*this, location); + if (s) {m_LastName = location; break; } + } + node = node -> GetNext(); + } + } + return (s); +} + + + +void wxFileSystem::AddHandler(wxFileSystemHandler *handler) +{ + m_Handlers.Append(handler); +} + + + + + + + + + + + +///// Module: + +class wxFileSystemModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxFileSystemModule) + + public: + virtual bool OnInit() + { + wxFileSystem::AddHandler(new wxLocalFSHandler); + return TRUE; + } + virtual void OnExit() {} +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) + + + + diff --git a/src/common/fs_inet.cpp b/src/common/fs_inet.cpp new file mode 100644 index 0000000000..acb0c25831 --- /dev/null +++ b/src/common/fs_inet.cpp @@ -0,0 +1,130 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_inet.cpp +// Purpose: HTTP and FTP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +/* + +REMARKS : + +This FS creates local cache (in /tmp directory). The cache is freed +on program exit. + +Size of cache is limited to cca 1000 items (due to GetTempFileName +limitation) + + +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include "wx/wfstream.h" +#include "wx/url.h" +#include "wx/filesys.h" +#include "wx/fs_inet.h" + +class wxInetCacheNode : public wxObject +{ + private: + wxString m_Temp; + wxString m_Mime; + + public: + wxInetCacheNode(const wxString& l, const wxString& m) : wxObject() {m_Temp = l; m_Mime = m;} + const wxString& GetTemp() const {return m_Temp;} + const wxString& GetMime() const {return m_Mime;} +}; + + + + + +//-------------------------------------------------------------------------------- +// wxInternetFSHandler +//-------------------------------------------------------------------------------- + + +bool wxInternetFSHandler::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return (p == "http") || (p == "ftp"); +} + + + + +wxFSFile* wxInternetFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + wxString right = GetProtocol(location) + ":" + GetRightLocation(location); + wxInputStream *s; + wxString content; + wxInetCacheNode *info; + + info = (wxInetCacheNode*) m_Cache.Get(right); + + // Add item into cache: + if (info == NULL) { + wxURL url(right); + s = url.GetInputStream(); + content = url.GetProtocol().GetContentType(); + if (content == wxEmptyString) content = GetMimeTypeFromExt(location); + if (s) { + char buf[256]; + + wxGetTempFileName("wxhtml", buf); + info = new wxInetCacheNode(buf, content); + m_Cache.Put(right, info); + + { // ok, now copy it: + wxFileOutputStream sout(buf); + s -> Read(sout); // copy the stream + } + delete s; + } + else return NULL; //we can't open the URL + } + + // Load item from cache: + s = new wxFileInputStream(info -> GetTemp()); + if (s) { + return new wxFSFile(s, + right, + info -> GetMime(), + GetAnchor(location)); + } + else return NULL; +} + + + +wxInternetFSHandler::~wxInternetFSHandler() +{ + wxNode *n; + wxInetCacheNode *n2; + + m_Cache.BeginFind(); + while ((n = m_Cache.Next()) != NULL) { + n2 = (wxInetCacheNode*) n -> GetData(); + wxRemoveFile(n2 -> GetTemp()); + delete n2; + } +} + + + + diff --git a/src/common/fs_zip.cpp b/src/common/fs_zip.cpp new file mode 100644 index 0000000000..2bd3b224ed --- /dev/null +++ b/src/common/fs_zip.cpp @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_zip.cpp +// Purpose: ZIP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include "wx/filesys.h" +#include "wx/zipstream.h" +#include "wx/fs_zip.h" + + +//-------------------------------------------------------------------------------- +// wxZipFSHandler +//-------------------------------------------------------------------------------- + + + +bool wxZipFSHandler::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return (p == "zip"); +} + + + + +wxFSFile* wxZipFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + wxString right = GetRightLocation(location); + wxString left = GetLeftLocation(location); + wxInputStream *s; + + if (GetProtocol(left) != "file") { + return NULL; + } + + s = new wxZipInputStream(left, right); + if (s && (s -> LastError() == wxStream_NOERROR)) { + return new wxFSFile(s, + left + "#zip:" + right, + GetMimeTypeFromExt(location), + GetAnchor(location)); + } + else return NULL; +} + + + +wxZipFSHandler::~wxZipFSHandler() +{ +} + + + + + + + diff --git a/src/common/unzip.c b/src/common/unzip.c new file mode 100644 index 0000000000..ff71a474da --- /dev/null +++ b/src/common/unzip.c @@ -0,0 +1,1294 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include <stddef.h> +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include <errno.h> +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char unz_copyright[] = + " unzip 0.15 Copyright 1998 Gilles Vollant "; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte(fin,pi) + FILE *fin; + int *pi; +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1<c2) + return -1; + if (c1>c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir(fin) + FILE *fin; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackRead<uMaxBack) + { + uLong uReadSize,uReadPos ; + int i; + if (uBackRead+BUFREADCOMMENT>uMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen (path) + const char *path; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pos<us.offset_central_dir+us.size_central_dir) && + (err==UNZ_OK)) + err=UNZ_BADZIPFILE; + + if (err!=UNZ_OK) + { + fclose(fin); + return NULL; + } + + us.file=fin; + us.byte_before_the_zipfile = central_pos - + (us.offset_central_dir+us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + + + s=(unz_s*)ALLOC(sizeof(unz_s)); + *s=us; + unzGoToFirstFile((unzFile)s); + return (unzFile)s; +} + + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzClose (file) + unzFile file; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + if (s->pfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename<fileNameBufferSize) + { + *(szFileName+file_info.size_filename)='\0'; + uSizeRead = file_info.size_filename; + } + else + uSizeRead = fileNameBufferSize; + + if ((file_info.size_filename>0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extra<extraFieldBufferSize) + uSizeRead = file_info.size_file_extra; + else + uSizeRead = extraFieldBufferSize; + + if (lSeek!=0) + if (fseek(s->file,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_comment<commentBufferSize) + { + *(szComment+file_info.size_file_comment)='\0'; + uSizeRead = file_info.size_file_comment; + } + else + uSizeRead = commentBufferSize; + + if (lSeek!=0) + if (fseek(s->file,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressed<uReadThis) + uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;i<uDoCopy;i++) + *(pfile_in_zip_read_info->stream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/src/common/unzip.h b/src/common/unzip.h new file mode 100644 index 0000000000..76692cb703 --- /dev/null +++ b/src/common/unzip.h @@ -0,0 +1,275 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/src/common/zipstream.cpp b/src/common/zipstream.cpp new file mode 100644 index 0000000000..39f4888df6 --- /dev/null +++ b/src/common/zipstream.cpp @@ -0,0 +1,110 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: zipstream.cpp +// Purpose: input stream for ZIP archive access +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/stream.h> +#include <wx/wfstream.h> +#include <wx/zipstream.h> +#include "unzip.h" + + + + +wxZipInputStream::wxZipInputStream(const wxString& archive, const wxString& file) : wxInputStream() +{ + unz_file_info zinfo; + + m_Pos = 0; + m_Size = 0; + m_Archive = (void*) unzOpen(archive); + if (m_Archive == NULL) { + m_lasterror = wxStream_READ_ERR; + return; + } + if (unzLocateFile((unzFile)m_Archive, file, 0) != UNZ_OK) { + m_lasterror = wxStream_READ_ERR; + return; + } + unzGetCurrentFileInfo((unzFile)m_Archive, &zinfo, NULL, 0, NULL, 0, NULL, 0); + + if (unzOpenCurrentFile((unzFile)m_Archive) != UNZ_OK) { + m_lasterror = wxStream_READ_ERR; + return; + } + m_Size = zinfo.uncompressed_size; +} + + + +wxZipInputStream::~wxZipInputStream() +{ + if (m_Archive) { + if (m_Size != 0) + unzCloseCurrentFile((unzFile)m_Archive); + unzClose((unzFile)m_Archive); + } +} + + + +size_t wxZipInputStream::OnSysRead(void *buffer, size_t bufsize) +{ + if (m_Pos + bufsize > m_Size) bufsize = m_Size - m_Pos; + unzReadCurrentFile((unzFile)m_Archive, buffer, bufsize); + m_Pos += bufsize; + return bufsize; +} + + + +off_t wxZipInputStream::OnSysSeek(off_t seek, wxSeekMode mode) +{ + off_t nextpos; + void *buf; + + switch (mode) { + case wxFromCurrent : nextpos = seek + m_Pos; break; + case wxFromStart : nextpos = seek; break; + case wxFromEnd : nextpos = m_Size - 1 + seek; break; + default : nextpos = m_Pos; break; /* just to fool compiler, never happens */ + } + + // cheated seeking : + if (nextpos > m_Pos) { + buf = malloc(nextpos - m_Pos); + unzReadCurrentFile((unzFile)m_Archive, buf, nextpos - m_Pos); + free(buf); + } + else if (nextpos < m_Pos) { + unzCloseCurrentFile((unzFile)m_Archive); + if (unzOpenCurrentFile((unzFile)m_Archive) != UNZ_OK) { + m_lasterror = wxStream_READ_ERR; + return m_Pos; + } + buf = malloc(nextpos); + unzReadCurrentFile((unzFile)m_Archive, buf, nextpos); + free(buf); + } + + m_Pos = nextpos; + return m_Pos; +} + diff --git a/src/generic/busyinfo.cpp b/src/generic/busyinfo.cpp new file mode 100644 index 0000000000..c443c1daa3 --- /dev/null +++ b/src/generic/busyinfo.cpp @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: busyinfo.cpp +// Purpose: Information window when app is busy +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include "wx/busyinfo.h" + + + + + +wxInfoFrame::wxInfoFrame(wxWindow *parent, const wxString& message) + : wxFrame(parent, -1, "", wxPoint(0, 0), wxSize(400, 80), wxTHICK_FRAME | wxSIMPLE_BORDER | wxFRAME_TOOL_WINDOW) +{ + wxPanel *p = new wxPanel(this); + wxStaticText *s = new wxStaticText(p, -1, message, wxPoint(20, 20), wxSize(360, 40), wxALIGN_CENTER); + Centre(wxBOTH); + p -> SetCursor(*wxHOURGLASS_CURSOR); + s -> SetCursor(*wxHOURGLASS_CURSOR); +} + + + + +wxBusyInfo::wxBusyInfo(const wxString& message) : wxObject() +{ + m_InfoFrame = new wxInfoFrame(NULL, message); + m_InfoFrame -> Show(TRUE); + wxYield(); + m_InfoFrame -> Refresh(); + wxYield(); +} + + + +wxBusyInfo::~wxBusyInfo() +{ + m_InfoFrame -> Show(FALSE); + m_InfoFrame -> Close(); + wxYield(); +} + + + + + + + + + + + diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am index 5bff538335..596102f8d1 100644 --- a/src/gtk/Makefile.am +++ b/src/gtk/Makefile.am @@ -12,7 +12,7 @@ SUFFIXES = .cpp .c DEFS = $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) LIBS = $(GUILIBS) -VPATH = .:${srcdir}:${srcdir}/../common:${srcdir}/../generic:${EXTRA_VPATH} +VPATH = .:${srcdir}:${srcdir}/../common:${srcdir}/../generic:${srcdir}/../html:${EXTRA_VPATH} lib_LTLIBRARIES = @WX_LIBRARY_NAME@ EXTRA_LTLIBRARIES = libwx_gtk.la libwx_motif.la libwx_msw.la @@ -44,7 +44,10 @@ libwx_gtk_la_SOURCES = \ file.cpp \ fileconf.cpp \ filefn.cpp \ + filesys.cpp \ framecmn.cpp \ + fs_inet.cpp \ + fs_zip.cpp \ ftp.cpp \ gdicmn.cpp \ hash.cpp \ @@ -90,6 +93,7 @@ libwx_gtk_la_SOURCES = \ time.cpp \ timercmn.cpp \ tokenzr.cpp \ + unzip.c \ url.cpp \ utilscmn.cpp \ valgen.cpp \ @@ -101,10 +105,12 @@ libwx_gtk_la_SOURCES = \ wxchar.cpp \ wxexpr.cpp \ zstream.cpp \ + zipstream.cpp \ \ db.cpp \ dbtable.cpp \ \ + busyinfo.cpp \ caret.cpp \ colrdlgg.cpp \ dcpsg.cpp \ @@ -192,7 +198,26 @@ libwx_gtk_la_SOURCES = \ utilsgtk.cpp \ utilsres.cpp \ wave.cpp \ - window.cpp + window.cpp \ +\ + htmlcell.cpp \ + htmlfilter.cpp \ + htmlhelp.cpp \ + htmlhelp_io.cpp \ + htmlparser.cpp \ + htmltag.cpp \ + htmlwin.cpp \ + htmlwinparser.cpp \ + mod_fonts.cpp \ + mod_hline.cpp \ + mod_image.cpp \ + mod_layout.cpp \ + mod_links.cpp \ + mod_list.cpp \ + mod_pre.cpp \ + mod_tables.cpp \ + search.cpp + # these are the sources which we build by our own rules # diff --git a/src/gtk1/Makefile.am b/src/gtk1/Makefile.am index 5bff538335..596102f8d1 100644 --- a/src/gtk1/Makefile.am +++ b/src/gtk1/Makefile.am @@ -12,7 +12,7 @@ SUFFIXES = .cpp .c DEFS = $(TOOLKIT_DEF) $(WXDEBUG_DEFINE) LIBS = $(GUILIBS) -VPATH = .:${srcdir}:${srcdir}/../common:${srcdir}/../generic:${EXTRA_VPATH} +VPATH = .:${srcdir}:${srcdir}/../common:${srcdir}/../generic:${srcdir}/../html:${EXTRA_VPATH} lib_LTLIBRARIES = @WX_LIBRARY_NAME@ EXTRA_LTLIBRARIES = libwx_gtk.la libwx_motif.la libwx_msw.la @@ -44,7 +44,10 @@ libwx_gtk_la_SOURCES = \ file.cpp \ fileconf.cpp \ filefn.cpp \ + filesys.cpp \ framecmn.cpp \ + fs_inet.cpp \ + fs_zip.cpp \ ftp.cpp \ gdicmn.cpp \ hash.cpp \ @@ -90,6 +93,7 @@ libwx_gtk_la_SOURCES = \ time.cpp \ timercmn.cpp \ tokenzr.cpp \ + unzip.c \ url.cpp \ utilscmn.cpp \ valgen.cpp \ @@ -101,10 +105,12 @@ libwx_gtk_la_SOURCES = \ wxchar.cpp \ wxexpr.cpp \ zstream.cpp \ + zipstream.cpp \ \ db.cpp \ dbtable.cpp \ \ + busyinfo.cpp \ caret.cpp \ colrdlgg.cpp \ dcpsg.cpp \ @@ -192,7 +198,26 @@ libwx_gtk_la_SOURCES = \ utilsgtk.cpp \ utilsres.cpp \ wave.cpp \ - window.cpp + window.cpp \ +\ + htmlcell.cpp \ + htmlfilter.cpp \ + htmlhelp.cpp \ + htmlhelp_io.cpp \ + htmlparser.cpp \ + htmltag.cpp \ + htmlwin.cpp \ + htmlwinparser.cpp \ + mod_fonts.cpp \ + mod_hline.cpp \ + mod_image.cpp \ + mod_layout.cpp \ + mod_links.cpp \ + mod_list.cpp \ + mod_pre.cpp \ + mod_tables.cpp \ + search.cpp + # these are the sources which we build by our own rules # diff --git a/src/html/bitmaps/back.xpm b/src/html/bitmaps/back.xpm new file mode 100644 index 0000000000..fbb4378bf6 --- /dev/null +++ b/src/html/bitmaps/back.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * back_xpm[] = { +"16 16 5 1", +" c None", +". c #000000", +"+ c #C0E4CB", +"@ c #77C490", +"# c #808080", +" ", +" ", +" . ", +" .. ", +" .+. ", +" .++........ ", +" .++@+++++++. ", +" .++@@@@@@@@@. ", +" .+@@@@@@@@@. ", +" #.+@........ ", +" #.+.####### ", +" #..# ", +" #.# ", +" ## ", +" # ", +" "}; diff --git a/src/html/bitmaps/book.xpm b/src/html/bitmaps/book.xpm new file mode 100644 index 0000000000..3146053f85 --- /dev/null +++ b/src/html/bitmaps/book.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static char * book_xpm[] = { +"16 16 21 1", +" c None", +". c #007F7F", +"+ c #660000", +"@ c #CC0000", +"# c #E50000", +"$ c #FF0000", +"% c #F20000", +"& c #D80000", +"* c #720000", +"= c #7F0000", +"- c #BFBFBF", +"; c #E57F7F", +"> c #7F7F7F", +", c #FFFFFF", +"' c #F2BFBF", +") c #723F3F", +"! c #A5A5A5", +"~ c #E5E5E5", +"{ c #B2B2B2", +"] c #003F3F", +"^ c #000000", +" ", +" ......... ", +" +@#$$$$$%&+ ", +" +##$$$$$$$* ", +" +##$$$$$$$=- ", +" +##$$$$$$$=;> ", +" +##$$$$$$$=;,. ", +" +##$$$$$$$=;,. ", +" +##$$$$$$$=''. ", +" +##$$$$$$$=,;. ", +" +##$$$$$$%+,;. ", +" +&++++++++),;. ", +" ++!~~~~~~~~~,. ", +" ++!~~~~~~~~~{. ", +" ]^^^^^^^^^^^ ", +" "}; diff --git a/src/html/bitmaps/folder.xpm b/src/html/bitmaps/folder.xpm new file mode 100644 index 0000000000..a7fbf85369 --- /dev/null +++ b/src/html/bitmaps/folder.xpm @@ -0,0 +1,50 @@ +/* XPM */ +static char * folder_xpm[] = { +"16 16 31 1", +" c None", +". c #000000", +"+ c #7F6E54", +"@ c #555555", +"# c #7F6140", +"$ c #FFCF94", +"% c #FFFFFF", +"& c #D5D5D5", +"* c #4B4336", +"= c #FFDCA8", +"- c #BFA57E", +"; c #EFEFEF", +"> c #DFDFDF", +", c #B8B8B9", +"' c #6E6E6F", +") c #BF7E42", +"! c #FFA858", +"~ c #FFC280", +"{ c #CFCFCF", +"] c #55402C", +"^ c #3C2C2C", +"/ c #7F542C", +"( c #C0C0C0", +"_ c #B0B0B2", +": c #969698", +"< c #A8A8AB", +"[ c #A0A0A4", +"} c #2C2C2C", +"| c #7C7C7E", +"1 c #161616", +"2 c #3F2A16", +" .+. ", +".@#$+. ", +".%&@#$+.+* ", +".%%%&@#$==-. ", +".%%;>,')!~$+ ", +".%;>{{,']^/~. ", +".;>{{((,,_:]/ ", +".>{{((,,_<[}/ ", +".{{((,,_<[[^/ ", +"._((,,_<[[[}/ ", +" }|_,_<[[[[}/ ", +" .}|<[[[[[}/ ", +" .}|[[[[}/ ", +" .}|[[}/.. ", +" .}|}/.. ", +" .12. "}; diff --git a/src/html/bitmaps/forward.xpm b/src/html/bitmaps/forward.xpm new file mode 100644 index 0000000000..6e3de64511 --- /dev/null +++ b/src/html/bitmaps/forward.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * forward_xpm[] = { +"16 16 5 1", +" c None", +". c #000000", +"+ c #C0E4CB", +"@ c #77C490", +"# c #808080", +" ", +" ", +" . ", +" .. ", +" .+. ", +" ........++. ", +" .+++++++@++. ", +" .@@@@@@@@@++. ", +" .@@@@@@@@@+. ", +" ........@+.# ", +" #######.+.# ", +" #..# ", +" #.# ", +" ## ", +" # ", +" "}; diff --git a/src/html/bitmaps/page.xpm b/src/html/bitmaps/page.xpm new file mode 100644 index 0000000000..f8bf0c0057 --- /dev/null +++ b/src/html/bitmaps/page.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * page_xpm[] = { +/* width height ncolors chars_per_pixel */ +"16 16 3 1", +/* colors */ +" s None c None", +". c #000000", +"+ c #ffffff", +/* pixels */ +" ", +" ........ ", +" .++++++.. ", +" .+.+.++.+. ", +" .++++++.... ", +" .+.+.+++++. ", +" .+++++++++. ", +" .+.+.+.+.+. ", +" .+++++++++. ", +" .+.+.+.+.+. ", +" .+++++++++. ", +" .+.+.+.+.+. ", +" .+++++++++. ", +" ........... ", +" ", +" "}; diff --git a/src/html/bitmaps/panel.xpm b/src/html/bitmaps/panel.xpm new file mode 100644 index 0000000000..42798ebbe3 --- /dev/null +++ b/src/html/bitmaps/panel.xpm @@ -0,0 +1,122 @@ +/* XPM */ +static char * panel_xpm[] = { +"16 15 104 2", +" c None", +". c #7F7C7C", +"+ c #8A8E8E", +"@ c #D03232", +"# c #BA7E7E", +"$ c #555858", +"% c #5F5F5F", +"& c #656565", +"* c #5D5D5D", +"= c #939696", +"- c #FFFFFF", +"; c #F4C8C8", +"> c #DCDCF4", +", c #D3D3D3", +"' c #4E5151", +") c #7E7E7E", +"! c #9E9E9E", +"~ c #A7A7A7", +"{ c #5C5C5C", +"] c #9B9E9E", +"^ c #A3A3FF", +"/ c #BBBBFF", +"( c #DBDBDB", +"_ c #808B8B", +": c #5E5E5E", +"< c #858571", +"[ c #AEAE4B", +"} c #90902D", +"| c #8B8B8B", +"1 c #000027", +"2 c #D7D7FF", +"3 c #C3C3FF", +"4 c #A7A7FF", +"5 c #9B9BFF", +"6 c #D7D7D7", +"7 c #717474", +"8 c #727D7D", +"9 c #575721", +"0 c #BFBF7F", +"a c #DFDF8F", +"b c #DFDF60", +"c c #7F7F3B", +"d c #2F2F7F", +"e c #AFAFF3", +"f c #E7E7E7", +"g c #9797E7", +"h c #8787F3", +"i c #AFAFC3", +"j c #4F4F37", +"k c #8E9898", +"l c #484824", +"m c #4D4D0B", +"n c #8C8C8C", +"o c #7D7D36", +"p c #74742D", +"q c #535353", +"r c #636363", +"s c #5C5C4C", +"t c #818149", +"u c #78784C", +"v c #787840", +"w c #7E7E40", +"x c #787E46", +"y c #757F7F", +"z c #616121", +"A c #87874B", +"B c #C8C88C", +"C c #F6F6B6", +"D c #D4D498", +"E c #6C6C30", +"F c #424242", +"G c #9D9D23", +"H c #FDFD7B", +"I c #FFFF7F", +"J c #7F7F3F", +"K c #737C7C", +"L c #808038", +"M c #6B6B5F", +"N c #797935", +"O c #6E6E62", +"P c #8B8B43", +"Q c #8D8D8D", +"R c #1C4B4B", +"S c #959523", +"T c #F9F973", +"U c #7F7F43", +"V c #737D7D", +"W c #939343", +"X c #4FD3D3", +"Y c #185353", +"Z c #8D8D27", +"` c #F5F56B", +" . c #9B9B43", +".. c #57CFCF", +"+. c #145B5B", +"@. c #85851E", +"#. c #A3A343", +"$. c #3BA7A7", +"%. c #636300", +"&. c #CFCF67", +"*. c #F3F367", +"=. c #909A9A", +"-. c #4B4B07", +";. c #434325", +" . ", +" + @ # ", +" $ % & * = - ; > , ", +" ' ) ! ~ ~ { ] - - ^ / - ( ", +"_ : < [ [ } | 1 2 - 3 / 4 5 6 7 ", +"8 9 0 a b c 3 d e f f g h i j ", +"k l m n o p q r s t t t u v w x ", +"y z A B C D E F G H I I I I I J ", +"K I L M N O P Q R S T I I I I U ", +"V I I I I I I W X Y Z ` I I I U ", +"8 I I I I I I I ...+.@.I I I U ", +"K I I I I I I I I #.$.%.I I I U ", +"8 I I I I I I I I I &.*.I I I U ", +"V I I I I I I I I I I I I I I U ", +"=.-.-.-.-.-.-.-.-.-.-.-.-.-.-.;."}; diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp new file mode 100644 index 0000000000..c70e0a281c --- /dev/null +++ b/src/html/htmlcell.cpp @@ -0,0 +1,507 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlcell.cpp +// Purpose: wxHtmlCell - basic element of HTML output +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/html/htmlcell.h> +#include <wx/html/htmlwin.h> +#include <stdlib.h> + + + + +//----------------------------------------------------------------------------- +// wxHtmlCell +//----------------------------------------------------------------------------- + + +void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right) +{ + if (GetLink() != wxEmptyString) + ((wxHtmlWindow*)parent) -> OnLinkClicked(GetLink()); + // note : this overcasting is legal because parent is *always* wxHtmlWindow +} + + + +//----------------------------------------------------------------------------- +// wxHtmlWordCell +//----------------------------------------------------------------------------- + +wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell() +{ + m_Word = word; + m_Word.Replace(" ", " ", TRUE); + m_Word.Replace(""", "\"", TRUE); + m_Word.Replace("<", "<", TRUE); + m_Word.Replace(">", ">", TRUE); + m_Word.Replace("&", "&", TRUE); + dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent); +} + + + +void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + dc.DrawText(m_Word, x + m_PosX, y + m_PosY); + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + + + + + +//----------------------------------------------------------------------------- +// wxHtmlContainerCell +//----------------------------------------------------------------------------- + + +wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell() +{ + m_Cells = m_LastCell = NULL; + m_Parent = parent; + if (m_Parent) m_Parent -> InsertCell(this); + m_AlignHor = HTML_ALIGN_LEFT; + m_AlignVer = HTML_ALIGN_BOTTOM; + m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0; + m_WidthFloat = 100; m_WidthFloatUnits = HTML_UNITS_PERCENT; + m_UseBkColour = FALSE; + m_UseBorder = FALSE; + m_MinHeight = m_MaxLineWidth = 0; + m_MinHeightAlign = HTML_ALIGN_TOP; +} + + + +void wxHtmlContainerCell::SetIndent(int i, int what, int units) +{ + int val = (units == HTML_UNITS_PIXELS) ? i : -i; + if (what & HTML_INDENT_LEFT) m_IndentLeft = val; + if (what & HTML_INDENT_RIGHT) m_IndentRight = val; + if (what & HTML_INDENT_TOP) m_IndentTop = val; + if (what & HTML_INDENT_BOTTOM) m_IndentBottom = val; +} + + + +int wxHtmlContainerCell::GetIndent(int ind) const +{ + if (ind & HTML_INDENT_LEFT) return m_IndentLeft; + else if (ind & HTML_INDENT_RIGHT) return m_IndentRight; + else if (ind & HTML_INDENT_TOP) return m_IndentTop; + else if (ind & HTML_INDENT_BOTTOM) return m_IndentBottom; + else return -1; /* BUG! Should not be called... */ +} + + + + +int wxHtmlContainerCell::GetIndentUnits(int ind) const +{ + bool p = FALSE; + if (ind & HTML_INDENT_LEFT) p = m_IndentLeft < 0; + else if (ind & HTML_INDENT_RIGHT) p = m_IndentRight < 0; + else if (ind & HTML_INDENT_TOP) p = m_IndentTop < 0; + else if (ind & HTML_INDENT_BOTTOM) p = m_IndentBottom < 0; + if (p) return HTML_UNITS_PERCENT; + else return HTML_UNITS_PIXELS; +} + + + +void wxHtmlContainerCell::Layout(int w) +{ + wxHtmlCell *cell = m_Cells, *line = m_Cells; + long xpos = 0, ypos = m_IndentTop; + int xdelta = 0, ybasicpos = 0, ydiff; + int s_width, s_indent; + int ysizeup = 0, ysizedown = 0; + + /* + + WIDTH ADJUSTING : + + */ + + if (m_WidthFloatUnits == HTML_UNITS_PERCENT) { + if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100; + else m_Width = m_WidthFloat * w / 100; + } + else { + if (m_WidthFloat < 0) m_Width = w + m_WidthFloat; + else m_Width = m_WidthFloat; + } + + if (m_Cells) { + int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft; + int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight; + m_Cells -> Layout(m_Width - (l + r)); + } + + /* + + LAYOUTING : + + */ + + // adjust indentation: + s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft; + s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight); + + m_MaxLineWidth = 0; + + // my own layouting: + while (cell != NULL) { + switch (m_AlignVer) { + case HTML_ALIGN_TOP : ybasicpos = 0; break; + case HTML_ALIGN_BOTTOM : ybasicpos = - cell -> GetHeight(); break; + case HTML_ALIGN_CENTER : ybasicpos = - cell -> GetHeight() / 2; break; + } + ydiff = cell -> GetHeight() + ybasicpos; + + if (cell -> GetDescent() + ydiff > ysizedown) ysizedown = cell -> GetDescent() + ydiff; + if (ybasicpos + cell -> GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell -> GetDescent()); + + cell -> SetPos(xpos, ybasicpos + cell -> GetDescent()); + xpos += cell -> GetWidth(); + cell = cell -> GetNext(); + + // force new line if occured: + if ((cell == NULL) || (xpos + cell -> GetWidth() > s_width)) { + if (xpos > m_MaxLineWidth) m_MaxLineWidth = xpos; + if (ysizeup < 0) ysizeup = 0; + if (ysizedown < 0) ysizedown = 0; + switch (m_AlignHor) { + case HTML_ALIGN_LEFT : xdelta = 0; break; + case HTML_ALIGN_RIGHT : xdelta = 0 + (s_width - xpos); break; + case HTML_ALIGN_CENTER : xdelta = 0 + (s_width - xpos) / 2; break; + } + if (xdelta < 0) xdelta = 0; + xdelta += s_indent; + + ypos += ysizeup; + while (line != cell) { + line -> SetPos(line -> GetPosX() + xdelta, ypos + line -> GetPosY()); + line = line -> GetNext(); + } + + ypos += ysizedown; + xpos = 0; + ysizeup = ysizedown = 0; + line = cell; + } + } + + // setup height & width, depending on container layout: + m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom; + + if (m_Height < m_MinHeight) { + if (m_MinHeightAlign != HTML_ALIGN_TOP) { + int diff = m_MinHeight - m_Height; + if (m_MinHeightAlign == HTML_ALIGN_CENTER) diff /= 2; + cell = m_Cells; + while (cell) { + cell -> SetPos(cell -> GetPosX(), cell -> GetPosY() + diff); + cell = cell -> GetNext(); + } + } + m_Height = m_MinHeight; + } + + m_MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight); + if (m_Width < m_MaxLineWidth) m_Width = m_MaxLineWidth; + + wxHtmlCell::Layout(w); +} + + +#define mMin(a, b) (((a) < (b)) ? (a) : (b)) +#define mMax(a, b) (((a) < (b)) ? (b) : (a)) + +void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + // container visible, draw it: + if ((y + m_PosY < view_y2) && (y + m_PosY + m_Height > view_y1)) { + + if (m_UseBkColour) { + wxBrush myb = wxBrush(m_BkColour, wxSOLID); + + int real_y1 = mMax(y + m_PosY, view_y1); + int real_y2 = mMin(y + m_PosY + m_Height - 1, view_y2); + + dc.SetBrush(myb); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(x + m_PosX, real_y1, m_Width, real_y2 - real_y1 + 1); + } + + if (m_UseBorder) { + wxPen mypen1(m_BorderColour1, 1, wxSOLID); + wxPen mypen2(m_BorderColour2, 1, wxSOLID); + + dc.SetPen(mypen1); + dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX, y + m_PosY + m_Height - 1); + dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY); + dc.SetPen(mypen2); + dc.DrawLine(x + m_PosX + m_Width - 1, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1); + dc.DrawLine(x + m_PosX, y + m_PosY + m_Height - 1, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1); + } + + if (m_Cells) m_Cells -> Draw(dc, x + m_PosX, y + m_PosY, view_y1, view_y2); + } + // container invisible, just proceed font+color changing: + else { + if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY); + } + + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + +void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y) +{ + if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY); + wxHtmlCell::DrawInvisible(dc, x, y); +} + + + +wxString wxHtmlContainerCell::GetLink(int x, int y) const +{ + wxHtmlCell *c = m_Cells; + int cx, cy, cw, ch; + + while (c) { + cx = c -> GetPosX(), cy = c -> GetPosY(); + cw = c -> GetWidth(), ch = c -> GetHeight(); + if ((x >= cx) && (x < cx + cw) && (y >= cy) && (y < cy + ch)) + return c -> GetLink(x - cx, y - cy); + c = c -> GetNext(); + } + return wxEmptyString; +} + + + +void wxHtmlContainerCell::InsertCell(wxHtmlCell *f) +{ + if (!m_Cells) m_Cells = m_LastCell = f; + else { + m_LastCell -> SetNext(f); + m_LastCell = f; + if (m_LastCell) while (m_LastCell -> GetNext()) m_LastCell = m_LastCell -> GetNext(); + } + f -> SetParent(this); +} + + + +void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag) +{ + if (tag.HasParam("ALIGN")) { + wxString alg = tag.GetParam("ALIGN"); + alg.MakeUpper(); + if (alg == "CENTER") + SetAlignHor(HTML_ALIGN_CENTER); + else if (alg == "LEFT") + SetAlignHor(HTML_ALIGN_LEFT); + else if (alg == "RIGHT") + SetAlignHor(HTML_ALIGN_RIGHT); + } +} + + + +void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag) +{ + if (tag.HasParam("WIDTH")) { + int wdi; + wxString wd = tag.GetParam("WIDTH"); + + if (wd[wd.Length()-1] == '%') { + sscanf(wd.c_str(), "%i%%", &wdi); + SetWidthFloat(wdi, HTML_UNITS_PERCENT); + } + else { + sscanf(wd.c_str(), "%i", &wdi); + SetWidthFloat(wdi, HTML_UNITS_PIXELS); + } + } +} + + + +const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const +{ + const wxHtmlCell *r = NULL; + + if (m_Cells) { + r = m_Cells -> Find(condition, param); + if (r) return r; + } + + return wxHtmlCell::Find(condition, param); +} + + + +void wxHtmlContainerCell::OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right) +{ + if (m_Cells) { + wxHtmlCell *c = m_Cells; + while (c) { + if ( (c -> GetPosX() <= x) && + (c -> GetPosY() <= y) && + (c -> GetPosX() + c -> GetWidth() > x) && + (c -> GetPosY() + c -> GetHeight() > y)) { + c -> OnMouseClick(parent, x - c -> GetPosX(), y - c -> GetPosY(), left, middle, right); + break; + } + c = c -> GetNext(); + } + } +} + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlColourCell +//-------------------------------------------------------------------------------- + +void wxHtmlColourCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + if (m_Flags & HTML_CLR_FOREGROUND) + dc.SetTextForeground(m_Colour); + if (m_Flags & HTML_CLR_BACKGROUND) { + dc.SetBackground(wxBrush(m_Colour, wxSOLID)); + dc.SetTextBackground(m_Colour); + } + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + +void wxHtmlColourCell::DrawInvisible(wxDC& dc, int x, int y) +{ + if (m_Flags & HTML_CLR_FOREGROUND) + dc.SetTextForeground(m_Colour); + if (m_Flags & HTML_CLR_BACKGROUND) { + dc.SetBackground(wxBrush(m_Colour, wxSOLID)); + dc.SetTextBackground(m_Colour); + } + wxHtmlCell::DrawInvisible(dc, x, y); +} + + + + +//-------------------------------------------------------------------------------- +// wxHtmlFontCell +//-------------------------------------------------------------------------------- + +void wxHtmlFontCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + dc.SetFont(*m_Font); + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + +void wxHtmlFontCell::DrawInvisible(wxDC& dc, int x, int y) +{ + dc.SetFont(*m_Font); + wxHtmlCell::DrawInvisible(dc, x, y); +} + + + + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlWidgetCell +//-------------------------------------------------------------------------------- + +wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w) +{ + int sx, sy; + m_Wnd = wnd; + m_Wnd -> GetSize(&sx, &sy); + m_Width = sx, m_Height = sy; + m_WidthFloat = w; +} + + +void wxHtmlWidgetCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + int absx = 0, absy = 0, stx, sty; + wxHtmlCell *c = this; + + while (c) { + absx += c -> GetPosX(); + absy += c -> GetPosY(); + c = c -> GetParent(); + } + + ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty); + + m_Wnd -> SetSize(absx - HTML_SCROLL_STEP * stx, absy - HTML_SCROLL_STEP * sty, m_Width, m_Height); +// m_Wnd -> Refresh(); + + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + +void wxHtmlWidgetCell::DrawInvisible(wxDC& dc, int x, int y) +{ + int absx = 0, absy = 0, stx, sty; + wxHtmlCell *c = this; + + while (c) { + absx += c -> GetPosX(); + absy += c -> GetPosY(); + c = c -> GetParent(); + } + ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty); + + m_Wnd -> SetSize(absx - HTML_SCROLL_STEP * stx, absy - HTML_SCROLL_STEP * sty, m_Width, m_Height); + wxHtmlCell::DrawInvisible(dc, x, y); +} + + + +void wxHtmlWidgetCell::Layout(int w) +{ + if (m_WidthFloat != 0) { + m_Width = (w * m_WidthFloat) / 100; + m_Wnd -> SetSize(m_Width, m_Height); + } + + wxHtmlCell::Layout(w); +} + +#endif diff --git a/src/html/htmlfilter.cpp b/src/html/htmlfilter.cpp new file mode 100644 index 0000000000..792240be7e --- /dev/null +++ b/src/html/htmlfilter.cpp @@ -0,0 +1,170 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: filter.cpp +// Purpose: wxHtmlFilter - input filter for translating into HTML format +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/html/htmlfilter.h> +#include <wx/html/htmlwin.h> + + +/* + +There is code for several default filters: + +*/ + +IMPLEMENT_ABSTRACT_CLASS(wxHtmlFilter, wxObject) + +//-------------------------------------------------------------------------------- +// wxHtmlFilterPlainText +// filter for text/plain or uknown +//-------------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterPlainText, wxHtmlFilter) + +bool wxHtmlFilterPlainText::CanRead(const wxFSFile& file) +{ + return TRUE; +} + + + +wxString wxHtmlFilterPlainText::ReadFile(const wxFSFile& file) +{ + wxInputStream *s = file.GetStream(); + char *src; + wxString doc, doc2; + + if (s == NULL) return wxEmptyString; + src = (char*) malloc(s -> StreamSize()); + src[s -> StreamSize()] = 0; + s -> Read(src, s -> StreamSize()); + doc = src; + free(src); + + doc.Replace("<", "<", TRUE); + doc.Replace(">", ">", TRUE); + doc2 = "<HTML><BODY><PRE>\n" + doc + "\n</PRE></BODY></HTML>"; + return doc2; +} + + + + + +//-------------------------------------------------------------------------------- +// wxHtmlFilterImage +// filter for image/* +//-------------------------------------------------------------------------------- + +class wxHtmlFilterImage : public wxHtmlFilter +{ + DECLARE_DYNAMIC_CLASS(wxHtmlFilterImage) + + public: + virtual bool CanRead(const wxFSFile& file); + virtual wxString ReadFile(const wxFSFile& file); +}; + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterImage, wxHtmlFilter) + + + +bool wxHtmlFilterImage::CanRead(const wxFSFile& file) +{ + return (file.GetMimeType().Left(6) == "image/"); +} + + + +wxString wxHtmlFilterImage::ReadFile(const wxFSFile& file) +{ + return ("<HTML><BODY><IMG SRC=\"" + file.GetLocation() + "\"></BODY></HTML>"); +} + + + + +//-------------------------------------------------------------------------------- +// wxHtmlFilterPlainText +// filter for text/plain or uknown +//-------------------------------------------------------------------------------- + +class wxHtmlFilterHTML : public wxHtmlFilter +{ + DECLARE_DYNAMIC_CLASS(wxHtmlFilterHTML) + + public: + virtual bool CanRead(const wxFSFile& file); + virtual wxString ReadFile(const wxFSFile& file); +}; + + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterHTML, wxHtmlFilter) + +bool wxHtmlFilterHTML::CanRead(const wxFSFile& file) +{ + return (file.GetMimeType() == "text/html"); +} + + + +wxString wxHtmlFilterHTML::ReadFile(const wxFSFile& file) +{ + wxInputStream *s = file.GetStream(); + char *src; + wxString doc; + + if (s == NULL) return wxEmptyString; + src = (char*) malloc(s -> StreamSize() + 1); + src[s -> StreamSize()] = 0; + s -> Read(src, s -> StreamSize()); + doc = src; + free(src); + + return doc; +} + + + + +///// Module: + +class wxHtmlFilterModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxHtmlFilterModule) + + public: + virtual bool OnInit() + { + wxHtmlWindow::AddFilter(new wxHtmlFilterHTML); + wxHtmlWindow::AddFilter(new wxHtmlFilterImage); + return TRUE; + } + virtual void OnExit() {} +}; + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlFilterModule, wxModule) + +#endif \ No newline at end of file diff --git a/src/html/htmlhelp.cpp b/src/html/htmlhelp.cpp new file mode 100644 index 0000000000..22d69b06cd --- /dev/null +++ b/src/html/htmlhelp.cpp @@ -0,0 +1,864 @@ +// Name: htmlhelp.cpp +// Purpose: Help controller +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + + +#include <wx/notebook.h> +#include <wx/imaglist.h> +#include <wx/treectrl.h> +#include <wx/tokenzr.h> +#include <wx/wfstream.h> +#include <wx/html/htmlwin.h> +#include <wx/html/htmlhelp.h> +#include <wx/busyinfo.h> + +#if !((wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7))) +#include <wx/progdlg.h> +#endif + + +// Bitmaps: + +#ifndef __WXMSW__ +#include "bitmaps/panel.xpm" +#include "bitmaps/back.xpm" +#include "bitmaps/forward.xpm" +#include "bitmaps/book.xpm" +#include "bitmaps/folder.xpm" +#include "bitmaps/page.xpm" +#endif + +#include "search.h" + + + +//----------------------------------------------------------------------------- +// Helper constants +//----------------------------------------------------------------------------- + + +// Command IDs : + +enum { + wxID_HTML_PANEL = wxID_HIGHEST + 1, + wxID_HTML_BACK, + wxID_HTML_FORWARD, + wxID_HTML_TREECTRL, + wxID_HTML_INDEXPAGE, + wxID_HTML_INDEXLIST, + wxID_HTML_NOTEBOOK, + wxID_HTML_SEARCHPAGE, + wxID_HTML_SEARCHTEXT, + wxID_HTML_SEARCHLIST, + wxID_HTML_SEARCHBUTTON +}; + + +// Images: + +enum { + IMG_Book = 0, + IMG_Folder, + IMG_Page +}; + + + + + + +class HtmlHelpTreeItemData : public wxTreeItemData +{ + private: + wxString m_Page; + + public: + HtmlHelpTreeItemData(HtmlContentsItem *it) : wxTreeItemData() {m_Page = it -> m_Book -> GetBasePath() + it -> m_Page;} + const wxString& GetPage() {return m_Page;} +}; + + + + + +#include <wx/arrimpl.cpp> +WX_DEFINE_OBJARRAY(HtmlBookRecArray) + + + + + + + + + +//----------------------------------------------------------------------------- +// wxHtmlHelpController +//----------------------------------------------------------------------------- + + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpController, wxEvtHandler) + + +wxHtmlHelpController::wxHtmlHelpController() : wxEvtHandler() +{ + m_Frame = NULL; + m_Config = NULL; + m_ConfigRoot = wxEmptyString; + m_TitleFormat = _("Help : %s"); + m_TempPath = wxEmptyString; + + m_Cfg.x = m_Cfg.y = 0; + m_Cfg.w = 700; m_Cfg.h = 480; + m_Cfg.sashpos = 240; + m_Cfg.navig_on = TRUE; + + m_ContentsImageList = new wxImageList(12, 12); + m_ContentsImageList -> Add(wxICON(book)); + m_ContentsImageList -> Add(wxICON(folder)); + m_ContentsImageList -> Add(wxICON(page)); + + m_Contents = NULL; + m_ContentsCnt = 0; + m_Index = NULL; + m_IndexCnt = 0; +} + + + +wxHtmlHelpController::~wxHtmlHelpController() +{ + int i; + + m_BookRecords.Empty(); + delete m_ContentsImageList; + if (m_Contents) { + for (i = 0; i < m_ContentsCnt; i++) { + free(m_Contents[i].m_Page); + free(m_Contents[i].m_Name); + } + free(m_Contents); + } + if (m_Index) { + for (i = 0; i < m_IndexCnt; i++) { + free(m_Index[i].m_Page); + free(m_Index[i].m_Name); + } + free(m_Index); + } +} + + + +void wxHtmlHelpController::SetTempDir(const wxString& path) +{ + if (path == wxEmptyString) m_TempPath = path; + else { + if (wxIsAbsolutePath(path)) m_TempPath = path; + else m_TempPath = wxGetCwd() + "/" + path; + + if (m_TempPath[m_TempPath.Length() - 1] != '/') + m_TempPath << "/"; + } +} + + + + +// Reads one line, stores it into buf and returns pointer to new line or NULL. +static char* ReadLine(char *line, char *buf) +{ + char *writeptr = buf, *readptr = line; + + while (*readptr != 0 && *readptr != '\r' && *readptr != '\n') *(writeptr++) = *(readptr++); + *writeptr = 0; + while (*readptr == '\r' || *readptr == '\n') readptr++; + if (*readptr == 0) return NULL; + else return readptr; +} + + +static wxString SafeFileName(const wxString& s) +{ + wxString res = s; + res.Replace(":", "_", TRUE); + res.Replace(" ", "_", TRUE); + res.Replace("/", "_", TRUE); + res.Replace("\\", "_", TRUE); + res.Replace("#", "_", TRUE); + res.Replace(".", "_", TRUE); + return res; +} + + +static int IndexCompareFunc(const void *a, const void *b) +{ + return strcmp(((HtmlContentsItem*)a) -> m_Name, ((HtmlContentsItem*)b) -> m_Name); +} + + + +bool wxHtmlHelpController::AddBook(const wxString& book, bool show_wait_msg = FALSE) +{ + wxFSFile *fi; + wxFileSystem fsys; + wxInputStream *s; + HtmlBookRecord *bookr; + wxString bookFull; + + int sz; + char *buff, *lineptr; + char linebuf[300]; + + wxString title = _("noname"), + safetitle, + start = wxEmptyString, + contents = wxEmptyString, index = wxEmptyString; + + if (wxIsAbsolutePath(book)) bookFull = book; + else bookFull = wxGetCwd() + "/" + book; + + fi = fsys.OpenFile(bookFull); + if (fi == NULL) return FALSE; + fsys.ChangePathTo(bookFull); + s = fi -> GetStream(); + sz = s -> StreamSize(); + buff = (char*) malloc(sz+1); + buff[sz] = 0; + s -> Read(buff, sz); + lineptr = buff; + delete fi; + + while ((lineptr = ReadLine(lineptr, linebuf)) != NULL) { + if (strstr(linebuf, "Title=") == linebuf) + title = linebuf + strlen("Title="); + if (strstr(linebuf, "Default topic=") == linebuf) + start = linebuf + strlen("Default topic="); + if (strstr(linebuf, "Index file=") == linebuf) + index = linebuf + strlen("Index file="); + if (strstr(linebuf, "Contents file=") == linebuf) + contents = linebuf + strlen("Contents file="); + } + free(buff); + + bookr = new HtmlBookRecord(fsys.GetPath(), title, start); + + if (m_ContentsCnt % HTML_REALLOC_STEP == 0) + m_Contents = (HtmlContentsItem*) realloc(m_Contents, (m_ContentsCnt + HTML_REALLOC_STEP) * sizeof(HtmlContentsItem)); + m_Contents[m_ContentsCnt].m_Level = 0; + m_Contents[m_ContentsCnt].m_ID = 0; + m_Contents[m_ContentsCnt].m_Page = (char*) malloc(start.Length() + 1); + strcpy(m_Contents[m_ContentsCnt].m_Page, start.c_str()); + m_Contents[m_ContentsCnt].m_Name = (char*) malloc(title.Length() + 1); + strcpy(m_Contents[m_ContentsCnt].m_Name, title.c_str()); + m_Contents[m_ContentsCnt].m_Book = bookr; + m_ContentsCnt++; + + // Try to find cached binary versions: + safetitle = SafeFileName(title); + fi = fsys.OpenFile(safetitle + ".cached"); + if (fi == NULL) fi = fsys.OpenFile(m_TempPath + safetitle + ".cached"); + if ((fi == NULL) || (m_TempPath == wxEmptyString)) { + LoadMSProject(bookr, fsys, index, contents, show_wait_msg); + if (m_TempPath != wxEmptyString) { + wxFileOutputStream *outs = new wxFileOutputStream(m_TempPath + safetitle + ".cached"); + SaveCachedBook(bookr, outs); + delete outs; + } + } + else { + LoadCachedBook(bookr, fi -> GetStream()); + delete fi; + } + + m_BookRecords.Add(bookr); + if (m_IndexCnt > 0) + qsort(m_Index, m_IndexCnt, sizeof(HtmlContentsItem), IndexCompareFunc); + + return TRUE; +} + + + + +void wxHtmlHelpController::Display(const wxString& x) +{ + int cnt; + int i; + wxFileSystem fsys; + wxFSFile *f; + + CreateHelpWindow(); + + /* 1. try to open given file: */ + + cnt = m_BookRecords.GetCount(); + for (i = 0; i < cnt; i++) { + f = fsys.OpenFile(m_BookRecords[i].GetBasePath() + x); + if (f) { + m_HtmlWin -> LoadPage(m_BookRecords[i].GetBasePath() + x); + delete f; + return; + } + } + + + /* 2. try to find a book: */ + + for (i = 0; i < cnt; i++) { + if (m_BookRecords[i].GetTitle() == x) { + m_HtmlWin -> LoadPage(m_BookRecords[i].GetBasePath() + m_BookRecords[i].GetStart()); + return; + } + } + + /* 3. try to find in contents: */ + + cnt = m_ContentsCnt; + for (i = 0; i < cnt; i++) { + if (strcmp(m_Contents[i].m_Name, x) == 0) { + m_HtmlWin -> LoadPage(m_Contents[i].m_Book -> GetBasePath() + m_Contents[i].m_Page); + return; + } + } + + + /* 4. try to find in index: */ + + cnt = m_IndexCnt; + for (i = 0; i < cnt; i++) { + if (strcmp(m_Index[i].m_Name, x) == 0) { + m_HtmlWin -> LoadPage(m_Index[i].m_Book -> GetBasePath() + m_Index[i].m_Page); + return; + } + } + + + /* 5. if everything failed, search the documents: */ + + KeywordSearch(x); +} + + + +void wxHtmlHelpController::Display(const int id) +{ + CreateHelpWindow(); + + for (int i = 0; i < m_ContentsCnt; i++) { + if (m_Contents[i].m_ID == id) { + m_HtmlWin -> LoadPage(m_Contents[i].m_Book -> GetBasePath() + m_Contents[i].m_Page); + return; + } + } +} + + + +void wxHtmlHelpController::DisplayContents() +{ + CreateHelpWindow(); + m_Frame -> Raise(); + if (!m_Splitter -> IsSplit()) { + m_NavigPan -> Show(TRUE); + m_HtmlWin -> Show(TRUE); + m_Splitter -> SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos); + } + m_NavigPan -> SetSelection(0); +} + + + +void wxHtmlHelpController::DisplayIndex() +{ + CreateHelpWindow(); + m_Frame -> Raise(); + if (!m_Splitter -> IsSplit()) { + m_NavigPan -> Show(TRUE); + m_HtmlWin -> Show(TRUE); + m_Splitter -> SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos); + } + m_NavigPan -> SetSelection(1); +} + + + + +#if (wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7)) + +class MyProgressDlg : public wxDialog +{ + public: + bool m_Canceled; + + MyProgressDlg(wxWindow *parent) : wxDialog(parent, -1, + _("Searching..."), + wxPoint(0, 0), +#ifdef __WXGTK__ + wxSize(300, 110)) +#else + wxSize(300, 130)) +#endif + {m_Canceled = FALSE;} + void OnCancel(wxCommandEvent& event) {m_Canceled = TRUE;} + DECLARE_EVENT_TABLE() +}; +BEGIN_EVENT_TABLE(MyProgressDlg, wxDialog) + EVT_BUTTON(wxID_CANCEL, MyProgressDlg::OnCancel) +END_EVENT_TABLE() + +#endif + + +bool wxHtmlHelpController::KeywordSearch(const wxString& keyword) +{ + int foundcnt = 0; + + CreateHelpWindow(); + m_Frame -> Raise(); + if (!m_Splitter -> IsSplit()) { + m_NavigPan -> Show(TRUE); + m_HtmlWin -> Show(TRUE); + m_Splitter -> SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos); + } + m_NavigPan -> SetSelection(2); + m_SearchList -> Clear(); + m_SearchText -> SetValue(keyword); + m_SearchButton -> Enable(FALSE); + + { + int cnt = m_ContentsCnt; + wxSearchEngine engine; + wxFileSystem fsys; + wxFSFile *file; + wxString lastpage = wxEmptyString; + wxString foundstr; + +#if (wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7)) + MyProgressDlg progress(m_Frame); + + wxStaticText *prompt = new wxStaticText(&progress, -1, "", wxPoint(20, 50), wxSize(260, 25), wxALIGN_CENTER); + wxGauge *gauge = new wxGauge(&progress, -1, cnt, wxPoint(20, 20), wxSize(260, 25)); + wxButton *btn = new wxButton(&progress, wxID_CANCEL, _("Cancel"), wxPoint(110, 70), wxSize(80, 25)); + btn = btn; /* fool compiler :-) */ + prompt -> SetLabel(_("No matching page found yet")); + + progress.Centre(wxBOTH); + progress.Show(TRUE); +#else + wxProgressDialog progress(_("Searching..."), _("No matching page found yet"), cnt, m_Frame, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE); +#endif + + engine.LookFor(keyword); + + for (int i = 0; i < cnt; i++) { +#if (wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7)) + gauge -> SetValue(i); + if (progress.m_Canceled) break; +#else + if (progress.Update(i) == FALSE) break; +#endif + wxYield(); + + file = fsys.OpenFile(m_Contents[i].m_Book -> GetBasePath() + m_Contents[i].m_Page); + if (file) { + if (lastpage != file -> GetLocation()) { + lastpage = file -> GetLocation(); + if (engine.Scan(file -> GetStream())) { + foundstr.Printf(_("Found %i matches"), ++foundcnt); +#if (wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7)) + prompt -> SetLabel(foundstr); +#else + progress.Update(i, foundstr); +#endif + wxYield(); + m_SearchList -> Append(m_Contents[i].m_Name, (char*)(m_Contents + i)); + } + } + delete file; + } + } + +#if (wxVERSION_NUMBER < 2100) || ((wxVERSION_NUMBER == 2100) && (wxBETA_NUMBER < 7)) + progress.Close(TRUE); +#endif + } + + m_SearchButton -> Enable(TRUE); + m_SearchText -> SetSelection(0, keyword.Length()); + m_SearchText -> SetFocus(); + if (foundcnt) { + HtmlContentsItem *it = (HtmlContentsItem*) m_SearchList -> GetClientData(0); + if (it) m_HtmlWin -> LoadPage(it -> m_Book -> GetBasePath() + it -> m_Page); + } + return (foundcnt > 0); +} + + + + + + +void wxHtmlHelpController::CreateHelpWindow() +{ + wxBusyCursor cur; + wxString oldpath; + wxStatusBar *sbar; + + if (m_Frame) { + m_Frame -> Raise(); + m_Frame -> Show(TRUE); + return; + } + + wxBusyInfo busyinfo(_("Preparing help window...")); + + if (m_Config) ReadCustomization(m_Config, m_ConfigRoot); + + m_Frame = new wxFrame(NULL, -1, "", wxPoint(m_Cfg.x, m_Cfg.y), wxSize(m_Cfg.w, m_Cfg.h)); + m_Frame -> PushEventHandler(this); + sbar = m_Frame -> CreateStatusBar(); + + { + wxToolBar *toolBar; + toolBar = m_Frame -> CreateToolBar(wxNO_BORDER | wxTB_HORIZONTAL | wxTB_FLAT | wxTB_DOCKABLE); + toolBar -> SetMargins(2, 2); + wxBitmap* toolBarBitmaps[3]; + +#ifdef __WXMSW__ + toolBarBitmaps[0] = new wxBitmap("panel"); + toolBarBitmaps[1] = new wxBitmap("back"); + toolBarBitmaps[2] = new wxBitmap("forward"); + int width = 24; +#else + toolBarBitmaps[0] = new wxBitmap(panel_xpm); + toolBarBitmaps[1] = new wxBitmap(back_xpm); + toolBarBitmaps[2] = new wxBitmap(forward_xpm); + int width = 16; +#endif + + int currentX = 5; + + toolBar -> AddTool(wxID_HTML_PANEL, *(toolBarBitmaps[0]), wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Show/hide navigation panel")); + currentX += width + 5; + toolBar -> AddSeparator(); + toolBar -> AddTool(wxID_HTML_BACK, *(toolBarBitmaps[1]), wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Go back to the previous HTML page")); + currentX += width + 5; + toolBar -> AddTool(wxID_HTML_FORWARD, *(toolBarBitmaps[2]), wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Go forward to the next HTML page")); + currentX += width + 5; + + toolBar -> Realize(); + + // Can delete the bitmaps since they're reference counted + for (int i = 0; i < 3; i++) delete toolBarBitmaps[i]; + } + + + { + m_Splitter = new wxSplitterWindow(m_Frame); + + m_HtmlWin = new wxHtmlWindow(m_Splitter); + m_HtmlWin -> SetRelatedFrame(m_Frame, m_TitleFormat); + m_HtmlWin -> SetRelatedStatusBar(0); + if (m_Config) m_HtmlWin -> ReadCustomization(m_Config, m_ConfigRoot); + + m_NavigPan = new wxNotebook(m_Splitter, wxID_HTML_NOTEBOOK, wxDefaultPosition, wxDefaultSize); + { + m_ContentsBox = new wxTreeCtrl(m_NavigPan, wxID_HTML_TREECTRL, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS | wxSUNKEN_BORDER); + m_ContentsBox -> SetImageList(m_ContentsImageList); + m_NavigPan -> AddPage(m_ContentsBox, _("Contents")); + } + + { + wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_INDEXPAGE); + wxLayoutConstraints *b1 = new wxLayoutConstraints; + b1 -> top.SameAs (dummy, wxTop, 0); + b1 -> left.SameAs (dummy, wxLeft, 0); + b1 -> width.PercentOf (dummy, wxWidth, 100); + b1 -> bottom.SameAs (dummy, wxBottom, 0); + m_IndexBox = new wxListBox(dummy, wxID_HTML_INDEXLIST, wxDefaultPosition, wxDefaultSize, 0); + m_IndexBox -> SetConstraints(b1); + dummy -> SetAutoLayout(TRUE); + m_NavigPan -> AddPage(dummy, _("Index")); + } + + { + wxWindow *dummy = new wxPanel(m_NavigPan, wxID_HTML_SEARCHPAGE); + + wxLayoutConstraints *b1 = new wxLayoutConstraints; + m_SearchText = new wxTextCtrl(dummy, wxID_HTML_SEARCHTEXT); + b1 -> top.SameAs (dummy, wxTop, 0); + b1 -> left.SameAs (dummy, wxLeft, 0); + b1 -> right.SameAs (dummy, wxRight, 0); + b1 -> height.AsIs(); + m_SearchText -> SetConstraints(b1); + + wxLayoutConstraints *b2 = new wxLayoutConstraints; + m_SearchButton = new wxButton(dummy, wxID_HTML_SEARCHBUTTON, _("Search!")); + b2 -> top.Below (m_SearchText, 10); + b2 -> right.SameAs (dummy, wxRight, 10); + b2 -> width.AsIs(); + b2 -> height.AsIs(); + m_SearchButton -> SetConstraints(b2); + + wxLayoutConstraints *b3 = new wxLayoutConstraints; + m_SearchList = new wxListBox(dummy, wxID_HTML_SEARCHLIST, wxDefaultPosition, wxDefaultSize, 0); + b3 -> top.Below (m_SearchButton, 10); + b3 -> left.SameAs (dummy, wxLeft, 0); + b3 -> right.SameAs (dummy, wxRight, 0); + b3 -> bottom.SameAs (dummy, wxBottom, 0); + m_SearchList -> SetConstraints(b3); + + dummy -> SetAutoLayout(TRUE); + dummy -> Layout(); + m_NavigPan -> AddPage(dummy, _("Search")); + } + + RefreshLists(); + m_NavigPan -> Show(TRUE); + m_HtmlWin -> Show(TRUE); + m_Splitter -> SetMinimumPaneSize(20); + m_Splitter -> SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos); + if (!m_Cfg.navig_on) m_Splitter -> Unsplit(m_NavigPan); + wxYield(); + } + + m_Frame -> Show(TRUE); + wxYield(); +} + + + +#define MAX_ROOTS 64 + +void wxHtmlHelpController::CreateContents() +{ + HtmlContentsItem *it; + wxTreeItemId roots[MAX_ROOTS]; + bool imaged[MAX_ROOTS]; + int count = m_ContentsCnt; + + m_ContentsBox -> DeleteAllItems(); + roots[0] = m_ContentsBox -> AddRoot(_("(Help)")); + imaged[0] = TRUE; + + for (int i = 0; i < count; i++) { + it = m_Contents + i; + roots[it -> m_Level + 1] = m_ContentsBox -> AppendItem(roots[it -> m_Level], it -> m_Name, IMG_Page, -1, new HtmlHelpTreeItemData(it)); + if (it -> m_Level == 0) { + m_ContentsBox -> SetItemBold(roots[1], TRUE); + m_ContentsBox -> SetItemImage(roots[1], IMG_Book); + m_ContentsBox -> SetItemSelectedImage(roots[1], IMG_Book); + imaged[1] = TRUE; + } + else imaged[it -> m_Level + 1] = FALSE; + + if (!imaged[it -> m_Level]) { + m_ContentsBox -> SetItemImage(roots[it -> m_Level], IMG_Folder); + m_ContentsBox -> SetItemSelectedImage(roots[it -> m_Level], IMG_Folder); + imaged[it -> m_Level] = TRUE; + } + } + + m_ContentsBox -> Expand(roots[0]); +} + + + + +void wxHtmlHelpController::CreateIndex() +{ + m_IndexBox -> Clear(); + + for (int i = 0; i < m_IndexCnt; i++) + m_IndexBox -> Append(m_Index[i].m_Name, (char*)(m_Index + i)); +} + + + +void wxHtmlHelpController::RefreshLists() +{ + if (m_Frame) { + CreateContents(); + CreateIndex(); + m_SearchList -> Clear(); + } +} + + + + + + + +void wxHtmlHelpController::ReadCustomization(wxConfigBase *cfg, wxString path) +{ + wxString oldpath; + wxString tmp; + + if (path != wxEmptyString) { + oldpath = cfg -> GetPath(); + cfg -> SetPath(path); + } + + m_Cfg.navig_on = (bool) cfg -> Read("hcNavigPanel", m_Cfg.navig_on); + m_Cfg.sashpos = cfg -> Read("hcSashPos", m_Cfg.sashpos); + m_Cfg.x = cfg -> Read("hcX", m_Cfg.x); + m_Cfg.y = cfg -> Read("hcY", m_Cfg.y); + m_Cfg.w = cfg -> Read("hcW", m_Cfg.w); + m_Cfg.h = cfg -> Read("hcH", m_Cfg.h); + + if (path != wxEmptyString) + cfg -> SetPath(oldpath); +} + + + +void wxHtmlHelpController::WriteCustomization(wxConfigBase *cfg, wxString path) +{ + wxString oldpath; + wxString tmp; + + if (path != wxEmptyString) { + oldpath = cfg -> GetPath(); + cfg -> SetPath(path); + } + + cfg -> Write("hcNavigPanel", m_Cfg.navig_on); + cfg -> Write("hcSashPos", (long)m_Cfg.sashpos); + cfg -> Write("hcX", (long)m_Cfg.x); + cfg -> Write("hcY", (long)m_Cfg.y); + cfg -> Write("hcW", (long)m_Cfg.w); + cfg -> Write("hcH", (long)m_Cfg.h); + + if (path != wxEmptyString) + cfg -> SetPath(oldpath); +} + + + + + +/* +EVENT HANDLING : +*/ + + +void wxHtmlHelpController::OnToolbar(wxCommandEvent& event) +{ + switch (event.GetId()) { + case wxID_HTML_BACK : + m_HtmlWin -> HistoryBack(); + break; + case wxID_HTML_FORWARD : + m_HtmlWin -> HistoryForward(); + break; + case wxID_HTML_PANEL : + if (m_Splitter -> IsSplit()) { + m_Cfg.sashpos = m_Splitter -> GetSashPosition(); + m_Splitter -> Unsplit(m_NavigPan); + } + else { + m_NavigPan -> Show(TRUE); + m_HtmlWin -> Show(TRUE); + m_Splitter -> SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos); + } + break; + } +} + + + +void wxHtmlHelpController::OnContentsSel(wxTreeEvent& event) +{ + HtmlHelpTreeItemData *pg; + + pg = (HtmlHelpTreeItemData*) m_ContentsBox -> GetItemData(event.GetItem()); + if (pg) m_HtmlWin -> LoadPage(pg -> GetPage()); +} + + + +void wxHtmlHelpController::OnIndexSel(wxCommandEvent& event) +{ + HtmlContentsItem *it = (HtmlContentsItem*) m_IndexBox -> GetClientData(m_IndexBox -> GetSelection()); + if (it) m_HtmlWin -> LoadPage(it -> m_Book -> GetBasePath() + it -> m_Page); +} + + + +void wxHtmlHelpController::OnSearchSel(wxCommandEvent& event) +{ + HtmlContentsItem *it = (HtmlContentsItem*) m_SearchList -> GetClientData(m_SearchList -> GetSelection()); + if (it) m_HtmlWin -> LoadPage(it -> m_Book -> GetBasePath() + it -> m_Page); +} + + + +void wxHtmlHelpController::OnCloseWindow(wxCloseEvent& event) +{ + int a, b; + + m_Cfg.navig_on = m_Splitter -> IsSplit(); + if (m_Cfg.navig_on) + m_Cfg.sashpos = m_Splitter -> GetSashPosition(); + m_Frame -> GetPosition(&a, &b); + m_Cfg.x = a, m_Cfg.y = b; + m_Frame -> GetSize(&a, &b); + m_Cfg.w = a, m_Cfg.h = b; + + if (m_Config) { + WriteCustomization(m_Config, m_ConfigRoot); + m_HtmlWin -> WriteCustomization(m_Config, m_ConfigRoot); + } + m_Frame = NULL; + + event.Skip(); +} + + + +void wxHtmlHelpController::OnSearch(wxCommandEvent& event) +{ + wxString sr = m_SearchText -> GetLineText(0); + + if (sr != wxEmptyString) KeywordSearch(sr); +} + + + +BEGIN_EVENT_TABLE(wxHtmlHelpController, wxEvtHandler) + EVT_TOOL_RANGE(wxID_HTML_PANEL, wxID_HTML_FORWARD, wxHtmlHelpController::OnToolbar) + EVT_TREE_SEL_CHANGED(wxID_HTML_TREECTRL, wxHtmlHelpController::OnContentsSel) + EVT_LISTBOX(wxID_HTML_INDEXLIST, wxHtmlHelpController::OnIndexSel) + EVT_LISTBOX(wxID_HTML_SEARCHLIST, wxHtmlHelpController::OnSearchSel) + EVT_CLOSE(wxHtmlHelpController::OnCloseWindow) + EVT_BUTTON(wxID_HTML_SEARCHBUTTON, wxHtmlHelpController::OnSearch) + EVT_TEXT_ENTER(wxID_HTML_SEARCHTEXT, wxHtmlHelpController::OnSearch) +END_EVENT_TABLE() + + + +#endif + diff --git a/src/html/htmlhelp_io.cpp b/src/html/htmlhelp_io.cpp new file mode 100644 index 0000000000..b4d82e7ec9 --- /dev/null +++ b/src/html/htmlhelp_io.cpp @@ -0,0 +1,250 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlhelp.cpp +// Purpose: Help controller +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +//#ifdef __GNUG__ +//#pragma implementation "htmlhelp.h" +//#endif +// --- already in htmlhelp.cpp + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + + +#include <wx/wxhtml.h> +#include <wx/busyinfo.h> + + + + +class HP_Parser : public wxHtmlParser +{ + public: + void AddText(const char* text) {} + wxObject* GetProduct() {return NULL;} +}; + + + +class HP_TagHandler : public wxHtmlTagHandler +{ + private: + wxString m_Name, m_Page; + int m_Level; + int m_ID; + int m_Index; + HtmlContentsItem *m_Items; + int m_ItemsCnt; + HtmlBookRecord *m_Book; + + public: + HP_TagHandler(HtmlBookRecord *b) : wxHtmlTagHandler() {m_Book = b; m_Items = NULL; m_ItemsCnt = 0; m_Name = m_Page = wxEmptyString; m_Level = 0;} + wxString GetSupportedTags() {return "UL,OBJECT,PARAM";} + bool HandleTag(const wxHtmlTag& tag); + void WriteOut(HtmlContentsItem*& array, int& size); + void ReadIn(HtmlContentsItem* array, int size); +}; + + +bool HP_TagHandler::HandleTag(const wxHtmlTag& tag) +{ + if (tag.GetName() == "UL") { + m_Level++; + ParseInner(tag); + m_Level--; + return TRUE; + } + + else if (tag.GetName() == "OBJECT") { + m_Name = m_Page = wxEmptyString; + ParseInner(tag); + if (m_Page != wxEmptyString) { + if (m_ItemsCnt % HTML_REALLOC_STEP == 0) + m_Items = (HtmlContentsItem*) realloc(m_Items, (m_ItemsCnt + HTML_REALLOC_STEP) * sizeof(HtmlContentsItem)); + m_Items[m_ItemsCnt].m_Level = m_Level; + m_Items[m_ItemsCnt].m_ID = m_ID; + m_Items[m_ItemsCnt].m_Page = (char*) malloc(m_Page.Length() + 1); + strcpy(m_Items[m_ItemsCnt].m_Page, m_Page.c_str()); + m_Items[m_ItemsCnt].m_Name = (char*) malloc(m_Name.Length() + 1); + strcpy(m_Items[m_ItemsCnt].m_Name, m_Name.c_str()); + m_Items[m_ItemsCnt].m_Book = m_Book; + m_ItemsCnt++; + } + return TRUE; + } + + else { // "PARAM" + if (m_Name == wxEmptyString && tag.GetParam("NAME") == "Name") m_Name = tag.GetParam("VALUE"); + if (tag.GetParam("NAME") == "Local") m_Page = tag.GetParam("VALUE"); + if (tag.GetParam("NAME") == "ID") tag.ScanParam("VALUE", "%i", &m_ID); + return FALSE; + } +} + + + +void HP_TagHandler::WriteOut(HtmlContentsItem*& array, int& size) +{ + array = m_Items; + size = m_ItemsCnt; + m_Items = NULL; + m_ItemsCnt = 0; +} + +void HP_TagHandler::ReadIn(HtmlContentsItem* array, int size) +{ + m_Items = array; + m_ItemsCnt = size; +} + + + + +void wxHtmlHelpController::LoadMSProject(HtmlBookRecord *book, wxFileSystem& fsys, const wxString& indexfile, const wxString& contentsfile, bool show_wait_msg) +{ + wxFSFile *f; + char *buf; + int sz; + wxString string; + wxBusyInfo *busyinfo = (show_wait_msg) ? new wxBusyInfo(_("Importing help file : \n") + book -> m_Title) : NULL; + + HP_Parser parser; + HP_TagHandler *handler = new HP_TagHandler(book); + parser.AddTagHandler(handler); + + f = fsys.OpenFile(contentsfile); + if (f) { + sz = f -> GetStream() -> StreamSize(); + buf = (char*) malloc(sz+1); + buf[sz] = 0; + f -> GetStream() -> Read(buf, sz); + delete f; + handler -> ReadIn(m_Contents, m_ContentsCnt); + parser.Parse(buf); + handler -> WriteOut(m_Contents, m_ContentsCnt); + free(buf); + } + + f = fsys.OpenFile(indexfile); + if (f) { + sz = f -> GetStream() -> StreamSize(); + buf = (char*) malloc(sz+1); + buf[sz] = 0; + f -> GetStream() -> Read(buf, sz); + delete f; + handler -> ReadIn(m_Index, m_IndexCnt); + parser.Parse(buf); + handler -> WriteOut(m_Index, m_IndexCnt); + free(buf); + } + if (show_wait_msg) delete busyinfo; +} + + + + + + +void wxHtmlHelpController::LoadCachedBook(HtmlBookRecord *book, wxInputStream *f) +{ + int i, st; + int x; + + /* load contents : */ + + f -> Read(&x, sizeof(x)); + st = m_ContentsCnt; + m_ContentsCnt += x; + m_Contents = (HtmlContentsItem*) realloc(m_Contents, (m_ContentsCnt / HTML_REALLOC_STEP + 1) * HTML_REALLOC_STEP * sizeof(HtmlContentsItem)); + for (i = st; i < m_ContentsCnt; i++) { + f -> Read(&x, sizeof(x)); + m_Contents[i].m_Level = x; + f -> Read(&x, sizeof(x)); + m_Contents[i].m_ID = x; + f -> Read(&x, sizeof(x)); + m_Contents[i].m_Name = (char*) malloc(x); + f -> Read(m_Contents[i].m_Name, x); + f -> Read(&x, sizeof(x)); + m_Contents[i].m_Page = (char*) malloc(x); + f -> Read(m_Contents[i].m_Page, x); + m_Contents[i].m_Book = book; + } + + /* load index : */ + + f -> Read(&x, sizeof(x)); + st = m_IndexCnt; + m_IndexCnt += x; + m_Index = (HtmlContentsItem*) realloc(m_Index, (m_IndexCnt / HTML_REALLOC_STEP + 1) * HTML_REALLOC_STEP * sizeof(HtmlContentsItem)); + for (i = st; i < m_IndexCnt; i++) { + f -> Read(&x, sizeof(x)); + m_Index[i].m_Name = (char*) malloc(x); + f -> Read(m_Index[i].m_Name, x); + f -> Read(&x, sizeof(x)); + m_Index[i].m_Page = (char*) malloc(x); + f -> Read(m_Index[i].m_Page, x); + m_Index[i].m_Book = book; + } +} + + + + + + +void wxHtmlHelpController::SaveCachedBook(HtmlBookRecord *book, wxOutputStream *f) +{ + int i; + int x; + + /* save contents : */ + + x = 0; + for (i = 0; i < m_ContentsCnt; i++) if (m_Contents[i].m_Book == book && m_Contents[i].m_Level > 0) x++; + f -> Write(&x, sizeof(x)); + for (i = 0; i < m_ContentsCnt; i++) { + if (m_Contents[i].m_Book != book || m_Contents[i].m_Level == 0) continue; + x = m_Contents[i].m_Level; + f -> Write(&x, sizeof(x)); + x = m_Contents[i].m_ID; + f -> Write(&x, sizeof(x)); + x = strlen(m_Contents[i].m_Name) + 1; + f -> Write(&x, sizeof(x)); + f -> Write(m_Contents[i].m_Name, x); + x = strlen(m_Contents[i].m_Page) + 1; + f -> Write(&x, sizeof(x)); + f -> Write(m_Contents[i].m_Page, x); + } + + /* save index : */ + + x = 0; + for (i = 0; i < m_IndexCnt; i++) if (m_Index[i].m_Book == book && m_Index[i].m_Level > 0) x++; + f -> Write(&x, sizeof(x)); + for (i = 0; i < m_IndexCnt; i++) { + if (m_Index[i].m_Book != book || m_Index[i].m_Level == 0) continue; + x = strlen(m_Index[i].m_Name) + 1; + f -> Write(&x, sizeof(x)); + f -> Write(m_Index[i].m_Name, x); + x = strlen(m_Index[i].m_Page) + 1; + f -> Write(&x, sizeof(x)); + f -> Write(m_Index[i].m_Page, x); + } +} + +#endif \ No newline at end of file diff --git a/src/html/htmlparser.cpp b/src/html/htmlparser.cpp new file mode 100644 index 0000000000..ff72c7d6cb --- /dev/null +++ b/src/html/htmlparser.cpp @@ -0,0 +1,169 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlparser.cpp +// Purpose: wxHtmlParser class (generic parser) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/tokenzr.h> +#include <wx/wfstream.h> +#include <wx/url.h> +#include <wx/html/htmldefs.h> +#include <wx/html/htmlparser.h> + + + +//----------------------------------------------------------------------------- +// wxHtmlParser +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxHtmlParser,wxObject) + + +wxObject* wxHtmlParser::Parse(const wxString& source) +{ + wxObject *result; + + InitParser(source); + DoParsing(); + result = GetProduct(); + DoneParser(); + return result; +} + + + +void wxHtmlParser::InitParser(const wxString& source) +{ + m_Source = source; + m_Cache = new wxHtmlTagsCache(m_Source); +} + + + +void wxHtmlParser::DoneParser() +{ + delete m_Cache; + m_Cache = NULL; +} + + + +#define HTML_MAX_BUFLEN 1024 + +void wxHtmlParser::DoParsing(int begin_pos, int end_pos) +{ + char temp[HTML_BUFLEN], c; + int i; + int templen; + + templen = 0; + i = begin_pos; + + while (i < end_pos) { + c = m_Source[i]; + + // continue building word: + if (c != '<') { + temp[templen++] = c; + if (templen == HTML_BUFLEN-1) { + temp[templen] = 0; + AddText(temp); + templen = 0; + } + i++; + } + + else if (c == '<') { + wxHtmlTag tag(m_Source, i, end_pos, m_Cache); + + if (templen) { + temp[templen] = 0; + AddText(temp); + templen = 0; + } + AddTag(tag); + if (tag.HasEnding()) i = tag.GetEndPos2(); + else i = tag.GetBeginPos(); + } + } + + if (templen) { // last word of block :-( + temp[templen] = 0; + AddText(temp); + } +} + + + +void wxHtmlParser::AddTag(const wxHtmlTag& tag) +{ + wxHtmlTagHandler *h; + bool inner = FALSE; + + h = (wxHtmlTagHandler*) m_HandlersHash.Get(tag.GetName()); + if (h) + inner = h -> HandleTag(tag); + if (!inner) { + if (tag.HasEnding()) + DoParsing(tag.GetBeginPos(), tag.GetEndPos1()); + } +} + + + +void wxHtmlParser::AddTagHandler(wxHtmlTagHandler *handler) +{ + wxString s(handler -> GetSupportedTags()); + wxStringTokenizer tokenizer(s, ", "); + +#if (wxVERSION_NUMBER < 2100) + while (tokenizer.HasMoreToken()) +#else + while (tokenizer.HasMoreTokens()) +#endif + m_HandlersHash.Put(tokenizer.NextToken(), handler); + + if (m_HandlersList.IndexOf(handler) == wxNOT_FOUND) + m_HandlersList.Append(handler); + + handler -> SetParser(this); +} + + + +wxHtmlParser::~wxHtmlParser() +{ + m_HandlersHash.Clear(); + m_HandlersList.DeleteContents(TRUE); + m_HandlersList.Clear(); +} + + + +//----------------------------------------------------------------------------- +// wxHtmlTagHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxHtmlTagHandler,wxObject) + +#endif \ No newline at end of file diff --git a/src/html/htmltag.cpp b/src/html/htmltag.cpp new file mode 100644 index 0000000000..16e780335f --- /dev/null +++ b/src/html/htmltag.cpp @@ -0,0 +1,248 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmltag.cpp +// Purpose: wxHtmlTag class (represents single tag) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/html/htmltag.h> +#include <stdarg.h> + + + + +//----------------------------------------------------------------------------- +// wxHtmlTagsCache +//----------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxHtmlTagsCache,wxObject) + +#define CACHE_INCREMENT 64 + +wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source) +{ + const char *src = source.c_str(); + int i, tg, pos, stpos; + int lng = source.Length(); + char dummy[256]; + + m_Cache = NULL; + m_CacheSize = 0; + m_CachePos = 0; + + pos = 0; + while (pos < lng) { + if (src[pos] == '<') { // tag found: + if (m_CacheSize % CACHE_INCREMENT == 0) + m_Cache = (sCacheItem*) realloc(m_Cache, (m_CacheSize + CACHE_INCREMENT) * sizeof(sCacheItem)); + tg = m_CacheSize++; + m_Cache[tg].Key = stpos = pos++; + dummy[0] = 0; i = 0; + while ((src[pos] != '>') && (src[pos] != ' ')) { + dummy[i] = src[pos++]; + if ((dummy[i] >= 'a') && (dummy[i] <= 'z')) dummy[i] -= ('a' - 'A'); + i++; + } + dummy[i] = 0; + m_Cache[tg].Name = (char*) malloc(i+1); + memcpy(m_Cache[tg].Name, dummy, i+1); + + while (src[pos] != '>') pos++; + + if (src[stpos+1] == '/') { // ending tag: + m_Cache[tg].End1 = m_Cache[tg].End2 = -2; + // find matching begin tag: + for (i = tg; i >= 0; i--) + if ((m_Cache[i].End1 == -1) && (strcmp(m_Cache[i].Name, dummy+1) == 0)) { + m_Cache[i].End1 = stpos; + m_Cache[i].End2 = pos + 1; + break; + } + } + else { + m_Cache[tg].End1 = m_Cache[tg].End2 = -1; + } + } + + pos++; + } + + // ok, we're done, now we'll free .Name members of cache - we don't need it anymore: + for (i = 0; i < m_CacheSize; i++) { + free(m_Cache[i].Name); + m_Cache[i].Name = NULL; + } +} + + + +void wxHtmlTagsCache::QueryTag(int at, int* end1, int* end2) +{ + if (m_Cache == NULL) return; + if (m_Cache[m_CachePos].Key != at) { + int delta = (at < m_Cache[m_CachePos].Key) ? -1 : 1; + do {m_CachePos += delta;} while (m_Cache[m_CachePos].Key != at); + } + *end1 = m_Cache[m_CachePos].End1; + *end2 = m_Cache[m_CachePos].End2; +} + + + + +//----------------------------------------------------------------------------- +// wxHtmlTag +//----------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxHtmlTag,wxObject) + +wxHtmlTag::wxHtmlTag(const wxString& source, int pos, int end_pos, wxHtmlTagsCache* cache) : wxObject() +{ + int i; + char c; + + // fill-in name, params and begin pos: + m_Name = m_Params = wxEmptyString; + i = pos+1; + if (source[i] == '/') {m_Ending = TRUE; i++;} + else m_Ending = FALSE; + + while ((i < end_pos) && ((c = source[i++]) != ' ') && (c != '>')) { + if ((c >= 'a') && (c <= 'z')) c -= ('a' - 'A'); + m_Name += c; + } + + if (source[i-1] != '>') + while ((i < end_pos) && ((c = source[i++]) != '>')) { + if ((c >= 'a') && (c <= 'z')) c -= ('a' - 'A'); + m_Params += c; + if (c == '"') { + while ((i < end_pos) && ((c = source[i++]) != '"')) m_Params += c; + m_Params += c; + } + } + m_Begin = i; + + cache -> QueryTag(pos, &m_End1, &m_End2); + if (m_End1 > end_pos) m_End1 = end_pos; + if (m_End2 > end_pos) m_End2 = end_pos; +} + + + +bool wxHtmlTag::HasParam(const wxString& par) const +{ + const char *st = m_Params, *p = par; + const char *st2, *p2; + + if (*st == 0) return FALSE; + if (*p == 0) return FALSE; + for (st2 = st, p2 = p; ; st2++) { + if (*p2 == 0) return TRUE; + if (*st2 == 0) return FALSE; + if (*p2 != *st2) p2 = p; + if (*p2 == *st2) p2++; + if (*st2 == ' ') p2 = p; + else if (*st2 == '=') { + p2 = p; + while (*st2 != ' ') { + if (*st2 == '"') { + st2++; + while (*st2 != '"') st2++; + } + st2++; + if (*st2 == 0) return FALSE; + } + } + } +} + + + +wxString wxHtmlTag::GetParam(const wxString& par, bool with_commas) const +{ + const char *st = m_Params, *p = par; + const char *st2, *p2; + bool comma; + + if (*st == 0) return ""; + if (*p == 0) return ""; + for (st2 = st, p2 = p; ; st2++) { + if (*p2 == 0) { // found + wxString fnd = ""; + st2++; // '=' character + comma = FALSE; + if (!with_commas && (*(st2) == '"')) {st2++; comma = TRUE;} + while (*st2 != 0) { + if (*st2 == '"') comma = !comma; + else if ((*st2 == ' ') && (!comma)) break; + fnd += (*(st2++)); + } + if (!with_commas && (*(st2-1) == '"')) fnd.RemoveLast(); + return fnd; + } + if (*st2 == 0) return ""; + if (*p2 != *st2) p2 = p; + if (*p2 == *st2) p2++; + if (*st2 == ' ') p2 = p; + else if (*st2 == '=') { + p2 = p; + while (*st2 != ' ') { + if (*st2 == '"') { + st2++; + while (*st2 != '"') st2++; + } + st2++; + } + } + } +} + + + +void wxHtmlTag::ScanParam(const wxString& par, char *format, ...) const +{ + va_list argptr; + wxString parval = GetParam(par); + + va_start(argptr, format); + +#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(__VISUALC__) + sscanf((const char*)parval, format, va_arg(argptr, void *)); +#else + vsscanf((const char*)parval, format, argptr); +#endif + +/* + --- vsscanf is not defined under Cygwin or Mingw32 or M$ Visual C++ environment + if this module doesn't compile with your compiler, + modify the def statement and let me know. Thanks... + + So far wxHtml functions are scanning only _one_ value + so I workarounded this by supposing that there is only + one ...-parameter +*/ + + va_end(argptr); +} + +#endif \ No newline at end of file diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp new file mode 100644 index 0000000000..b0077c8b1a --- /dev/null +++ b/src/html/htmlwin.cpp @@ -0,0 +1,542 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlwin.cpp +// Purpose: wxHtmlWindow class for parsing & displaying HTML (implementation) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/html/htmlwin.h> + +#include <wx/html/forcelink.h> + +///// This is my own wxBusyCursor. It works only with one window. + +#if (defined __WXGTK__) && (wxVERSION_NUMBER < 2100) +class wxLocalBusyCursor +#else +class wxLocalBusyCursor : public wxBusyCursor +#endif +{ + private: + wxWindow *m_Wnd; + public: +#if (defined __WXGTK__) && (wxVERSION_NUMBER < 2100) + wxLocalBusyCursor(wxWindow *w) {m_Wnd = w; m_Wnd -> SetCursor(*wxHOURGLASS_CURSOR);} + ~wxLocalBusyCursor() {m_Wnd -> SetCursor(*wxSTANDARD_CURSOR);} +#else + wxLocalBusyCursor(wxWindow *w) : wxBusyCursor() {} +#endif +}; + + + + +//----------------------------------------------------------------------------- +// wxHtmlWindow +//----------------------------------------------------------------------------- + + + +#include <wx/arrimpl.cpp> +WX_DEFINE_OBJARRAY(HtmlHistoryArray) + + +wxHtmlWindow::wxHtmlWindow(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + const wxString& name, bool scrollable) : wxScrolledWindow(parent, id, pos, size, wxVSCROLL, name) +{ + m_tmpMouseMoved = FALSE; + m_tmpCanDraw = TRUE; + m_FS = new wxFileSystem(); + m_RelatedStatusBar = -1; + m_RelatedFrame = NULL; + m_TitleFormat = "%s"; + m_OpenedPage = m_OpenedAnchor = wxEmptyString; + m_Cell = NULL; + m_Parser = new wxHtmlWinParser(this); + m_Parser -> SetFS(m_FS); + SetBorders(10); + m_HistoryPos = -1; + m_HistoryOn = TRUE; + m_Scrollable = scrollable; + SetPage("<html><body></body></html>"); +} + + + +wxHtmlWindow::~wxHtmlWindow() +{ + HistoryClear(); + + if (m_Cell) delete m_Cell; + + wxList *parser_data = m_Parser -> GetTempData(); + if (parser_data) delete parser_data; + + delete m_Parser; + delete m_FS; +} + + + +void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format) +{ + m_RelatedFrame = frame; + m_TitleFormat = format; +} + + + +void wxHtmlWindow::SetRelatedStatusBar(int bar) +{ + m_RelatedStatusBar = bar; +} + + + +void wxHtmlWindow::SetFonts(wxString normal_face, int normal_italic_mode, wxString fixed_face, int fixed_italic_mode, int *sizes) +{ + m_Parser -> SetFonts(normal_face, normal_italic_mode, fixed_face, fixed_italic_mode, sizes); + if (!m_OpenedPage.IsEmpty()) LoadPage(m_OpenedPage); +} + + + +bool wxHtmlWindow::SetPage(const wxString& source) +{ + wxClientDC *dc = new wxClientDC(this); + + dc -> SetMapMode(wxMM_TEXT); + SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF)); + m_OpenedPage = m_OpenedAnchor = wxEmptyString; + m_Parser -> SetDC(dc); + if (m_Cell) delete m_Cell; + m_Cell = (wxHtmlContainerCell*) m_Parser -> Parse(source); + delete dc; + m_Cell -> SetIndent(m_Borders, HTML_INDENT_ALL, HTML_UNITS_PIXELS); + m_Cell -> SetAlignHor(HTML_ALIGN_CENTER); + CreateLayout(); + Refresh(); + return TRUE; +} + + +bool wxHtmlWindow::LoadPage(const wxString& location) +{ + wxFSFile *f; + bool rt_val; + wxLocalBusyCursor b(this); + + m_tmpCanDraw = FALSE; + if (m_HistoryOn && (m_HistoryPos != -1)) { // store scroll position into history item + int x, y; + ViewStart(&x, &y); + m_History[m_HistoryPos].SetPos(y); + } + + if (location[0] == '#') { // local anchor + wxString anch = location.Mid(1) /*1 to end*/; + m_tmpCanDraw = TRUE; + rt_val = ScrollToAnchor(anch); + } + + else { + // load&display it: + if (m_RelatedStatusBar != -1) { + m_RelatedFrame -> SetStatusText(_("Connecting..."), m_RelatedStatusBar); + Refresh(); + } + + f = m_FS -> OpenFile(location); + if (f == NULL) { + wxString err; + + err.Printf(_("The browser is unable to open requested location :\n\n%s"), WXSTRINGCAST location); + wxMessageBox(err, "Error"); + m_tmpCanDraw = TRUE; + return FALSE; + } + + else { + wxNode *node; + wxString src = wxEmptyString; + + if (m_RelatedStatusBar != -1) { + wxString msg = _("Loading : ") + location; + m_RelatedFrame -> SetStatusText(msg, m_RelatedStatusBar); + Refresh(); + } + + node = m_Filters.GetFirst(); + while (node){ + wxHtmlFilter *h = (wxHtmlFilter*) node -> GetData(); + if (h -> CanRead(*f)) { + src = h -> ReadFile(*f); + break; + } + node = node -> GetNext(); + } + if (src == wxEmptyString) src = m_DefaultFilter.ReadFile(*f); + + m_FS -> ChangePathTo(f -> GetLocation()); + rt_val = SetPage(src); + m_OpenedPage = f -> GetLocation(); + if (f -> GetAnchor() != wxEmptyString) { + m_tmpCanDraw = TRUE; + ScrollToAnchor(f -> GetAnchor()); + m_tmpCanDraw = FALSE; + } + + delete f; + + if (m_RelatedStatusBar != -1) m_RelatedFrame -> SetStatusText(_("Done"), m_RelatedStatusBar); + } + } + + if (m_HistoryOn) { // add this page to history there: + int c = m_History.GetCount() - (m_HistoryPos + 1); + + m_HistoryPos++; + for (int i = 0; i < c; i++) + m_History.Remove(m_HistoryPos); + m_History.Add(new HtmlHistoryItem(m_OpenedPage, m_OpenedAnchor)); + } + + m_tmpCanDraw = TRUE; + Refresh(); + return rt_val; +} + + + +bool wxHtmlWindow::ScrollToAnchor(const wxString& anchor) +{ + const wxHtmlCell *c = m_Cell -> Find(HTML_COND_ISANCHOR, &anchor); + if (!c) return FALSE; + else { + int y; + + for (y = 0; c != NULL; c = c -> GetParent()) y += c -> GetPosY(); + Scroll(-1, y / HTML_SCROLL_STEP); + m_OpenedAnchor = anchor; + return TRUE; + } +} + + +void wxHtmlWindow::SetTitle(const wxString& title) +{ + if (m_RelatedFrame) { + wxString tit; + tit.Printf(m_TitleFormat, title.c_str()); + m_RelatedFrame -> SetTitle(tit); + } +} + + + + + +void wxHtmlWindow::CreateLayout() +{ + int ClientWidth, ClientHeight; + + if (!m_Cell) return; + GetClientSize(&ClientWidth, &ClientHeight); + m_Cell -> Layout(ClientWidth); + if (m_Scrollable) + SetScrollbars(HTML_SCROLL_STEP, HTML_SCROLL_STEP, + m_Cell -> GetWidth() / HTML_SCROLL_STEP, + m_Cell -> GetHeight() / HTML_SCROLL_STEP + /*cheat: top-level frag is always container*/ ); +} + + + +void wxHtmlWindow::ReadCustomization(wxConfigBase *cfg, wxString path) +{ + wxString oldpath; + wxString tmp; + + if (path != wxEmptyString) { + oldpath = cfg -> GetPath(); + cfg -> SetPath(path); + } + + m_Borders = cfg -> Read("wxHtmlWindow/Borders", m_Borders); + m_Parser -> m_FontFaceFixed = cfg -> Read("wxHtmlWindow/FontFaceFixed", m_Parser -> m_FontFaceFixed); + m_Parser -> m_FontFaceNormal = cfg -> Read("wxHtmlWindow/FontFaceNormal", m_Parser -> m_FontFaceNormal); + m_Parser -> m_ItalicModeFixed = cfg -> Read("wxHtmlWindow/ItalicModeFixed", m_Parser -> m_ItalicModeFixed); + m_Parser -> m_ItalicModeNormal = cfg -> Read("wxHtmlWindow/ItalicModeNormal", m_Parser -> m_ItalicModeNormal); + for (int i = 0; i < 7; i++) { + tmp.Printf("wxHtmlWindow/FontsSize%i", i); + m_Parser -> m_FontsSizes[i] = cfg -> Read(tmp, m_Parser -> m_FontsSizes[i]); + } + + if (path != wxEmptyString) + cfg -> SetPath(oldpath); +} + + + +void wxHtmlWindow::WriteCustomization(wxConfigBase *cfg, wxString path) +{ + wxString oldpath; + wxString tmp; + + if (path != wxEmptyString) { + oldpath = cfg -> GetPath(); + cfg -> SetPath(path); + } + + cfg -> Write("wxHtmlWindow/Borders", (long) m_Borders); + cfg -> Write("wxHtmlWindow/FontFaceFixed", m_Parser -> m_FontFaceFixed); + cfg -> Write("wxHtmlWindow/FontFaceNormal", m_Parser -> m_FontFaceNormal); + cfg -> Write("wxHtmlWindow/ItalicModeFixed", (long) m_Parser -> m_ItalicModeFixed); + cfg -> Write("wxHtmlWindow/ItalicModeNormal", (long) m_Parser -> m_ItalicModeNormal); + for (int i = 0; i < 7; i++) { + tmp.Printf("wxHtmlWindow/FontsSize%i", i); + cfg -> Write(tmp, (long) m_Parser -> m_FontsSizes[i]); + } + + if (path != wxEmptyString) + cfg -> SetPath(oldpath); +} + + + +bool wxHtmlWindow::HistoryBack() +{ + wxString a, l; + + if (m_HistoryPos < 1) return FALSE; + + m_HistoryPos--; + + l = m_History[m_HistoryPos].GetPage(); + a = m_History[m_HistoryPos].GetAnchor(); + m_HistoryOn = FALSE; + if (a == wxEmptyString) LoadPage(l); + else LoadPage(l + "#" + a); + m_HistoryOn = TRUE; + Scroll(0, m_History[m_HistoryPos].GetPos()); + Refresh(); + return TRUE; +} + + + +bool wxHtmlWindow::HistoryForward() +{ + wxString a, l; + + if (m_HistoryPos == -1) return FALSE; + if (m_HistoryPos >= (int)m_History.GetCount() - 1)return FALSE; + + m_OpenedPage = wxEmptyString; // this will disable adding new entry into history in LoadPage() + + m_HistoryPos++; + l = m_History[m_HistoryPos].GetPage(); + a = m_History[m_HistoryPos].GetAnchor(); + m_HistoryOn = FALSE; + if (a == wxEmptyString) LoadPage(l); + else LoadPage(l + "#" + a); + m_HistoryOn = TRUE; + Scroll(0, m_History[m_HistoryPos].GetPos()); + Refresh(); + return TRUE; +} + + + +void wxHtmlWindow::HistoryClear() +{ + m_History.Empty(); + m_HistoryPos = -1; +} + + + +wxList wxHtmlWindow::m_Filters; +wxHtmlFilterPlainText wxHtmlWindow::m_DefaultFilter; + +void wxHtmlWindow::AddFilter(wxHtmlFilter *filter) +{ + m_Filters.DeleteContents(TRUE); + m_Filters.Append(filter); +} + + + + +void wxHtmlWindow::OnLinkClicked(const wxString& link) +{ + LoadPage(link); +} + + + +void wxHtmlWindow::OnDraw(wxDC& dc) +{ + int x, y; + wxRegionIterator upd(GetUpdateRegion()); // get the update rect list + int v_y, v_h; + + if (!m_tmpCanDraw) return; + dc.SetMapMode(wxMM_TEXT); +#if defined(_MSC_VER) && (_MSC_VER == 1200) + ::SetMapMode((HDC)dc.GetHDC(), MM_TEXT); +#endif + dc.SetBackgroundMode(wxTRANSPARENT); + ViewStart(&x, &y); + + while (upd) { + v_y = upd.GetY(); + v_h = upd.GetH(); + if (m_Cell) m_Cell -> Draw(dc, 0, 0, y * HTML_SCROLL_STEP + v_y, y * HTML_SCROLL_STEP + v_h + v_y); + upd++; + } +} + + + + +void wxHtmlWindow::OnSize(wxSizeEvent& event) +{ + wxScrolledWindow::OnSize(event); + CreateLayout(); +} + + + +void wxHtmlWindow::OnKeyDown(wxKeyEvent& event) +{ + int dummy; + int sty, szy, cliy; + + ViewStart(&dummy, &sty); + GetClientSize(&dummy, &cliy); cliy /= HTML_SCROLL_STEP; + GetVirtualSize(&dummy, &szy); szy /= HTML_SCROLL_STEP; + + switch (event.KeyCode()) { + case WXK_PAGEUP : + case WXK_PRIOR : + Scroll(-1, sty - cliy); + break; + case WXK_PAGEDOWN : + case WXK_NEXT : + Scroll(-1, sty + cliy); + break; + case WXK_HOME : + Scroll(-1, 0); + break; + case WXK_END : + Scroll(-1, szy - cliy); + break; + case WXK_UP : + Scroll(-1, sty - 1); + break; + case WXK_DOWN : + Scroll(-1, sty + 1); + break; + } +} + + + +void wxHtmlWindow::OnMouseEvent(wxMouseEvent& event) +{ + m_tmpMouseMoved = TRUE; + + if (event.ButtonDown()) { + int sx, sy; + wxPoint pos; + wxString lnk; + + ViewStart(&sx, &sy); sx *= HTML_SCROLL_STEP; sy *= HTML_SCROLL_STEP; + pos = event.GetPosition(); + + if (m_Cell) + m_Cell -> OnMouseClick(this, sx + pos.x, sy + pos.y, event.ButtonDown(1), event.ButtonDown(2), event.ButtonDown(3)); + } +} + + + +void wxHtmlWindow::OnIdle(wxIdleEvent& event) +{ + static wxCursor cur_hand(wxCURSOR_HAND), cur_arrow(wxCURSOR_ARROW); + + if (m_tmpMouseMoved && (m_Cell != NULL)) { + int sx, sy; + int x, y; + wxString lnk; + + ViewStart(&sx, &sy); sx *= HTML_SCROLL_STEP; sy *= HTML_SCROLL_STEP; + wxGetMousePosition(&x, &y); + ScreenToClient(&x, &y); + lnk = m_Cell -> GetLink(sx + x, sy + y); + + if (lnk == wxEmptyString) { + SetCursor(cur_arrow); + if (m_RelatedStatusBar != -1) m_RelatedFrame -> SetStatusText(wxEmptyString, m_RelatedStatusBar); + } + else { + SetCursor(cur_hand); + if (m_RelatedStatusBar != -1) m_RelatedFrame -> SetStatusText(lnk, m_RelatedStatusBar); + } + m_tmpMouseMoved = FALSE; + } +} + + + + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindow,wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow) + EVT_SIZE(wxHtmlWindow::OnSize) + EVT_LEFT_DOWN(wxHtmlWindow::OnMouseEvent) + EVT_MOTION(wxHtmlWindow::OnMouseEvent) + EVT_IDLE(wxHtmlWindow::OnIdle) + EVT_KEY_DOWN(wxHtmlWindow::OnKeyDown) +END_EVENT_TABLE() + + + + + + + + +///// default mod handlers are forced there: + +FORCE_LINK(mod_layout) +FORCE_LINK(mod_fonts) +FORCE_LINK(mod_image) +FORCE_LINK(mod_list) +FORCE_LINK(mod_pre) +FORCE_LINK(mod_hline) +FORCE_LINK(mod_links) +FORCE_LINK(mod_tables) + + +#endif \ No newline at end of file diff --git a/src/html/htmlwinparser.cpp b/src/html/htmlwinparser.cpp new file mode 100644 index 0000000000..efc1d0d198 --- /dev/null +++ b/src/html/htmlwinparser.cpp @@ -0,0 +1,288 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: htmlwinparser.cpp +// Purpose: wxHtmlParser class (generic parser) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include "wx/defs.h" +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include <wx/html/htmldefs.h> +#include <wx/html/htmlwinparser.h> +#include <wx/html/htmlwin.h> + + +//----------------------------------------------------------------------------- +// wxHtmlWinParser +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinParser,wxHtmlParser) + +wxList wxHtmlWinParser::m_Modules; + +wxHtmlWinParser::wxHtmlWinParser(wxWindow *wnd) : wxHtmlParser() +{ + m_Window = wnd; + m_Container = NULL; + m_DC = NULL; + m_CharHeight = m_CharWidth = 0; + m_UseLink = FALSE; + + { + int i, j, k, l, m; + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + for (l = 0; l < 2; l++) + for (m = 0; m < 7; m++) + m_FontsTable[i][j][k][l][m] = NULL; +#ifdef __WXMSW__ + int default_sizes[7] = {7, 8, 10, 12, 16, 22, 30}; +#else + int default_sizes[7] = {10, 12, 14, 16, 19, 24, 32}; +#endif + SetFonts("", wxSLANT, "", wxSLANT, default_sizes); + } + + // fill in wxHtmlParser's tables: + wxNode *node = m_Modules.GetFirst(); + while (node){ + wxHtmlTagsModule *mod = (wxHtmlTagsModule*) node -> GetData(); + mod -> FillHandlersTable(this); + node = node -> GetNext(); + } +} + + + +void wxHtmlWinParser::AddModule(wxHtmlTagsModule *module) +{ + m_Modules.Append(module); +} + + + +void wxHtmlWinParser::SetFonts(wxString normal_face, int normal_italic_mode, wxString fixed_face, int fixed_italic_mode, int *sizes) +{ + for (int i = 0; i < 7; i++) m_FontsSizes[i] = sizes[i]; + m_FontFaceFixed = fixed_face; + m_FontFaceNormal = normal_face; + m_ItalicModeFixed = fixed_italic_mode; + m_ItalicModeNormal = normal_italic_mode; +} + + + +void wxHtmlWinParser::InitParser(const wxString& source) +{ + wxHtmlParser::InitParser(source); + wxASSERT_MSG(m_DC != NULL, _("no DC assigned to wxHtmlWinParser!!")); + + m_FontBold = m_FontItalic = m_FontUnderlined = m_FontFixed = FALSE; + m_FontSize = 0; + CreateCurrentFont(); // we're selecting default font into + m_DC -> GetTextExtent("H", &m_CharWidth, &m_CharHeight); + /* NOTE : we're not using GetCharWidth/Height() because + of differences under X and win + */ + + m_Link = ""; + m_LinkColor.Set(0, 0, 0xFF); + m_ActualColor.Set(0, 0, 0); + m_Align = HTML_ALIGN_LEFT; + m_tmpLastWasSpace = FALSE; + + OpenContainer(); + + OpenContainer(); + m_Container -> InsertCell(new wxHtmlColourCell(m_ActualColor)); + m_Container -> InsertCell(new wxHtmlFontCell(CreateCurrentFont())); +} + + + +void wxHtmlWinParser::DoneParser() +{ + m_Container = NULL; + wxHtmlParser::DoneParser(); +} + + + +wxObject* wxHtmlWinParser::GetProduct() +{ + wxHtmlContainerCell *top; + + CloseContainer(); + OpenContainer(); + GetContainer() -> SetIndent(m_CharHeight, HTML_INDENT_TOP); + top = m_Container; + while (top -> GetParent()) top = top -> GetParent(); + return top; +} + + + +wxList* wxHtmlWinParser::GetTempData() +{ + int i, j, k, l, m; + wxFont *f; + wxList *lst = wxHtmlParser::GetTempData(); + + if (lst == NULL) lst = new wxList; + lst -> DeleteContents(TRUE); + + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + for (l = 0; l < 2; l++) + for (m = 0; m < 7; m++) { + f = m_FontsTable[i][j][k][l][m]; + if (f) lst -> Append(f); + } + return lst; +} + + + +void wxHtmlWinParser::AddText(const char* txt) +{ + wxHtmlCell *c; + int i = 0, x, lng = strlen(txt); + char temp[HTML_BUFLEN]; + register char d; + int templen = 0; + + if (m_tmpLastWasSpace) { + while ((i < lng) && ((txt[i] == '\n') || (txt[i] == '\r') || (txt[i] == ' ') || (txt[i] == '\t'))) i++; + } + + while (i < lng) { + x = 0; + d = temp[templen++] = txt[i]; + if ((d == '\n') || (d == '\r') || (d == ' ') || (d == '\t')) { + i++, x++; + while ((i < lng) && ((txt[i] == '\n') || (txt[i] == '\r') || (txt[i] == ' ') || (txt[i] == '\t'))) i++, x++; + } + else i++; + + if (x) { + temp[templen-1] = ' '; + temp[templen] = 0; + templen = 0; + c = new wxHtmlWordCell(temp, *(GetDC())); + if (m_UseLink) c -> SetLink(m_Link); + m_Container -> InsertCell(c); + m_tmpLastWasSpace = TRUE; + } + } + if (templen) { + temp[templen] = 0; + c = new wxHtmlWordCell(temp, *(GetDC())); + if (m_UseLink) c -> SetLink(m_Link); + m_Container -> InsertCell(c); + m_tmpLastWasSpace = FALSE; + } +} + + + +wxHtmlContainerCell* wxHtmlWinParser::OpenContainer() +{ + m_Container = new wxHtmlContainerCell(m_Container); + m_Container -> SetAlignHor(m_Align); + m_tmpLastWasSpace = TRUE; + /* to avoid space being first character in paragraph */ + return m_Container; +} + + + +wxHtmlContainerCell* wxHtmlWinParser::SetContainer(wxHtmlContainerCell *c) +{ + m_tmpLastWasSpace = TRUE; + /* to avoid space being first character in paragraph */ + return m_Container = c; +} + + + +wxHtmlContainerCell* wxHtmlWinParser::CloseContainer() +{ + m_Container = m_Container -> GetParent(); + return m_Container; +} + + + +wxFont* wxHtmlWinParser::CreateCurrentFont() +{ + int fb = GetFontBold(), + fi = GetFontItalic(), + fu = GetFontUnderlined(), + ff = GetFontFixed(), + fs = GetFontSize() + 2 /*remap from <-2;4> to <0;7>*/ ; + + if (m_FontsTable[fb][fi][fu][ff][fs] == NULL) { + m_FontsTable[fb][fi][fu][ff][fs] = + //wxTheFontList -> FindOrCreateFont( + new wxFont( + m_FontsSizes[fs], + ff ? wxMODERN : wxSWISS, + fi ? (ff ? m_ItalicModeFixed : m_ItalicModeNormal) : wxNORMAL, + fb ? wxBOLD : wxNORMAL, + fu ? TRUE : FALSE, ff ? m_FontFaceFixed : m_FontFaceNormal); + } + m_DC -> SetFont(*(m_FontsTable[fb][fi][fu][ff][fs])); + return (m_FontsTable[fb][fi][fu][ff][fs]); +} + + + + +//----------------------------------------------------------------------------- +// wxHtmlWinTagHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler, wxHtmlTagHandler) + + + +//----------------------------------------------------------------------------- +// wxHtmlTagsModule +//----------------------------------------------------------------------------- + + +IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule, wxModule) + + +bool wxHtmlTagsModule::OnInit() +{ + wxHtmlWinParser::AddModule(this); + return TRUE; +} + + + +void wxHtmlTagsModule::OnExit() +{ +} + +#endif \ No newline at end of file diff --git a/src/html/mod_fonts.cpp b/src/html/mod_fonts.cpp new file mode 100644 index 0000000000..45c723c1fb --- /dev/null +++ b/src/html/mod_fonts.cpp @@ -0,0 +1,175 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_fonts.cpp +// Purpose: wxHtml module for fonts & colors of fonts +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +FORCE_LINK_ME(mod_fonts) + + +TAG_HANDLER_BEGIN(FONT, "FONT") + + TAG_HANDLER_PROC(tag) + { + unsigned long tmp; + wxColour oldclr = m_WParser -> GetActualColor(); + int oldsize = m_WParser -> GetFontSize(); + + if (tag.HasParam("COLOR")) { + wxColour clr; + tag.ScanParam("COLOR", "#%lX", &tmp); + clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); + m_WParser -> SetActualColor(clr); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(clr)); + } + + if (tag.HasParam("SIZE")) { + tag.ScanParam("SIZE", "%li", &tmp); + m_WParser -> SetFontSize(tmp); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + } + + ParseInner(tag); + + if (oldclr != m_WParser -> GetActualColor()) { + m_WParser -> SetActualColor(oldclr); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(oldclr)); + } + if (oldsize != m_WParser -> GetFontSize()) { + m_WParser -> SetFontSize(oldsize); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + } + return TRUE; + } + +TAG_HANDLER_END(FONT) + + +TAG_HANDLER_BEGIN(FACES, "U,I,B,TT") + + TAG_HANDLER_PROC(tag) + { + int fixed = m_WParser -> GetFontFixed(), + italic = m_WParser -> GetFontItalic(), + underlined = m_WParser -> GetFontUnderlined(), + bold = m_WParser -> GetFontBold(); + + if (tag.GetName() == "U") + m_WParser -> SetFontUnderlined(TRUE); + else if (tag.GetName() == "B") + m_WParser -> SetFontBold(TRUE); + else if (tag.GetName() == "I") + m_WParser -> SetFontItalic(TRUE); + else + m_WParser -> SetFontFixed(TRUE); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + + ParseInner(tag); + + m_WParser -> SetFontUnderlined(underlined); + m_WParser -> SetFontBold(bold); + m_WParser -> SetFontItalic(italic); + m_WParser -> SetFontFixed(fixed); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + return TRUE; + } + +TAG_HANDLER_END(FACES) + + + + + +TAG_HANDLER_BEGIN(Hx, "H1,H2,H3,H4,H5,H6") + + TAG_HANDLER_PROC(tag) + { + int old_size, old_b, old_i, old_u, old_f, old_al; + wxHtmlContainerCell *c; + + old_size = m_WParser -> GetFontSize(); + old_b = m_WParser -> GetFontBold(); + old_i = m_WParser -> GetFontItalic(); + old_u = m_WParser -> GetFontUnderlined(); + old_f = m_WParser -> GetFontFixed(); + old_al = m_WParser -> GetAlign(); + + m_WParser -> SetFontBold(TRUE); + m_WParser -> SetFontItalic(FALSE); + m_WParser -> SetFontUnderlined(FALSE); + m_WParser -> SetFontFixed(FALSE); + + if (tag.GetName() == "H1") + m_WParser -> SetFontSize(+4); + else if (tag.GetName() == "H2") + m_WParser -> SetFontSize(+3); + else if (tag.GetName() == "H3") + m_WParser -> SetFontSize(+2); + else if (tag.GetName() == "H4") { + m_WParser -> SetFontSize(+2); + m_WParser -> SetFontItalic(TRUE); + m_WParser -> SetFontBold(FALSE); + } + else if (tag.GetName() == "H5") + m_WParser -> SetFontSize(+1); + else if (tag.GetName() == "H6") { + m_WParser -> SetFontSize(+1); + m_WParser -> SetFontItalic(TRUE); + m_WParser -> SetFontBold(FALSE); + } + + c = m_WParser -> GetContainer(); + if (c -> GetFirstCell()) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + c = m_WParser -> GetContainer(); + } + c = m_WParser -> GetContainer(); + + c -> SetAlign(tag); + c -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_TOP); + m_WParser -> SetAlign(c -> GetAlignHor()); + + ParseInner(tag); + + m_WParser -> SetFontSize(old_size); + m_WParser -> SetFontBold(old_b); + m_WParser -> SetFontItalic(old_i); + m_WParser -> SetFontUnderlined(old_u); + m_WParser -> SetFontFixed(old_f); + m_WParser -> SetAlign(old_al); + + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + c = m_WParser -> GetContainer(); + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_TOP); + + return TRUE; + } + +TAG_HANDLER_END(Hx) + + + + +TAGS_MODULE_BEGIN(Fonts) + + TAGS_MODULE_ADD(FONT) + TAGS_MODULE_ADD(FACES) + TAGS_MODULE_ADD(Hx) + +TAGS_MODULE_END(Fonts) + + +#endif \ No newline at end of file diff --git a/src/html/mod_hline.cpp b/src/html/mod_hline.cpp new file mode 100644 index 0000000000..c79c3ad13e --- /dev/null +++ b/src/html/mod_hline.cpp @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_hline.cpp +// Purpose: wxHtml module for horizontal line (HR tag) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/html/htmlcell.h> + +FORCE_LINK_ME(mod_hline) + + +//----------------------------------------------------------------------------- +// wxHtmlLineCell +//----------------------------------------------------------------------------- + +class wxHtmlLineCell : public wxHtmlCell +{ + public: + wxHtmlLineCell(int size) : wxHtmlCell() {m_Height = size;} + void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); + void Layout(int w) {m_Width = w; if (m_Next) m_Next -> Layout(w);} +}; + + +void wxHtmlLineCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + wxBrush mybrush("BLACK", wxSOLID); + wxPen mypen("BLACK", 1, wxSOLID); + dc.SetBrush(mybrush); + dc.SetPen(mypen); + dc.DrawRectangle(x + m_PosX, y + m_PosY, m_Width, m_Height); + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + + +//----------------------------------------------------------------------------- +// The list handler: +//----------------------------------------------------------------------------- + + +TAG_HANDLER_BEGIN(HR, "HR") + + TAG_HANDLER_PROC(tag) + { + wxHtmlContainerCell *c; + int sz; + + m_WParser -> CloseContainer(); + c = m_WParser -> OpenContainer(); + + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_VERTICAL); + c -> SetAlignHor(HTML_ALIGN_CENTER); + c -> SetAlign(tag); + c -> SetWidthFloat(tag); + if (tag.HasParam("SIZE")) tag.ScanParam("SIZE", "%i", &sz); + else sz = 1; + c -> InsertCell(new wxHtmlLineCell(sz)); + + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + + return FALSE; + } + +TAG_HANDLER_END(HR) + + + + + +TAGS_MODULE_BEGIN(HLine) + + TAGS_MODULE_ADD(HR) + +TAGS_MODULE_END(HLine) + +#endif diff --git a/src/html/mod_image.cpp b/src/html/mod_image.cpp new file mode 100644 index 0000000000..908e4b6241 --- /dev/null +++ b/src/html/mod_image.cpp @@ -0,0 +1,147 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_image.cpp +// Purpose: wxHtml module for displaying images +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/wxhtml.h> +#include <wx/image.h> + +FORCE_LINK_ME(mod_image) + + +//-------------------------------------------------------------------------------- +// wxHtmlImageCell +// Image/bitmap +//-------------------------------------------------------------------------------- + +class wxHtmlImageCell : public wxHtmlCell +{ + public: + wxBitmap *m_Image; + + wxHtmlImageCell(wxFSFile *input, int w = -1, int h = -1, int align = HTML_ALIGN_BOTTOM); + ~wxHtmlImageCell() {if (m_Image) delete m_Image;} + void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); +}; + + + +//-------------------------------------------------------------------------------- +// wxHtmlImageCell +//-------------------------------------------------------------------------------- + +wxHtmlImageCell::wxHtmlImageCell(wxFSFile *input, int w, int h, int align) : wxHtmlCell() +{ + wxImage *img; + int ww, hh; + wxString m = input -> GetMimeType(); + wxInputStream *s = input -> GetStream(); + +#if wxVERSION_NUMBER < 2100 +/* NOTE : use this *old* code only if you have old 2.0.1 wxWindows distribution + and don't want to upgrade it with stuffs from add-on/wxwin201 */ + if (wxMimeTypesManager::IsOfType(m, "image/png")) img = new wxImage(*s, wxBITMAP_TYPE_PNG); + else if (wxMimeTypesManager::IsOfType(m, "image/jpeg")) img = new wxImage(*s, wxBITMAP_TYPE_JPEG); + else if (wxMimeTypesManager::IsOfType(m, "image/bmp")) img = new wxImage(*s, wxBITMAP_TYPE_BMP); + else if (wxMimeTypesManager::IsOfType(m, "image/gif")) img = new wxImage(*s, wxBITMAP_TYPE_GIF); + else if (wxMimeTypesManager::IsOfType(m, "image/tiff")) img = new wxImage(*s, wxBITMAP_TYPE_TIF); + else if (wxMimeTypesManager::IsOfType(m, "image/xpm")) img = new wxImage(*s, wxBITMAP_TYPE_XPM); + else if (wxMimeTypesManager::IsOfType(m, "image/xbm")) img = new wxImage(*s, wxBITMAP_TYPE_XBM); + else img = NULL; +#else + img = new wxImage(*s, m); +#endif + + m_Image = NULL; + if (img && (img -> Ok())) { + ww = img -> GetWidth(); + hh = img -> GetHeight(); + if (w != -1) m_Width = w; else m_Width = ww; + if (h != -1) m_Height = h; else m_Height = hh; + if ((m_Width != ww) || (m_Height != hh)) { + wxImage img2 = img -> Scale(m_Width, m_Height); + m_Image = new wxBitmap(img2.ConvertToBitmap()); + } + else + m_Image = new wxBitmap(img -> ConvertToBitmap()); + delete img; + } + switch (align) { + case HTML_ALIGN_TOP : + m_Descent = m_Height; break; + case HTML_ALIGN_CENTER : + m_Descent = m_Height / 2; break; + case HTML_ALIGN_BOTTOM : default : + m_Descent = 0; break; + } +} + + + +void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + if (m_Image) + dc.DrawBitmap(*m_Image, x + m_PosX, y + m_PosY, TRUE); + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + + + +//-------------------------------------------------------------------------------- +// tag handler +//-------------------------------------------------------------------------------- + +TAG_HANDLER_BEGIN(IMG, "IMG") + + TAG_HANDLER_PROC(tag) + { + if (tag.HasParam("SRC")) { + int w = -1, h = -1; + int al; + wxFSFile *str; + wxString tmp = tag.GetParam("SRC"); + + str = m_WParser -> GetFS() -> OpenFile(tmp); + if (tag.HasParam("WIDTH")) tag.ScanParam("WIDTH", "%i", &w); + if (tag.HasParam("HEIGHT")) tag.ScanParam("HEIGHT", "%i", &h); + al = HTML_ALIGN_BOTTOM; + if (tag.HasParam("ALIGN")) { + wxString alstr = tag.GetParam("ALIGN"); + alstr.MakeUpper(); // for the case alignment was in ".." + if (alstr == "TEXTTOP") al = HTML_ALIGN_TOP; + else if ((alstr == "CENTER") || (alstr == "ABSCENTER")) al = HTML_ALIGN_CENTER; + } + if (str) { + wxHtmlCell *cel = new wxHtmlImageCell(str, w, h, al); + cel -> SetLink(m_WParser -> GetLink()); + m_WParser -> GetContainer() -> InsertCell(cel); + delete str; + } + } + + return FALSE; + } + +TAG_HANDLER_END(IMAGE) + + + +TAGS_MODULE_BEGIN(Image) + + TAGS_MODULE_ADD(IMG) + +TAGS_MODULE_END(Image) + + +#endif \ No newline at end of file diff --git a/src/html/mod_layout.cpp b/src/html/mod_layout.cpp new file mode 100644 index 0000000000..42b1de108c --- /dev/null +++ b/src/html/mod_layout.cpp @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_layout.cpp +// Purpose: wxHtml module for basic paragraphs/layout handling +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/html/htmlwin.h> + +FORCE_LINK_ME(mod_layout) + + +TAG_HANDLER_BEGIN(P, "P") + + TAG_HANDLER_PROC(tag) + { + if (m_WParser -> GetContainer() -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + } + m_WParser -> GetContainer() -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_TOP); + m_WParser -> GetContainer() -> SetAlign(tag); + return FALSE; + } + +TAG_HANDLER_END(P) + + + +TAG_HANDLER_BEGIN(BR, "BR") + + TAG_HANDLER_PROC(tag) + { + int al = m_WParser -> GetContainer() -> GetAlignHor(); + wxHtmlContainerCell *c; + + m_WParser -> CloseContainer(); + c = m_WParser -> OpenContainer(); + c -> SetAlignHor(al); + c -> SetAlign(tag); + return FALSE; + } + +TAG_HANDLER_END(BR) + + + +TAG_HANDLER_BEGIN(CENTER, "CENTER") + + TAG_HANDLER_PROC(tag) + { + int old = m_WParser -> GetAlign(); + wxHtmlContainerCell *c = m_WParser -> GetContainer(); + + m_WParser -> SetAlign(HTML_ALIGN_CENTER); + if (c -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + } + else + c -> SetAlignHor(HTML_ALIGN_CENTER); + + if (tag.HasEnding()) { + ParseInner(tag); + + m_WParser -> SetAlign(old); + if (c -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + } + else + c -> SetAlignHor(old); + + return TRUE; + } + else return FALSE; + } + +TAG_HANDLER_END(CENTER) + + + +TAG_HANDLER_BEGIN(DIV, "DIV") + + TAG_HANDLER_PROC(tag) + { + int old = m_WParser -> GetAlign(); + wxHtmlContainerCell *c = m_WParser -> GetContainer(); + if (c -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + c = m_WParser -> GetContainer(); + c -> SetAlign(tag); + m_WParser -> SetAlign(c -> GetAlignHor()); + } + else { + c -> SetAlign(tag); + m_WParser -> SetAlign(c -> GetAlignHor()); + } + + ParseInner(tag); + + m_WParser -> SetAlign(old); + if (c -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + } + else + c -> SetAlignHor(old); + + return TRUE; + } + +TAG_HANDLER_END(DIV) + + + + +TAG_HANDLER_BEGIN(TITLE, "TITLE") + + TAG_HANDLER_PROC(tag) + { + if (m_WParser -> GetWindow()) { + wxHtmlWindow *wfr = (wxHtmlWindow*)(m_WParser -> GetWindow()); + if (wfr) { + wxString title = ""; + wxString *src = m_WParser -> GetSource(); + + for (int i = tag.GetBeginPos(); i < tag.GetEndPos1(); i++) title += (*src)[i]; + wfr -> SetTitle(title); + } + } + return TRUE; + } + +TAG_HANDLER_END(TITLE) + + + + +TAG_HANDLER_BEGIN(BODY, "BODY") + + TAG_HANDLER_PROC(tag) + { + unsigned long tmp; + wxColour clr; + + if (tag.HasParam("TEXT")) { + tag.ScanParam("TEXT", "#%lX", &tmp); + clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); + m_WParser -> SetActualColor(clr); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(clr)); + } + + if (tag.HasParam("LINK")) { + tag.ScanParam("LINK", "#%lX", &tmp); + clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); + m_WParser -> SetLinkColor(clr); + } + + if (tag.HasParam("BGCOLOR")) { + tag.ScanParam("BGCOLOR", "#%lX", &tmp); + clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(clr, HTML_CLR_BACKGROUND)); + if (m_WParser -> GetWindow() != NULL) + m_WParser -> GetWindow() -> SetBackgroundColour(clr); + } + return FALSE; + } + +TAG_HANDLER_END(BODY) + + + +TAG_HANDLER_BEGIN(BLOCKQUOTE, "BLOCKQUOTE") + + TAG_HANDLER_PROC(tag) + { + wxHtmlContainerCell *c; + + m_WParser -> CloseContainer(); + c = m_WParser -> OpenContainer(); + if (c -> GetAlignHor() == HTML_ALIGN_RIGHT) + c -> SetIndent(5 * m_WParser -> GetCharWidth(), HTML_INDENT_RIGHT); + else + c -> SetIndent(5 * m_WParser -> GetCharWidth(), HTML_INDENT_LEFT); + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_TOP); + m_WParser -> OpenContainer(); + ParseInner(tag); + c = m_WParser -> CloseContainer(); + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_BOTTOM); + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + return TRUE; + } + +TAG_HANDLER_END(BLOCKQUOTE) + + + + + + +TAGS_MODULE_BEGIN(Layout) + + TAGS_MODULE_ADD(P) + TAGS_MODULE_ADD(BR) + TAGS_MODULE_ADD(CENTER) + TAGS_MODULE_ADD(DIV) + TAGS_MODULE_ADD(TITLE) + TAGS_MODULE_ADD(BODY) + TAGS_MODULE_ADD(BLOCKQUOTE) + +TAGS_MODULE_END(Layout) + +#endif diff --git a/src/html/mod_links.cpp b/src/html/mod_links.cpp new file mode 100644 index 0000000000..9b92982866 --- /dev/null +++ b/src/html/mod_links.cpp @@ -0,0 +1,80 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_links.cpp +// Purpose: wxHtml module for links & anchors +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> +#include <wx/wxhtml.h> + +FORCE_LINK_ME(mod_links) + + +class wxHtmlAnchorCell : public wxHtmlCell +{ + private: + wxString m_AnchorName; + + public: + wxHtmlAnchorCell(const wxString& name) : wxHtmlCell() {m_AnchorName = name;} + virtual const wxHtmlCell* Find(int condition, const void* param) const + { + if ((condition == HTML_COND_ISANCHOR) && (m_AnchorName == (*((const wxString*)param)))) + return this; + else + return wxHtmlCell::Find(condition, param); + } +}; + + + +TAG_HANDLER_BEGIN(A, "A") + + TAG_HANDLER_PROC(tag) + { + if (tag.HasParam("NAME")) { + m_WParser -> GetContainer() -> InsertCell(new wxHtmlAnchorCell(tag.GetParam("NAME"))); + } + + if (tag.HasParam("HREF")) { + wxString oldlnk = m_WParser -> GetLink(); + wxColour oldclr = m_WParser -> GetActualColor(); + int oldund = m_WParser -> GetFontUnderlined(); + + m_WParser -> SetActualColor(m_WParser -> GetLinkColor()); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(m_WParser -> GetLinkColor())); + m_WParser -> SetFontUnderlined(TRUE); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + m_WParser -> SetLink(tag.GetParam("HREF")); + + ParseInner(tag); + + m_WParser -> SetLink(oldlnk); + m_WParser -> SetFontUnderlined(oldund); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + m_WParser -> SetActualColor(oldclr); + m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(oldclr)); + + return TRUE; + } + else return FALSE; + } + +TAG_HANDLER_END(A) + + + +TAGS_MODULE_BEGIN(Links) + + TAGS_MODULE_ADD(A) + +TAGS_MODULE_END(Links) + + +#endif diff --git a/src/html/mod_list.cpp b/src/html/mod_list.cpp new file mode 100644 index 0000000000..4222d6bc02 --- /dev/null +++ b/src/html/mod_list.cpp @@ -0,0 +1,142 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_list.cpp +// Purpose: wxHtml module for lists +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/html/htmlcell.h> + +FORCE_LINK_ME(mod_list) + + +//----------------------------------------------------------------------------- +// wxHtmlListmarkCell +//----------------------------------------------------------------------------- + +class wxHtmlListmarkCell : public wxHtmlCell +{ + private: + wxBrush m_Brush; + public: + wxHtmlListmarkCell(wxDC *dc, const wxColour& clr); + void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); +}; + +wxHtmlListmarkCell::wxHtmlListmarkCell(wxDC* dc, const wxColour& clr) : wxHtmlCell(), m_Brush(clr, wxSOLID) +{ + m_Width = dc -> GetCharWidth(); + m_Height = dc -> GetCharHeight(); + m_Descent = 0; +} + + + +void wxHtmlListmarkCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + dc.SetBrush(m_Brush); + dc.DrawEllipse(x + m_PosX + m_Width / 4, y + m_PosY + m_Height / 4, m_Width / 2, m_Width / 2); + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + + +//----------------------------------------------------------------------------- +// The list handler: +//----------------------------------------------------------------------------- + + +TAG_HANDLER_BEGIN(OLULLI, "OL,UL,LI") + + TAG_HANDLER_VARS + int m_Numbering; + // this is number of actual item of list or 0 for dots + + TAG_HANDLER_CONSTR(OLULLI) + { + m_Numbering = 0; + } + + TAG_HANDLER_PROC(tag) + { + wxHtmlContainerCell *c; + + // List Item: + if (tag.GetName() == "LI") { + if (!tag.IsEnding()) { + m_WParser -> CloseContainer(); + m_WParser -> CloseContainer(); + + c = m_WParser -> OpenContainer(); + c -> SetWidthFloat(2 * m_WParser -> GetCharWidth(), HTML_UNITS_PIXELS); + c -> SetAlignHor(HTML_ALIGN_RIGHT); + if (m_Numbering == 0) + c -> InsertCell(new wxHtmlListmarkCell(m_WParser -> GetDC(), m_WParser -> GetActualColor())); + else { + wxString mark; + mark.Printf("%i.", m_Numbering); + c -> InsertCell(new wxHtmlWordCell(mark, *(m_WParser -> GetDC()))); + } + m_WParser -> CloseContainer(); + + c = m_WParser -> OpenContainer(); + c -> SetIndent(m_WParser -> GetCharWidth() / 4, HTML_INDENT_LEFT); + c -> SetWidthFloat(-2 * m_WParser -> GetCharWidth(), HTML_UNITS_PIXELS); + + m_WParser -> OpenContainer(); + + if (m_Numbering != 0) m_Numbering++; + } + return FALSE; + } + + // Begin of List (not-numbered): "UL", "OL" + else { + int oldnum = m_Numbering; + + if (tag.GetName() == "UL") m_Numbering = 0; + else m_Numbering = 1; + + c = m_WParser -> GetContainer(); + if (c -> GetFirstCell() != NULL) { + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + c = m_WParser -> GetContainer(); + } + c -> SetAlignHor(HTML_ALIGN_LEFT); + c -> SetIndent(2 * m_WParser -> GetCharWidth(), HTML_INDENT_LEFT); + m_WParser -> OpenContainer() -> SetAlignVer(HTML_ALIGN_TOP); + + m_WParser -> OpenContainer(); + m_WParser -> OpenContainer(); + ParseInner(tag); + m_WParser -> CloseContainer(); + + m_WParser -> CloseContainer(); + m_WParser -> CloseContainer(); + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + + m_Numbering = oldnum; + return TRUE; + } + } + +TAG_HANDLER_END(OLULLI) + + +TAGS_MODULE_BEGIN(List) + + TAGS_MODULE_ADD(OLULLI) + +TAGS_MODULE_END(List) + +#endif diff --git a/src/html/mod_pre.cpp b/src/html/mod_pre.cpp new file mode 100644 index 0000000000..e2fa697bda --- /dev/null +++ b/src/html/mod_pre.cpp @@ -0,0 +1,157 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_pre.cpp +// Purpose: wxHtml module for <PRE> ... </PRE> tag (code citation) +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/html/htmlcell.h> +#include <wx/tokenzr.h> + +FORCE_LINK_ME(mod_pre) + + +//----------------------------------------------------------------------------- +// wxHtmlCodeCell +//----------------------------------------------------------------------------- + +class wxHtmlPRECell : public wxHtmlCell +{ + private: + wxString** m_Text; + // list of wxString objects. + int m_LinesCnt; + // number of lines + int m_LineHeight; + // height of single line of text + + public: + wxHtmlPRECell(const wxString& s, wxDC& dc); + ~wxHtmlPRECell(); + void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); +}; + + +wxHtmlPRECell::wxHtmlPRECell(const wxString& s, wxDC& dc) : wxHtmlCell() +{ + wxStringTokenizer tokenizer(s, "\n"); + wxString tmp; + long int x, z; + int i; + + m_LineHeight = dc.GetCharHeight(); + m_LinesCnt = 0; + m_Text = NULL; + m_Width = m_Height = 0; + + i = 0; +#if (wxVERSION_NUMBER < 2100) + while (tokenizer.HasMoreToken()) { +#else + while (tokenizer.HasMoreTokens()) { +#endif + if (i % 10 == 0) m_Text = (wxString**) realloc(m_Text, sizeof(wxString*) * (i + 10)); + tmp = tokenizer.NextToken(); + tmp.Replace(" ", " ", TRUE); + tmp.Replace(""", "\"", TRUE); + tmp.Replace("<", "<", TRUE); + tmp.Replace(">", ">", TRUE); + tmp.Replace("&", "&", TRUE); + tmp.Replace("\t", " ", TRUE); + tmp.Replace("\r", "", TRUE); + m_Text[i++] = new wxString(tmp); + + dc.GetTextExtent(tmp, &x, &z, &z); + if (x > m_Width) m_Width = x; + m_Height += m_LineHeight; + m_LinesCnt++; + } +} + + + +wxHtmlPRECell::~wxHtmlPRECell() +{ + for (int i = 0; i < m_LinesCnt; i++) delete m_Text[i]; + free(m_Text); +} + + +void wxHtmlPRECell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) +{ + for (int i = 0; i < m_LinesCnt; i++) + dc.DrawText(*(m_Text[i]), x + m_PosX, y + m_PosY + m_LineHeight * i); + + wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); +} + + + + +//----------------------------------------------------------------------------- +// The list handler: +//----------------------------------------------------------------------------- + + +TAG_HANDLER_BEGIN(PRE, "PRE") + + TAG_HANDLER_PROC(tag) + { + wxHtmlContainerCell *c; + + int fixed = m_WParser -> GetFontFixed(), + italic = m_WParser -> GetFontItalic(), + underlined = m_WParser -> GetFontUnderlined(), + bold = m_WParser -> GetFontBold(), + fsize = m_WParser -> GetFontSize(); + + m_WParser -> CloseContainer(); + c = m_WParser -> OpenContainer(); + c -> SetAlignHor(HTML_ALIGN_LEFT); + c -> SetIndent(m_WParser -> GetCharHeight(), HTML_INDENT_VERTICAL); + + m_WParser -> SetFontUnderlined(FALSE); + m_WParser -> SetFontBold(FALSE); + m_WParser -> SetFontItalic(FALSE); + m_WParser -> SetFontFixed(TRUE); + m_WParser -> SetFontSize(0); + c -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + + { + wxString cit; + cit = m_WParser -> GetSource() -> Mid(tag.GetBeginPos(), tag.GetEndPos1() - tag.GetBeginPos()); + c -> InsertCell(new wxHtmlPRECell(cit, *(m_WParser -> GetDC()))); + } + + m_WParser -> SetFontUnderlined(underlined); + m_WParser -> SetFontBold(bold); + m_WParser -> SetFontItalic(italic); + m_WParser -> SetFontFixed(fixed); + m_WParser -> SetFontSize(fsize); + c -> InsertCell(new wxHtmlFontCell(m_WParser -> CreateCurrentFont())); + + m_WParser -> CloseContainer(); + m_WParser -> OpenContainer(); + return TRUE; + } + +TAG_HANDLER_END(PRE) + + + + + +TAGS_MODULE_BEGIN(Pre) + + TAGS_MODULE_ADD(PRE) + +TAGS_MODULE_END(Pre) + +#endif diff --git a/src/html/mod_tables.cpp b/src/html/mod_tables.cpp new file mode 100644 index 0000000000..7f9e31c08e --- /dev/null +++ b/src/html/mod_tables.cpp @@ -0,0 +1,480 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mod_tables.cpp +// Purpose: wxHtml module for tables +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" +#if wxUSE_HTML + +/* +REMARKS: + 1. This version of mod_tables doesn't support auto-layout algorithm. + This means that all columns are of same width unless explicitly specified. +*/ + + +#include <wx/html/forcelink.h> +#include <wx/html/mod_templ.h> + +#include <wx/html/htmlcell.h> + +FORCE_LINK_ME(mod_tables) + + +#define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5) +#define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62) + + +//----------------------------------------------------------------------------- +// wxHtmlTableCell +//----------------------------------------------------------------------------- + + +typedef struct { + int width, units; // universal + int leftpos, pixwidth, maxrealwidth; // temporary (depends on width of table) + } colStruct; + +typedef enum { + cellSpan, + cellUsed, + cellFree + } cellState; + +typedef struct { + wxHtmlContainerCell *cont; + int colspan, rowspan; + int minheight, valign; + cellState flag; + } cellStruct; + + +class wxHtmlTableCell : public wxHtmlContainerCell +{ + protected: + /* These are real attributes: */ + bool m_HasBorders; + // should we draw borders or not? + int m_NumCols, m_NumRows; + // number of columns; rows + colStruct *m_ColsInfo; + // array of column information + cellStruct **m_CellInfo; + // 2D array of all cells in the table : m_CellInfo[row][column] + int m_Spacing; + // spaces between cells + int m_Padding; + // cells internal indentation + + private: + /* ...and these are valid only during parsing of table: */ + int m_ActualCol, m_ActualRow; + // number of actual column (ranging from 0..m_NumCols) + + // default values (for table and row): + int m_tBkg, m_rBkg; + wxString m_tValign, m_rValign; + + + public: + wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag); + ~wxHtmlTableCell(); + virtual void Layout(int w); + + void AddRow(const wxHtmlTag& tag); + void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag); + private: + void ReallocCols(int cols); + void ReallocRows(int rows); + // reallocates memory to given number of cols/rows + // and changes m_NumCols/m_NumRows value to reflect this change + // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!! +}; + + + +wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag) + : wxHtmlContainerCell(parent) +{ + m_HasBorders = tag.HasParam("BORDER"); + m_ColsInfo = NULL; + m_NumCols = m_NumRows = 0; + m_CellInfo = NULL; + m_ActualCol = m_ActualRow = -1; + + /* scan params: */ + m_tBkg = m_rBkg = -1; + if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &m_tBkg); + if (tag.HasParam("VALIGN")) m_tValign = tag.GetParam("VALIGN"); else m_tValign = wxEmptyString; + if (tag.HasParam("CELLSPACING")) tag.ScanParam("CELLSPACING", "%i", &m_Spacing); else m_Spacing = 2; + if (tag.HasParam("CELLPADDING")) tag.ScanParam("CELLPADDING", "%i", &m_Padding); else m_Padding = 3; + + if (m_HasBorders) + SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2); +} + + + +wxHtmlTableCell::~wxHtmlTableCell() +{ + if (m_ColsInfo) free(m_ColsInfo); + if (m_CellInfo) { + for (int i = 0; i < m_NumRows; i++) + free(m_CellInfo[i]); + free(m_CellInfo); + } +} + + + +void wxHtmlTableCell::ReallocCols(int cols) +{ + int i,j; + + for (i = 0; i < m_NumRows; i++) { + m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols); + for (j = m_NumCols; j < cols; j++) + m_CellInfo[i][j].flag = cellFree; + } + + m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols); + for (j = m_NumCols; j < cols; j++) { + m_ColsInfo[j].width = 0; + m_ColsInfo[j].units = HTML_UNITS_PERCENT; + } + + m_NumCols = cols; +} + + + +void wxHtmlTableCell::ReallocRows(int rows) +{ + m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows); + if (m_NumCols != 0) { + int x = rows - 1; + m_CellInfo[x] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols); + for (int i = 0; i < m_NumCols; i++) + m_CellInfo[x][i].flag = cellFree; + } + else + m_CellInfo[rows - 1] = NULL; + m_NumRows = rows; +} + + + +void wxHtmlTableCell::AddRow(const wxHtmlTag& tag) +{ + if (m_ActualRow + 1 > m_NumRows - 1) + ReallocRows(m_ActualRow + 2); + m_ActualRow++; + m_ActualCol = -1; + + /* scan params: */ + m_rBkg = m_tBkg; + if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &m_rBkg); + if (tag.HasParam("VALIGN")) m_rValign = tag.GetParam("VALIGN"); else m_rValign = m_tValign; +} + + + +void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag) +{ + do { + m_ActualCol++; + } while ((m_ActualCol < m_NumCols) && (m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree)); + if (m_ActualCol > m_NumCols - 1) + ReallocCols(m_ActualCol + 1); + + int r = m_ActualRow, c = m_ActualCol; + + m_CellInfo[r][c].cont = cell; + m_CellInfo[r][c].colspan = 1; + m_CellInfo[r][c].rowspan = 1; + m_CellInfo[r][c].flag = cellUsed; + m_CellInfo[r][c].minheight = 0; + m_CellInfo[r][c].valign = HTML_ALIGN_TOP; + + /* scan for parameters: */ + + // width: + { + if (tag.HasParam("WIDTH")) { + wxString wd = tag.GetParam("WIDTH"); + + if (wd[wd.Length()-1] == '%') { + sscanf(wd.c_str(), "%i%%", &m_ColsInfo[c].width); + m_ColsInfo[c].units = HTML_UNITS_PERCENT; + } + else { + sscanf(wd.c_str(), "%i", &m_ColsInfo[c].width); + m_ColsInfo[c].units = HTML_UNITS_PIXELS; + } + } + } + + + // spanning: + { + if (tag.HasParam("COLSPAN")) tag.ScanParam("COLSPAN", "%i", &m_CellInfo[r][c].colspan); + if (tag.HasParam("ROWSPAN")) tag.ScanParam("ROWSPAN", "%i", &m_CellInfo[r][c].rowspan); + if ((m_CellInfo[r][c].colspan != 1) || (m_CellInfo[r][c].rowspan != 1)) { + int i, j; + + if (r + m_CellInfo[r][c].rowspan > m_NumRows) ReallocRows(r + m_CellInfo[r][c].rowspan); + if (c + m_CellInfo[r][c].colspan > m_NumCols) ReallocCols(c + m_CellInfo[r][c].colspan); + for (i = r; i < r + m_CellInfo[r][c].rowspan; i++) + for (j = c; j < c + m_CellInfo[r][c].colspan; j++) + m_CellInfo[i][j].flag = cellSpan; + m_CellInfo[r][c].flag = cellUsed; + } + } + + //background color: + { + int bk = m_rBkg; + if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &bk); + if (bk != -1) { + wxColour clr = wxColour((bk & 0xFF0000) >> 16 , (bk & 0x00FF00) >> 8, (bk & 0x0000FF)); + cell -> SetBackgroundColour(clr); + } + } + if (m_HasBorders) + cell -> SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1); + + // vertical alignment: + { + wxString valign; + if (tag.HasParam("VALIGN")) valign = tag.GetParam("VALIGN"); else valign = m_tValign; + valign.MakeUpper(); + if (valign == "TOP") m_CellInfo[r][c].valign = HTML_ALIGN_TOP; + else if (valign == "BOTTOM") m_CellInfo[r][c].valign = HTML_ALIGN_BOTTOM; + else m_CellInfo[r][c].valign = HTML_ALIGN_CENTER; + } + + cell -> SetIndent(m_Padding, HTML_INDENT_ALL, HTML_UNITS_PIXELS); +} + + + + + +void wxHtmlTableCell::Layout(int w) +{ + /* + + WIDTH ADJUSTING : + + */ + + if (m_WidthFloatUnits == HTML_UNITS_PERCENT) { + if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100; + else m_Width = m_WidthFloat * w / 100; + } + else { + if (m_WidthFloat < 0) m_Width = w + m_WidthFloat; + else m_Width = m_WidthFloat; + } + + + /* + + LAYOUTING : + + */ + + /* 1. setup columns widths: */ + { + int wpix = m_Width - (m_NumCols + 1) * m_Spacing; + int i, j; + int wtemp = 0; + + // 1a. setup fixed-width columns: + for (i = 0; i < m_NumCols; i++) + if (m_ColsInfo[i].units == HTML_UNITS_PIXELS) + wpix -= (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width); + + // 1b. setup floating-width columns: + for (i = 0; i < m_NumCols; i++) + if ((m_ColsInfo[i].units == HTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0)) + wtemp += (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width * wpix / 100); + wpix -= wtemp; + + // 1c. setup defalut columns (no width specification supplied): + // NOTE! This algorithm doesn't conform to HTML standard : it assigns equal widths + // instead of optimal + for (i = j = 0; i < m_NumCols; i++) + if (m_ColsInfo[i].width == 0) j++; + for (i = 0; i < m_NumCols; i++) + if (m_ColsInfo[i].width == 0) + m_ColsInfo[i].pixwidth = wpix / j; + } + + /* 2. compute positions of columns: */ + { + int wpos = m_Spacing; + for (int i = 0; i < m_NumCols; i++) { + m_ColsInfo[i].leftpos = wpos; + wpos += m_ColsInfo[i].pixwidth + m_Spacing; + } + } + + /* 3. sub-layout all cells: */ + { + int *ypos = (int*) malloc(sizeof(int) * (m_NumRows + 1)); + + int actcol, actrow; + int fullwid; + wxHtmlContainerCell *actcell; + + for (actrow = 0; actrow <= m_NumRows; actrow++) ypos[actrow] = m_Spacing; + + for (actrow = 0; actrow < m_NumRows; actrow++) { + + // 3a. sub-layout and detect max height: + + for (actcol = 0; actcol < m_NumCols; actcol++) { + if (m_CellInfo[actrow][actcol].flag != cellUsed) continue; + actcell = m_CellInfo[actrow][actcol].cont; + fullwid = 0; + for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++) + fullwid += m_ColsInfo[i].pixwidth; + actcell -> SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign); + actcell -> Layout(fullwid); + + if (ypos[actrow] + actcell -> GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan]) + ypos[actrow + m_CellInfo[actrow][actcol].rowspan] = + ypos[actrow] + actcell -> GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing; + } + } + + + for (actrow = 0; actrow < m_NumRows; actrow++) { + + // 3b. place cells in row & let'em all have same height: + + for (actcol = 0; actcol < m_NumCols; actcol++) { + if (m_CellInfo[actrow][actcol].flag != cellUsed) continue; + actcell = m_CellInfo[actrow][actcol].cont; + actcell -> SetMinHeight( + ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_CellInfo[actrow][actcol].rowspan * m_Spacing, + m_CellInfo[actrow][actcol].valign); + fullwid = 0; + for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++) + fullwid += m_ColsInfo[i].pixwidth; + actcell -> Layout(fullwid); + actcell -> SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]); + } + + } + m_Height = ypos[m_NumRows]; + free(ypos); + } +} + + + + + + +//----------------------------------------------------------------------------- +// The tables handler: +//----------------------------------------------------------------------------- + + +TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH") + + TAG_HANDLER_VARS + wxHtmlTableCell* m_Table; + wxString m_tAlign, m_rAlign; + int m_OldAlign; + + TAG_HANDLER_CONSTR(TABLE) + { + m_Table = NULL; + m_tAlign = m_rAlign = wxEmptyString; + m_OldAlign = HTML_ALIGN_LEFT; + } + + + TAG_HANDLER_PROC(tag) + { + wxHtmlContainerCell *c; + + // new table started, backup upper-level table (if any) and create new: + if (tag.GetName() == "TABLE") { + wxHtmlTableCell *oldt = m_Table; + wxHtmlContainerCell *oldcont; + int m_OldAlign; + + oldcont = c = m_WParser -> OpenContainer(); + + c -> SetWidthFloat(tag); + m_Table = new wxHtmlTableCell(c, tag); + m_OldAlign = m_WParser -> GetAlign(); + m_tAlign = wxEmptyString; + if (tag.HasParam("ALIGN")) m_tAlign = tag.GetParam("ALIGN"); + + ParseInner(tag); + + m_WParser -> SetAlign(m_OldAlign); + m_WParser -> SetContainer(oldcont); + m_WParser -> CloseContainer(); + m_Table = oldt; + return TRUE; + } + + + else if (m_Table && !tag.IsEnding()) { + // new row in table + if (tag.GetName() == "TR") { + m_Table -> AddRow(tag); + m_rAlign = m_tAlign; + if (tag.HasParam("ALIGN")) m_rAlign = tag.GetParam("ALIGN"); + } + + // new cell + else { + m_WParser -> SetAlign(m_OldAlign); + c = m_WParser -> SetContainer(new wxHtmlContainerCell(m_Table)); + m_Table -> AddCell(c, tag); + + m_WParser -> OpenContainer(); + + if (tag.GetName() == "TH") /*header style*/ { + m_WParser -> SetAlign(HTML_ALIGN_CENTER); + } + + { + wxString als; + + als = m_rAlign; + if (tag.HasParam("ALIGN")) als = tag.GetParam("ALIGN"); + als.MakeUpper(); + if (als == "RIGHT") m_WParser -> SetAlign(HTML_ALIGN_RIGHT); + else if (als == "CENTER") m_WParser -> SetAlign(HTML_ALIGN_CENTER); + } + m_WParser -> OpenContainer(); + } + } + return FALSE; + } + +TAG_HANDLER_END(TABLE) + + + + + +TAGS_MODULE_BEGIN(Tables) + + TAGS_MODULE_ADD(TABLE) + +TAGS_MODULE_END(Tables) + + +#endif diff --git a/src/html/search.cpp b/src/html/search.cpp new file mode 100644 index 0000000000..aab3906fd5 --- /dev/null +++ b/src/html/search.cpp @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: search.cpp +// Purpose: search engine +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + + + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <wx/wxprec.h> + +#include <wx/defs.h> +#if wxUSE_HTML + +#ifdef __BORDLANDC__ +#pragma hdrstop +#endif + +#ifndef WXPRECOMP +#include <wx/wx.h> +#endif + +#include "search.h" + + + +//-------------------------------------------------------------------------------- +// wxSearchEngine +//-------------------------------------------------------------------------------- + +void wxSearchEngine::LookFor(const wxString& keyword) +{ + if (m_Keyword) free(m_Keyword); + m_Keyword = (char*) malloc(keyword.Length() + 1); + strcpy(m_Keyword, keyword.c_str()); + for (int i = strlen(m_Keyword) - 1; i >= 0; i--) + if ((m_Keyword[i] >= 'A') && (m_Keyword[i] <= 'Z')) + m_Keyword[i] += 'a' - 'A'; +} + + + +bool wxSearchEngine::Scan(wxInputStream *stream) +{ + wxASSERT_MSG(m_Keyword != NULL, _("wxSearchEngine::LookFor must be called before scanning!")); + + int i, j; + int lng = stream -> StreamSize(); + int wrd = strlen(m_Keyword); + bool found = FALSE; + char *buf = (char*) malloc(lng + 1); + stream -> Read(buf, lng); + buf[lng] = 0; + + for (i = 0; i < lng; i++) + if ((buf[i] >= 'A') && (buf[i] <= 'Z')) buf[i] += 'a' - 'A'; + + for (i = 0; i < lng - wrd; i++) { + j = 0; + while ((j < wrd) && (buf[i + j] == m_Keyword[j])) j++; + if (j == wrd) {found = TRUE; break;} + } + + free(buf); + return found; +} + +#endif diff --git a/src/html/search.h b/src/html/search.h new file mode 100644 index 0000000000..ff9db742e0 --- /dev/null +++ b/src/html/search.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: search.h +// Purpose: wxSearchEngine - class for searching keywords +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows Licence +///////////////////////////////////////////////////////////////////////////// + +#if wxUSE_HTML + +#ifndef __SEARCH_H__ +#define __SEARCH_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + + +#include <wx/stream.h> + +//-------------------------------------------------------------------------------- +// wxSearchEngine +// This class takes input streams and scans them for occurence +// of keyword(s) +//-------------------------------------------------------------------------------- + + +class wxSearchEngine : public wxObject +{ + private: + char *m_Keyword; + + public: + wxSearchEngine() : wxObject() {m_Keyword = NULL;} + ~wxSearchEngine() {if (m_Keyword) free(m_Keyword);} + + virtual void LookFor(const wxString& keyword); + // Sets the keyword we will be searching for + + virtual bool Scan(wxInputStream *stream); + // Scans the stream for the keyword. + // Returns TRUE if the stream contains keyword, fALSE otherwise +}; + + + + +#endif + +#endif \ No newline at end of file diff --git a/src/motif/Makefile.am b/src/motif/Makefile.am index 7a692f9537..5822878182 100644 --- a/src/motif/Makefile.am +++ b/src/motif/Makefile.am @@ -61,6 +61,9 @@ libwx_motif_la_SOURCES = \ event.cpp \ file.cpp \ fileconf.cpp \ + filesys.cpp \ + fs_inet.cpp \ + fs_zip.cpp \ framecmn.cpp \ ftp.cpp \ gdicmn.cpp \ @@ -105,8 +108,11 @@ libwx_motif_la_SOURCES = \ wfstream.cpp \ wincmn.cpp \ wxexpr.cpp \ + unzip.c \ + zipstream.cpp \ zstream.cpp \ \ + busyinfo.cpp \ caret.cpp \ choicdgg.cpp \ colrdlgg.cpp \ @@ -188,7 +194,25 @@ libwx_motif_la_SOURCES = \ timer.cpp \ toolbar.cpp \ utils.cpp \ - window.cpp + window.cpp \ +\ + htmlcell.cpp \ + htmlfilter.cpp \ + htmlhelp.cpp \ + htmlhelp_io.cpp \ + htmlparser.cpp \ + htmltag.cpp \ + htmlwin.cpp \ + htmlwinparser.cpp \ + mod_fonts.cpp \ + mod_hline.cpp \ + mod_image.cpp \ + mod_layout.cpp \ + mod_links.cpp \ + mod_list.cpp \ + mod_pre.cpp \ + mod_tables.cpp \ + search.cpp # propform.cpp \ # proplist.cpp \ -- 2.47.2