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