1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //           Application Programming Interface           //
9 //                                                       //
10 //                  Library: SAGA_GDI                    //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                    sgdi_helper.cpp                    //
15 //                                                       //
16 //                 Copyright (C) 2008 by                 //
17 //                      Olaf Conrad                      //
18 //                                                       //
19 //-------------------------------------------------------//
20 //                                                       //
21 // This file is part of 'SAGA - System for Automated     //
22 // Geoscientific Analyses'. SAGA is free software; you   //
23 // can redistribute it and/or modify it under the terms  //
24 // of the GNU General Public License as published by the //
25 // Free Software Foundation, either version 2 of the     //
26 // License, or (at your option) any later version.       //
27 //                                                       //
28 // SAGA is distributed in the hope that it will be       //
29 // useful, but WITHOUT ANY WARRANTY; without even the    //
30 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
31 // PARTICULAR PURPOSE. See the GNU General Public        //
32 // License for more details.                             //
33 //                                                       //
34 // You should have received a copy of the GNU General    //
35 // Public License along with this program; if not, see   //
36 // <http://www.gnu.org/licenses/>.                       //
37 //                                                       //
38 //-------------------------------------------------------//
39 //                                                       //
40 //    e-mail:     oconrad@saga-gis.org                   //
41 //                                                       //
42 //    contact:    Olaf Conrad                            //
43 //                Institute of Geography                 //
44 //                University of Hamburg                  //
45 //                Germany                                //
46 //                                                       //
47 ///////////////////////////////////////////////////////////
48 
49 //---------------------------------------------------------
50 #include <wx/wxprec.h>
51 #include <wx/settings.h>
52 #include <wx/dc.h>
53 
54 //---------------------------------------------------------
55 #include "sgdi_helper.h"
56 
57 
58 ///////////////////////////////////////////////////////////
59 //														 //
60 //														 //
61 //														 //
62 ///////////////////////////////////////////////////////////
63 
64 //---------------------------------------------------------
Draw_Edge(wxDC & dc,int Edge_Style,int ax,int ay,int bx,int by)65 void		Draw_Edge(wxDC &dc, int Edge_Style, int ax, int ay, int bx, int by)
66 {
67 	wxPen	oldPen(dc.GetPen());
68 
69 	switch( Edge_Style )
70 	{
71 	//-----------------------------------------------------
72 	case EDGE_STYLE_SIMPLE:
73 		dc.DrawLine(bx, ay, bx, by);
74 		dc.DrawLine(bx, by, ax, by);
75 		dc.DrawLine(ax, ay, bx, ay);
76 		dc.DrawLine(ax, by, ax, ay);
77 		break;
78 
79 	//-----------------------------------------------------
80 	case EDGE_STYLE_STATIC:
81 		Draw_Edge(dc, EDGE_STYLE_SUNKEN, ax + 0, ay + 0, bx - 0, by - 0);
82 		Draw_Edge(dc, EDGE_STYLE_RAISED, ax + 1, ay + 1, bx - 1, by - 1);
83 		break;
84 
85 	//-----------------------------------------------------
86 	case EDGE_STYLE_SUNKEN:
87 		oldPen	= dc.GetPen();
88 
89 		dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 0, wxPENSTYLE_SOLID));
90 		dc.DrawLine(bx, ay, bx, by);
91 		dc.DrawLine(bx, by, ax, by);
92 
93 		dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW   ), 0, wxPENSTYLE_SOLID));
94 		dc.DrawLine(ax, by, ax, ay);
95 		dc.DrawLine(ax, ay, bx, ay);
96 
97 		dc.SetPen(oldPen);
98 		break;
99 
100 	//-----------------------------------------------------
101 	case EDGE_STYLE_RAISED:
102 		dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW   ), 0, wxPENSTYLE_SOLID));
103 		dc.DrawLine(bx, ay, bx, by);
104 		dc.DrawLine(bx, by, ax, by);
105 
106 		dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 0, wxPENSTYLE_SOLID));
107 		dc.DrawLine(ax, by, ax, ay);
108 		dc.DrawLine(ax, ay, bx, ay);
109 		break;
110 	}
111 
112 	dc.SetPen(oldPen);
113 }
114 
115 //---------------------------------------------------------
Draw_Edge(wxDC & dc,int Edge_Style,wxRect r)116 void		Draw_Edge(wxDC &dc, int Edge_Style, wxRect r)
117 {
118 	Draw_Edge(dc, Edge_Style, r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
119 }
120 
121 
122 ///////////////////////////////////////////////////////////
123 //														 //
124 //														 //
125 //														 //
126 ///////////////////////////////////////////////////////////
127 
128 //---------------------------------------------------------
Draw_Rect(wxDC & dc,wxColour Color,int ax,int ay,int bx,int by)129 void		Draw_Rect(wxDC &dc, wxColour Color, int ax, int ay, int bx, int by)
130 {
131 	Draw_FillRect(dc, Color, ax, ay, bx, by);
132 
133 	Draw_Edge(dc, EDGE_STYLE_SIMPLE, ax, ay, bx, by);
134 }
135 
136 //---------------------------------------------------------
Draw_Rect(wxDC & dc,wxColour Color,wxRect r)137 void		Draw_Rect(wxDC &dc, wxColour Color, wxRect r)
138 {
139 	Draw_Rect(dc, Color, r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
140 }
141 
142 
143 ///////////////////////////////////////////////////////////
144 //														 //
145 //														 //
146 //														 //
147 ///////////////////////////////////////////////////////////
148 
149 //---------------------------------------------------------
Draw_FillRect(wxDC & dc,wxColour Color,int ax,int ay,int bx,int by)150 void		Draw_FillRect(wxDC &dc, wxColour Color, int ax, int ay, int bx, int by)
151 {
152 	if( ax > bx )
153 	{
154 		int i = ax; ax = bx; bx = i;
155 	}
156 
157 	if( ay > by )
158 	{
159 		int i = ay; ay = by; by = i;
160 	}
161 
162 	//-----------------------------------------------------
163 	wxPen oldPen(dc.GetPen()); dc.SetPen(wxPen(Color));
164 
165 	if( bx - ax < by - ay )
166 	{
167 		for(int i=ax; i<bx; i++)
168 		{
169 			dc.DrawLine(i, ay, i, by);
170 		}
171 	}
172 	else
173 	{
174 		for(int i=ay; i<by; i++)
175 		{
176 			dc.DrawLine(ax, i, bx, i);
177 		}
178 	}
179 
180 	//-----------------------------------------------------
181 	dc.SetPen(oldPen);
182 }
183 
184 //---------------------------------------------------------
Draw_FillRect(wxDC & dc,wxColour Color,wxRect r)185 void		Draw_FillRect(wxDC &dc, wxColour Color, wxRect r)
186 {
187 	Draw_FillRect(dc, Color, r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
188 }
189 
190 
191 ///////////////////////////////////////////////////////////
192 //														 //
193 //														 //
194 //														 //
195 ///////////////////////////////////////////////////////////
196 
197 //---------------------------------------------------------
Draw_Text(wxDC & dc,int Align,int x,int y,const wxString & Text)198 void		Draw_Text(wxDC &dc, int Align, int x, int y, const wxString &Text)
199 {
200 	if( Align != TEXTALIGN_TOPLEFT )
201 	{
202 		wxCoord	xSize, ySize;
203 
204 		dc.GetTextExtent(Text, &xSize, &ySize);
205 
206 		//-------------------------------------------------
207 		if		( Align & TEXTALIGN_XCENTER )
208 		{
209 			x	-= xSize / 2;
210 		}
211 		else if	( Align & TEXTALIGN_RIGHT )
212 		{
213 			x	-= xSize;
214 		}
215 
216 		//-------------------------------------------------
217 		if		( Align & TEXTALIGN_YCENTER )
218 		{
219 			y	-= ySize / 2;
220 		}
221 		else if	( Align & TEXTALIGN_BOTTOM )
222 		{
223 			y	-= ySize;
224 		}
225 	}
226 
227 	dc.DrawText(Text, x, y);
228 }
229 
230 //---------------------------------------------------------
Draw_Text(wxDC & dc,int Align,int x,int y,double Angle,const wxString & Text)231 void		Draw_Text(wxDC &dc, int Align, int x, int y, double Angle, const wxString &Text)
232 {
233 	if( Angle == 0. )
234 	{
235 		Draw_Text(dc, Align, x, y, Text);
236 
237 		return;
238 	}
239 
240 	if( Align != TEXTALIGN_TOPLEFT )
241 	{
242 		wxCoord	xSize, ySize;	double	d;
243 
244 		dc.GetTextExtent(Text, &xSize, &ySize);
245 
246 		//-------------------------------------------------
247 		d	 = M_DEG_TO_RAD * Angle;
248 
249 		if		( Align & TEXTALIGN_XCENTER )
250 		{
251 			x	-= (int)(xSize * cos(d) / 2.);
252 			y	+= (int)(xSize * sin(d) / 2.);
253 		}
254 		else if	( Align & TEXTALIGN_RIGHT )
255 		{
256 			x	-= (int)(xSize * cos(d));
257 			y	+= (int)(xSize * sin(d));
258 		}
259 
260 		//-------------------------------------------------
261 		d	 = M_DEG_TO_RAD * (Angle - 90.);
262 
263 		if		( Align & TEXTALIGN_YCENTER )
264 		{
265 			x	-= (int)(ySize * cos(d) / 2.);
266 			y	+= (int)(ySize * sin(d) / 2.);
267 		}
268 		else if	( Align & TEXTALIGN_BOTTOM )
269 		{
270 			x	-= (int)(ySize * cos(d));
271 			y	+= (int)(ySize * sin(d));
272 		}
273 	}
274 
275 	dc.DrawRotatedText(Text, x, y, Angle);
276 }
277 
278 //---------------------------------------------------------
Draw_Text(wxDC & dc,int Align,int x,int y,const wxString & Text,int Effect,wxColour Effect_Color,int Effect_Size)279 void			Draw_Text			(wxDC &dc, int Align, int x, int y, const wxString &Text, int Effect, wxColour Effect_Color, int Effect_Size)
280 {
281 	Draw_Text(dc, Align, x, y, 0., Text, Effect, Effect_Color);
282 }
283 
Draw_Text(wxDC & dc,int Align,int x,int y,double Angle,const wxString & Text,int Effect,wxColour Effect_Color,int Effect_Size)284 void			Draw_Text			(wxDC &dc, int Align, int x, int y, double Angle, const wxString &Text, int Effect, wxColour Effect_Color, int Effect_Size)
285 {
286 	if( Effect != TEXTEFFECT_NONE )
287 	{
288 		wxColour	oldColor	= dc.GetTextForeground();	dc.SetTextForeground(Effect_Color);
289 
290 		if( Effect_Size <= 1 )
291 		{
292 			int	d	= 1;
293 
294 			if( Effect & TEXTEFFECT_TOP         )	Draw_Text(dc, Align, x    , y - d, Angle, Text);
295 			if( Effect & TEXTEFFECT_TOPLEFT     )	Draw_Text(dc, Align, x - d, y - d, Angle, Text);
296 			if( Effect & TEXTEFFECT_LEFT        )	Draw_Text(dc, Align, x - d, y    , Angle, Text);
297 			if( Effect & TEXTEFFECT_BOTTOMLEFT  )	Draw_Text(dc, Align, x - d, y + d, Angle, Text);
298 			if( Effect & TEXTEFFECT_BOTTOM      )	Draw_Text(dc, Align, x    , y + d, Angle, Text);
299 			if( Effect & TEXTEFFECT_BOTTOMRIGHT )	Draw_Text(dc, Align, x + d, y + d, Angle, Text);
300 			if( Effect & TEXTEFFECT_RIGHT       )	Draw_Text(dc, Align, x + d, y    , Angle, Text);
301 			if( Effect & TEXTEFFECT_TOPRIGHT    )	Draw_Text(dc, Align, x + d, y - d, Angle, Text);
302 		}
303 		else if( Effect != TEXTEFFECT_FRAME )
304 		{
305 			for(int d=1; d<=Effect_Size; d++)
306 			{
307 				if( Effect & TEXTEFFECT_TOP         )	Draw_Text(dc, Align, x    , y - d, Angle, Text);
308 				if( Effect & TEXTEFFECT_TOPLEFT     )	Draw_Text(dc, Align, x - d, y - d, Angle, Text);
309 				if( Effect & TEXTEFFECT_LEFT        )	Draw_Text(dc, Align, x - d, y    , Angle, Text);
310 				if( Effect & TEXTEFFECT_BOTTOMLEFT  )	Draw_Text(dc, Align, x - d, y + d, Angle, Text);
311 				if( Effect & TEXTEFFECT_BOTTOM      )	Draw_Text(dc, Align, x    , y + d, Angle, Text);
312 				if( Effect & TEXTEFFECT_BOTTOMRIGHT )	Draw_Text(dc, Align, x + d, y + d, Angle, Text);
313 				if( Effect & TEXTEFFECT_RIGHT       )	Draw_Text(dc, Align, x + d, y    , Angle, Text);
314 				if( Effect & TEXTEFFECT_TOPRIGHT    )	Draw_Text(dc, Align, x + d, y - d, Angle, Text);
315 			}
316 		}
317 		else
318 		{
319 			for(int dy=y-Effect_Size; dy<=y+Effect_Size; dy++)
320 			{
321 				for(int dx=x-Effect_Size; dx<=x+Effect_Size; dx++)
322 				{
323 					Draw_Text(dc, Align, dx, dy, Angle, Text);
324 				}
325 			}
326 		}
327 
328 		dc.SetTextForeground(oldColor);
329 	}
330 
331 	Draw_Text(dc, Align, x, y, Angle, Text);
332 }
333 
334 
335 ///////////////////////////////////////////////////////////
336 //														 //
337 //														 //
338 //														 //
339 ///////////////////////////////////////////////////////////
340 
341 //---------------------------------------------------------
342 #define TEXTSPACE	6
343 
344 //---------------------------------------------------------
Draw_Scale(wxDC & dc,const wxRect & r,double zMin,double zMax,int Orientation,int Tick,int Style,const wxString & Unit)345 void		Draw_Scale(wxDC &dc, const wxRect &r, double zMin, double zMax, int Orientation, int Tick, int Style, const wxString &Unit)
346 {
347 	//-----------------------------------------------------
348 	int	Width	= Orientation != SCALE_VERTICAL ? r.GetWidth() : r.GetHeight();
349 	int	Height	= Orientation != SCALE_VERTICAL ? r.GetHeight() : r.GetWidth();
350 
351 	if( zMin >= zMax || Width < 5 || Height < 5 )
352 	{
353 		return;
354 	}
355 
356 	//-----------------------------------------------------
357 	if( Style & SCALE_STYLE_GLOOMING )
358 	{
359 		Style	^= SCALE_STYLE_GLOOMING;
360 
361 		wxRect	rTmp;
362 
363 		dc.SetPen     (wxPen(*wxWHITE));
364 		dc.SetTextForeground(*wxWHITE);
365 
366 		rTmp	= r; rTmp.Offset( 0,  1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
367 		rTmp	= r; rTmp.Offset( 1,  1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
368 		rTmp	= r; rTmp.Offset( 1,  0); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
369 		rTmp	= r; rTmp.Offset( 1, -1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
370 		rTmp	= r; rTmp.Offset( 0, -1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
371 		rTmp	= r; rTmp.Offset(-1, -1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
372 		rTmp	= r; rTmp.Offset(-1,  0); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
373 		rTmp	= r; rTmp.Offset(-1,  1); Draw_Scale(dc, rTmp, zMin, zMax, Orientation, Tick, Style, Unit);
374 
375 		dc.SetPen     (wxPen(*wxBLACK));
376 		dc.SetTextForeground(*wxBLACK);
377 	}
378 
379 	//-----------------------------------------------------
380 	wxPen	oldPen  (dc.GetPen  ());
381 	wxBrush	oldBrush(dc.GetBrush());
382 	wxFont	oldFont (dc.GetFont ());
383 
384 	dc.SetFont(wxFont(
385 		(int)((Tick == SCALE_TICK_NONE ? 0.60 : 0.45) * (double)Height),
386 		wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL
387 	));
388 
389 	//-----------------------------------------------------
390 	double	zToDC		= (double)Width / (zMax - zMin);
391 	double	dz			= pow(10., floor(log10(zMax - zMin)) - 1.);
392 	int		Decimals	= dz >= 1. ? 0 : (int)floor(-log10(dz));
393 
394 	int		h	= dc.GetTextExtent(wxString::Format("%.*f", Decimals, zMax)).GetWidth();
395 
396 	while( zToDC * dz < h + TEXTSPACE )	{	dz	*= 2;	}
397 
398 	//-----------------------------------------------------
399 	int		Align, x[2], y[2];	h	= 0;
400 
401 	switch( Tick )
402 	{
403 	default               :	Align = TEXTALIGN_TOPLEFT     ;	break;
404 	case SCALE_TICK_TOP   :	Align = TEXTALIGN_TOPCENTER   ;	break;
405 	case SCALE_TICK_BOTTOM:	Align = TEXTALIGN_BOTTOMCENTER;	break;
406 	}
407 
408 	if( Orientation != SCALE_VERTICAL )
409 	{
410 		x[0]	= -1;	x[1]	= (int)((Tick == SCALE_TICK_NONE ? 1.00 : 0.30) * (double)Height);
411 		y[0]	= r.GetTop () + (Tick != SCALE_TICK_BOTTOM ? 0    : Height);
412 		y[1]	= r.GetTop () + (Tick != SCALE_TICK_BOTTOM ? x[1] : Height - x[1]);
413 	}
414 	else // if( Orientation == SCALE_VERTICAL )
415 	{
416 		y[0]	= -1;	y[1]	= (int)((Tick == SCALE_TICK_NONE ? 1.00 : 0.30) * (double)Height);
417 		x[0]	= r.GetLeft() + (Tick != SCALE_TICK_BOTTOM ? 0    : Height);
418 		x[1]	= r.GetLeft() + (Tick != SCALE_TICK_BOTTOM ? y[1] : Height - y[1]);
419 	}
420 
421 	//-----------------------------------------------------
422 	for(double z=dz*floor(zMin/dz); !std::isinf(z) && z<=zMax; z+=dz)
423 	{
424 		if( Tick == SCALE_TICK_NONE || z >= zMin )
425 		{
426 			int	zDC	= Style & SCALE_STYLE_DESCENDENT
427 				? Width - 1 - (int)(zToDC * (z - zMin))
428 				:             (int)(zToDC * (z - zMin));
429 
430 			if( Orientation != SCALE_VERTICAL )
431 			{
432 				int	xLast	= x[0];	x[0] = x[1] = r.GetLeft() + zDC;
433 
434 				if( Style & SCALE_STYLE_BLACKWHITE && xLast >= 0 )
435 				{
436 					dc.SetBrush(h++ % 2 ? *wxWHITE : *wxBLACK);
437 
438 					dc.DrawRectangle(xLast, y[0], x[1] - xLast, y[1] - y[0]);
439 				}
440 			}
441 			else // if( Orientation == SCALE_VERTICAL )
442 			{
443 				int	yLast	= y[0]; y[0] = y[1] = r.GetTop () + zDC;
444 
445 				if( Style & SCALE_STYLE_BLACKWHITE && yLast >= 0 )
446 				{
447 					dc.SetBrush(h++ % 2 ? *wxWHITE : *wxBLACK);
448 
449 					dc.DrawRectangle(x[0], yLast, x[1] - x[0], y[1] - yLast);
450 				}
451 			}
452 
453 			if( !(Style & SCALE_STYLE_BLACKWHITE) )
454 			{
455 				dc.DrawLine(x[0], y[0], x[1], y[1]);
456 			}
457 
458 			Draw_Text(dc, Align, x[1], y[1], Orientation != SCALE_VERTICAL ? 0 : 90,
459 				wxString::Format("%.*f", Decimals, z)
460 			);
461 		}
462 	}
463 
464 	//-----------------------------------------------------
465 	if( Orientation != SCALE_VERTICAL )
466 	{
467 		if( Style & SCALE_STYLE_LINECONN )
468 		{
469 			dc.DrawLine(r.GetLeft(), y[0], x[1], y[0]);
470 		}
471 
472 		if( !Unit.IsEmpty() )
473 		{
474 			if( Style & SCALE_STYLE_UNIT_BELOW )
475 			{
476 				Draw_Text(dc, TEXTALIGN_TOPCENTER   , r.GetLeft() + r.GetWidth() / 2, r.GetBottom(), Unit);
477 			}
478 			else // if( Style & SCALE_STYLE_UNIT_ABOVE )
479 			{
480 				Draw_Text(dc, TEXTALIGN_BOTTOMCENTER, r.GetLeft() + r.GetWidth() / 2, r.GetTop   (), Unit);
481 			}
482 		}
483 	}
484 	else
485 	{
486 		if( Style & SCALE_STYLE_LINECONN )
487 		{
488 			dc.DrawLine(x[0], r.GetTop(), x[0], y[1]);
489 		}
490 
491 		if( !Unit.IsEmpty() )
492 		{
493 			if( Style & SCALE_STYLE_UNIT_BELOW )
494 			{
495 				Draw_Text(dc, TEXTALIGN_TOPCENTER   , r.GetRight(), r.GetTop() + r.GetHeight() / 2, 90., Unit);
496 			}
497 			else // if( Style & SCALE_STYLE_UNIT_ABOVE )
498 			{
499 				Draw_Text(dc, TEXTALIGN_BOTTOMCENTER, r.GetLeft (), r.GetTop() + r.GetHeight() / 2, 90., Unit);
500 			}
501 		}
502 	}
503 
504 	//-----------------------------------------------------
505 	dc.SetPen  (oldPen  );
506 	dc.SetBrush(oldBrush);
507 	dc.SetFont (oldFont );
508 }
509 
510 //---------------------------------------------------------
Draw_Scale(wxDC & dc,const wxRect & r,double zMin,double zMax,bool bHorizontal,bool bAscendent,bool bTickAtTop)511 void		Draw_Scale(wxDC &dc, const wxRect &r, double zMin, double zMax, bool bHorizontal, bool bAscendent, bool bTickAtTop)
512 {
513 	Draw_Scale(dc, r, zMin, zMax, bHorizontal ? SCALE_HORIZONTAL : SCALE_VERTICAL, bTickAtTop ? SCALE_TICK_TOP : SCALE_TICK_BOTTOM, bAscendent ? SCALE_STYLE_DEFAULT : SCALE_STYLE_DESCENDENT);
514 }
515 
516 
517 ///////////////////////////////////////////////////////////
518 //														 //
519 //														 //
520 //														 //
521 ///////////////////////////////////////////////////////////
522 
523 //---------------------------------------------------------
524 #define RULER_TEXT_SPACE	4
525 
526 //---------------------------------------------------------
Draw_Ruler(wxDC & dc,const wxRect & r,bool bHorizontal,double zMin,double zMax,bool bAscendent,int FontSize,const wxColour & Colour)527 bool		Draw_Ruler(wxDC &dc, const wxRect &r, bool bHorizontal, double zMin, double zMax, bool bAscendent, int FontSize, const wxColour &Colour)
528 {
529 	if( zMin < zMax && r.GetWidth() > 0 && r.GetHeight() > 0 )
530 	{
531 		dc.SetPen(wxPen(Colour));
532 		dc.SetFont(wxFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
533 
534 		double	Width	= bHorizontal ? r.GetWidth() : r.GetHeight();
535 
536 		int		xMin	= r.GetX();
537 		int		xMax	= r.GetX() + r.GetWidth();
538 		int		yMin	= r.GetY() + r.GetHeight();
539 		int		yMax	= r.GetY();
540 
541 		//-------------------------------------------------
542 		double	zToDC	= (double)Width / (zMax - zMin);
543 
544 		double	dz		= pow(10., floor(log10(zMax - zMin)) - 1.);
545 		int	Decimals	= dz >= 1. ? 0 : (int)fabs(log10(dz));
546 
547 		wxSize	Extent	= dc.GetTextExtent(wxString::Format("%.*f", Decimals, zMax));
548 		int		dyFont	= RULER_TEXT_SPACE + Extent.y;
549 		int		dxFont	= RULER_TEXT_SPACE;
550 
551 		double	zDC		= 2 * Extent.x;
552 		while( zToDC * dz < zDC + RULER_TEXT_SPACE )
553 		{
554 			dz	*= 2;
555 		}
556 
557 		//-------------------------------------------------
558 		double	z		= dz * floor(zMin / dz);	if( z < zMin )	z	+= dz;
559 
560 		for(; z<=zMax; z+=dz)
561 		{
562 			zDC	= bAscendent ? zToDC * (z - zMin) : Width - zToDC * (z - zMin);
563 
564 			if( bHorizontal )
565 			{
566 				int	zPos	= (int)(xMin + zDC);
567 				dc.DrawLine(zPos, yMin, zPos, yMax);
568 				dc.DrawText(wxString::Format("%.*f", Decimals, z), zPos + dxFont, yMin - dyFont);
569 			}
570 			else
571 			{
572 				int	zPos	= (int)(yMin - zDC);
573 				dc.DrawLine(xMin, zPos, xMax, zPos);
574 				dc.DrawText(wxString::Format("%.*f", Decimals, z), xMin + dxFont, zPos - dyFont);
575 			}
576 		}
577 
578 		return( true );
579 	}
580 
581 	return( false );
582 }
583 
584 
585 ///////////////////////////////////////////////////////////
586 //														 //
587 //														 //
588 //														 //
589 ///////////////////////////////////////////////////////////
590 
591 //---------------------------------------------------------
592