You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.8KB

  1. //
  2. // "$Id: fl_scroll_area.cxx 8055 2010-12-18 22:31:01Z manolo $"
  3. //
  4. // Scrolling routines for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-2010 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. // Drawing function to move the contents of a rectangle. This is passed
  28. // a "callback" which is called to draw rectangular areas that are moved
  29. // into the drawing area.
  30. #include <config.h>
  31. #include <FL/Fl.H>
  32. #include <FL/x.H>
  33. #include <FL/fl_draw.H>
  34. // scroll a rectangle and redraw the newly exposed portions:
  35. /**
  36. Scroll a rectangle and draw the newly exposed portions.
  37. \param[in] X,Y position of top-left of rectangle
  38. \param[in] W,H size of rectangle
  39. \param[in] dx,dy pixel offsets for shifting rectangle
  40. \param[in] draw_area callback function to draw rectangular areas
  41. \param[in] data pointer to user data for callback
  42. The contents of the rectangular area is first shifted by \p dx
  43. and \p dy pixels. The \p draw_area callback is then called for
  44. every newly exposed rectangular area.
  45. */
  46. void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
  47. void (*draw_area)(void*, int,int,int,int), void* data)
  48. {
  49. if (!dx && !dy) return;
  50. if (dx <= -W || dx >= W || dy <= -H || dy >= H) {
  51. // no intersection of old an new scroll
  52. draw_area(data,X,Y,W,H);
  53. return;
  54. }
  55. int src_x, src_w, dest_x, clip_x, clip_w;
  56. if (dx > 0) {
  57. src_x = X;
  58. dest_x = X+dx;
  59. src_w = W-dx;
  60. clip_x = X;
  61. clip_w = dx;
  62. } else {
  63. src_x = X-dx;
  64. dest_x = X;
  65. src_w = W+dx;
  66. clip_x = X+src_w;
  67. clip_w = W-src_w;
  68. }
  69. int src_y, src_h, dest_y, clip_y, clip_h;
  70. if (dy > 0) {
  71. src_y = Y;
  72. dest_y = Y+dy;
  73. src_h = H-dy;
  74. clip_y = Y;
  75. clip_h = dy;
  76. } else {
  77. src_y = Y-dy;
  78. dest_y = Y;
  79. src_h = H+dy;
  80. clip_y = Y+src_h;
  81. clip_h = H-src_h;
  82. }
  83. #if defined(USE_X11)
  84. XCopyArea(fl_display, fl_window, fl_window, fl_gc,
  85. src_x, src_y, src_w, src_h, dest_x, dest_y);
  86. // we have to sync the display and get the GraphicsExpose events! (sigh)
  87. for (;;) {
  88. XEvent e; XWindowEvent(fl_display, fl_window, ExposureMask, &e);
  89. if (e.type == NoExpose) break;
  90. // otherwise assume it is a GraphicsExpose event:
  91. draw_area(data, e.xexpose.x, e.xexpose.y,
  92. e.xexpose.width, e.xexpose.height);
  93. if (!e.xgraphicsexpose.count) break;
  94. }
  95. #elif defined(WIN32)
  96. typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT);
  97. static fl_GetRandomRgn_func fl_GetRandomRgn = 0L;
  98. static char first_time = 1;
  99. // We will have to do some Region magic now, so let's see if the
  100. // required function is available (and it should be staring w/Win95)
  101. if (first_time) {
  102. HMODULE hMod = GetModuleHandle("GDI32.DLL");
  103. if (hMod) {
  104. fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn");
  105. }
  106. first_time = 0;
  107. }
  108. // Now check if the source scrolling area is fully visible.
  109. // If it is, we will do a quick scroll and just update the
  110. // newly exposed area. If it is not, we go the safe route and
  111. // re-render the full area instead.
  112. // Note 1: we could go and find the areas that are actually
  113. // obscured and recursively call fl_scroll for the newly found
  114. // rectangles. However, this practice would rely on the
  115. // elements of the undocumented Rgn structure.
  116. // Note 2: although this method should take care of most
  117. // multi-screen solutions, it will not solve issues scrolling
  118. // from a different resolution screen onto another.
  119. // Note 3: this has been tested with image maps, too.
  120. if (fl_GetRandomRgn) {
  121. // get the DC region minus all overlapping windows
  122. HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0);
  123. fl_GetRandomRgn(fl_gc, sys_rgn, 4);
  124. // now get the source scrolling rectangle
  125. HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h);
  126. POINT offset = { 0, 0 };
  127. if (GetDCOrgEx(fl_gc, &offset)) {
  128. OffsetRgn(src_rgn, offset.x, offset.y);
  129. }
  130. // see if all source pixels are available in the system region
  131. // Note: we could be a bit more merciful and subtract the
  132. // scroll destination region as well.
  133. HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0);
  134. int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF);
  135. DeleteObject(dst_rgn);
  136. DeleteObject(src_rgn);
  137. DeleteObject(sys_rgn);
  138. if (r!=NULLREGION) {
  139. draw_area(data,X,Y,W,H);
  140. return;
  141. }
  142. }
  143. // Great, we can do an accelerated scroll instead of re-rendering
  144. BitBlt(fl_gc, dest_x, dest_y, src_w, src_h, fl_gc, src_x, src_y,SRCCOPY);
  145. #elif defined(__APPLE_QUARTZ__)
  146. CGImageRef img = Fl_X::CGImage_from_window_rect(Fl_Window::current(), src_x, src_y, src_w, src_h);
  147. CGRect rect = { { dest_x, dest_y }, { src_w, src_h } };
  148. Fl_X::q_begin_image(rect, 0, 0, src_w, src_h);
  149. CGContextDrawImage(fl_gc, rect, img);
  150. Fl_X::q_end_image();
  151. CFRelease(img);
  152. #else
  153. # error unsupported platform
  154. #endif
  155. if (dx) draw_area(data, clip_x, dest_y, clip_w, src_h);
  156. if (dy) draw_area(data, X, clip_y, W, clip_h);
  157. }
  158. //
  159. // End of "$Id: fl_scroll_area.cxx 8055 2010-12-18 22:31:01Z manolo $".
  160. //