Index: uspace/lib/ui/src/paint.c
===================================================================
--- uspace/lib/ui/src/paint.c	(revision d70dc1c40835f7e957ea1b4fa52c29db4d21ced4)
+++ uspace/lib/ui/src/paint.c	(revision b085815052c20b5affe3aa85fe5a2e655cfaf6b8)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2021 Jiri Svoboda
  * All rights reserved.
  *
@@ -149,4 +149,120 @@
 }
 
+/** Paint filled circle vertical scanline.
+ *
+ * @param gc Graphic context
+ * @param center Coordinates of the center of the circle
+ * @param x X-coordinate of the scanline
+ * @param y0 Lowest Y coordinate of the scanline (inclusive)
+ * @param y1 Highest Y coordinate of the scanline (inclusive)
+ * @param part Which part(s) of cicle to paint
+ * @return EOK on success or an error code
+ */
+static errno_t ui_paint_fcircle_line(gfx_context_t *gc, gfx_coord2_t *center,
+    gfx_coord_t x, gfx_coord_t y0, gfx_coord_t y1, ui_fcircle_part_t part)
+{
+	gfx_rect_t rect;
+	gfx_rect_t trect;
+
+	rect.p0.x = x;
+	rect.p0.y = y0;
+	rect.p1.x = x + 1;
+	rect.p1.y = y1;
+
+	/* Clip to upper-left/lower-right half of circle, if required */
+
+	if ((part & ui_fcircle_upleft) == 0) {
+		if (rect.p0.y < -rect.p1.x)
+			rect.p0.y = -rect.p1.x;
+	}
+
+	if ((part & ui_fcircle_lowright) == 0) {
+		if (rect.p1.y > -rect.p1.x)
+			rect.p1.y = -rect.p1.x;
+	}
+
+	/* If coordinates are reversed, there is nothing to do */
+	if (rect.p1.y <= rect.p0.y)
+		return EOK;
+
+	gfx_rect_translate(center, &rect, &trect);
+
+	return gfx_fill_rect(gc, &trect);
+}
+
+/** Paint filled circle scanlines corresponding to octant point.
+ *
+ * Fills the four vertical scanlines lying between the eight reflections
+ * of a circle point.
+ *
+ * @param gc Graphic context
+ * @param center Coordinates of the center
+ * @param r Radius in pixels
+ * @param part Which part(s) of cicle to paint
+ * @return EOK on success or an error code
+ */
+static int ui_paint_fcircle_point(gfx_context_t *gc, gfx_coord2_t *center,
+    gfx_coord2_t *p, ui_fcircle_part_t part)
+{
+	errno_t rc;
+
+	rc = ui_paint_fcircle_line(gc, center, +p->x, -p->y, p->y + 1, part);
+	if (rc != EOK)
+		return rc;
+	rc = ui_paint_fcircle_line(gc, center, -p->x, -p->y, p->y + 1, part);
+	if (rc != EOK)
+		return rc;
+	rc = ui_paint_fcircle_line(gc, center, +p->y, -p->x, p->x + 1, part);
+	if (rc != EOK)
+		return rc;
+	rc = ui_paint_fcircle_line(gc, center, -p->y, -p->x, p->x + 1, part);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+/** Paint a filled circle.
+ *
+ * @param gc Graphic context
+ * @param center Coordinates of the center
+ * @param r Radius in pixels
+ * @param part Which part(s) of cicle to paint
+ * @return EOK on success or an error code
+ */
+errno_t ui_paint_filled_circle(gfx_context_t *gc, gfx_coord2_t *center,
+    gfx_coord_t r, ui_fcircle_part_t part)
+{
+	gfx_coord2_t p;
+	gfx_coord_t f;
+	errno_t rc;
+
+	/* Run through one octant using circle midpoint algorithm */
+
+	p.x = r;
+	p.y = 0;
+	f = 1 - r;
+
+	rc = ui_paint_fcircle_point(gc, center, &p, part);
+	if (rc != EOK)
+		return rc;
+
+	while (p.x > p.y) {
+		if (f < 0) {
+			f = f + 2 * p.y + 3;
+		} else {
+			f = f + 2 * (p.y - p.x) + 5;
+			--p.x;
+		}
+		++p.y;
+
+		rc = ui_paint_fcircle_point(gc, center, &p, part);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
 /** @}
  */
