Ecere DLL update - class Circle

General help with the Ecere Cross Platform GUI toolkit: Window, common controls, events, etc.
Help with the 2D Graphics library: Surface, Display, Bitmap, Font and others.
Post Reply
D.Bane
Posts: 78
Joined: Thu Jul 29, 2010 2:51 pm

Ecere DLL update - class Circle

Post by D.Bane »

Hi,

I wanted to do this on Git, but I can not download anything at the moment (for some time, who knows for how long :/) so it is easier to copy paste it here, I hope you do not mind :)

I personally really like the option of having a Circular button but, not the one that will 'shine' when you are inside of its box, but the one that follows its lines - if you like that same thing then this code should help.

Ecere.dll/src/sys/units.ec

Code: Select all

public enum CircleBorder { outsideBevel, insideBevel };

public struct Circle
{
   CircleBorder borderType;
      borderType = outsideBevel;
   //Point center;
   int cX, cY;
   int radius;
   int borderSize;
      borderSize = 1;

   property int borderSize
   {
      get { return borderSize; }
      set
      {
         if(value < 1)  { borderSize = 1; }
         else           { borderSize = value; }
      }
   }

   property int leftMostPoint
   {
      get { return cX - radius; }
   }

   property int topMostPoint
   {
      get { return cY - radius; }
   }

   property int rightMostPoint
   {
      get { return cX + radius; }
   }

   property int bottomMostPoint
   {
      get { return cY + radius; }
   }

   public bool isPointInside(Point point, bool countOnBorder)
   {
      float gps; //it can be int (will function properly, but will give warning).
      int nrad;
      int rMin, rMax;

      nrad = radius * -1;

      //Some faster calculations to speed things up..
      if( (point.y - cY) < nrad || (point.y - cY) > radius)
         { return false; }
      if((point.x-cX) < nrad || (point.x-cX) > radius)
         { return false; }

      gps = fastSqrt((point.x-cX)*(point.x-cX) + (point.y-cY)*(point.y-cY));

      if(borderType == insideBevel)
      {
         rMin = radius - borderSize;
         rMax = radius;
      }
      else // borderType == outsideBevel
      {
         rMin = radius;
         rMax = radius + borderSize;
      }

      if(gps < radius)
      {
         //The point is inside of a circle
         return true;
      }
      else if(gps == radius || (gps > rMin && gps < rMax) )
      {
         //The point is on the border
         if(countOnBorder) { return true; }
      }
      //Else - The point is not in the circle nor on the border (or the border is not included)
      return false;
   }

   //Other functions found in Box struct
   //-----------------------------------------------------------------
   //Check what these do for box and if applicable...
   void ClipOffset(Circle against, int x, int y)
   {
   }
   void Clip(Circle against)
   {
   }

   bool Overlap(Circle circle)
   {
      if( leftMostPoint < circle.rightMostPoint && rightMostPoint > circle.leftMostPoint && topMostPoint < circle.bottomMostPoint && bottomMostPoint > circle.topMostPoint)
      {
         //It is inside of the circle's `box` so it should be studied more carefully if it is
         // trully overlaping or not...
         float overlap; //it can be int (will function properly, but will give warning).
         int rad;
         float h, w;

         w = cX - circle.cX;
         h = cY - circle.cY;

         overlap = fastSqrt((w*w)+(h*h));

         rad = radius + circle.radius;

         if(overlap < rad) { return true; }
      }

      return false;
   }
};
I did a bit of research and this seems like a very fast algorithm for squareRoot (faster being done in asm) - the link is included to the most valuable source - at least that I think. So all the thanks/reps, etc. go to the person that spent a lot of time finding these algorithms..

Code: Select all

private float fastSqrt(float x)  
{
   //http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
   //Method number 1
   union
   {
      int i;
      float x;
   } u;

   u.x = x;
   u.i = (1<<29) + (u.i >> 1) - (1<<22); 

   // Two Babylonian Steps (simplified from:)
   // u.x = 0.5f * (u.x + x/u.x);
   // u.x = 0.5f * (u.x + x/u.x);
   u.x = u.x + x/u.x;
   u.x = 0.25f*u.x + x/u.x;

   return u.x;
}
Now we need to add some other code that will allow us to draw the circle when in OnRedraw or when we have the surface of any object...

Ecere.dll/src/gfx/Surface.ec

Code: Select all

void DrawCircle(Circle circle)
   {
      ColorAlpha color[2];

      color[0] = black;
      color[1] = black;
      DrawCircleF(circle.cX, circle.cY, circle.radius, emptyCircle, color, circle.borderSize, circle.borderType);
   }

   void DrawCircleF(int x0, int y0, int radius, CircleType circleType, ColorAlpha color[2], int borderSize, CircleBorder borderStyle )
   {
      int f, fX, fY, x, y;

      f = 1 - radius;
      fX = 1;
      fY = -2 * radius;
      x = 0;
      y = radius;

      //Put the dot in the center of the circle
      //SetForeground(red);
      //driver.PutPixel(display, this, x0,y0);

      //The border should always be drawn, not only if empty, as that way you can have
      // only line drawn, full color circle and colored circle with borders
      // this might not be wanted for circle if angles only

      //Draw borders
      SetForeground(color[0]);
      driver.PutPixel(display, this, x0, y0 + radius);
      driver.PutPixel(display, this, x0, y0 - radius);

      //circle dots on the X axis on both sides of circle
      driver.PutPixel(display, this, x0 + radius, y0);
      driver.PutPixel(display, this, x0 - radius, y0);

      if(circleType == fullCircle)
      {
         SetForeground(color[1]);
         driver.DrawLine(display, this, x0, y0 + radius, x0, y0 - radius);
         driver.DrawLine(display, this, x0 + radius, y0, x0 - radius+1, y0);
      }

      while(x < y)
      {
         // fX == 2 * x + 1;
         // fY == -2 * y;
         // f == x*x + y*y - radius*radius + 2*x - y + 1;
         if(f >= 0) 
         {
            y--;
            fY += 2;
            f += fY;
         }

         x++;
         fX += 2;
         f += fX;

         //Draw other dots... each line representing one sector...
         if(circleType == emptyCircle) //only border is shown
         {
            driver.PutPixel(display, this, x0 + x, y0 + y);
            driver.PutPixel(display, this, x0 - x, y0 + y);
            driver.PutPixel(display, this, x0 + x, y0 - y);
            driver.PutPixel(display, this, x0 - x, y0 - y);
            driver.PutPixel(display, this, x0 + y, y0 + x);
            driver.PutPixel(display, this, x0 - y, y0 + x);
            driver.PutPixel(display, this, x0 + y, y0 - x);
            driver.PutPixel(display, this, x0 - y, y0 - x);
         }
         else if(circleType == fullCircle) //everything is filled up..
         {
            driver.DrawLine(display, this, x0 + x, y0 + y, x0 - x, y0 + y);
            driver.DrawLine(display, this, x0 + x, y0 - y, x0 - x, y0 - y);
            driver.DrawLine(display, this, x0 + y, y0 + x, x0 - y, y0 + x);
            driver.DrawLine(display, this, x0 + y, y0 - x, x0 - y, y0 - x);
         }
      }

      if(borderSize > 1)
      {
         if(borderStyle == insideBevel)
         {
            DrawCircleF(x0, y0, radius-1, circleType, color, borderSize-1, borderStyle );
         }
         else
         {
            DrawCircleF(x0, y0, radius+1, circleType, color, borderSize-1, borderStyle );
         }
      }
   }
Here are two examples of how it might work...

form1-basic.ec

Code: Select all

import "ecere"

class Form1 : Window
{
   caption = "Form1";
   background = formColor;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   clientSize = { 632, 438 };

   //Lets add few circles
   Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; };
   Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; };
   Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; };

   // The Clip() functions that work for the box are not done
   // The filled angles will be available at some other time, but the idea was to have the
   //  possibility of pie chart if it was needed, but it should be based on angles and I have
   //  some other idea in mind for that so will see what will happen - it might end up transferred to
   //  some other class instead...

   void OnRedraw(Surface surface)
   {
      ColorAlpha colors[2];
      ColorAlpha colors2[2];

      colors[0] = black; //border color
      colors[1] = red; //background color

      colors2[0] = blue;
      colors2[1] = green;

      //Lets draw these circles
      surface.DrawCircle(c1); //A quick way to draw them, which does not give you a lot of
                              // room to do anything with it
      //surface.DrawCircleF(x0,y0,radius,curcleType,color[2],borderSize,borderStyle);
      surface.DrawCircleF(c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType);
      surface.DrawCircleF(c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType);
   }

   //Lets see what we can do with this...

   bool OnLeftButtonDown(int x, int y, Modifiers mods)
   {
      bool tc1, tc2, tc3;
      String msg;

      msg = "The click happened outside of any circle"; //default value

      tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the
                                    // part of the circle, then you say true, but if you do not want
                                    // to have border included in the calculations then just put
                                    // false and it will not be counted
      tc2 = c2.isPointInside({x,y},false);
      tc3 = c3.isPointInside({x,y},true);

      if(tc1)  { msg = "the 'c1' circle was hit"; }
      else if(tc2) { msg = "the 'c2' circle was hit"; }
      else if(tc3) { msg = "the 'c3' circle was hit"; }

      MessageBox {this, text = "results", contents = msg}.Modal();

      return true;
   }

   bool OnRightButtonDown(int x, int y, Modifiers mods)
   {
      //Lets see if the circles are overlapping each other...
      if(c1.Overlap(c2))
      {
         MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal();
      }
      if(c1.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal();
      }
      if(c2.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal();
      }
      return true;
   }

}

Form1 form1 {};
form1-bitmorecomplex.ec

Code: Select all

import "ecere"

class Form1 : Window
{
   caption = "Form1";
   background = formColor;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   clientSize = { 632, 438 };

   //Lets add few circles
   Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; };
   Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; };
   Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; };

   //Lets do something more with it..
   bool c1Inside, c2Inside, c3Inside;
   c1Inside = false;
   c2Inside = false;
   c3Inside = false;

   // The Clip() functions that work for the box are not done
   // The filled angles will be available at some other time, but the idea was to have the
   //  possibility of pie chart if it was needed, but it should be based on angles and I have
   //  some other idea in mind for that so will see what will happen - it might end up transferred to
   //  some other class instead...

   void OnRedraw(Surface surface)
   {
      ColorAlpha colors[2];
      ColorAlpha colors2[2];
      ColorAlpha colorsO[2];
      ColorAlpha colors2O[2];

      //Normal colors
      colors[0] = black;
      colors[1] = red;
      colors2[0] = blue;
      colors2[1] = green;

      //Over
      colorsO[0] = white;
      colorsO[1] = yellow;
      colors2O[0] = red;
      colors2O[1] = brown;

      //Lets draw these circles
      if(c1Inside)
      {
         surface.DrawCircleF(c1.cX,c1.cY,c1.radius,fullCircle,colorsO,c1.borderSize,c1.borderType);
      }
      else
      {
         surface.DrawCircle(c1); //A quick way to draw them, which does not give you a lot of
                                 // room to do anything with it
      }
      //surface.DrawCircleF(x0,y0,radius,curcleType,color[2],borderSize,borderStyle);
      if(c2Inside)
      {
         surface.DrawCircleF(c2.cX,c2.cY,c2.radius,fullCircle,colors2O,c2.borderSize,c2.borderType);
      }
      else
      {
         surface.DrawCircleF(c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType);
      }
      
      if(c3Inside)
      {
         surface.DrawCircle(c3);
      }
      else
      {
         surface.DrawCircleF(c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType);
      }
   }

   //Lets see what we can do with this...

   bool OnMouseMove(int x, int y, Modifiers mods)
   {
      c1Inside = false;
      c2Inside = false;
      c3Inside = false;

      if(c1.isPointInside({x,y},true)) { c1Inside = true; }
      if(c2.isPointInside({x,y},true)) { c2Inside = true; }
      if(c3.isPointInside({x,y},true)) { c3Inside = true; }

      Update(null);
      return true;
   }


   bool OnLeftButtonDown(int x, int y, Modifiers mods)
   {
      bool tc1, tc2, tc3;
      String msg;

      msg = "The click happened outside of any circle"; //default value

      tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the
                                    // part of the circle, then you say true, but if you do not want
                                    // to have border included in the calculations then just put
                                    // false and it will not be counted
      tc2 = c2.isPointInside({x,y},false);
      tc3 = c3.isPointInside({x,y},true);

      if(tc1)  { msg = "the 'c1' circle was hit"; }
      else if(tc2) { msg = "the 'c2' circle was hit"; }
      else if(tc3) { msg = "the 'c3' circle was hit"; }

      MessageBox {this, text = "results", contents = msg}.Modal();

      return true;
   }

   bool OnRightButtonDown(int x, int y, Modifiers mods)
   {
      //Lets see if the circles are overlapping each other...
      if(c1.Overlap(c2))
      {
         MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal();
      }
      if(c1.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal();
      }
      if(c2.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal();
      }
      return true;
   }

}

Form1 form1 {};
I hope someone will like the code and that it will be useful.

All the best to you all,
D.Bane.
Attachments
form1-bitmorecomplex.ec
The same (a bit more complex) file as the above in post
(4.08 KiB) Downloaded 1449 times
form1-basic.ec
The same (basic) file as the above in post
(3 KiB) Downloaded 1463 times
No army is to big, if the heart is beating strong.
There's no bad luck, it's just easier to blame someone else.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Ecere DLL update - class Circle

Post by jerome »

Hi D.Bane!

Thanks for sharing with us those circles :)

I put all this code together in one simple file outside of libecere for those who would like to try it quickly. It was missing the CircleType enum which I added. Both versions of the forms will show up.

Code: Select all

public import "ecere"
 
public enum CircleBorder { outsideBevel, insideBevel };
public enum CircleType { emptyCircle, fullCircle };
 
public struct Circle
{
   CircleBorder borderType;
      borderType = outsideBevel;
   //Point center;
   int cX, cY;
   int radius;
   int borderSize;
      borderSize = 1;
 
   property int borderSize
   {
      get { return borderSize; }
      set
      {
         if(value < 1)  { borderSize = 1; }
         else           { borderSize = value; }
      }
   }
 
   property int leftMostPoint
   {
      get { return cX - radius; }
   }
 
   property int topMostPoint
   {
      get { return cY - radius; }
   }
 
   property int rightMostPoint
   {
      get { return cX + radius; }
   }
 
   property int bottomMostPoint
   {
      get { return cY + radius; }
   }
 
   public bool isPointInside(Point point, bool countOnBorder)
   {
      float gps; //it can be int (will function properly, but will give warning).
      int nrad;
      int rMin, rMax;
 
      nrad = radius * -1;
 
      //Some faster calculations to speed things up..
      if( (point.y - cY) < nrad || (point.y - cY) > radius)
         { return false; }
      if((point.x-cX) < nrad || (point.x-cX) > radius)
         { return false; }
 
      gps = fastSqrt((point.x-cX)*(point.x-cX) + (point.y-cY)*(point.y-cY));
 
      if(borderType == insideBevel)
      {
         rMin = radius - borderSize;
         rMax = radius;
      }
      else // borderType == outsideBevel
      {
         rMin = radius;
         rMax = radius + borderSize;
      }
 
      if(gps < radius)
      {
         //The point is inside of a circle
         return true;
      }
      else if(gps == radius || (gps > rMin && gps < rMax) )
      {
         //The point is on the border
         if(countOnBorder) { return true; }
      }
      //Else - The point is not in the circle nor on the border (or the border is not included)
      return false;
   }
 
   //Other functions found in Box struct
   //-----------------------------------------------------------------
   //Check what these do for box and if applicable...
   void ClipOffset(Circle against, int x, int y)
   {
   }
   void Clip(Circle against)
   {
   }
 
   bool Overlap(Circle circle)
   {
      if( leftMostPoint < circle.rightMostPoint && rightMostPoint > circle.leftMostPoint && topMostPoint < circle.bottomMostPoint && bottomMostPoint > circle.topMostPoint)
      {
         //It is inside of the circle's `box` so it should be studied more carefully if it is
         // trully overlaping or not...
         float overlap; //it can be int (will function properly, but will give warning).
         int rad;
         float h, w;
 
         w = cX - circle.cX;
         h = cY - circle.cY;
 
         overlap = fastSqrt((w*w)+(h*h));
 
         rad = radius + circle.radius;
 
         if(overlap < rad) { return true; }
      }
 
      return false;
   }
};
 
 
private float fastSqrt(float x)  
{
   //http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
   //Method number 1
   union
   {
      int i;
      float x;
   } u;
 
   u.x = x;
   u.i = (1<<29) + (u.i >> 1) - (1<<22); 
 
   // Two Babylonian Steps (simplified from:)
   // u.x = 0.5f * (u.x + x/u.x);
   // u.x = 0.5f * (u.x + x/u.x);
   u.x = u.x + x/u.x;
   u.x = 0.25f*u.x + x/u.x;
 
   return u.x;
}
 
 
void DrawCircle(Surface surface, Circle circle)
{
   ColorAlpha color[2];
 
   color[0] = black;
   color[1] = black;
   DrawCircleF(surface, circle.cX, circle.cY, circle.radius, emptyCircle, color, circle.borderSize, circle.borderType);
}
 
void DrawCircleF(Surface surface, int x0, int y0, int radius, CircleType circleType, ColorAlpha color[2], int borderSize, CircleBorder borderStyle )
{
   int f, fX, fY, x, y;
 
   f = 1 - radius;
   fX = 1;
   fY = -2 * radius;
   x = 0;
   y = radius;
 
   //Put the dot in the center of the circle
   //SetForeground(red);
   //PutPixel(x0,y0);
 
   //The border should always be drawn, not only if empty, as that way you can have
   // only line drawn, full color circle and colored circle with borders
   // this might not be wanted for circle if angles only
 
   //Draw borders
   surface.SetForeground(color[0]);
   surface.PutPixel(x0, y0 + radius);
   surface.PutPixel(x0, y0 - radius);
 
   //circle dots on the X axis on both sides of circle
   surface.PutPixel(x0 + radius, y0);
   surface.PutPixel(x0 - radius, y0);
 
   if(circleType == fullCircle)
   {
      surface.SetForeground(color[1]);
      surface.DrawLine(x0, y0 + radius, x0, y0 - radius);
      surface.DrawLine(x0 + radius, y0, x0 - radius+1, y0);
   }
 
   while(x < y)
   {
      // fX == 2 * x + 1;
      // fY == -2 * y;
      // f == x*x + y*y - radius*radius + 2*x - y + 1;
      if(f >= 0) 
      {
         y--;
         fY += 2;
         f += fY;
      }
 
      x++;
      fX += 2;
      f += fX;
 
      //Draw other dots... each line representing one sector...
      if(circleType == emptyCircle) //only border is shown
      {
         surface.PutPixel(x0 + x, y0 + y);
         surface.PutPixel(x0 - x, y0 + y);
         surface.PutPixel(x0 + x, y0 - y);
         surface.PutPixel(x0 - x, y0 - y);
         surface.PutPixel(x0 + y, y0 + x);
         surface.PutPixel(x0 - y, y0 + x);
         surface.PutPixel(x0 + y, y0 - x);
         surface.PutPixel(x0 - y, y0 - x);
      }
      else if(circleType == fullCircle) //everything is filled up..
      {
         surface.DrawLine(x0 + x, y0 + y, x0 - x, y0 + y);
         surface.DrawLine(x0 + x, y0 - y, x0 - x, y0 - y);
         surface.DrawLine(x0 + y, y0 + x, x0 - y, y0 + x);
         surface.DrawLine(x0 + y, y0 - x, x0 - y, y0 - x);
      }
   }
 
   if(borderSize > 1)
   {
      if(borderStyle == insideBevel)
      {
         DrawCircleF(surface, x0, y0, radius-1, circleType, color, borderSize-1, borderStyle );
      }
      else
      {
         DrawCircleF(surface, x0, y0, radius+1, circleType, color, borderSize-1, borderStyle );
      }
   }
}
 
class Form1 : Window
{
   caption = "Form1";
   background = formColor;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   clientSize = { 632, 438 };
 
   //Lets add few circles
   Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; };
   Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; };
   Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; };
 
   // The Clip() functions that work for the box are not done
   // The filled angles will be available at some other time, but the idea was to have the
   //  possibility of pie chart if it was needed, but it should be based on angles and I have
   //  some other idea in mind for that so will see what will happen - it might end up transferred to
   //  some other class instead...
 
   void OnRedraw(Surface surface)
   {
      ColorAlpha colors[2];
      ColorAlpha colors2[2];
 
      colors[0] = black; //border color
      colors[1] = red; //background color
 
      colors2[0] = blue;
      colors2[1] = green;
 
      //Lets draw these circles
      DrawCircle(surface, c1); //A quick way to draw them, which does not give you a lot of
                              // room to do anything with it
      //DrawCircleF(surface, x0,y0,radius,curcleType,color[2],borderSize,borderStyle);
      DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType);
      DrawCircleF(surface, c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType);
   }
 
   //Lets see what we can do with this...
 
   bool OnLeftButtonDown(int x, int y, Modifiers mods)
   {
      bool tc1, tc2, tc3;
      String msg;
 
      msg = "The click happened outside of any circle"; //default value
 
      tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the
                                    // part of the circle, then you say true, but if you do not want
                                    // to have border included in the calculations then just put
                                    // false and it will not be counted
      tc2 = c2.isPointInside({x,y},false);
      tc3 = c3.isPointInside({x,y},true);
 
      if(tc1)  { msg = "the 'c1' circle was hit"; }
      else if(tc2) { msg = "the 'c2' circle was hit"; }
      else if(tc3) { msg = "the 'c3' circle was hit"; }
 
      MessageBox {this, text = "results", contents = msg}.Modal();
 
      return true;
   }
 
   bool OnRightButtonDown(int x, int y, Modifiers mods)
   {
      //Lets see if the circles are overlapping each other...
      if(c1.Overlap(c2))
      {
         MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal();
      }
      if(c1.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal();
      }
      if(c2.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal();
      }
      return true;
   }
 
}
 
class Form2 : Window
{
   caption = "Form2";
   background = formColor;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   clientSize = { 632, 438 };
 
   //Lets add few circles
   Circle c1 {borderSize = 1;borderType = outsideBevel; cX = 270; cY = 65; radius = 38; };
   Circle c2 {borderSize = 1;borderType = outsideBevel; cX = 102; cY = 83; radius = 150; };
   Circle c3 {borderSize = 1;borderType = outsideBevel; cX = 321; cY = 130; radius = 50; };
 
   //Lets do something more with it..
   bool c1Inside, c2Inside, c3Inside;
   c1Inside = false;
   c2Inside = false;
   c3Inside = false;
 
   // The Clip() functions that work for the box are not done
   // The filled angles will be available at some other time, but the idea was to have the
   //  posibility of pie chart if it was needed, but it should be based on angles and I have
   //  some other idea in mind for that so will see what will happen - it might end up transfered to
   //  some other class instead...
 
   void OnRedraw(Surface surface)
   {
      ColorAlpha colors[2];
      ColorAlpha colors2[2];
      ColorAlpha colorsO[2];
      ColorAlpha colors2O[2];
 
      //Normal colors
      colors[0] = black;
      colors[1] = red;
      colors2[0] = blue;
      colors2[1] = green;
 
      //Over
      colorsO[0] = white;
      colorsO[1] = yellow;
      colors2O[0] = red;
      colors2O[1] = brown;
 
      //Lets draw these circles
      if(c1Inside)
      {
         DrawCircleF(surface, c1.cX,c1.cY,c1.radius,fullCircle,colorsO,c1.borderSize,c1.borderType);
      }
      else
      {
         DrawCircle(surface, c1); //A quick way to draw them, which does not give you a lot of
                                 // room to do anything with it
      }
      //surface.DrawCircleF(x0,y0,radius,curcleType,color[2],borderSize,borderStyle);
      if(c2Inside)
      {
         DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors2O,c2.borderSize,c2.borderType);
      }
      else
      {
         DrawCircleF(surface, c2.cX,c2.cY,c2.radius,fullCircle,colors,c2.borderSize,c2.borderType);
      }
 
      if(c3Inside)
      {
         DrawCircle(surface, c3);
      }
      else
      {
         DrawCircleF(surface, c3.cX,c3.cY,c3.radius,fullCircle,colors2,c3.borderSize,c3.borderType);
      }
   }
 
   //Lets see what we can do with this...
 
   bool OnMouseMove(int x, int y, Modifiers mods)
   {
      c1Inside = false;
      c2Inside = false;
      c3Inside = false;
 
      if(c1.isPointInside({x,y},true)) { c1Inside = true; }
      if(c2.isPointInside({x,y},true)) { c2Inside = true; }
      if(c3.isPointInside({x,y},true)) { c3Inside = true; }
 
      Update(null);
      return true;
   }
 
 
   bool OnLeftButtonDown(int x, int y, Modifiers mods)
   {
      bool tc1, tc2, tc3;
      String msg;
 
      msg = "The click happend outside of any circle"; //default value
 
      tc1 = c1.isPointInside({x,y},true); // Sometimes you want the border to be considered as the
                                    // part of the circle, then you say true, but if you do not want
                                    // to have border included in the calculations then just put
                                    // false and it will not be counted
      tc2 = c2.isPointInside({x,y},false);
      tc3 = c3.isPointInside({x,y},true);
 
      if(tc1)  { msg = "the 'c1' circle was hit"; }
      else if(tc2) { msg = "the 'c2' circle was hit"; }
      else if(tc3) { msg = "the 'c3' circle was hit"; }
 
      MessageBox {this, text = "results", contents = msg}.Modal();
 
      return true;
   }
 
   bool OnRightButtonDown(int x, int y, Modifiers mods)
   {
      //Lets see if the circles are overlapping each other...
      if(c1.Overlap(c2))
      {
         MessageBox {this, text = "results", contents = "c1 and c2 overlap"}.Modal();
      }
      if(c1.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c1 and c3 overlap"}.Modal();
      }
      if(c2.Overlap(c3))
      {
         MessageBox {this, text = "results", contents = "c2 and c3 overlap"}.Modal();
      }
      return true;
   }
 
}
 
Form1 form1 {};
Form2 form2 {};
I might pick some things from this code when I add more graphics features to the Ecere graphics engine. Ideally though, the circle implementation would be a bit more optimal, implemented at the graphics driver level. If I don't have time to do this before the next release, I might include this circles.ec as part of the sdk/extras if you wish! Also I want to add round rectangle buttons since I read Steve Jobs biography, hehe he was a big fan of round rectangles!

Keep up the great work! =)

All the best,

Jerome
Attachments
circles.ec
(12.9 KiB) Downloaded 1431 times
D.Bane
Posts: 78
Joined: Thu Jul 29, 2010 2:51 pm

Re: Ecere DLL update - class Circle

Post by D.Bane »

Hi Jerome,

Thank you for putting it all in one file. Yes, now that you have mentioned it, I searched for it and for some reason I had it in Surface.ec, not in units.ec, don't know why.. Thanks for noticing it.

If you want you can put it in extras, as far as I know all code we 'give to Ecere' is for everyone to use in Ecere :) (do not remember the exact post, something with 3D engine..) so it is up to you to put it in any place you think it would benefit people the best :)

I also like rounded buttons, and circles as buttons, so when I have time I will surely have a better algorithm for rounded rectangles, the one I currently have is hard coded for a bit roundish effect and I want 'border-radius' property on buttons..

[quote=jerome]Ideally though, the circle implementation would be a bit more optimal, implemented at the graphics driver level.[/quote] - Is it not like that? Should I have not added it in Surface.ec but in all .ec files found at ecere.dll/src/gfx/drivers? If that is true I would do that when I have some time again for ecere (hope soon) as well as for any other thing that I create (similar to this).

Best wishes,
D.Bane.
No army is to big, if the heart is beating strong.
There's no bad luck, it's just easier to blame someone else.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Ecere DLL update - class Circle

Post by jerome »

Hi D.Bane,

Yes, in each driver. For example in OpenGL, a circle would ideally be done with a vertex buffer object (VBO) with precomputed vertices. But all this is really part of doing a big graphics system improvement, so it is best to work together to get that going.

Regards,

Jerome
D.Bane
Posts: 78
Joined: Thu Jul 29, 2010 2:51 pm

Re: Ecere DLL update - class Circle

Post by D.Bane »

Hi Jerome,

OK, then we will talk about it later on to see exactly how that could be accomplished :)

Also, just a note, for now, the Draw Circle function is recursive if you have borderSize bigger then 1, so for borderSize = 3, it would draw 3 circles. When I figure it out for a fast way to fill in the color, that will be replaced as 3 circles, just 1 pixel each smaller then another, will not create a fine border but would instead have few dots missing from it and when filling in the color, you would only need to draw 2 circles and fill in the gaps.

All the best,
D.Bane.
No army is to big, if the heart is beating strong.
There's no bad luck, it's just easier to blame someone else.
Post Reply