home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / dcbase.cpp < prev    next >
C/C++ Source or Header  |  2001-12-04  |  16KB  |  547 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        common/dcbase.cpp
  3. // Purpose:     generic methods of the wxDC Class
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. // Created:     05/25/99
  7. // RCS-ID:      $Id: dcbase.cpp,v 1.15 2001/12/04 23:44:12 VS Exp $
  8. // Copyright:   (c) wxWindows team
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. #ifdef __GNUG__
  17.     #pragma implementation "dcbase.h"
  18. #endif
  19.  
  20. // ----------------------------------------------------------------------------
  21. // headers
  22. // ----------------------------------------------------------------------------
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.     #pragma hdrstop
  29. #endif
  30.  
  31. #include "wx/dc.h"
  32.  
  33. #include <math.h>
  34.  
  35. // bool wxDCBase::sm_cacheing = FALSE;
  36.  
  37. // ============================================================================
  38. // implementation
  39. // ============================================================================
  40.  
  41. // ----------------------------------------------------------------------------
  42. // special symbols
  43. // ----------------------------------------------------------------------------
  44.  
  45. void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
  46.                                wxCoord width, wxCoord height)
  47. {
  48.     wxCHECK_RET( Ok(), wxT("invalid window dc") );
  49.  
  50.     wxCoord x2 = x1 + width,
  51.             y2 = y1 + height;
  52.  
  53.     // this is to yield width of 3 for width == height == 10
  54.     SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID));
  55.  
  56.     // we're drawing a scaled version of wx/generic/tick.xpm here
  57.     wxCoord x3 = x1 + (4*width) / 10,   // x of the tick bottom
  58.             y3 = y1 + height / 2;       // y of the left tick branch
  59.     DoDrawLine(x1, y3, x3, y2);
  60.     DoDrawLine(x3, y2, x2, y1);
  61.  
  62.     CalcBoundingBox(x1, y1);
  63.     CalcBoundingBox(x2, y2);
  64. }
  65.  
  66. // ----------------------------------------------------------------------------
  67. // line/polygons
  68. // ----------------------------------------------------------------------------
  69.  
  70. void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
  71. {
  72.     int n = list->Number();
  73.     wxPoint *points = new wxPoint[n];
  74.  
  75.     int i = 0;
  76.     for ( wxNode *node = list->First(); node; node = node->Next(), i++ )
  77.     {
  78.         wxPoint *point = (wxPoint *)node->Data();
  79.         points[i].x = point->x;
  80.         points[i].y = point->y;
  81.     }
  82.  
  83.     DoDrawLines(n, points, xoffset, yoffset);
  84.  
  85.     delete [] points;
  86. }
  87.  
  88.  
  89. void wxDCBase::DrawPolygon(const wxList *list,
  90.                            wxCoord xoffset, wxCoord yoffset,
  91.                            int fillStyle)
  92. {
  93.     int n = list->Number();
  94.     wxPoint *points = new wxPoint[n];
  95.  
  96.     int i = 0;
  97.     for ( wxNode *node = list->First(); node; node = node->Next(), i++ )
  98.     {
  99.         wxPoint *point = (wxPoint *)node->Data();
  100.         points[i].x = point->x;
  101.         points[i].y = point->y;
  102.     }
  103.  
  104.     DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
  105.  
  106.     delete [] points;
  107. }
  108.  
  109. // ----------------------------------------------------------------------------
  110. // splines
  111. // ----------------------------------------------------------------------------
  112.  
  113. #if wxUSE_SPLINES
  114.  
  115. // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
  116. void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
  117. {
  118.     wxList point_list;
  119.  
  120.     wxPoint *point1 = new wxPoint;
  121.     point1->x = x1; point1->y = y1;
  122.     point_list.Append((wxObject*)point1);
  123.  
  124.     wxPoint *point2 = new wxPoint;
  125.     point2->x = x2; point2->y = y2;
  126.     point_list.Append((wxObject*)point2);
  127.  
  128.     wxPoint *point3 = new wxPoint;
  129.     point3->x = x3; point3->y = y3;
  130.     point_list.Append((wxObject*)point3);
  131.  
  132.     DrawSpline(&point_list);
  133.  
  134.     for( wxNode *node = point_list.First(); node; node = node->Next() )
  135.     {
  136.         wxPoint *p = (wxPoint *)node->Data();
  137.         delete p;
  138.     }
  139. }
  140.  
  141. void wxDCBase::DrawSpline(int n, wxPoint points[])
  142. {
  143.     wxList list;
  144.     for (int i =0; i < n; i++)
  145.     {
  146.         list.Append((wxObject*)&points[i]);
  147.     }
  148.  
  149.     DrawSpline(&list);
  150. }
  151.  
  152. // ----------------------------------- spline code ----------------------------------------
  153.  
  154. void wx_quadratic_spline(double a1, double b1, double a2, double b2,
  155.                          double a3, double b3, double a4, double b4);
  156. void wx_clear_stack();
  157. int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
  158.         double *y3, double *x4, double *y4);
  159. void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
  160.           double x4, double y4);
  161. static bool wx_spline_add_point(double x, double y);
  162. static void wx_spline_draw_point_array(wxDCBase *dc);
  163.  
  164. wxList wx_spline_point_list;
  165.  
  166. #define                half(z1, z2)        ((z1+z2)/2.0)
  167. #define                THRESHOLD        5
  168.  
  169. /* iterative version */
  170.  
  171. void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
  172.                  double b4)
  173. {
  174.     register double  xmid, ymid;
  175.     double           x1, y1, x2, y2, x3, y3, x4, y4;
  176.  
  177.     wx_clear_stack();
  178.     wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
  179.  
  180.     while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
  181.         xmid = (double)half(x2, x3);
  182.         ymid = (double)half(y2, y3);
  183.         if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
  184.             fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
  185.             wx_spline_add_point( x1, y1 );
  186.             wx_spline_add_point( xmid, ymid );
  187.         } else {
  188.             wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
  189.                  (double)half(x3, x4), (double)half(y3, y4), x4, y4);
  190.             wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
  191.                  (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
  192.         }
  193.     }
  194. }
  195.  
  196. /* utilities used by spline drawing routines */
  197.  
  198. typedef struct wx_spline_stack_struct {
  199.     double           x1, y1, x2, y2, x3, y3, x4, y4;
  200. } Stack;
  201.  
  202. #define         SPLINE_STACK_DEPTH             20
  203. static Stack    wx_spline_stack[SPLINE_STACK_DEPTH];
  204. static Stack   *wx_stack_top;
  205. static int      wx_stack_count;
  206.  
  207. void wx_clear_stack()
  208. {
  209.     wx_stack_top = wx_spline_stack;
  210.     wx_stack_count = 0;
  211. }
  212.  
  213. void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
  214. {
  215.     wx_stack_top->x1 = x1;
  216.     wx_stack_top->y1 = y1;
  217.     wx_stack_top->x2 = x2;
  218.     wx_stack_top->y2 = y2;
  219.     wx_stack_top->x3 = x3;
  220.     wx_stack_top->y3 = y3;
  221.     wx_stack_top->x4 = x4;
  222.     wx_stack_top->y4 = y4;
  223.     wx_stack_top++;
  224.     wx_stack_count++;
  225. }
  226.  
  227. int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
  228.                   double *x3, double *y3, double *x4, double *y4)
  229. {
  230.     if (wx_stack_count == 0)
  231.         return (0);
  232.     wx_stack_top--;
  233.     wx_stack_count--;
  234.     *x1 = wx_stack_top->x1;
  235.     *y1 = wx_stack_top->y1;
  236.     *x2 = wx_stack_top->x2;
  237.     *y2 = wx_stack_top->y2;
  238.     *x3 = wx_stack_top->x3;
  239.     *y3 = wx_stack_top->y3;
  240.     *x4 = wx_stack_top->x4;
  241.     *y4 = wx_stack_top->y4;
  242.     return (1);
  243. }
  244.  
  245. static bool wx_spline_add_point(double x, double y)
  246. {
  247.   wxPoint *point = new wxPoint ;
  248.   point->x = (int) x;
  249.   point->y = (int) y;
  250.   wx_spline_point_list.Append((wxObject*)point);
  251.   return TRUE;
  252. }
  253.  
  254. static void wx_spline_draw_point_array(wxDCBase *dc)
  255. {
  256.   dc->DrawLines(&wx_spline_point_list, 0, 0 );
  257.   wxNode *node = wx_spline_point_list.First();
  258.   while (node)
  259.   {
  260.     wxPoint *point = (wxPoint *)node->Data();
  261.     delete point;
  262.     delete node;
  263.     node = wx_spline_point_list.First();
  264.   }
  265. }
  266.  
  267. void wxDCBase::DoDrawSpline( wxList *points )
  268. {
  269.     wxCHECK_RET( Ok(), wxT("invalid window dc") );
  270.  
  271.     wxPoint *p;
  272.     double           cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  273.     double           x1, y1, x2, y2;
  274.  
  275.     wxNode *node = points->First();
  276.     p = (wxPoint *)node->Data();
  277.  
  278.     x1 = p->x;
  279.     y1 = p->y;
  280.  
  281.     node = node->Next();
  282.     p = (wxPoint *)node->Data();
  283.  
  284.     x2 = p->x;
  285.     y2 = p->y;
  286.     cx1 = (double)((x1 + x2) / 2);
  287.     cy1 = (double)((y1 + y2) / 2);
  288.     cx2 = (double)((cx1 + x2) / 2);
  289.     cy2 = (double)((cy1 + y2) / 2);
  290.  
  291.     wx_spline_add_point(x1, y1);
  292.  
  293.     while ((node = node->Next()) != NULL)
  294.     {
  295.         p = (wxPoint *)node->Data();
  296.         x1 = x2;
  297.         y1 = y2;
  298.         x2 = p->x;
  299.         y2 = p->y;
  300.         cx4 = (double)(x1 + x2) / 2;
  301.         cy4 = (double)(y1 + y2) / 2;
  302.         cx3 = (double)(x1 + cx4) / 2;
  303.         cy3 = (double)(y1 + cy4) / 2;
  304.  
  305.         wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
  306.  
  307.         cx1 = cx4;
  308.         cy1 = cy4;
  309.         cx2 = (double)(cx1 + x2) / 2;
  310.         cy2 = (double)(cy1 + y2) / 2;
  311.     }
  312.  
  313.     wx_spline_add_point( cx1, cy1 );
  314.     wx_spline_add_point( x2, y2 );
  315.  
  316.     wx_spline_draw_point_array( this );
  317. }
  318.  
  319. #endif // wxUSE_SPLINES
  320.  
  321. // ----------------------------------------------------------------------------
  322. // enhanced text drawing
  323. // ----------------------------------------------------------------------------
  324.  
  325. void wxDCBase::GetMultiLineTextExtent(const wxString& text,
  326.                                       wxCoord *x,
  327.                                       wxCoord *y,
  328.                                       wxCoord *h,
  329.                                       wxFont *font)
  330. {
  331.     wxCoord widthTextMax = 0, widthLine,
  332.             heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
  333.  
  334.     wxString curLine;
  335.     for ( const wxChar *pc = text; ; pc++ )
  336.     {
  337.         if ( *pc == _T('\n') || *pc == _T('\0') )
  338.         {
  339.             if ( curLine.empty() )
  340.             {
  341.                 // we can't use GetTextExtent - it will return 0 for both width
  342.                 // and height and an empty line should count in height
  343.                 // calculation
  344.  
  345.                 // assume that this line has the same height as the previous
  346.                 // one
  347.                 if ( !heightLineDefault )
  348.                     heightLineDefault = heightLine;
  349.  
  350.                 if ( !heightLineDefault )
  351.                 {
  352.                     // but we don't know it yet - choose something reasonable
  353.                     GetTextExtent(_T("W"), NULL, &heightLineDefault,
  354.                                   NULL, NULL, font);
  355.                 }
  356.  
  357.                 heightTextTotal += heightLineDefault;
  358.             }
  359.             else
  360.             {
  361.                 GetTextExtent(curLine, &widthLine, &heightLine,
  362.                               NULL, NULL, font);
  363.                 if ( widthLine > widthTextMax )
  364.                     widthTextMax = widthLine;
  365.                 heightTextTotal += heightLine;
  366.             }
  367.  
  368.             if ( *pc == _T('\n') )
  369.             {
  370.                curLine.clear();
  371.             }
  372.             else
  373.             {
  374.                // the end of string
  375.                break;
  376.             }
  377.         }
  378.         else
  379.         {
  380.             curLine += *pc;
  381.         }
  382.     }
  383.  
  384.     if ( x )
  385.         *x = widthTextMax;
  386.     if ( y )
  387.         *y = heightTextTotal;
  388.     if ( h )
  389.         *h = heightLine;
  390. }
  391.  
  392. void wxDCBase::DrawLabel(const wxString& text,
  393.                          const wxBitmap& bitmap,
  394.                          const wxRect& rect,
  395.                          int alignment,
  396.                          int indexAccel,
  397.                          wxRect *rectBounding)
  398. {
  399.     // find the text position
  400.     wxCoord widthText, heightText, heightLine;
  401.     GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
  402.  
  403.     wxCoord width, height;
  404.     if ( bitmap.Ok() )
  405.     {
  406.         width = widthText + bitmap.GetWidth();
  407.         height = bitmap.GetHeight();
  408.     }
  409.     else // no bitmap
  410.     {
  411.         width = widthText;
  412.         height = heightText;
  413.     }
  414.  
  415.     wxCoord x, y;
  416.     if ( alignment & wxALIGN_RIGHT )
  417.     {
  418.         x = rect.GetRight() - width;
  419.     }
  420.     else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
  421.     {
  422.         x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
  423.     }
  424.     else // alignment & wxALIGN_LEFT
  425.     {
  426.         x = rect.GetLeft();
  427.     }
  428.  
  429.     if ( alignment & wxALIGN_BOTTOM )
  430.     {
  431.         y = rect.GetBottom() - height;
  432.     }
  433.     else if ( alignment & wxALIGN_CENTRE_VERTICAL )
  434.     {
  435.         y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
  436.     }
  437.     else // alignment & wxALIGN_TOP
  438.     {
  439.         y = rect.GetTop();
  440.     }
  441.  
  442.     // draw the bitmap first
  443.     wxCoord x0 = x,
  444.             y0 = y,
  445.             width0 = width;
  446.     if ( bitmap.Ok() )
  447.     {
  448.         DrawBitmap(bitmap, x, y, TRUE /* use mask */);
  449.  
  450.         wxCoord offset = bitmap.GetWidth() + 4;
  451.         x += offset;
  452.         width -= offset;
  453.  
  454.         y += (height - heightText) / 2;
  455.     }
  456.  
  457.     // we will draw the underscore under the accel char later
  458.     wxCoord startUnderscore = 0,
  459.             endUnderscore = 0,
  460.             yUnderscore = 0;
  461.  
  462.     // split the string into lines and draw each of them separately
  463.     wxString curLine;
  464.     for ( const wxChar *pc = text; ; pc++ )
  465.     {
  466.         if ( *pc == _T('\n') || *pc == _T('\0') )
  467.         {
  468.             int xRealStart = x; // init it here to avoid compielr warnings
  469.  
  470.             if ( !curLine.empty() )
  471.             {
  472.                 // NB: can't test for !(alignment & wxALIGN_LEFT) because
  473.                 //     wxALIGN_LEFT is 0
  474.                 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
  475.                 {
  476.                     wxCoord widthLine;
  477.                     GetTextExtent(curLine, &widthLine, NULL);
  478.  
  479.                     if ( alignment & wxALIGN_RIGHT )
  480.                     {
  481.                         xRealStart += width - widthLine;
  482.                     }
  483.                     else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
  484.                     {
  485.                         xRealStart += (width - widthLine) / 2;
  486.                     }
  487.                 }
  488.                 //else: left aligned, nothing to do
  489.  
  490.                 DrawText(curLine, xRealStart, y);
  491.             }
  492.  
  493.             y += heightLine;
  494.  
  495.             // do we have underscore in this line? we can check yUnderscore
  496.             // because it is set below to just y + heightLine if we do
  497.             if ( y == yUnderscore )
  498.             {
  499.                 // adjust the horz positions to account for the shift
  500.                 startUnderscore += xRealStart;
  501.                 endUnderscore += xRealStart;
  502.             }
  503.  
  504.             if ( *pc == _T('\0') )
  505.                 break;
  506.  
  507.             curLine.clear();
  508.         }
  509.         else // not end of line
  510.         {
  511.             if ( pc - text.c_str() == indexAccel )
  512.             {
  513.                 // remeber to draw underscore here
  514.                 GetTextExtent(curLine, &startUnderscore, NULL);
  515.                 curLine += *pc;
  516.                 GetTextExtent(curLine, &endUnderscore, NULL);
  517.  
  518.                 yUnderscore = y + heightLine;
  519.             }
  520.             else
  521.             {
  522.                 curLine += *pc;
  523.             }
  524.         }
  525.     }
  526.  
  527.     // draw the underscore if found
  528.     if ( startUnderscore != endUnderscore )
  529.     {
  530.         // it should be of the same colour as text
  531.         SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
  532.  
  533.         yUnderscore--;
  534.  
  535.         DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
  536.     }
  537.  
  538.     // return bounding rect if requested
  539.     if ( rectBounding )
  540.     {
  541.         *rectBounding = wxRect(x, y - heightText, widthText, heightText);
  542.     }
  543.  
  544.     CalcBoundingBox(x0, y0);
  545.     CalcBoundingBox(x0 + width0, y0 + height);
  546. }
  547.