00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #pragma once
00018 #include <background_wnd/detail/include.hpp>
00019 #include <background_wnd/background_wnd.hpp>
00020
00021 #include <win32gui/window.hpp>
00022 #include <win32gui/event_handler.hpp>
00023
00024
00025 namespace win32 { namespace gui {
00026
00027
00028
00029
00030
00061
00062
00063
00064
00065 background_wnd::background_wnd() : cr_bkgnd_(RGB(255, 255, 255)), bRedraw_on_changes_(true), next_index_(0)
00066 {}
00067
00069 void background_wnd::bk_color(COLORREF cr)
00070 {
00071 if (cr != cr_bkgnd_) {
00072 cr_bkgnd_ = cr;
00073 if (bRedraw_on_changes_)
00074 redraw_painters();
00075 }
00076 }
00077
00079 COLORREF background_wnd::bk_color() const
00080 {
00081 return cr_bkgnd_;
00082 }
00083
00085 unsigned background_wnd::add_painter(const painter_base& painter)
00086 {
00087 return add_raw_painter(painter.clone());
00088 }
00089
00093 void background_wnd::delete_painter(unsigned idx)
00094 {
00095 coll_painters_.erase( find_painter_info_iterator(idx) );
00096 if (bRedraw_on_changes_)
00097 redraw_painters();
00098 }
00099
00101 void background_wnd::delete_all_painters()
00102 {
00103 coll_painters_.clear();
00104 if (bRedraw_on_changes_)
00105 redraw_painters();
00106 }
00107
00111 painter_base& background_wnd::get_painter(unsigned idx) const
00112 {
00113 return find_painter_info(idx).get_painter();
00114 }
00115
00116
00121 std::vector<unsigned> background_wnd::get_indices() const
00122 {
00123 std::vector<unsigned> indices;
00124 indices.reserve(coll_painters_.size());
00125 for (iterator it = coll_painters_.begin(); it != coll_painters_.end(); ++it)
00126 indices.push_back( (*it)->idx_ );
00127 return indices;
00128 }
00129
00138 void background_wnd::drawing_rect(unsigned idx, const rectangle& rc)
00139 {
00140 find_painter_info(idx).rc_drawing_ = rc;
00141 if (bRedraw_on_changes_)
00142 redraw_painters();
00143 }
00144
00150 rectangle background_wnd::drawing_rect(unsigned idx) const
00151 {
00152 return find_painter_info(idx).rc_drawing_;
00153 }
00154
00158 bool background_wnd::is_painter_visible(unsigned idx) const
00159 {
00160 return find_painter_info(idx).bVisible_;
00161 }
00162
00166 void background_wnd::show_painter(unsigned idx, bool bVisible)
00167 {
00168 painter_info& info = find_painter_info(idx);
00169 if ( info.bVisible_ != bVisible) {
00170 info.bVisible_ = bVisible;
00171 if (bRedraw_on_changes_)
00172 redraw_painters();
00173 }
00174 }
00175
00180 void background_wnd::redraw_on_changes(bool bRedraw)
00181 {
00182 bRedraw_on_changes_ = bRedraw;
00183 }
00184
00186 bool background_wnd::redraw_on_changes() const
00187 {
00188 return bRedraw_on_changes_;
00189 }
00190
00192 void background_wnd::redraw_painters()
00193 {
00194 if (mem_dc_) {
00195
00196 HBRUSH hbr = CreateSolidBrush(cr_bkgnd_);
00197 FillRect(mem_dc_, &window_rect(rel_to_self), hbr);
00198 DeleteObject((HGDIOBJ) hbr);
00199
00200
00201 redraw_mem_dc();
00202 redraw();
00203 }
00204 }
00205
00211 void background_wnd::transparency(unsigned idx, unsigned transparency)
00212 {
00213 painter_info& info = find_painter_info(idx);
00214
00215 transparency = min<unsigned> (255, transparency);
00216 if (info.transparency_ != transparency) {
00217 info.transparency_ = transparency;
00218 if (bRedraw_on_changes_)
00219 redraw_painters();
00220 }
00221 }
00222
00226 unsigned background_wnd::transparency(unsigned idx) const
00227 {
00228 return find_painter_info(idx).transparency_;
00229 }
00230
00232
00233
00234
00241 void background_wnd::zorder_to_front(unsigned idx)
00242 {
00243 iterator it = find_painter_info_iterator(idx);
00244 if (it != coll_painters_.end() - 1) {
00245 PainterInfoPtr p = *it;
00246 coll_painters_.erase(it);
00247 coll_painters_.push_back(p);
00248
00249 if (bRedraw_on_changes_)
00250 redraw_painters();
00251 }
00252 }
00253
00260 void background_wnd::zorder_to_back(unsigned idx)
00261 {
00262 iterator it = find_painter_info_iterator(idx);
00263 if (it != coll_painters_.begin()) {
00264 PainterColl tmp;
00265 tmp.reserve(coll_painters_.size());
00266 tmp.push_back(*it);
00267 std::copy( coll_painters_.begin(), it, std::back_inserter(tmp) );
00268 std::copy( it + 1, coll_painters_.end(), std::back_inserter(tmp) );
00269 coll_painters_.swap(tmp);
00270
00271 if (bRedraw_on_changes_)
00272 redraw_painters();
00273 }
00274 }
00275
00282 void background_wnd::zorder_forward(unsigned idx)
00283 {
00284 iterator it = find_painter_info_iterator(idx);
00285 if (it != coll_painters_.end() - 1) {
00286 std::swap(*it, *(it + 1));
00287
00288 if (bRedraw_on_changes_)
00289 redraw_painters();
00290 }
00291 }
00292
00299 void background_wnd::zorder_backward(unsigned idx)
00300 {
00301 iterator it = find_painter_info_iterator(idx);
00302 if (it != coll_painters_.begin()) {
00303 std::swap(*it, *(it - 1));
00304
00305 if (bRedraw_on_changes_)
00306 redraw_painters();
00307 }
00308 }
00309
00310
00311
00312
00313
00317 bg_wnd::memory_dc& background_wnd::get_mem_dc()
00318 {
00319 return mem_dc_;
00320 }
00321
00325 const bg_wnd::memory_dc& background_wnd::get_mem_dc() const
00326 {
00327 return mem_dc_;
00328 }
00329
00330
00331
00332
00333
00334
00335 unsigned background_wnd::add_raw_painter(painter_base* pPainter)
00336 {
00337 try {
00338 coll_painters_.push_back( PainterInfoPtr(new painter_info(next_index_, pPainter)) );
00339 ++next_index_;
00340 }
00341 catch (...) {
00342 delete pPainter;
00343 throw;
00344 }
00345
00346 if (bRedraw_on_changes_)
00347 redraw_painters();
00348 return next_index_ - 1;
00349 }
00350
00351
00352 background_wnd::iterator background_wnd::find_painter_info_iterator(unsigned idx) const
00353 {
00354 for (iterator it = coll_painters_.begin(); it != coll_painters_.end(); ++it) {
00355 if ((*it)->idx_ == idx)
00356 return it;
00357 }
00358 throw index_invalid(*this);
00359 }
00360
00361
00362 background_wnd::painter_info& background_wnd::find_painter_info(unsigned idx) const
00363 {
00364 iterator it = find_painter_info_iterator(idx);
00365 return *( (*it).get() );
00366 }
00367
00368
00369 void background_wnd::create_mem_dc(HDC hDC)
00370 {
00371 if (mem_dc_ == NULL) {
00372 rectangle rc = window_rect(rel_to_self);
00373 COLORREF crOld = SetBkColor(hDC, cr_bkgnd_);
00374 mem_dc_.create_dc(hDC, rc.width(), rc.height());
00375 SetBkColor(hDC, crOld);
00376
00377
00378 redraw_mem_dc();
00379 }
00380 }
00381
00382
00383
00384 rectangle background_wnd::get_actual_drawing_rect(PainterInfoPtr pInfo) const
00385 {
00386
00387
00388
00389
00390
00391 rectangle rc_painter = pInfo->rc_drawing_;
00392 rectangle rc_window = window_rect(rel_to_self);
00393 if (rc_painter.width() <= 0)
00394 rc_painter.right = rc_window.width();
00395 if (rc_painter.height() <= 0)
00396 rc_painter.bottom = rc_window.height();
00397
00398 return rc_painter;
00399 }
00400
00401
00402
00403 bool background_wnd::is_overlapped(const rectangle& rc, const std::vector<rectangle>& rects)
00404 {
00405 typedef std::vector<rectangle> RectangleCont;
00406 RectangleCont intersecting;
00407 unsigned area_rect = rc.height() * rc.width();
00408 unsigned area_total = 0;
00409
00410
00411 for (RectangleCont::const_iterator it_added = rects.begin(); it_added != rects.end(); ++it_added) {
00412 rectangle rc_intersect;
00413 if ( IntersectRect(&rc_intersect, &rc, &(*it_added)) ) {
00414
00415
00416 for (RectangleCont::const_iterator it_intersected = intersecting.begin(); it_intersected != intersecting.end(); ++it_intersected) {
00417 rectangle rc_temp;
00418 if ( IntersectRect(&rc_temp, &rc_intersect, &(*it_intersected)) ) {
00419
00420
00421
00422 const int width = rc_temp.width();
00423 const int height = rc_temp.height();
00424 if (width < rc_intersect.width() && height < rc_intersect.height())
00425 area_total -= width * height;
00426 else
00427 SubtractRect( &rc_intersect, &rc_intersect, &(*it_intersected) );
00428 }
00429 }
00430
00431 const int width = rc_intersect.width();
00432 const int height = rc_intersect.height();
00433 if (width && height) {
00434 intersecting.push_back(rc_intersect);
00435 area_total += rc_intersect.width() * rc_intersect.height();
00436
00437
00438 if (area_total >= area_rect)
00439 return true;
00440 }
00441 }
00442 }
00443 return area_total >= area_rect;
00444 }
00445
00446
00447 bool background_wnd::is_partially_visible(const_iterator it_info, const rectangle& rc_painter) const
00448 {
00449
00450 if ( (*it_info)->bVisible_ == false || (*it_info)->transparency_ == 0)
00451 return false;
00452
00453
00454
00455
00456
00457
00458
00459
00460 std::vector<rectangle> rects_accumulated;
00461 for (const_iterator it = it_info + 1; it != coll_painters_.end(); ++it) {
00462
00463 if ( (*it_info)->bVisible_ == true && (*it)->transparency_ == 255 && (*it)->get_painter().is_opaque(rc_painter.width(), rc_painter.height()) ) {
00464 rectangle rc = get_actual_drawing_rect(*it);
00465 ++rc.right; ++rc.bottom;
00466 if ( rc.contains_point(rc_painter.top_left()) && rc.contains_point(rc_painter.bottom_right()) )
00467 return false;
00468 else {
00469 --rc.right; --rc.bottom;
00470 rects_accumulated.push_back(rc);
00471 }
00472 }
00473 }
00474
00475
00476
00477 return is_overlapped(rc_painter, rects_accumulated) == false;
00478 }
00479
00480
00481 void background_wnd::redraw_mem_dc()
00482 {
00483
00484 for (iterator it = coll_painters_.begin(); it != coll_painters_.end(); ++it) {
00485 rectangle rc_painter = get_actual_drawing_rect(*it);
00486
00487
00488 if (is_partially_visible(it, rc_painter))
00489 redraw_one_painter(*it, rc_painter);
00490 }
00491 }
00492
00493
00494 void background_wnd::redraw_one_painter(PainterInfoPtr pInfo, const rectangle& rc_painter)
00495 {
00496 const int x = rc_painter.left; const int y = rc_painter.top;
00497 const int cx = rc_painter.width(); const int cy = rc_painter.height();
00498
00499
00500
00501
00502
00503
00504
00505 bg_wnd::memory_dc hPainterDC;
00506 hPainterDC.create_dc(get_mem_dc(), cx, cy);
00507
00508
00509
00510
00511
00512 get_mem_dc().bitblt(hPainterDC, 0, 0, cx, cy, x, y);
00513
00514
00515
00516 pInfo->get_painter().draw( hPainterDC, cx, cy );
00517
00518
00519 if (pInfo->transparency_ == 255) {
00520 hPainterDC.bitblt(get_mem_dc(), x, y, cx, cy);
00521 }
00522
00523 else {
00524 BLENDFUNCTION bf;
00525 bf.BlendOp = AC_SRC_OVER;
00526 bf.BlendFlags = NULL;
00527 bf.SourceConstantAlpha = pInfo->transparency_;
00528 bf.AlphaFormat = 0;
00529 AlphaBlend(get_mem_dc(), x, y, cx, cy, hPainterDC, 0, 0, cx, cy, bf);
00530 }
00531 }
00532
00533
00534
00535
00536
00537 struct background_wnd_handler : event_handler<background_wnd_handler, background_wnd>
00538 {
00539 handle_event on_erase_bkgnd(w_param<HDC> hDC, result res)
00540 {
00541
00542 window()->create_mem_dc(hDC);
00543 rectangle rc = window()->window_rect(rel_to_self);
00544 window()->mem_dc_.bitblt(hDC, 0, 0, rc.width(), rc.height());
00545
00546 res = true;
00547 return event<WM_ERASEBKGND> ().HANDLED_BY(&me::on_erase_bkgnd);
00548 }
00549
00550 handle_event on_size(l_param_lo cx, l_param_hi cy)
00551 {
00552 if (cx > 0 && cy > 0 && window()->mem_dc_) {
00553 SIZE size = window()->mem_dc_.size();
00554
00555
00556
00557
00558
00559 const int FACTOR = 2;
00560 if (size.cx < cx || size.cy < cy || cx * FACTOR < size.cx || cy * FACTOR < size.cy)
00561 window()->mem_dc_.delete_dc();
00562 }
00563 return event<WM_SIZE> ().HANDLED_BY(&me::on_size);
00564 }
00565 };
00566
00567
00568 } }