From cf7d6329530d0a9f181ac24dcc722d276885f05e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 30 May 2003 21:08:31 +0000 Subject: [PATCH] added wxVScrolledWindow git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20772 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/category.tex | 1 + docs/latex/wx/classes.tex | 1 + docs/latex/wx/scrolwin.tex | 3 +- docs/latex/wx/vscroll.tex | 194 ++++++++++++++++++++++ include/wx/vscroll.h | 167 +++++++++++++++++++ samples/vscroll/vscroll.dsp | 155 +++++++++++++++++ samples/vscroll/vstest.cpp | 286 ++++++++++++++++++++++++++++++++ src/generic/vscroll.cpp | 322 ++++++++++++++++++++++++++++++++++++ 8 files changed, 1128 insertions(+), 1 deletion(-) create mode 100644 docs/latex/wx/vscroll.tex create mode 100644 include/wx/vscroll.h create mode 100644 samples/vscroll/vscroll.dsp create mode 100644 samples/vscroll/vstest.cpp create mode 100644 src/generic/vscroll.cpp diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex index c04aeb916a..f41578b7c2 100644 --- a/docs/latex/wx/category.tex +++ b/docs/latex/wx/category.tex @@ -43,6 +43,7 @@ The following are a variety of classes that are derived from wxWindow. \twocolitem{\helpref{wxPlotWindow}{wxplotwindow}}{A class to display data.} \twocolitem{\helpref{wxSashWindow}{wxsashwindow}}{Window with four optional sashes that can be dragged} \twocolitem{\helpref{wxSashLayoutWindow}{wxsashlayoutwindow}}{Window that can be involved in an IDE-like layout arrangement} +\twocolitem{\helpref{wxVScrolledWindow}{wxvscrolledwindow}}{As wxScrolledWindow but supports lines of variable height} \twocolitem{\helpref{wxWizardPage}{wxwizardpage}}{A base class for the page in wizard dialog.} \twocolitem{\helpref{wxWizardPageSimple}{wxwizardpagesimple}}{A page in wizard dialog.} \end{twocollist} diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index ffacfd8ab7..4d374a4d41 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -308,6 +308,7 @@ \input validatr.tex \input variant.tex \input view.tex +\input vscroll.tex \input wave.tex \input window.tex \input windowdc.tex diff --git a/docs/latex/wx/scrolwin.tex b/docs/latex/wx/scrolwin.tex index 52ccf938eb..58a60fc533 100644 --- a/docs/latex/wx/scrolwin.tex +++ b/docs/latex/wx/scrolwin.tex @@ -97,7 +97,8 @@ to build your own scroll behaviour. \wxheading{See also} -\helpref{wxScrollBar}{wxscrollbar}, \helpref{wxClientDC}{wxclientdc}, \helpref{wxPaintDC}{wxpaintdc} +\helpref{wxScrollBar}{wxscrollbar}, \helpref{wxClientDC}{wxclientdc},\\ +\helpref{wxPaintDC}{wxpaintdc}, \helpref{wxVScrolledWindow}{wxvscrolledwindow} \latexignore{\rtfignore{\wxheading{Members}}} diff --git a/docs/latex/wx/vscroll.tex b/docs/latex/wx/vscroll.tex new file mode 100644 index 0000000000..3489ab5885 --- /dev/null +++ b/docs/latex/wx/vscroll.tex @@ -0,0 +1,194 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: vscroll.tex +%% Purpose: wxVScrolledWindow documentation +%% Author: Vadim Zeitlin +%% Modified by: +%% Created: 30.05.03 +%% RCS-ID: $Id$ +%% Copyright: (c) 2003 Vadim Zeitlin +%% License: wxWindows license +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxVScrolledWindow}}\label{wxvscrolledwindow} + +In the name of this class, "V" may stand for "variable" because it can be +used for scrolling lines of variable heights; "virtual" because it is not +necessary to know the heights of all lines in advance -- only those which +are shown on the screen need to be measured; or, even, "vertical" because +this class only supports scrolling in one direction currently (this could +and probably will change in the future however). + +In any case, this is a generalization of the +\helpref{wxScrolledWindow}{wxScrolledWindow} class which can be only used when +all lines have the same height. It lacks some other wxScrolledWindow features +however, notably there is currently no support for horizontal scrolling; it +can't scroll another window nor only a rectangle of the window and not its +entire client area. + +To use this class, you need to derive from it and implement +\helpref{OnGetLineHeight()}{wxvscrolledwindowongetlineheight} pure virtual +method. You also must call \helpref{SetLineCount}{wxvscrolledwindowsetlinecount} +to let the base class know how many lines it should display but from that +moment on the scrolling is handled entirely by wxVScrolledWindow, you only +need to draw the visible part of contents in your {\tt OnPaint()} method as +usual. You should use \helpref{GetFirstVisibleLine()}{wxvscrolledwindowgetfirstvisibleline} +and \helpref{GetLastVisibleLine()}{wxvscrolledwindowgetlastvisibleline} to +select the lines to display. ote that the device context origin is not shifted +so the first visible line always appears at the point $(0, 0)$ in physical as +well as logical coordinates. + +\wxheading{Derived from} + +\helpref{wxPanel}{wxpanel} + +\wxheading{Include files} + + + + +\latexignore{\rtfignore{\wxheading{Members}}} + + +\membersection{wxVScrolledWindow::wxVScrolledWindow}\label{wxvscrolledwindowctor} + +\func{}{wxVScrolledWindow}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = 0}, \param{const wxString\& }{name = wxPanelNameStr}} + +This is the normal constructor, no need to call Create() after using this one. + +Note that {\tt wxVSCROLL} is always automatically added to our style, there is +no need to specify it explicitly. + +\func{}{wxVScrolledWindow}{\void} + +Default constructor, you must call \helpref{Create()}{wxvscrolledwindowcreate} +later. + +\wxheading{Parameters} + +\docparam{parent}{The parent window, must not be {\tt NULL}} + +\docparam{id}{The identifier of this window, {\tt wxID\_ANY} by default} + +\docparam{pos}{The initial window position} + +\docparam{size}{The initial window size} + +\docparam{style}{The window style. There are no special style bits defined for +this class.} + +\docparam{name}{The name for this window; usually not used} + + +\membersection{wxVScrolledWindow::Create}\label{wxvscrolledwindowcreate} + +\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = 0}, \param{const wxString\& }{name = wxPanelNameStr}} + +Same as the \helpref{non default ctor}{wxvscrolledwindowctor} but returns +status code: {\tt true} if ok, {\tt false} if the window couldn't have been created. + +Just as with the ctor above, {\tt wxVSCROLL| style is always used, there is no +need to specify it explicitly. + + +\membersection{wxVScrolledWindow::GetFirstVisibleLine}\label{wxvscrolledwindowgetfirstvisibleline} + +\constfunc{size\_t}{GetFirstVisibleLine}{\void} + +Returns the index of the first currently visible line. + + +\membersection{wxVScrolledWindow::GetLastVisibleLine}\label{wxvscrolledwindowgetlastvisibleline} + +\constfunc{size\_t}{GetLastVisibleLine}{\void} + +Returns the index of the last currently visible line. + + +\membersection{wxVScrolledWindow::GetLineCount}\label{wxvscrolledwindowgetlinecount} + +\constfunc{size\_t}{GetLineCount}{\void} + +Get the number of lines this window contains (previously set by +\helpref{SetLineCount()}{wxvscrolledwindowsetlinecount}) + + +\membersection{wxVScrolledWindow::OnGetLineHeight}\label{wxvscrolledwindowongetlineheight} + +\constfunc{wxCoord}{OnGetLineHeight}{\param{size\_t }{n}} + +This protected virtual function must be overridden in the derived class and it +should return the height of the given line in pixels. + +\wxheading{See also} + +\helpref{OnGetLinesHint}{wxvscrolledwindowongetlineshint} + + +\membersection{wxVScrolledWindow::OnGetLinesHint}\label{wxvscrolledwindowongetlineshint} + +\constfunc{void}{OnGetLinesHint}{\param{size\_t }{lineMin}, \param{size\_t }{lineMax}} + +This function doesn't have to be overridden but it may be useful to do +it if calculating the lines heights is a relatively expensive operation +as it gives the user code a possibility to calculate several of them at +once. + +{\tt OnGetLinesHint()} is normally called just before +\helpref{OnGetLineHeight()}{wxvscrolledwindowongetlineheight} but you +shouldn't rely on the latter being called for all lines in the interval +specified here. It is also possible that OnGetLineHeight() will be +called for the lines outside of this interval, so this is really just a +hint, not a promise. + +Finally note that {\it lineMin} is inclusive, while {\it lineMax} is exclusive, +as usual. + + +\membersection{wxVScrolledWindow::ScrollLines}\label{wxvscrolledwindowscrolllines} + +\func{bool}{ScrollLines}{\param{int }{lines}} + +Scroll by the specified number of lines which may be positive (to scroll down) +or negative (to scroll up). + +Returns {\tt true} if the window was scrolled, {\tt false} otherwise (for +example if we're trying to scroll down but we are already showing the last +line). + +\wxheading{See also} + +\helpref{LineUp}{wxwindowlineup}, \helpref{LineDown}{wxwindowlinedown} + + +\membersection{wxVScrolledWindow::ScrollPages}\label{wxvscrolledwindowscrollpages} + +\func{bool}{ScrollPages}{\param{int }{pages}} + +Scroll by the specified number of pages which may be positive (to scroll down) +or negative (to scroll up). + +\wxheading{See also} + +\helpref{ScrollLines}{wxvscrolledwindowscrolllines},\\ +\helpref{PageUp}{wxwindowpageup}, \helpref{PageDown}{wxwindowpagedown} + + +\membersection{wxVScrolledWindow::ScrollToLine}\label{wxvscrolledwindowscrolltoline} + +\func{bool}{ScrollToLine}{\param{size\_t }{line}} + +Scroll to the specified line: it will become the first visible line in +the window. + +Return {\tt true} if we scrolled the window, {\tt false} if nothing was done. + + +\membersection{wxVScrolledWindow::SetLineCount}\label{wxvscrolledwindowsetlinecount} + +\func{void}{SetLineCount}{\param{size\_t }{count}} + +Set the number of lines the window contains: the derived class must +provide the heights for all lines with indices up to the one given here +in its \helpref{OnGetLineHeight()}{wxvscrolledwindowongetlineheight}. + + diff --git a/include/wx/vscroll.h b/include/wx/vscroll.h new file mode 100644 index 0000000000..9bf5cce2d9 --- /dev/null +++ b/include/wx/vscroll.h @@ -0,0 +1,167 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: include/wx/vscroll.h +// Purpose: wxVScrolledWindow: generalization of wxScrolledWindow +// Author: Vadim Zeitlin +// Modified by: +// Created: 30.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_VSCROLL_H_ +#define _WX_VSCROLL_H_ + +#include "wx/panel.h" // base class + +// ---------------------------------------------------------------------------- +// wxVScrolledWindow +// ---------------------------------------------------------------------------- + +/* + In the name of this class, "V" may stand for "variable" because it can be + used for scrolling lines of variable heights; "virtual" because it is not + necessary to know the heights of all lines in advance -- only those which + are shown on the screen need to be measured; or, even, "vertical" because + this class only supports scrolling in one direction currently (this could + and probably will change in the future however). + + In any case, this is a generalization of the wxScrolledWindow class which + can be only used when all lines have the same height. It lacks some other + wxScrolledWindow features however, notably it currently lacks support for + horizontal scrolling; it can't scroll another window nor only a rectangle + of the window and not its entire client area. + */ +class wxVScrolledWindow : public wxPanel +{ +public: + // constructors and such + // --------------------- + + // default ctor, you must call Create() later + wxVScrolledWindow() { Init(); } + + // normal ctor, no need to call Create() after this one + // + // note that wxVSCROLL is always automatically added to our style, there is + // no need to specify it explicitly + wxVScrolledWindow(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxPanelNameStr) + { + Init(); + + (void)Create(parent, id, pos, size, style, name); + } + + // same as the previous ctor but returns status code: true if ok + // + // just as with the ctor above, wxVSCROLL style is always used, there is no + // need to specify it + bool Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxPanelNameStr) + { + return wxPanel::Create(parent, id, pos, size, style | wxVSCROLL, name); + } + + + // operations + // ---------- + + // set the number of lines the window contains: the derived class must + // provide the heights for all lines with indices up to the one given here + // in its OnGetLineHeight() + void SetLineCount(size_t count); + + // scroll to the specified line: it will become the first visible line in + // the window + // + // return true if we scrolled the window, false if nothing was done + bool ScrollToLine(size_t line); + + // scroll by the specified number of lines/pages + virtual bool ScrollLines(int lines); + virtual bool ScrollPages(int pages); + + + // accessors + // --------- + + // get the number of lines this window contains (previously set by + // SetLineCount()) + size_t GetLineCount() const { return m_lineMax; } + + // get the first currently visible line + size_t GetFirstVisibleLine() const { return m_lineFirst; } + + // get the last currently visible line + size_t GetLastVisibleLine() const { return m_lineFirst + m_nVisible - 1; } + + +//protected: + // this function must be overridden in the derived class and it should + // return the height of the given line in pixels + virtual wxCoord OnGetLineHeight(size_t n) const = 0; + + // this function doesn't have to be overridden but it may be useful to do + // it if calculating the lines heights is a relatively expensive operation + // as it gives the user code a possibility to calculate several of them at + // once + // + // OnGetLinesHint() is normally called just before OnGetLineHeight() but you + // shouldn't rely on the latter being called for all lines in the interval + // specified here. It is also possible that OnGetLineHeight() will be + // called for the lines outside of this interval, so this is really just a + // hint, not a promise. + // + // finally note that lineMin is inclusive, while lineMax is exclusive, as + // usual + virtual void OnGetLinesHint(size_t lineMin, size_t lineMax) const { } + +protected: + // the event handlers + void OnSize(wxSizeEvent& event); + void OnScroll(wxScrollWinEvent& event); + + // find the index of the line we need to show at the top of the window such + // that the last line shown is the given one + size_t FindFirstFromBottom(size_t lineLast); + + // get the total height of the lines between lineMin (inclusive) and + // lineMax (exclusive) + wxCoord GetLinesHeight(size_t lineMin, size_t lineMax) const; + + // update the thumb size shown by the scrollbar + void UpdateScrollbar(); + +private: + // common part of all ctors + void Init(); + + + // the total number of (logical) lines + size_t m_lineMax; + + // the total (estimated) height + wxCoord m_heightTotal; + + // the first currently visible line + size_t m_lineFirst; + + // the number of currently visible lines (including the last, possibly only + // partly, visible one) + size_t m_nVisible; + + + DECLARE_EVENT_TABLE() +}; + +#endif // _WX_VSCROLL_H_ + diff --git a/samples/vscroll/vscroll.dsp b/samples/vscroll/vscroll.dsp new file mode 100644 index 0000000000..33a4fc318e --- /dev/null +++ b/samples/vscroll/vscroll.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="vscroll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=vscroll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "vscroll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "vscroll.mak" CFG="vscroll - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "vscroll - Win32 Release DLL" (based on "Win32 (x86) Application") +!MESSAGE "vscroll - Win32 Debug DLL" (based on "Win32 (x86) Application") +!MESSAGE "vscroll - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "vscroll - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "vscroll - Win32 Release DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseDll" +# PROP BASE Intermediate_Dir "ReleaseDll" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseDll" +# PROP Intermediate_Dir "ReleaseDll" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c +# ADD CPP /nologo /MD /W4 /O2 /I "../../include" /I "..\..\lib\mswdll" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "WXUSINGDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /i "../../include" /d "NDEBUG" +# ADD RSC /l 0x409 /i "../../include" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib ..\..\lib\wxmsw250.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "vscroll - Win32 Debug DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugDll" +# PROP BASE Intermediate_Dir "DebugDll" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugDll" +# PROP Intermediate_Dir "DebugDll" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c +# ADD CPP /nologo /MDd /W4 /Zi /Od /I "../../include" /I "..\..\lib\mswdlld" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "__WXDEBUG__" /D WXDEBUG=1 /D "WXUSINGDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /i "../../include" /d "_DEBUG" +# ADD RSC /l 0x409 /i "../../include" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib ..\..\lib\wxmsw250d.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "vscroll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c +# ADD CPP /nologo /MD /W4 /O2 /I "../../include" /I "..\..\lib\msw" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /i "../../include" /d "NDEBUG" +# ADD RSC /l 0x409 /i "../../include" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib ..\..\lib\zlib.lib ..\..\lib\regex.lib ..\..\lib\png.lib ..\..\lib\jpeg.lib ..\..\lib\tiff.lib ..\..\lib\wxmsw.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "vscroll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c +# ADD CPP /nologo /MDd /W4 /Zi /Od /I "../../include" /I "..\..\lib\mswd" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /D "__WXDEBUG__" /D WXDEBUG=1 /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD BASE RSC /l 0x409 /i "../../include" /d "_DEBUG" +# ADD RSC /l 0x409 /i "../../include" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib ..\..\lib\zlibd.lib ..\..\lib\regexd.lib ..\..\lib\pngd.lib ..\..\lib\jpegd.lib ..\..\lib\tiffd.lib ..\..\lib\wxmswd.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "vscroll - Win32 Release DLL" +# Name "vscroll - Win32 Debug DLL" +# Name "vscroll - Win32 Release" +# Name "vscroll - Win32 Debug" +# Begin Source File + +SOURCE=.\vscroll.cpp +# End Source File +# Begin Source File + +SOURCE=.\vstest.cpp +# End Source File +# End Target +# End Project diff --git a/samples/vscroll/vstest.cpp b/samples/vscroll/vstest.cpp new file mode 100644 index 0000000000..04255ef947 --- /dev/null +++ b/samples/vscroll/vstest.cpp @@ -0,0 +1,286 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: vscroll.cpp +// Purpose: VScroll wxWindows sample +// Author: Vadim Zeitlin +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// 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/app.h" + #include "wx/frame.h" +#endif + +// we need to include the headers not included from wx/wx.h explicitly anyhow +#include "wx/vscroll.h" + +// ---------------------------------------------------------------------------- +// resources +// ---------------------------------------------------------------------------- + +// the application icon (under Windows and OS/2 it is in resources) +#if !defined(__WXMSW__) && !defined(__WXOS2__) + #include "mondrian.xpm" +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp +class VScrollApp : public wxApp +{ +public: + // create our main window + virtual bool OnInit(); +}; + +// Define a new frame type: this is going to be our main frame +class VScrollFrame : public wxFrame +{ +public: + // ctor + VScrollFrame(); + + // event handlers (these functions should _not_ be virtual) + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + + void OnSize(wxSizeEvent& event) + { + // show current size in the status bar +#if wxUSE_STATUSBAR + if ( m_frameStatusBar ) + { + wxSize sz = GetClientSize(); + SetStatusText(wxString::Format("%dx%d", sz.x, sz.y), 1); + } +#endif // wxUSE_STATUSBAR + + event.Skip(); + } + +private: + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() +}; + +class VScrollWindow : public wxVScrolledWindow +{ +public: + VScrollWindow(wxFrame *frame) : wxVScrolledWindow(frame, -1) + { + m_frame = frame; + + SetLineCount(200); + + m_changed = true; + } + + void OnIdle(wxIdleEvent&) + { + m_frame->SetStatusText(wxString::Format + ( + "Page size = %d, pos = %d, max = %d", + GetScrollThumb(wxVERTICAL), + GetScrollPos(wxVERTICAL), + GetScrollRange(wxVERTICAL) + )); + m_changed = false; + } + + void OnPaint(wxPaintEvent&) + { + wxPaintDC dc(this); + + dc.SetPen(*wxBLACK_DASHED_PEN); + + const size_t lineFirst = GetFirstVisibleLine(), + lineLast = GetLastVisibleLine(); + + const wxCoord hText = dc.GetCharHeight(); + + wxCoord y = 0; + for ( size_t line = lineFirst; line <= lineLast; line++ ) + { + dc.DrawLine(0, y, 1000, y); + + wxCoord hLine = OnGetLineHeight(line); + dc.DrawText(wxString::Format(_T("Line %lu"), (unsigned long)line), + 0, y + (hLine - hText) / 2); + + y += hLine; + dc.DrawLine(0, y, 1000, y); + } + } + + void OnScroll(wxScrollWinEvent& event) + { + m_changed = true; + + event.Skip(); + } + + + virtual wxCoord OnGetLineHeight(size_t n) const + { + wxASSERT( n < GetLineCount() ); + + return n % 2 ? 15 : 30; // 15 + 2*n + } + +private: + wxFrame *m_frame; + + bool m_changed; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(VScrollWindow, wxVScrolledWindow) + EVT_IDLE(VScrollWindow::OnIdle) + EVT_PAINT(VScrollWindow::OnPaint) + EVT_SCROLLWIN(VScrollWindow::OnScroll) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands +enum +{ + // menu items + VScroll_Quit = 1, + + // it is important for the id corresponding to the "About" command to have + // this standard value as otherwise it won't be handled properly under Mac + // (where it is special and put into the "Apple" menu) + VScroll_About = wxID_ABOUT +}; + +// ---------------------------------------------------------------------------- +// 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(VScrollFrame, wxFrame) + EVT_MENU(VScroll_Quit, VScrollFrame::OnQuit) + EVT_MENU(VScroll_About, VScrollFrame::OnAbout) + EVT_SIZE(VScrollFrame::OnSize) +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. VScrollApp and +// not wxApp) +IMPLEMENT_APP(VScrollApp) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// the application class +// ---------------------------------------------------------------------------- + +// 'Main program' equivalent: the program execution "starts" here +bool VScrollApp::OnInit() +{ + // create the main application window + VScrollFrame *frame = new VScrollFrame; + + // and show it (the frames, unlike simple controls, are not shown when + // created initially) + frame->Show(TRUE); + + // ok + return TRUE; +} + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +// frame constructor +VScrollFrame::VScrollFrame() + : wxFrame(NULL, + -1, + _T("VScroll wxWindows Sample"), + wxDefaultPosition, + wxSize(400, 350)) +{ + // set the frame icon + SetIcon(wxICON(mondrian)); + +#if wxUSE_MENUS + // create a menu bar + wxMenu *menuFile = new wxMenu; + + // the "About" item should be in the help menu + wxMenu *menuHelp = new wxMenu; + menuHelp->Append(VScroll_About, _T("&About...\tF1"), _T("Show about dialog")); + + menuFile->Append(VScroll_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menuFile, _T("&File")); + menuBar->Append(menuHelp, _T("&Help")); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + // create a status bar just for fun (by default with 1 pane only) + CreateStatusBar(2); + SetStatusText(_T("Welcome to wxWindows!")); +#endif // wxUSE_STATUSBAR + + // create our one and only child -- it will take our entire client area + new VScrollWindow(this); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void VScrollFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // TRUE is to force the frame to close + Close(TRUE); +} + +void VScrollFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox(_T("VScroll shows how to implement scrolling with\n") + _T("variable line heights.\n") + _T("© 2003 Vadim Zeitlin"), + _T("About VScroll"), + wxOK | wxICON_INFORMATION, + this); +} diff --git a/src/generic/vscroll.cpp b/src/generic/vscroll.cpp new file mode 100644 index 0000000000..aa52fab013 --- /dev/null +++ b/src/generic/vscroll.cpp @@ -0,0 +1,322 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/vscroll.cpp +// Purpose: wxVScrolledWindow implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 30.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/vscroll.h" + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel) + EVT_SIZE(wxVScrolledWindow::OnSize) + EVT_SCROLLWIN(wxVScrolledWindow::OnScroll) +END_EVENT_TABLE() + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::Init() +{ + // we're initially empty + m_lineMax = + m_lineFirst = 0; + + // this one should always be strictly positive + m_nVisible = 1; + + m_heightTotal = 0; +} + +// ---------------------------------------------------------------------------- +// various helpers +// ---------------------------------------------------------------------------- + +wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const +{ + if ( lineMin == lineMax ) + return 0; + else if ( lineMin > lineMax ) + return -GetLinesHeight(lineMax, lineMin); + //else: lineMin < lineMax + + // let the user code know that we're going to need all these lines + OnGetLinesHint(lineMin, lineMax); + + // do sum up their heights + wxCoord height = 0; + for ( size_t line = lineMin; line < lineMax; line++ ) + { + height += OnGetLineHeight(line); + } + + return height; +} + +size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast) +{ + const wxCoord hWindow = GetClientSize().y; + + // go upwards until we arrive at a line such that lineLast is not visible + // any more when it is shown + size_t lineFirst = lineLast; + wxCoord h = 0; + for ( ;; ) + { + h += OnGetLineHeight(lineFirst); + + if ( h > hWindow ) + { + lineFirst++; + + break; + } + + if ( !lineFirst ) + break; + + lineFirst--; + } + + return lineFirst; +} + +void wxVScrolledWindow::UpdateScrollbar() +{ + // see how many lines can we fit on screen + const wxCoord hWindow = GetClientSize().y; + + wxCoord h = 0; + size_t line; + for ( line = m_lineFirst; line < m_lineMax; line++ ) + { + if ( h > hWindow ) + break; + + h += OnGetLineHeight(line); + } + + m_nVisible = line - m_lineFirst; + + int pageSize = m_nVisible; + if ( h > hWindow ) + { + // last line is only partially visible, we still need the scrollbar and + // so we have to "fix" pageSize because if it is equal to m_lineMax the + // scrollbar is not shown at all under MSW + pageSize--; + } + + // set the scrollbar parameters to reflect this + SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax); +} + +// ---------------------------------------------------------------------------- +// operations +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::SetLineCount(size_t count) +{ + // save the number of lines + m_lineMax = count; + + + // estimate the total height: it is impossible to call + // OnGetLineHeight() for every line because there may be too many of + // them, so we just make a guess using some lines in the beginning, + // some in the end and some in the middle + static const size_t NUM_LINES_TO_SAMPLE = 10; + + if ( count < 3*NUM_LINES_TO_SAMPLE ) + { + // in this case calculating exactly is faster and more correct than + // guessing + m_heightTotal = GetLinesHeight(0, m_lineMax); + } + else // too many lines to calculate exactly + { + // look at some lines in the beginning/middle/end + m_heightTotal = + GetLinesHeight(0, NUM_LINES_TO_SAMPLE) + + GetLinesHeight(count - NUM_LINES_TO_SAMPLE, count) + + GetLinesHeight(count/2 - NUM_LINES_TO_SAMPLE/2, + count/2 + NUM_LINES_TO_SAMPLE/2); + + // use the height of the lines we looked as the average + m_heightTotal = ((float)m_heightTotal / (3*NUM_LINES_TO_SAMPLE)) * + m_lineMax; + } + + + // recalculate the scrollbars parameters + ScrollToLine(0); +} + +// ---------------------------------------------------------------------------- +// scrolling +// ---------------------------------------------------------------------------- + +bool wxVScrolledWindow::ScrollToLine(size_t line) +{ + if ( !m_lineMax ) + { + // we're empty, code below doesn't make sense in this case + return false; + } + + // determine the real first line to scroll to: we shouldn't scroll beyond + // the end + size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1); + if ( line > lineFirstLast ) + line = lineFirstLast; + + // anything to do? + if ( line == m_lineFirst ) + { + // no + return false; + } + + + // remember the currently shown lines for the refresh code below + size_t lineFirstOld = GetFirstVisibleLine(), + lineLastOld = GetLastVisibleLine(); + + m_lineFirst = line; + + + // the size of scrollbar thumb could have changed + UpdateScrollbar(); + + + // finally refresh the display -- but only redraw as few lines as possible + // to avoid flicker + if ( GetFirstVisibleLine() > lineLastOld || + GetLastVisibleLine() < lineFirstOld ) + { + // the simplest case: we don't have any old lines left, just redraw + // everything + Refresh(); + } + else // overlap between the lines we showed before and should show now + { + ScrollWindow(0, GetLinesHeight(GetFirstVisibleLine(), lineFirstOld)); + } + + return true; +} + +bool wxVScrolledWindow::ScrollLines(int lines) +{ + lines += m_lineFirst; + if ( lines < 0 ) + lines = 0; + + return ScrollToLine(lines); +} + +bool wxVScrolledWindow::ScrollPages(int pages) +{ + bool didSomething = false; + + while ( pages ) + { + int line; + if ( pages > 0 ) + { + line = GetLastVisibleLine(); + pages--; + } + else // pages < 0 + { + line = FindFirstFromBottom(GetFirstVisibleLine()); + pages++; + } + + didSomething = ScrollToLine(line); + } + + return didSomething; +} + +// ---------------------------------------------------------------------------- +// event handling +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::OnSize(wxSizeEvent& event) +{ + UpdateScrollbar(); + + event.Skip(); +} + +void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) +{ + size_t lineFirstNew; + + const wxEventType evtType = event.GetEventType(); + if ( evtType == wxEVT_SCROLLWIN_TOP ) + { + lineFirstNew = 0; + } + else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) + { + lineFirstNew = m_lineMax; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) + { + lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) + { + lineFirstNew = m_lineFirst + 1; + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) + { + lineFirstNew = FindFirstFromBottom(m_lineFirst); + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) + { + lineFirstNew = GetLastVisibleLine(); + } + else // unknown scroll event? + { + if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) + { + lineFirstNew = event.GetPosition(); + } + else + { + wxASSERT_MSG( evtType == wxEVT_SCROLLWIN_THUMBTRACK, + _T("unknown scroll event type?") ); + + // don't do anything, otherwise dragging the thumb around would + // be too slow + return; + } + } + + ScrollToLine(lineFirstNew); +} + -- 2.45.2