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;
}
};
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;
}
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 );
}
}
}
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 {};
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 {};
All the best to you all,
D.Bane.