4 * ---------------------------------------------------------------------------
6 * Implementation of a minimal C++ class framework for use with the
7 * Microsoft Windows Application Programming Interface.
11 * This file provides the implementation for each of the three C++ classes
12 * which are required to implement sash window controls. It must be compiled
13 * to generate three separate object modules:--
15 * c++ -c sashctrl.cpp -o sashctrl.o
16 * c++ -D HSASH_IMPLEMENTATION -c sashctrl.cpp -o hsashctl.o
17 * c++ -D VSASH_IMPLEMENTATION -c sashctrl.cpp -o vsashctl.o
19 * to obtain the implementations of the SashWindowMaker abstract base class,
20 * together with its HorizontalSashWindowMaker and VerticalSashWindowMaker
21 * derived classes, respectively.
23 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
24 * Copyright (C) 2012, MinGW.org Project.
26 * ---------------------------------------------------------------------------
28 * Permission is hereby granted, free of charge, to any person obtaining a
29 * copy of this software and associated documentation files (the "Software"),
30 * to deal in the Software without restriction, including without limitation
31 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32 * and/or sell copies of the Software, and to permit persons to whom the
33 * Software is furnished to do so, subject to the following conditions:
35 * The above copyright notice and this permission notice shall be included
36 * in all copies or substantial portions of the Software.
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
39 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
43 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
44 * DEALINGS IN THE SOFTWARE.
46 * ---------------------------------------------------------------------------
49 #define WIN32_LEAN_AND_MEAN
53 /* Identify the class implementation to be compiled; each of
54 * the HSASH_IMPLEMENTATION and VSASH_IMPLEMENTATION must be
55 * explicitly requested. Initially, we assume that either of
56 * these may have been specified, so we deselect the fallback
59 #undef CORE_IMPLEMENTATION
63 #ifdef HSASH_IMPLEMENTATION
64 /* ...when the horizontal sash case IS selected, we ensure that
65 * the vertical sash case ISN'T...
67 # undef VSASH_IMPLEMENTATION
69 /* ...otherwise, when the horizontal sash case ISN'T selected...
71 #elif !defined VSASH_IMPLEMENTATION
72 /* ...and the vertical sash case ISN'T either, then we reselect
75 # define CORE_IMPLEMENTATION
80 # ifdef CORE_IMPLEMENTATION
81 /* Neither the HSASH_IMPLEMENTATION nor the VSASH_IMPLEMENTATION
82 * was selected; implement the SashWindowMaker class.
84 SashWindowMaker::SashWindowMaker
85 ( HINSTANCE app, double minval, double initval, double maxval ):
86 ChildWindowMaker( app ), MinRangeFactor( minval ), MaxRangeFactor( maxval ),
87 DisplacementFactor( initval ){ ValidateDisplacementFactor(); }
89 void SashWindowMaker::RegisterWindowClassName( const char *ClassName )
91 /* Helper routine, to ensure that an appropriate window class name
92 * is registered, as required for instantiation of any object of the
93 * derived HorizontalSashWindowMaker or VerticalSashWindowMaker class.
95 WindowClassMaker WindowClassRegistry( AppInstance );
96 WindowClassRegistry.SetCursor( LoadCursor( NULL, CursorStyle() ));
97 WindowClassRegistry.Register( ClassName );
100 long SashWindowMaker::OnLeftButtonDown( void )
102 /* Capture the mouse over a sash bar, and initiate the drag
103 * operation to resize the adjacent sash panes.
106 SetCapture( AppWindow );
108 /* Establish the viewport region of the owner window, within
109 * which the sash panes are defined.
111 GetClientRect( (owner = GetParent( AppWindow )), &frame );
112 long width = GetFrameWidth(), height = GetFrameHeight();
114 /* Adjust the frame bounds to accommodate the entire extent
115 * of the owner window, then relative to those, establish the
116 * clipping region within which mouse movement is to be confined
117 * while dragging the sash bar.
119 GetWindowRect( owner, &frame );
120 long border = (GetFrameWidth() - width) / 2;
121 SetClippingRegion( width, height, border );
122 ClipCursor( &frame );
124 /* Readjust the frame bounds to the entire extent of the owner
125 * window, (they will have been modified while setting up the
126 * clipping region), then further adjust the top edge and left
127 * side entries, to reflect the offset of the viewport within
128 * the overall window bounds.
130 GetWindowRect( owner, &frame );
131 frame.top = frame.bottom - border - height;
132 frame.left += border;
136 long SashWindowMaker::OnMouseMove( WPARAM flags )
138 /* When the mouse has been captured over a sash bar...
140 if( flags & MK_LBUTTON )
142 /* ...compute the position to which it has been dragged,
143 * ensuring that it remains within the permitted bounds...
145 SetDisplacementFactor( GetMessagePos() );
146 ValidateDisplacementFactor();
148 /* ...then dynamically update the owner window display,
149 * to reflect the sash movement.
151 WindowObjectReference( GetParent( AppWindow ))->AdjustLayout();
155 void SashWindowMaker::ValidateDisplacementFactor()
157 /* Helper routine to ensure that sash bar movement
158 * remains within permitted bounds.
160 if( DisplacementFactor < MinRangeFactor )
161 DisplacementFactor = MinRangeFactor;
162 else if( DisplacementFactor > MaxRangeFactor )
163 DisplacementFactor = MaxRangeFactor;
166 long SashWindowMaker::OnLeftButtonUp( void )
168 /* Complete a drag operation on a sash bar; first we
169 * release the mouse from the clipping region...
174 /* ...then perform a final update of the owner window,
175 * to clean up any display artefacts which may have been
176 * left behind by dragging the sash bar...
178 HWND owner = GetParent( AppWindow );
179 InvalidateRect( owner, NULL, TRUE );
180 UpdateWindow( owner );
182 /* ...and we are done.
188 /* When compiling each of the HSASH_IMPLEMENTATION module, and
189 * the VSASH_IMPLEMENTATION module...
191 class MousePositionMapper
193 /* This locally declared, all-inline class is used to facilitate
194 * identification of the co-ordinates of the mouse position.
197 union { unsigned long v; struct { unsigned short x, y; }; } pos;
200 MousePositionMapper( unsigned long v ){ pos.v = v; }
201 long X(){ return pos.x; }
202 long Y(){ return pos.y; }
206 #ifdef HSASH_IMPLEMENTATION
207 /* This is the case where we are compiling the implementation for
208 * the HorizontalSashWindowMaker class.
210 const char *HorizontalSashWindowMaker::ClassName = NULL;
211 const char *HorizontalSashWindowMaker::RegisteredClassName( void )
213 /* Helper routine to ensure that the appropriate window class
214 * name is registered on first instantiation of any class object.
216 if( ClassName == NULL )
217 RegisterWindowClassName( ClassName = "HSashCtrl" );
221 void HorizontalSashWindowMaker::
222 SetClippingRegion( long width, long height, long border )
224 /* Helper routine, called by the OnLeftButtonDown() method which is
225 * inherited from the SashWindowMaker base class, to establish left
226 * and right movement bounds for the sash bar, within the frame of
229 ScaleFactor = (double)(width);
230 frame.right -= border + (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
231 frame.left += border + (long)( MinRangeFactor * ScaleFactor );
234 void HorizontalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
236 /* Helper routine, called by the OnMouseMove() method which is
237 * inherited from the SashWindowMaker base class, to establish the
238 * offset of the sash bar from the left hand side of the owner
239 * window, as it is dragged by the mouse.
241 MousePositionMapper locate( pos );
242 DisplacementFactor = (double)(locate.X() - frame.left) / ScaleFactor;
245 # elif defined VSASH_IMPLEMENTATION
246 /* This is the case where we are compiling the implementation for
247 * the VerticalSashWindowMaker class.
249 const char *VerticalSashWindowMaker::ClassName = NULL;
250 const char *VerticalSashWindowMaker::RegisteredClassName( void )
252 /* Helper routine to ensure that the appropriate window class
253 * name is registered on first instantiation of any class object.
255 if( ClassName == NULL )
256 RegisterWindowClassName( ClassName = "VSashCtrl" );
260 void VerticalSashWindowMaker::
261 SetClippingRegion( long width, long height, long border )
263 /* Helper routine, called by the OnLeftButtonDown() method which is
264 * inherited from the SashWindowMaker base class, to establish upper
265 * and lower movement bounds for the sash bar, within the frame of
268 ScaleFactor = (double)(height); frame.bottom -= border;
269 frame.top = frame.bottom - (long)( (1.0 - MinRangeFactor) * ScaleFactor );
270 frame.bottom -= (long)( (1.0 - MaxRangeFactor) * ScaleFactor );
273 void VerticalSashWindowMaker::SetDisplacementFactor( unsigned long pos )
275 /* Helper routine, called by the OnMouseMove() method which is
276 * inherited from the SashWindowMaker base class, to establish the
277 * offset of the sash bar from the top edge of the owner window,
278 * as it is dragged by the mouse.
280 MousePositionMapper locate( pos );
281 DisplacementFactor = (double)(locate.Y() - frame.top) / ScaleFactor;
287 /* $RCSfile$: end of file */