# Learn graphics for theoretical gui with rust

Hello guys, I would like to show you my repository:

Its purpose is to help learn how the complex graphics we find in modern graphical user interfaces are drawn, and how the UI works.

I also hope that it is consistent with the goals mentioned at https://areweguiyet.com/

1 Like

# Pie chart algorithm

To draw a pie chart - which is used to represent data in circular sections- there are several ways Algorithms in order to do this.
In this example we will use straight lines and mask to do this with Tiny-Skia.

We have user defined inputs:
x, y are the position of the pie chart, r is radius, pie_slices is represented data: (red, green, blue, alpha, value), full_pie is the total/full value, mask is mask layer, paint is shader/color in pixmap.

First, we draw a complete circle that serves as the background or the complementary part of the pie chart if the total data is less than the full value full_pie

``````    let mut bgcircle = PathBuilder::new();
bgcircle.push_circle(x, y , r);
let mut bgpaint = Paint::default();
bgpaint.set_color_rgba8(bgcolor.0 as u8, bgcolor.1 as u8, bgcolor.2 as u8, bgcolor.3 as u8);
bgpaint.anti_alias = true;
let bgpath = bgcircle.finish().unwrap();
pixmap.fill_path(
&bgpath,
&bgpaint,
FillRule::EvenOdd,
Transform::identity(),
None
);

`````` Now we draw the pie, by drawing a square and dividing it into 8 equal parts, each part has an angle at the point (x, y) measuring 45 degrees. A line will be drawn whose starting point is (x,y) and whose ending point is (last_point_x , last_point_y ).

``````        pb.move_to(x , y );
pb.line_to(last_point_x , last_point_y );
``````

The ending point (last_point_x , last_point_y) is predetermined given the degree of the previous segment along with the degree of the current segment, and it will be on one of the sides of the square.

``````if degree > 0.0 && degree <= 45.0{
new_point_x = x + (r * (degree/45.0));
new_point_y = y-r
}
else if degree > 45.0 && degree <= 90.0 {
new_point_x = x+r;
new_point_y = y - (r * (90.0-degree )/45.0);
}
else if degree > 90.0 && degree <= 135.0{
new_point_x = x+r;
new_point_y = y + (r * (degree-90.0)/45.0 );
}
else if degree > 135.0 && degree <= 180.0{
new_point_x = x+r - (r * (degree-135.0)/45.0 );
new_point_y = y+r;
}
else if degree > 180.0 && degree <= 225.0 {
new_point_x = x - (r * (degree-180.0)/45.0 );
new_point_y = y+r;
}
else if  degree > 225.0 && degree <= 270.0{
new_point_x = x - r;
new_point_y = y+r - (r * (degree-225.0)/45.0 )
}
else if  degree > 270.0 && degree <= 315.0{
new_point_x = x- r;
new_point_y = y - (r * (degree-270.0)/45.0 );
}
else if  degree > 315.0 && degree <= 360.0{
new_point_x = x-r + (r * (degree-315.0)/45.0 );
new_point_y = y-r
}
``````

Then we draw other lines to close the section of the square

``````if used_degree>=0.0 && used_degree<45.0 {
if degree > 45.0 && degree <= 135.0{
pb.line_to(x+r , last_point_y );
}
else if degree > 135.0 && degree <= 225.0{
pb.line_to(x+r , y-r );
pb.line_to(x+r , y+r );
pb.line_to(last_point_x , y+r );
}
else if degree > 225.0 && degree <= 315.0{
pb.line_to(x+r , y-r );
pb.line_to(x+r , y+r );
pb.line_to(x-r , y+r );
pb.line_to(x-r , last_point_y );
}
else if degree > 315.0 && degree <= 360.0{
pb.line_to(x+r , y-r );
pb.line_to(x+r , y+r );
pb.line_to(x-r , y+r );
pb.line_to(x-r , y-r );
pb.line_to(last_point_x , y-r );
}
}
else if  used_degree>=45.0 && used_degree<135.0 {
if degree > 135.0 && degree <= 225.0{
pb.line_to(x+r , y+r );
pb.line_to(last_point_x , y+r );
}
else if degree > 225.0 && degree <= 315.0{
pb.line_to(x+r , y+r );
pb.line_to(x-r , y+r );
pb.line_to(x-r , last_point_y );
}
else if degree > 315.0 && degree <= 360.0{
pb.line_to(x+r , y+r );
pb.line_to(x-r , y+r );
pb.line_to(x-r , y-r );
pb.line_to(last_point_x , y-r );
}
}
else if used_degree>=135.0 && used_degree<225.0 {
if degree > 225.0 && degree <= 315.0{
pb.line_to(x-r , y+r );
pb.line_to(x-r , last_point_y );
}
else if degree > 315.0 && degree <= 360.0{
pb.line_to(x-r , y+r );
pb.line_to(x-r , y-r );
}
}
else if  used_degree>=225.0 && used_degree<315.0{
if degree > 315.0 && degree <= 360.0{
pb.line_to(x-r , y+r );
pb.line_to(x-r , y-r );
pb.line_to(last_point_x , y-r );
}

}
``````

For example: When we draw the first segment whose degree is 60, the following values are as follows:

``````last_point_x = x, last_point_y = y-r, used_degree = 0.0, degree = 60.0
``````

Note : degree = 360.0 * (the value from pie_slices's item / full_pie ) + used_degree =
360.0 * (60.0 / 360.0) + 0.0 = 60
, full_pie = 360.0
In this case:

``````        else if degree > 45.0 && degree <= 90.0 {
new_point_x = x+r;
new_point_y = y - (r * (90.0-degree )/45.0);
}
``````
``````if used_degree>=0.0 && used_degree<45.0 {
if degree > 45.0 && degree <= 135.0{
pb.line_to(x+r , last_point_y );
}
`````` The variables are then assigned values ​​that are used to plot the next section

``````last_point_x = new_point_x = x+r, last_point_y = new_point_y = y - (r * (90.0-degree )/45.0), used_degree = degree = 60.0
``````

When we draw the second segment whose degree is 95, the following values are as follows:

``````last_point_x = x+r, last_point_y = y - (r * (90.0-60.0 )/45.0), used_degree = 60.0,
degree = 360.0 * (the value from pie_slices's item / full_pie ) + used_degree = 360.0 * (95.0 / 360) + 60.0 = 155.0
``````

In this case:

``````        else if degree > 135.0 && degree <= 180.0{
new_point_x = x+r - (r * (degree-135.0)/45.0 );
new_point_y = y+r;
}
``````
``````        else if  used_degree>=45.0 && used_degree<135.0 {
if degree > 135.0 && degree <= 225.0{
pb.line_to(x+r , y+r );
pb.line_to(last_point_x , y+r );
}
`````` The variables are then assigned values ​​that are used to plot the next section

``````last_point_x = new_point_x = x+r - (r * (degree-135.0)/45.0 ), last_point_y = new_point_y = y+r, used_degree = degree = 155.0
``````

And so on.
We will end up with this form: We see that there is a missing part because the sum of the data values ​​is less than the full value specified by the user. The back circle will appear as if it is the missing part.

Finally, we draw another circle that will be used as a mask to cut the square and turn it into a circle:

``````let mut mpb = PathBuilder::new();
mpb.push_circle(x , y , r );
let mut mpaint = Paint::default();
mpaint.set_color_rgba8(0, 0, 0, 255);
mpaint.anti_alias = true;
let path = pb.finish().unwrap();
let mpath = mpb.finish().unwrap();
``````
``````        paint.set_color_rgba8(red as u8,green as u8, blue as u8, alpha as u8);
paint.anti_alias = true;
pixmap.fill_path(
&path,
&paint,
FillRule::EvenOdd,
Transform::identity(),
);
``````

We get the final output: # Rounded rectangle algorithm

To draw a rounded rectangle - which is used as a button widget in modern GUI - there are several ways Algorithms in order to do this.
In this example we will use straight lines and cubic curves to do this with Tiny-Skia.
In the file rounded_corners_rectangle_1.rs:

``````    // x, y are shape position, w is width, h is height and r is cubic curve sides length.
//  Set limits for r, such that the sides of the curves do not intersect each other.
//==============================================================================
if h>w{
if r > 0.24 * w{
r = 0.24 * w
}
}
else if h<w {
if r > 0.24 * h{
r = 0.24 * h
}
}
else if h==w {
if r > 0.24 * w{
r = 0.24 * w
}
}
//==============================================================================
// Cubic curves used as corners of the rectangle.
//==============================================================================
let mut pb = PathBuilder::new();
pb.move_to(x+r, y);
pb.line_to(w-r, y);
pb.cubic_to(w-(r/2 as f32),y,w,y+(r/2 as f32),w,y+r);
pb.line_to(w, h-r);
pb.cubic_to(w,h-(r/2 as f32),w-(r/2 as f32),h,w-r, h);
pb.line_to(x+r, h);
pb.cubic_to(x+(r/2 as f32),h,x,h-(r/2 as f32), x ,h-r);
pb.line_to(x, y+r);
pb.cubic_to(x,y+(r/2 as f32),x+(r/2 as f32),y, x+r, y);
pb.close();
``````

The following image may explain how the code works: When we put the values ​​w=800, h=500, and r=60 in the function

``````rounded_corners_rectangle_draw_1(x:f32,y:f32,w:f32,h:f32,mut r:f32) -> Path
``````

, we get the following form:

​​ w=800, h=500, and r=120: ​​w=h: # Graph algorithm

To draw a graph - which is used to represent data in x and y axis- we will use straight lines to do this with Tiny-Skia. We get the final output: 