Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

gradient_painter.cpp

00001 // gradient_painter.cpp
00002 
00003 // Copyright (C) 2004 Steven Weiß (steven11@gmx.de)
00004 //
00005 // Permission to copy, use, sell and distribute this software is granted
00006 // provided this copyright notice appears in all copies.
00007 // Permission to modify the code and to distribute modified code is granted
00008 // provided this copyright notice appears in all copies, and a notice
00009 // that the code was modified is included with the copyright notice.
00010 //
00011 // This software is provided "as is" without express or implied warranty,
00012 // and with no claim as to its suitability for any purpose.
00013 
00014 
00015 #include <background_wnd/painters/gradient_painter.hpp>
00016 #include <math.h>
00017 
00018 
00019 namespace win32 { namespace gui {
00020 
00021 namespace detail {
00022 
00024      // Helper functions & classes
00025 
00026      const double PI = 3.141592654;
00027 
00028      double degree_to_rad(double n)
00029      {    
00030           return PI / 180.0 * n;
00031      }
00032 
00033      double rad_to_degree(double n)
00034      {    
00035           return (180.0 / PI) * n;
00036      }
00037 
00038      class triangle
00039      {
00040      public:
00041           triangle() : alpha_(0), beta_(0), a_(0), b_(0), c_(0)
00042           {}
00043 
00044           void set_a(double a)
00045           {
00046                a_ = a;
00047           }
00048 
00049           void set_b(double b)
00050           {
00051                b_ = b;
00052           }
00053 
00054           void set_hypotenuse(double c)
00055           {
00056                c_ = c;
00057           }
00058 
00059           void set_alpha(double alpha)
00060           {
00061                alpha_ = alpha;
00062           }
00063 
00064           void set_beta(double beta)
00065           {
00066                beta_ = beta;
00067           }
00068 
00069           double get_a() const
00070           {
00071                if (a_)
00072                     return a_;
00073                else if (b_)
00074                     return leg_from_pythagoras(b_, get_hypotenuse());
00075                else if (c_ && alpha_)
00076                     return cos(degree_to_rad(alpha_)) / c_;
00077                else if (c_ && beta_)
00078                     return sin(degree_to_rad(beta_)) / c_;       
00079                return 0;
00080           }
00081 
00082           double get_b() const
00083           {
00084                if (b_)
00085                     return b_;
00086                else if (a_)
00087                     return leg_from_pythagoras(a_, get_hypotenuse());
00088                else if (c_ && alpha_)
00089                     return sin(degree_to_rad(alpha_)) / c_;
00090                else if (c_ && beta_)
00091                     return cos(degree_to_rad(beta_)) / c_;       
00092                return 0;
00093           }
00094 
00095           double get_hypotenuse() const
00096           {
00097                if (c_)
00098                     return c_;
00099                else if (a_ && b_)
00100                     return hypotenuse_from_pythagoras(a_, b_);
00101                else if (a_ && alpha_)
00102                     return a_ / cos(degree_to_rad(alpha_));
00103                else if (a_ && beta_)
00104                     return a_ / sin(degree_to_rad(beta_));
00105                else if (b_ && alpha_)             
00106                     return b_ / sin(degree_to_rad(alpha_));      
00107                else if (b_ && beta_)
00108                     return b_ / cos(degree_to_rad(beta_));                 
00109                return 0;
00110           }
00111 
00112           double get_alpha() const
00113           {
00114                if (alpha_)
00115                     return alpha_;
00116                if (beta_)
00117                     return 90 - beta_;
00118                double hypo = get_hypotenuse();
00119                if (a_ && hypo)
00120                     return rad_to_degree(acos(a_ / hypo));
00121                else if (b_ && hypo)
00122                     return rad_to_degree(asin(b_ / hypo));
00123                return 0;
00124           }
00125 
00126           double get_beta() const
00127           {
00128                if (beta_)
00129                     return beta_;
00130                if (alpha_)
00131                     return 90 - alpha_;
00132                double hypo = get_hypotenuse();
00133                if (a_ && hypo)               
00134                     return rad_to_degree(asin(a_ / hypo));                      
00135                else if (b_ && hypo)
00136                     return rad_to_degree(acos(b_ / hypo));
00137                return 0;
00138           }
00139 
00140 
00141 
00142      private:
00143           static double leg_from_pythagoras(double leg, double hypotenuse)
00144           {
00145                double leg_square = hypotenuse * hypotenuse - leg * leg;
00146                return sqrt(leg_square);
00147           }
00148 
00149           static double hypotenuse_from_pythagoras(double adj_leg, double opp_leg)
00150           {
00151                double hyp_square = adj_leg * adj_leg + opp_leg * opp_leg;
00152                return sqrt(hyp_square);
00153           }
00154 
00155           double alpha_;
00156           double beta_;
00157           
00158           double a_;
00159           double b_;
00160           double c_;          // hypotenuse
00161      };
00162 
00163 }    // namespace detail
00164 
00165 
00166 // ========================================================================================================= //
00167 // gradient_painter
00168 
00175 gradient_painter::gradient_painter(param0 colors, param1 angle) : colors_(colors), angle_(angle)
00176 {}
00177 
00178 gradient_painter* gradient_painter::clone() const
00179 {
00180      return new gradient_painter(*this);
00181 }
00182 
00183 void gradient_painter::draw(HDC hDC, int cx, int cy)
00184 {    
00185      if (cx == 0 || cy == 0)
00186           return;
00187 
00188      int r1 = GetRValue(colors_.first);
00189      int g1 = GetGValue(colors_.first);
00190      int b1 = GetBValue(colors_.first);
00191      int r2 = GetRValue(colors_.second);
00192      int g2 = GetGValue(colors_.second);
00193      int b2 = GetBValue(colors_.second);
00194 
00195      draw_linear (hDC, cx, cy, r1, g1, b1, r2, g2, b2);
00196 }
00197 
00198 // draws a linear gradient
00199 void gradient_painter::draw_linear(HDC hDC, int cx, int cy, int r1, int g1, int b1, int r2, int g2, int b2)
00200 {    
00201      double r, g, b;
00202      unsigned angle = angle_ % 360;               // normalize angle to 0° - 359°
00203      HPEN hOldPen = (HPEN) GetCurrentObject(hDC, OBJ_PEN);
00204 
00205      // vertical gradients
00206      if (angle % 180 == 0) {
00207           for (int x = 0; x < cx; ++x) {     
00208                // adjust colors if angle is 0°
00209                if (angle == 0) {
00210                     r = r1 + (x * (r2 - r1)) / cx;
00211                     g = g1 + (x * (g2 - g1)) / cx;
00212                     b = b1 + (x * (b2 - b1)) / cx;
00213                }
00214                // adjust colors if angle is 180°
00215                else {
00216                     r = r2 + (x * (r1 - r2)) / cx;
00217                     g = g2 + (x * (g1 - g2)) / cx;
00218                     b = b2 + (x * (b1 - b2)) / cx;
00219                }
00220                                              
00221                SelectObject( hDC, CreatePen(PS_SOLID, 1, RGB(r, g, b)) );
00222                MoveToEx(hDC, x, 0, NULL);         
00223                LineTo(hDC, x, cy);           
00224                DeleteObject( SelectObject(hDC, hOldPen) );
00225           }
00226      }
00227      // other angles
00228      else {         
00229           detail::triangle triangle;
00230           triangle.set_a(cx);
00231           triangle.set_beta(angle);
00232           double y_diff = triangle.get_b();
00233           double whole_cy = cy + y_diff;
00234           
00235           for (int y = 0; y <= whole_cy; ++y) {   
00236                // adjust colors if angle is less than 180°
00237                if (angle < 180) {
00238                     r = r1 + ( (whole_cy - y) * (r2 - r1) ) / whole_cy;
00239                     g = g1 + ( (whole_cy - y) * (g2 - g1) ) / whole_cy;
00240                     b = b1 + ( (whole_cy - y) * (b2 - b1) ) / whole_cy;
00241                }
00242                // adjust colors if angle greater than 180°
00243                else {
00244                     r = r2 + ( (whole_cy - y) * (r1 - r2) ) / whole_cy;
00245                     g = g2 + ( (whole_cy - y) * (g1 - g2) ) / whole_cy;
00246                     b = b2 + ( (whole_cy - y) * (b1 - b2) ) / whole_cy;
00247                }              
00248                     
00249                int y_from = (int) (y - y_diff);
00250                int y_to   = y;
00251 
00252                // rotate gradient if necessary
00253                if ( (angle / 90) % 2 == 1 )
00254                     std::swap(y_from, y_to);
00255                                    
00256                SelectObject( hDC, CreatePen(PS_SOLID, 1, RGB(r, g, b)) );
00257                MoveToEx(hDC, 0, y_from, NULL);         
00258                LineTo(hDC, cx, y_to);             
00259                DeleteObject( SelectObject(hDC, hOldPen) );
00260           }
00261      }
00262 }    
00263 
00264 
00265 bool gradient_painter::is_opaque(int, int) const
00266 {
00267      return true;
00268 }
00269 
00271 void gradient_painter::gradient_colors(const GradientColors& colors)
00272 {
00273      colors_ = colors;
00274 }
00275 
00277 gradient_painter::GradientColors gradient_painter::gradient_colors() const
00278 {
00279      return colors_;
00280 }
00281 
00283 void gradient_painter::angle(unsigned angle)
00284 {
00285      angle_ = angle;
00286 }
00287 
00289 unsigned gradient_painter::angle() const
00290 {
00291      return angle_;
00292 }
00293 
00295 gradient_painter::GradientColors gradient_painter::make_gradient_colors(COLORREF crStart, COLORREF crEnd)
00296 {
00297      return std::make_pair(crStart, crEnd);
00298 }
00299 
00300 } }  // namespace win32::gui

Generated on Mon Dec 27 15:30:11 2004 for background_wnd by  doxygen 1.3.9.1