Index: uspace/app/uidemo/uidemo.c
===================================================================
--- uspace/app/uidemo/uidemo.c	(revision 2866531314f5a94a44dbcac43bee242556262ce7)
+++ uspace/app/uidemo/uidemo.c	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2024 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -956,4 +956,10 @@
 	}
 
+	rc = ui_tab_create(demo.tabset, "Bars", &demo.tbars);
+	if (rc != EOK) {
+		printf("Error creating tab.\n");
+		return rc;
+	}
+
 	rc = ui_fixed_add(demo.fixed, ui_tab_set_ctl(demo.tabset));
 	if (rc != EOK) {
@@ -1428,4 +1434,39 @@
 
 	ui_tab_add(demo.tlists, ui_fixed_ctl(demo.lfixed));
+
+	rc = ui_fixed_create(&demo.bars_fixed);
+	if (rc != EOK) {
+		printf("Error creating fixed layout.\n");
+		return rc;
+	}
+
+	rc = ui_progress_create(ui_res, 0, &demo.progress);
+	if (rc != EOK) {
+		printf("Error creating entry.\n");
+		return rc;
+	}
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 4;
+		rect.p0.y = 5;
+		rect.p1.x = 42;
+		rect.p1.y = 6;
+	} else {
+		rect.p0.x = 15;
+		rect.p0.y = 88;
+		rect.p1.x = 243;
+		rect.p1.y = 113;
+	}
+
+	ui_progress_set_rect(demo.progress, &rect);
+
+	rc = ui_fixed_add(demo.bars_fixed, ui_progress_ctl(demo.progress));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		return rc;
+	}
+
+	ui_tab_add(demo.tbars, ui_fixed_ctl(demo.bars_fixed));
 
 	ui_window_add(window, ui_fixed_ctl(demo.fixed));
Index: uspace/app/uidemo/uidemo.h
===================================================================
--- uspace/app/uidemo/uidemo.h	(revision 2866531314f5a94a44dbcac43bee242556262ce7)
+++ uspace/app/uidemo/uidemo.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -46,4 +46,5 @@
 #include <ui/menubar.h>
 #include <ui/pbutton.h>
+#include <ui/progress.h>
 #include <ui/rbutton.h>
 #include <ui/scrollbar.h>
@@ -61,4 +62,5 @@
 	ui_fixed_t *bfixed;
 	ui_fixed_t *lfixed;
+	ui_fixed_t *bars_fixed;
 	ui_menu_bar_t *mbar;
 	ui_menu_t *mfile;
@@ -69,4 +71,5 @@
 	ui_tab_t *tbasic;
 	ui_tab_t *tlists;
+	ui_tab_t *tbars;
 	ui_entry_t *entry;
 	ui_image_t *image;
@@ -83,4 +86,5 @@
 	ui_scrollbar_t *vscrollbar;
 	ui_list_t *list;
+	ui_progress_t *progress;
 } ui_demo_t;
 
Index: uspace/lib/ui/include/types/ui/progress.h
===================================================================
--- uspace/lib/ui/include/types/ui/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
+++ uspace/lib/ui/include/types/ui/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libui
+ * @{
+ */
+/**
+ * @file Progress bar
+ */
+
+#ifndef _UI_TYPES_PROGRESS_H
+#define _UI_TYPES_PROGRESS_H
+
+struct ui_progress;
+typedef struct ui_progress ui_progress_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/include/ui/progress.h
===================================================================
--- uspace/lib/ui/include/ui/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
+++ uspace/lib/ui/include/ui/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libui
+ * @{
+ */
+/**
+ * @file Progress bar
+ */
+
+#ifndef _UI_PROGRESS_H
+#define _UI_PROGRESS_H
+
+#include <errno.h>
+#include <gfx/coord.h>
+#include <types/ui/progress.h>
+#include <types/ui/control.h>
+#include <types/ui/resource.h>
+
+extern errno_t ui_progress_create(ui_resource_t *, unsigned, ui_progress_t **);
+extern void ui_progress_destroy(ui_progress_t *);
+extern ui_control_t *ui_progress_ctl(ui_progress_t *);
+extern void ui_progress_set_rect(ui_progress_t *, gfx_rect_t *);
+extern void ui_progress_set_value(ui_progress_t *, unsigned);
+extern errno_t ui_progress_paint(ui_progress_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/meson.build
===================================================================
--- uspace/lib/ui/meson.build	(revision 2866531314f5a94a44dbcac43bee242556262ce7)
+++ uspace/lib/ui/meson.build	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -1,4 +1,4 @@
 #
-# Copyright (c) 2023 Jiri Svoboda
+# Copyright (c) 2026 Jiri Svoboda
 # All rights reserved.
 #
@@ -49,4 +49,5 @@
 	'src/pbutton.c',
 	'src/popup.c',
+	'src/progress.c',
 	'src/promptdialog.c',
 	'src/rbutton.c',
@@ -85,4 +86,5 @@
 	'test/popup.c',
 	'test/promptdialog.c',
+	'test/progress.c',
 	'test/rbutton.c',
 	'test/resource.c',
Index: uspace/lib/ui/private/progress.h
===================================================================
--- uspace/lib/ui/private/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
+++ uspace/lib/ui/private/progress.h	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libui
+ * @{
+ */
+/**
+ * @file Progress bar structure
+ *
+ */
+
+#ifndef _UI_PRIVATE_PROGRESS_H
+#define _UI_PRIVATE_PROGRESS_H
+
+#include <gfx/coord.h>
+
+/** Actual structure of progress bar.
+ *
+ * This is private to libui.
+ */
+struct ui_progress {
+	/** Base control object */
+	struct ui_control *control;
+	/** UI resource */
+	struct ui_resource *res;
+	/** Progress bar rectangle */
+	gfx_rect_t rect;
+	/** Progress value (percentage) */
+	unsigned value;
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ui/src/progress.c
===================================================================
--- uspace/lib/ui/src/progress.c	(revision 2f1be23019121ef252e253d50391d830bc095887)
+++ uspace/lib/ui/src/progress.c	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libui
+ * @{
+ */
+/**
+ * @file Progress bar
+ */
+
+#include <errno.h>
+#include <gfx/color.h>
+#include <gfx/context.h>
+#include <gfx/render.h>
+#include <gfx/text.h>
+#include <io/pos_event.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ui/control.h>
+#include <ui/paint.h>
+#include <ui/progress.h>
+#include "../private/progress.h"
+#include "../private/resource.h"
+
+enum {
+	progress_box_w = 16,
+	progress_box_h = 16,
+	progress_label_margin = 8,
+	progress_cross_n = 5,
+	progress_cross_w = 2,
+	progress_cross_h = 2
+};
+
+static void ui_progress_ctl_destroy(void *);
+static errno_t ui_progress_ctl_paint(void *);
+static ui_evclaim_t ui_progress_ctl_pos_event(void *, pos_event_t *);
+
+/** Progress bar control ops */
+ui_control_ops_t ui_progress_ops = {
+	.destroy = ui_progress_ctl_destroy,
+	.paint = ui_progress_ctl_paint,
+	.pos_event = ui_progress_ctl_pos_event
+};
+
+/** Create new progress bar.
+ *
+ * @param resource UI resource
+ * @param value Initial progress value
+ * @param rprogress Place to store pointer to new progress bar
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t ui_progress_create(ui_resource_t *resource, unsigned value,
+    ui_progress_t **rprogress)
+{
+	ui_progress_t *progress;
+	errno_t rc;
+
+	progress = calloc(1, sizeof(ui_progress_t));
+	if (progress == NULL)
+		return ENOMEM;
+
+	rc = ui_control_new(&ui_progress_ops, (void *) progress,
+	    &progress->control);
+	if (rc != EOK) {
+		free(progress);
+		return rc;
+	}
+
+	progress->value = value;
+	progress->res = resource;
+	*rprogress = progress;
+	return EOK;
+}
+
+/** Destroy progress bar.
+ *
+ * @param progress Progress bar or @c NULL
+ */
+void ui_progress_destroy(ui_progress_t *progress)
+{
+	if (progress == NULL)
+		return;
+
+	ui_control_delete(progress->control);
+	free(progress);
+}
+
+/** Get base control from progress bar.
+ *
+ * @param progress Progress bar
+ * @return Control
+ */
+ui_control_t *ui_progress_ctl(ui_progress_t *progress)
+{
+	return progress->control;
+}
+
+/** Set progress bar rectangle.
+ *
+ * @param progress Progress bar
+ * @param rect New progress bar rectangle
+ */
+void ui_progress_set_rect(ui_progress_t *progress, gfx_rect_t *rect)
+{
+	progress->rect = *rect;
+}
+
+/** Set progress bar value.
+ *
+ * @param progress Progress bar
+ * @param value New progress bar value
+ */
+void ui_progress_set_value(ui_progress_t *progress, unsigned value)
+{
+	progress->value = value;
+}
+
+/** Paint done/remaining part of progress bar.
+ *
+ * @param progress Progress bar
+ * @param bool remain @c true to paint remaining part
+ * @param rect Rectangle of the part
+ * @return EOK on success or an error code
+ */
+static errno_t ui_progress_paint_part(ui_progress_t *progress,
+    gfx_rect_t *rect, bool remain)
+{
+	gfx_coord2_t pos;
+	gfx_text_fmt_t fmt;
+	errno_t rc;
+
+	/* Set clipping rectangle. */
+	rc = gfx_set_clip_rect(progress->res->gc, rect);
+	if (rc != EOK)
+		return rc;
+
+	/* Paint background */
+
+	rc = gfx_set_color(progress->res->gc, remain ?
+	    progress->res->entry_bg_color :
+	    progress->res->entry_sel_text_bg_color);
+	if (rc != EOK)
+		goto error;
+
+	rc = gfx_fill_rect(progress->res->gc, rect);
+	if (rc != EOK)
+		goto error;
+
+	/* Paint label */
+
+	pos.x = (progress->rect.p0.x + progress->rect.p1.x) / 2;
+	pos.y = (progress->rect.p0.y + progress->rect.p1.y) / 2;
+
+	gfx_text_fmt_init(&fmt);
+	fmt.font = progress->res->font;
+	fmt.color = remain ? progress->res->entry_fg_color :
+	    progress->res->entry_sel_text_fg_color;
+	fmt.halign = gfx_halign_center;
+	fmt.valign = gfx_valign_center;
+
+	rc = gfx_puttext(&pos, &fmt, "42 %");
+	if (rc != EOK)
+		goto error;
+
+	rc = gfx_update(progress->res->gc);
+	if (rc != EOK)
+		goto error;
+
+	return gfx_set_clip_rect(progress->res->gc, NULL);
+error:
+	(void)gfx_set_clip_rect(progress->res->gc, NULL);
+	return rc;
+}
+
+/** Paint progress bar.
+ *
+ * @param progress Progress bar
+ * @return EOK on success or an error code
+ */
+errno_t ui_progress_paint(ui_progress_t *progress)
+{
+	gfx_rect_t inside;
+	gfx_rect_t part;
+	errno_t rc;
+
+	if (progress->res->textmode) {
+		/* no frame in textmode */
+		inside = progress->rect;
+	} else {
+		/* Paint progress frame */
+
+		rc = ui_paint_inset_frame(progress->res, &progress->rect,
+		    &inside);
+		if (rc != EOK)
+			goto error;
+	}
+
+	/* Paint completed part. */
+	part.p0 = inside.p0;
+	part.p1.x = (inside.p0.x + inside.p1.x) / 2;
+	part.p1.y = inside.p1.y;
+
+	rc = ui_progress_paint_part(progress, &part, false);
+	if (rc != EOK)
+		goto error;
+
+	/* Paint remaining part. */
+	part.p0.x = part.p1.x;
+	part.p1.x = inside.p1.x;
+
+	rc = ui_progress_paint_part(progress, &part, true);
+	if (rc != EOK)
+		goto error;
+
+	rc = gfx_update(progress->res->gc);
+	if (rc != EOK)
+		goto error;
+
+	return EOK;
+error:
+	return rc;
+}
+
+/** Destroy progress bar control.
+ *
+ * @param arg Argument (ui_progress_t *)
+ */
+void ui_progress_ctl_destroy(void *arg)
+{
+	ui_progress_t *progress = (ui_progress_t *) arg;
+
+	ui_progress_destroy(progress);
+}
+
+/** Paint progress bar control.
+ *
+ * @param arg Argument (ui_progress_t *)
+ * @return EOK on success or an error code
+ */
+errno_t ui_progress_ctl_paint(void *arg)
+{
+	ui_progress_t *progress = (ui_progress_t *) arg;
+
+	return ui_progress_paint(progress);
+}
+
+/** Handle progress bar position event.
+ *
+ * @param arg Argument (ui_progress_t *)
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_progress_ctl_pos_event(void *arg, pos_event_t *event)
+{
+	ui_progress_t *progress = (ui_progress_t *) arg;
+
+	(void) progress;
+	return ui_unclaimed;
+}
+
+/** @}
+ */
Index: uspace/lib/ui/test/progress.c
===================================================================
--- uspace/lib/ui/test/progress.c	(revision 2f1be23019121ef252e253d50391d830bc095887)
+++ uspace/lib/ui/test/progress.c	(revision 2f1be23019121ef252e253d50391d830bc095887)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gfx/context.h>
+#include <gfx/coord.h>
+#include <mem.h>
+#include <pcut/pcut.h>
+#include <stdbool.h>
+#include <ui/control.h>
+#include <ui/progress.h>
+#include <ui/resource.h>
+#include "../private/progress.h"
+#include "../private/testgc.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(progress);
+
+/** Create and destroy progress bar */
+PCUT_TEST(create_destroy)
+{
+	ui_progress_t *progress = NULL;
+	errno_t rc;
+
+	rc = ui_progress_create(NULL, 0, &progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(progress);
+
+	ui_progress_destroy(progress);
+}
+
+/** ui_progress_destroy() can take NULL argument (no-op) */
+PCUT_TEST(destroy_null)
+{
+	ui_progress_destroy(NULL);
+}
+
+/** ui_progress_ctl() returns control that has a working virtual destructor */
+PCUT_TEST(ctl)
+{
+	ui_progress_t *progress;
+	ui_control_t *control;
+	errno_t rc;
+
+	rc = ui_progress_create(NULL, 0, &progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	control = ui_progress_ctl(progress);
+	PCUT_ASSERT_NOT_NULL(control);
+
+	ui_control_destroy(control);
+}
+
+/** Set progress bar rectangle sets internal field */
+PCUT_TEST(set_rect)
+{
+	ui_progress_t *progress;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = ui_progress_create(NULL, 0, &progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 1;
+	rect.p0.y = 2;
+	rect.p1.x = 3;
+	rect.p1.y = 4;
+
+	ui_progress_set_rect(progress, &rect);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.x, progress->rect.p0.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p0.y, progress->rect.p0.y);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.x, progress->rect.p1.x);
+	PCUT_ASSERT_INT_EQUALS(rect.p1.y, progress->rect.p1.y);
+
+	ui_progress_destroy(progress);
+}
+
+/** Set progress bar value sets internal field */
+PCUT_TEST(set_value)
+{
+	ui_progress_t *progress;
+	errno_t rc;
+
+	rc = ui_progress_create(NULL, 0, &progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_progress_set_value(progress, 42);
+	PCUT_ASSERT_INT_EQUALS(42, progress->value);
+
+	ui_progress_destroy(progress);
+}
+
+/** Paint progress bar */
+PCUT_TEST(paint)
+{
+	errno_t rc;
+	gfx_context_t *gc = NULL;
+	test_gc_t tgc;
+	ui_resource_t *resource = NULL;
+	ui_progress_t *progress;
+
+	memset(&tgc, 0, sizeof(tgc));
+	rc = gfx_context_new(&ops, &tgc, &gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_resource_create(gc, false, &resource);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(resource);
+
+	rc = ui_progress_create(resource, 0, &progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = ui_progress_paint(progress);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_progress_destroy(progress);
+	ui_resource_destroy(resource);
+
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
+PCUT_EXPORT(progress);
