00001 /* 00002 libwt - Vassilis Virvilis Toolkit - a widget library 00003 Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm> 00004 Copyright (C) 2002 Malcolm Walker <malcolm@worldforge.org> 00005 Based on code copyright (C) 1999-2002 Karsten Laux 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2.1 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the 00019 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00020 Boston, MA 02111-1307, SA. 00021 */ 00022 // originally written by Karsten Laux, June 1999 00023 00024 #include <wt/painter.h> 00025 #include <wt/pixmap.h> 00026 #include <wt/color.h> 00027 #include <wt/rect.h> 00028 #include <wt/region.h> 00029 #include <wt/rootwindow.h> 00030 #include <wt/trace.h> 00031 00032 namespace Wt { 00033 00034 Painter::Painter(const Pixmap* pixmap, bool clipping) : 00035 active_(false), 00036 pixmap_(const_cast<Pixmap *>(pixmap)) { 00037 begin(pixmap_, clipping); 00038 } 00039 00040 Painter::~Painter() { 00041 end(); 00042 } 00043 00044 bool Painter::begin(const Pixmap* pixmap, bool clipping) { 00045 bool status = false; 00046 if (!active_) { 00047 pixmap_ = const_cast<Pixmap *>(pixmap); 00048 if (pixmap_ && *pixmap_) { 00049 setClipping(clipping); 00050 active_ = true; 00051 status = true; 00052 } 00053 } 00054 return status; 00055 } 00056 00057 bool Painter::begin() { 00058 return begin(pixmap_); 00059 } 00060 00061 bool Painter::end() { 00062 bool status = false; 00063 if (active_) { 00064 while (!state_stack.empty()) { 00065 restore(); 00066 } 00067 active_ = false; 00068 status = true; 00069 } 00070 return status; 00071 } 00072 00073 bool Painter::isActive () const { 00074 return active_; 00075 } 00076 00077 bool Painter::isClipped(int x, int y) const { 00078 return !isActive() || (state.clipping && !pixmap_->rect().contains(x, y)); 00079 } 00080 00081 bool Painter::isClipped(const Point& p) const { 00082 return isClipped(p.x(), p.y()); 00083 } 00084 00085 void Painter::rop(int pixel_offset, int pixel) { 00086 switch(state.raster_op) { 00087 case CopyROP: 00088 pixmap_->setPixel(pixel_offset, pixel); 00089 break; 00090 case XorROP: 00091 pixel = pixel ^ pixmap_->pixel(pixel_offset); 00092 pixmap_->setPixel(pixel_offset, pixel); 00093 break; 00094 case AndROP: 00095 pixel = pixel & pixmap_->pixel(pixel_offset); 00096 pixmap_->setPixel(pixel_offset, pixel); 00097 break; 00098 case OrROP: 00099 pixel = pixel | pixmap_->pixel(pixel_offset); 00100 pixmap_->setPixel(pixel_offset, pixel); 00101 break; 00102 default: 00103 Warn("Unknown Raster Operation %d\n", state.raster_op); 00104 pixmap_->setPixel(pixel_offset, pixel); 00105 break; 00106 } 00107 } 00108 00109 void Painter::drawPoint(int x, int y) { 00110 if (!isClipped(x, y)) { 00111 int pixel_offset = pixmap_->pixelOffset(x, y); 00112 int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color()); 00113 00114 pixmap_->lock() 00115 ; 00116 rop(pixel_offset, pixel); 00117 pixmap_->unlock(); 00118 } 00119 } 00120 00121 void Painter::drawPoint(const Point& p) { 00122 drawPoint(p.x(), p.y()); 00123 } 00124 00125 void Painter::drawPoints(const PointArray& points, int start, int end) { 00126 int i; 00127 int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color()); 00128 00129 end = (end > 0) ? end : points.size(); 00130 00131 pixmap_->lock() 00132 ; 00133 for (i = start; i < end; i++) { 00134 const Point& p = points[i]; 00135 if (!isClipped(p)) { 00136 int pixel_offset = pixmap_->pixelOffset(p.x(), p.y()); 00137 rop(pixel_offset, pixel); 00138 } 00139 } 00140 pixmap_->unlock(); 00141 } 00142 00143 void Painter::drawHorizontalLine(int x1, int x2, int y) { 00144 if(!isActive() || y < 0 || y >= pixmap_->height()) 00145 return; 00146 00147 int w = pixmap_->width(); 00148 00149 if (state.clipping) { 00150 x1 = std::max(0, x1); 00151 x1 = std::min(x1, w - 1); 00152 x2 = std::max(0, x2); 00153 x2 = std::min(x2, w - 1); 00154 } 00155 00156 if (x1 > x2) 00157 std::swap(x1, x2); 00158 00159 int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color()); 00160 int pixel_offset = pixmap_->pixelOffset(x1, y); 00161 int skip = pixmap_->pixelFormat().bytesPerPixel(); 00162 00163 pixmap_->lock() 00164 ; 00165 while(x1 <= x2) { 00166 rop(pixel_offset, pixel); 00167 x1++; 00168 pixel_offset += skip; 00169 } 00170 pixmap_->unlock(); 00171 00172 } 00173 00174 void Painter::drawVerticalLine(int x, int y1, int y2) { 00175 if(!isActive() || x < 0 || x >= pixmap_->width()) 00176 return; 00177 00178 int h = pixmap_->height(); 00179 00180 if (state.clipping) { 00181 y1 = std::max(0, y1); 00182 y1 = std::min(y1, h - 1); 00183 y2 = std::max(0, y2); 00184 y2 = std::min(y2, h - 1); 00185 } 00186 00187 if (y1 > y2) 00188 std::swap(y1, y2); 00189 00190 int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color()); 00191 int pixel_offset = pixmap_->pixelOffset(x, y1); 00192 int skip = pixmap_->bytesPerLine(); 00193 00194 pixmap_->lock() 00195 ; 00196 while(y1 <= y2) { 00197 rop(pixel_offset, pixel); 00198 y1++; 00199 pixel_offset += skip; 00200 } 00201 pixmap_->unlock(); 00202 } 00203 00204 void Painter::drawLine(int x1, int y1, int x2, int y2) { 00205 if(!isActive()) 00206 return; 00207 00208 int dx, dy, sdx, sdy, x, y, px, py; 00209 00210 dx = x2 - x1; 00211 dy = y2 - y1; 00212 00213 //check if we may optimize to either vLine or hLine ... 00214 if(dx == 0) { 00215 //this is a vertical line, call vLine and return 00216 drawVerticalLine(x1, y1, y2); 00217 return; 00218 } 00219 if(dy == 0) { 00220 //this is a horizontal line, call hLine and return 00221 drawHorizontalLine(x1, x2, y1); 00222 return; 00223 } 00224 00225 // if clipping is enabled x1, y1, x2, y2 are the clipped values 00226 if (state.clipping && !pixmap_->rect().clipLine(x1, y1, x2, y2)) { 00227 dx = x2 - x1; 00228 dy = y2 - y1; 00229 return; 00230 } 00231 00232 // here comes the hard job ... bresenham: 00233 00234 sdx = (dx < 0) ? -1 : 1; 00235 sdy = (dy < 0) ? -1 : 1; 00236 00237 dx = sdx * dx + 1; 00238 dy = sdy * dy + 1; 00239 00240 x = y = 0; 00241 00242 px = x1; 00243 py = y1; 00244 00245 // map the color to the appropriate bit pattern to write ... 00246 int pixel = pixmap_->pixelFormat().mapToPixelValue(state.pen.color()); 00247 int pixel_offset; 00248 00249 /// \todo the calculation of the pixel_offset could be reduced to addings ... 00250 /// no multiplies are needed in fact 00251 pixmap_->lock() 00252 ; 00253 if (dx >= dy) { 00254 for (x = 0; x < dx; x++) { 00255 pixel_offset = pixmap_->pixelOffset(px, py); 00256 rop(pixel_offset, pixel); 00257 00258 y += dy; 00259 if (y >= dx) { 00260 y -= dx; 00261 py += sdy; 00262 } 00263 px += sdx; 00264 } 00265 } else { 00266 for (y = 0; y < dy; y++) { 00267 pixel_offset = pixmap_->pixelOffset(px, py); 00268 rop(pixel_offset, pixel); 00269 00270 x += dx; 00271 if (x >= dy) { 00272 x -= dy; 00273 px += sdx; 00274 } 00275 py += sdy; 00276 } 00277 } 00278 pixmap_->unlock(); 00279 } 00280 00281 void Painter::drawLine(const Point& p1, const Point& p2) { 00282 drawLine(p1.x(), p1.y(), p2.x(), p2.y()); 00283 } 00284 00285 void Painter::fillRect(const Rect& r, const Brush& brush) { 00286 if (brush.style() == Brush::NoBrush) 00287 return; 00288 00289 pixmap_->fill(r, brush.color()); 00290 } 00291 00292 void Painter::fillRect(int x, int y, int w, int h, const Brush& brush) { 00293 fillRect(Rect(x, y, w, h), brush); 00294 } 00295 00296 void Painter::fillRegion(const Region& r, const Brush& brush) { 00297 if (brush.style() == Brush::NoBrush) 00298 return; 00299 00300 pixmap_->fill(r, brush.color()); 00301 } 00302 00303 void Painter::blendRect(const Rect& r, const Brush& brush) { 00304 if (brush.style() == Brush::NoBrush) 00305 return; 00306 00307 pixmap_->blend(r, brush.color()); 00308 } 00309 00310 void Painter::blendRect(int x, int y, int w, int h, const Brush& brush) { 00311 blendRect(Rect(x, y, w, h), brush); 00312 } 00313 00314 void Painter::blendRegion(const Region& r, const Brush& brush) { 00315 if (brush.style() == Brush::NoBrush) 00316 return; 00317 00318 pixmap_->blend(r, brush.color()); 00319 } 00320 00321 void Painter::eraseRect(const Rect& r) { 00322 fillRect(r, state.bg_color); 00323 } 00324 00325 void Painter::eraseRect(int x, int y, int w, int h) { 00326 eraseRect(Rect(x, y, w, h)); 00327 } 00328 00329 void Painter::eraseRegion(const Region& r) { 00330 fillRegion(r, state.bg_color); 00331 } 00332 00333 void Painter::drawRect(int x, int y, int w, int h) { 00334 int x2 = x + w - 1; 00335 int y2 = y + h - 1; 00336 00337 drawHorizontalLine(x, x2, y); 00338 drawVerticalLine(x, y, y2); 00339 drawHorizontalLine(x, x2, y2); 00340 drawVerticalLine(x2, y, y2); 00341 00342 if (state.brush.style() != Brush::NoBrush) { 00343 fillRect(x + 1, y + 1, w - 1, h - 1, state.brush); 00344 } 00345 } 00346 00347 void Painter::drawRect(const Rect& r) { 00348 drawRect(r.left(), r.top(), r.width(), r.height()); 00349 } 00350 00351 void Painter::drawLineSegments(const PointArray& points, int start, int end) { 00352 int i; 00353 end = (end > 0) ? end : points.size(); 00354 00355 for (i = start; i < end - 1; i += 2) { 00356 drawLine(points[i], points[i + 1]); 00357 } 00358 } 00359 00360 void Painter::drawPolyline(const PointArray& points, int start, int end) { 00361 int i; 00362 end = (end > 0) ? end : points.size(); 00363 00364 for (i = start; i < end; i++) { 00365 drawLine(points[i], points[i + 1]); 00366 } 00367 } 00368 00369 void Painter::drawPolygon(const PointArray& points, int start, int end) { 00370 int i; 00371 end = (end > 0) ? end : points.size(); 00372 00373 for (i = start; i < end; i++) { 00374 drawLine(points[i], points[i + 1 % end]); 00375 } 00376 00377 if (state.brush.style() != Brush::NoBrush) { 00378 /// \todo we have to actually fill the damn thing 00379 } 00380 } 00381 00382 void Painter::drawPixmap(const Point& p, const Pixmap& src, const Rect& sr) { 00383 pixmap_->blit(p.x(), p.y(), src, sr); 00384 } 00385 00386 void Painter::drawPixmap(const Point& p, const Pixmap& src) { 00387 pixmap_->blit(p.x(), p.y(), src); 00388 } 00389 00390 void Painter::drawPixmap(int x, int y, const Pixmap& src, int sx, int sy, int sw, int sh) { 00391 pixmap_->blit(x, y, src, Rect(sx, sy, sw, sh)); 00392 } 00393 00394 void Painter::drawPixmap(const Rect& r, const Pixmap& src) { 00395 pixmap_->blit(r.topLeft(), src.scale(r.size())); 00396 } 00397 00398 void Painter::drawTiledPixmap(const Rect& r, 00399 const Pixmap& src, const Point& sp) { 00400 00401 int src_w = src.width(); 00402 int src_h = src.height(); 00403 int dst_w = r.width(); 00404 int dst_h = r.height(); 00405 int x, y, w; 00406 int h = src_h - sp.y(); 00407 Rect dst_rect(0, 0, 0, h); 00408 Rect src_rect(sp, Size(0, h)); 00409 00410 trace("painter") << "Tiling a " << Size(src_w, src_h) 00411 << " background onto a " << Size(dst_w, dst_h) << " surface" << std::endl; 00412 00413 for(y = r.top(); y <= r.bottom(); y += h) { 00414 dst_rect.setY(y); 00415 w = src_w - sp.x(); 00416 dst_rect.setWidth(w); 00417 src_rect.setWidth(w); 00418 for(x = r.left(); x <= r.right(); x += w) { 00419 dst_rect.setX(x); 00420 trace("painter") << "Blitting tile at " << dst_rect.topLeft() << std::endl; 00421 pixmap_->blit(dst_rect.topLeft(), src, src_rect); 00422 w = src_w; 00423 dst_rect.setWidth(w); 00424 src_rect.setWidth(w); 00425 } 00426 h = src_h; 00427 dst_rect.setHeight(h); 00428 src_rect.setHeight(h); 00429 } 00430 } 00431 00432 void Painter::drawTiledPixmap(const Rect& r, const Pixmap& src) { 00433 drawTiledPixmap(r, src, Point(0, 0)); 00434 } 00435 00436 void Painter::drawTiledPixmap(int x, int y, int w, int h, 00437 const Pixmap& src, int sx, int sy) { 00438 drawTiledPixmap(Rect(x, y, w, h), src, Point(sx, sy)); 00439 } 00440 00441 void Painter::drawText(const Point& p, const std::string& text, int len) { 00442 const std::string& t = (len == -1) ? text : text.substr(0, len); 00443 const Point p1 = p - Point(0, state.font.ascent()); 00444 00445 if (state.bg_color.alpha() != Color::Transparent) { 00446 pixmap_->blit(p1, state.font.blitText(t)); 00447 } else { 00448 pixmap_->blitAlphaCopy(p1, state.font.blitText(t)); 00449 } 00450 } 00451 00452 void Painter::drawText(int x, int y, const std::string& text, int len) { 00453 drawText(Point(x, y), text, len); 00454 } 00455 00456 void Painter::drawText(const Point& p, 00457 const std::string& text, int pos, int len) { 00458 len = (len - 1) ? text.length() : len; 00459 const std::string& t = text.substr(pos, len); 00460 drawText(p, t); 00461 } 00462 00463 void Painter::drawText(int x, int y, 00464 const std::string& text, int pos, int len) { 00465 drawText(Point(x, y), text, pos, len); 00466 } 00467 00468 Rect Painter::boundingRect(const std::string& text, int pos, int len) { 00469 len = (len - 1) ? text.length() : len; 00470 return state.font.boundingRect(text.substr(pos, len)); 00471 } 00472 00473 #if 0 00474 00475 void 00476 Painter::circle(const Point& c, unsigned int r, unsigned int t) { 00477 if(fill_) 00478 ellipseFill(c,r,r); 00479 else 00480 ellipse(c,r,r,t); 00481 } 00482 00483 void 00484 Painter::ellipse(const Point& c, 00485 unsigned int rx, unsigned int ry, unsigned int t) { 00486 if(!pixmap_ || pixmap_->empty()) 00487 return; 00488 if(rx == 0 || ry == 0) 00489 return; 00490 00491 if(fill_) { 00492 ellipseFill(c,rx,ry); 00493 return; 00494 } 00495 00496 int steps = 3 * (rx > ry) ? rx : ry; 00497 00498 float alpha = 0; 00499 float delta = M_PI/2/steps; 00500 00501 Point p; 00502 Point v; 00503 int pixel_offset; 00504 00505 int pixel = pixmap_->pixelformat().mapToPixel(color_); 00506 00507 pixmap_->lock() 00508 ; 00509 00510 while(steps > 0) { 00511 v.x = (int)(rx * cos(alpha)); 00512 v.y = (int)(ry * sin(alpha)); 00513 00514 p.x = c.x + v.x; 00515 p.y = c.y + v.y; 00516 00517 if(Rect(0,0, pixmap_->width(), pixmap_->height()).contains(p)) { 00518 pixel_offset=pixmap_->pixelformat().bpp()*p.x +pixmap_->pitch()*p.y; 00519 for(unsigned int i=0; i < t; i++) { 00520 writePixel(pixel_offset, pixel); 00521 pixel_offset++; 00522 } 00523 } 00524 00525 v.x = -v.x; 00526 p.x = c.x + v.x; 00527 00528 if(Rect(0,0, pixmap_->width(), pixmap_->height()).contains(p)) { 00529 pixel_offset=pixmap_->pixelformat().bpp()*p.x +surface_->pitch()*p.y; 00530 for(unsigned int i=0; i < t; i++) { 00531 writePixel(pixel_offset, pixel); 00532 pixel_offset++; 00533 } 00534 } 00535 00536 v.y = -v.y; 00537 p.y = c.y + v.y; 00538 if(Rect(0,0, surface_->width(), surface_->height()).contains(p)) { 00539 pixel_offset=surface_->pixelformat().bpp()*p.x +surface_->pitch()*p.y; 00540 for(unsigned int i=0; i < t; i++) { 00541 writePixel(pixel_offset, pixel); 00542 pixel_offset++; 00543 } 00544 } 00545 00546 v.x = -v.x; 00547 p.x = c.x + v.x; 00548 if(Rect(0,0, surface_->width(), surface_->height()).contains(p)) { 00549 pixel_offset=surface_->pixelformat().bpp()*p.x +surface_->pitch()*p.y; 00550 for(unsigned int i=0; i < t; i++) { 00551 writePixel(pixel_offset, pixel); 00552 pixel_offset++; 00553 } 00554 } 00555 00556 alpha = alpha + delta; 00557 steps--; 00558 } 00559 00560 00561 surface_->unlock(); 00562 } 00563 00564 00565 void 00566 Painter::ellipseFill(const Point& c, 00567 unsigned int rx, unsigned int ry) { 00568 if(!surface_ || surface_->empty()) 00569 return; 00570 if(rx == 0 || ry == 0) 00571 return; 00572 unsigned int steps = 0; 00573 00574 Point p1; 00575 Point p2; 00576 Point v; 00577 00578 while(steps < ry) { 00579 00580 v.x = (int)(rx * cos(asin((double)steps/ry))); 00581 00582 p1.x = c.x - v.x; 00583 p1.y = c.y - steps; 00584 00585 p2.x = c.x + v.x; 00586 p2.y = c.y - steps; 00587 00588 hLine(p1,p2,color_); 00589 00590 00591 p1.x = c.x - v.x; 00592 p1.y = c.y + steps; 00593 00594 p2.x = c.x + v.x; 00595 p2.y = c.y + steps; 00596 00597 hLine(p1,p2,color_); 00598 00599 steps++; 00600 } 00601 } 00602 00603 #endif 00604 00605 } //namespace Wt
This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.