FLTK logo

[master] b16309f - Refactor code to make rounded rectangles accessible (#553)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] b16309f - Refactor code to make rounded rectangles accessible (#553) "Matthias Melcher" Nov 24, 2022  
 
commit b16309f13e732e566c1beb4a02a2165ebb3ab4ab
Author:     Matthias Melcher <github@matthiasm.com>
AuthorDate: Thu Nov 24 12:47:49 2022 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Thu Nov 24 12:47:49 2022 +0100

    Refactor code to make rounded rectangles accessible (#553)
    
    This adds fl_rounded_rect and fl_rounded_rectf so the
    user can draw rounded rectangles. This uses existing and
    optimised code that is rearranged.

 FL/Fl_Graphics_Driver.H       |  3 +++
 FL/fl_draw.H                  | 17 +++++++++++++++++
 documentation/src/drawing.dox |  6 ++++++
 src/Fl_Graphics_Driver.cxx    | 44 +++++++++++++++++++++++++++++++++++++++++++
 src/fl_rounded_box.cxx        | 25 ++++--------------------
 5 files changed, 74 insertions(+), 21 deletions(-)

diff --git FL/Fl_Graphics_Driver.H FL/Fl_Graphics_Driver.H
index 5de9835..0f25756 100644
--- FL/Fl_Graphics_Driver.H
+++ FL/Fl_Graphics_Driver.H
@@ -264,6 +264,9 @@ public:
   virtual void rect(int x, int y, int w, int h);
   virtual void focus_rect(int x, int y, int w, int h);
   virtual void rectf(int x, int y, int w, int h);
+  virtual void _rbox(int fill, int x, int y, int w, int h, int r);
+  virtual void rounded_rect(int x, int y, int w, int h, int r);
+  virtual void rounded_rectf(int x, int y, int w, int h, int r);
   // the default implementation is most likely enough
   virtual void colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b);
   virtual void line(int x, int y, int x1, int y1);
diff --git FL/fl_draw.H FL/fl_draw.H
index 359405b..fc3e401 100644
--- FL/fl_draw.H
+++ FL/fl_draw.H
@@ -291,6 +291,15 @@ inline void fl_rect(int x, int y, int w, int h) {
 }
 
 /**
+ Draw a 1-pixel rounded border \e inside the given bounding box.
+ The radius code is optimized for speed and works best for values between
+ 5 and 15 units.
+ */
+inline void fl_rounded_rect(int x, int y, int w, int h, int r) {
+  fl_graphics_driver->rounded_rect(x, y, w, h, r);
+}
+
+/**
   Draw a 1-pixel border \e inside the given bounding box.
   This is the same as fl_rect(int x, int y, int w, int h) but with
   Fl_Rect \p r as input argument.
@@ -320,6 +329,14 @@ inline void fl_rectf(int x, int y, int w, int h) {
   fl_graphics_driver->rectf(x, y, w, h);
 }
 
+/** Color with current color a rounded rectangle that exactly fills the given bounding box.
+ The radius code is optimized for speed and works best for values between
+ 5 and 15 units.
+*/
+inline void fl_rounded_rectf(int x, int y, int w, int h, int r) {
+  fl_graphics_driver->rounded_rectf(x, y, w, h, r);
+}
+
 /** Color with passed color a rectangle that exactly fills the given bounding box. */
 inline void fl_rectf(int x, int y, int w, int h, Fl_Color c) {
   fl_color(c);
diff --git documentation/src/drawing.dox documentation/src/drawing.dox
index a80286f..f69796d 100644
--- documentation/src/drawing.dox
+++ documentation/src/drawing.dox
@@ -461,6 +461,12 @@ void fl_rect(int x, int y, int w, int h, Fl_Color c)
 \par
 Draw a 1-pixel border \e inside this bounding box.
 
+void fl_rounded_rect(int x, int y, int w, int h, int radius)
+void fl_rounded_rectf(int x, int y, int w, int h, int radius)
+
+\par
+Draw an outlined or filled rectangle with rounded corners.
+
 void fl_line(int x, int y, int x1, int y1) <br>
 void fl_line(int x, int y, int x1, int y1, int x2, int y2)
 
diff --git src/Fl_Graphics_Driver.cxx src/Fl_Graphics_Driver.cxx
index 95f79ee..9d12096 100644
--- src/Fl_Graphics_Driver.cxx
+++ src/Fl_Graphics_Driver.cxx
@@ -455,6 +455,50 @@ void Fl_Graphics_Driver::rect(int x, int y, int w, int h) {}
 /** see fl_rectf() */
 void Fl_Graphics_Driver::rectf(int x, int y, int w, int h) {}
 
+void Fl_Graphics_Driver::_rbox(int fill, int x, int y, int w, int h, int r) {
+  static double lut[] = { 0.0, 0.07612, 0.29289, 0.61732, 1.0};
+  if (r == 5) r = 4;  // use only even sizes for small corners (STR #2943)
+  if (r == 7) r = 8;  // note: 8 is better than 6 (really)
+  double xd = x, yd = y, rd = (x+w-1), bd = (y+h-1);
+  double rr = r;
+  if (fill) begin_polygon(); else begin_loop();
+  // top left
+  transformed_vertex(xd+lut[0]*rr, yd+lut[4]*rr);
+  transformed_vertex(xd+lut[1]*rr, yd+lut[3]*rr);
+  transformed_vertex(xd+lut[2]*rr, yd+lut[2]*rr);
+  transformed_vertex(xd+lut[3]*rr, yd+lut[1]*rr);
+  transformed_vertex(xd+lut[4]*rr, yd+lut[0]*rr);
+  // top right
+  transformed_vertex(rd-lut[4]*rr, yd+lut[0]*rr);
+  transformed_vertex(rd-lut[3]*rr, yd+lut[1]*rr);
+  transformed_vertex(rd-lut[2]*rr, yd+lut[2]*rr);
+  transformed_vertex(rd-lut[1]*rr, yd+lut[3]*rr);
+  transformed_vertex(rd-lut[0]*rr, yd+lut[4]*rr);
+  // bottom right
+  transformed_vertex(rd-lut[0]*rr, bd-lut[4]*rr);
+  transformed_vertex(rd-lut[1]*rr, bd-lut[3]*rr);
+  transformed_vertex(rd-lut[2]*rr, bd-lut[2]*rr);
+  transformed_vertex(rd-lut[3]*rr, bd-lut[1]*rr);
+  transformed_vertex(rd-lut[4]*rr, bd-lut[0]*rr);
+  // bottom left
+  transformed_vertex(xd+lut[4]*rr, bd-lut[0]*rr);
+  transformed_vertex(xd+lut[3]*rr, bd-lut[1]*rr);
+  transformed_vertex(xd+lut[2]*rr, bd-lut[2]*rr);
+  transformed_vertex(xd+lut[1]*rr, bd-lut[3]*rr);
+  transformed_vertex(xd+lut[0]*rr, bd-lut[4]*rr);
+  if (fill) fl_end_polygon(); else fl_end_loop();
+}
+
+/** see fl_rrect() */
+void Fl_Graphics_Driver::rounded_rect(int x, int y, int w, int h, int r) {
+  _rbox(0, x, y, w, h, r);
+}
+
+/** see fl_rrectf() */
+void Fl_Graphics_Driver::rounded_rectf(int x, int y, int w, int h, int r) {
+  _rbox(1, x, y, w, h, r);
+}
+
 void Fl_Graphics_Driver::colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
   color(r, g, b);
   rectf(x, y, w, h);
diff --git src/fl_rounded_box.cxx src/fl_rounded_box.cxx
index df41b4f..f1b3511 100644
--- src/fl_rounded_box.cxx
+++ src/fl_rounded_box.cxx
@@ -23,35 +23,18 @@
 //  RS = max. corner radius
 //  BW = box shadow width
 
-#define RN 5
 #define RS (Fl::box_border_radius_max())
 #define BW (Fl::box_shadow_width())
 
-static double offset[RN] = { 0.0, 0.07612, 0.29289, 0.61732, 1.0};
-
-static inline void fl_vertex_r(double x, double y) {
-  fl_vertex(x + 0.5, y + 0.5);
-}
-
 static void rbox(int fill, int x, int y, int w, int h) {
-  int i;
   int rs, rsy;
   rs = w*2/5; rsy = h*2/5;
   if (rs > rsy) rs = rsy; // use smaller radius
   if (rs > RS) rs = RS;
-  if (rs == 5) rs = 4;  // use only even sizes for small corners (STR #2943)
-  if (rs == 7) rs = 8;  // note: 8 is better than 6 (really)
-
-  if (fill) fl_begin_polygon(); else fl_begin_loop();
-  for (i=0; i<RN; i++)
-    fl_vertex_r(x + offset[RN-i-1]*rs, y + offset[i] * rs);
-  for (i=0; i<RN; i++)
-    fl_vertex_r(x + offset[i]*rs, y + h-1 - offset[RN-i-1] * rs);
-  for (i=0; i<RN; i++)
-    fl_vertex_r(x + w-1 - offset[RN-i-1]*rs, y + h-1 - offset[i] * rs);
-  for (i=0; i<RN; i++)
-    fl_vertex_r(x + w-1 - offset[i]*rs, y + offset[RN-i-1] * rs);
-  if (fill) fl_end_polygon(); else fl_end_loop();
+  if (fill)
+    fl_rounded_rectf(x, y, w, h, rs);
+  else
+    fl_rounded_rect(x, y, w, h, rs);
 }
 
 static void fl_rflat_box(int x, int y, int w, int h, Fl_Color c) {
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.