Index: uspace/lib/ui/include/ui/paint.h
===================================================================
--- uspace/lib/ui/include/ui/paint.h	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/include/ui/paint.h	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2022 Jiri Svoboda
  * All rights reserved.
  *
@@ -59,4 +59,6 @@
 extern errno_t ui_paint_text_hbrace(ui_resource_t *, gfx_rect_t *,
     ui_box_style_t, gfx_color_t *);
+extern errno_t ui_paint_text_rect(ui_resource_t *, gfx_rect_t *, gfx_color_t *,
+    const char *);
 extern void ui_text_fmt_init(ui_text_fmt_t *);
 extern gfx_coord_t ui_text_width(gfx_font_t *, const char *);
Index: uspace/lib/ui/private/scrollbar.h
===================================================================
--- uspace/lib/ui/private/scrollbar.h	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/private/scrollbar.h	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -107,6 +107,5 @@
 
 extern errno_t ui_scrollbar_paint_gfx(ui_scrollbar_t *);
-extern errno_t ui_scrollbar_paint_text_horiz(ui_scrollbar_t *);
-extern errno_t ui_scrollbar_paint_text_vert(ui_scrollbar_t *);
+extern errno_t ui_scrollbar_paint_text(ui_scrollbar_t *);
 extern void ui_scrollbar_get_geom(ui_scrollbar_t *, ui_scrollbar_geom_t *);
 
Index: uspace/lib/ui/src/paint.c
===================================================================
--- uspace/lib/ui/src/paint.c	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/src/paint.c	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -555,4 +555,59 @@
 }
 
+/** Fill rectangle with text character.
+ *
+ * @param resource UI resource
+ * @param rect Rectangle
+ * @param color Color
+ * @param gchar Character to fill with
+ * @return EOK on success or an error code
+ */
+errno_t ui_paint_text_rect(ui_resource_t *resource, gfx_rect_t *rect,
+    gfx_color_t *color, const char *gchar)
+{
+	gfx_coord2_t pos;
+	gfx_text_fmt_t fmt;
+	gfx_rect_t srect;
+	gfx_coord_t w, i;
+	char *buf;
+	size_t gcharsz;
+	errno_t rc;
+
+	gfx_rect_points_sort(rect, &srect);
+
+	gfx_text_fmt_init(&fmt);
+	fmt.font = resource->font;
+	fmt.color = color;
+	fmt.halign = gfx_halign_left;
+	fmt.valign = gfx_valign_top;
+
+	w = srect.p1.x - srect.p0.x;
+	if (w == 0)
+		return EOK;
+
+	gcharsz = str_size(gchar);
+
+	buf = malloc(w * gcharsz + 1);
+	if (buf == NULL)
+		return ENOMEM;
+
+	for (i = 0; i < w; i++)
+		str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
+	buf[w * gcharsz] = '\0';
+
+	pos.x = srect.p0.x;
+	for (pos.y = srect.p0.y; pos.y < srect.p1.y; pos.y++) {
+		rc = gfx_puttext(&pos, &fmt, buf);
+		if (rc != EOK)
+			goto error;
+	}
+
+	free(buf);
+	return EOK;
+error:
+	free(buf);
+	return rc;
+}
+
 /** Initialize UI text formatting structure.
  *
Index: uspace/lib/ui/src/scrollbar.c
===================================================================
--- uspace/lib/ui/src/scrollbar.c	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/src/scrollbar.c	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -526,52 +526,22 @@
 }
 
-/** Paint horizontal scrollbar in text mode.
+/** Paint scrollbar in text mode.
  *
  * @param scrollbar Scrollbar
  * @return EOK on success or an error code
  */
-errno_t ui_scrollbar_paint_text_horiz(ui_scrollbar_t *scrollbar)
+errno_t ui_scrollbar_paint_text(ui_scrollbar_t *scrollbar)
 {
 	ui_resource_t *resource;
-	gfx_coord2_t pos;
-	gfx_text_fmt_t fmt;
-	gfx_coord_t w, i;
-	char *buf;
-	const char *gchar;
-	size_t gcharsz;
+	ui_scrollbar_geom_t geom;
 	errno_t rc;
 
 	resource = ui_window_get_res(scrollbar->window);
+	ui_scrollbar_get_geom(scrollbar, &geom);
 
 	/* Paint scrollbar through */
 
-	pos = scrollbar->rect.p0;
-	pos.x += ui_scrollbar_btn_len_text;
-
-	gfx_text_fmt_init(&fmt);
-	fmt.font = resource->font;
-	fmt.color = resource->sbar_through_color;
-	fmt.halign = gfx_halign_left;
-	fmt.valign = gfx_valign_top;
-
-	w = scrollbar->rect.p1.x - scrollbar->rect.p0.x -
-	    2 * ui_scrollbar_btn_len_text;
-	assert(w >= 0);
-	if (w < 0)
-		return EINVAL;
-
-	gchar = "\u2592";
-	gcharsz = str_size(gchar);
-
-	buf = malloc(w * gcharsz + 1);
-	if (buf == NULL)
-		return ENOMEM;
-
-	for (i = 0; i < w; i++)
-		str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
-	buf[w * gcharsz] = '\0';
-
-	rc = gfx_puttext(&pos, &fmt, buf);
-	free(buf);
+	rc = ui_paint_text_rect(resource, &geom.through_rect,
+	    resource->sbar_through_color, "\u2592");
 	if (rc != EOK)
 		goto error;
@@ -579,22 +549,10 @@
 	/* Paint scrollbar thumb */
 
-	pos.x += scrollbar->pos;
-
-	gchar = "\u25a0";
-	gcharsz = str_size(gchar);
-	w = scrollbar->thumb_len;
-
-	buf = malloc(w * gcharsz + 1);
-	if (buf == NULL)
-		return ENOMEM;
-
-	for (i = 0; i < w; i++)
-		str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
-	buf[w * gcharsz] = '\0';
-
-	rc = gfx_puttext(&pos, &fmt, buf);
-	free(buf);
-	if (rc != EOK)
-		goto error;
+	rc = ui_paint_text_rect(resource, &geom.thumb_rect,
+	    resource->sbar_through_color, "\u25a0");
+	if (rc != EOK)
+		goto error;
+
+	/* Paint buttons */
 
 	rc = ui_pbutton_paint(scrollbar->up_btn);
@@ -615,68 +573,9 @@
 }
 
-/** Paint vertical scrollbar in text mode.
+/** Paint scrollbar.
  *
  * @param scrollbar Scrollbar
  * @return EOK on success or an error code
  */
-errno_t ui_scrollbar_paint_text_vert(ui_scrollbar_t *scrollbar)
-{
-	ui_resource_t *resource;
-	ui_scrollbar_geom_t geom;
-	gfx_coord2_t pos;
-	gfx_text_fmt_t fmt;
-	errno_t rc;
-
-	resource = ui_window_get_res(scrollbar->window);
-	ui_scrollbar_get_geom(scrollbar, &geom);
-
-	/* Paint scrollbar through */
-
-	gfx_text_fmt_init(&fmt);
-	fmt.font = resource->font;
-	fmt.color = resource->sbar_through_color;
-	fmt.halign = gfx_halign_left;
-	fmt.valign = gfx_valign_top;
-
-	pos.x = scrollbar->rect.p0.x;
-	for (pos.y = geom.through_rect.p0.y; pos.y < geom.through_rect.p1.y;
-	    pos.y++) {
-		rc = gfx_puttext(&pos, &fmt, "\u2592");
-		if (rc != EOK)
-			goto error;
-	}
-
-	/* Paint scrollbar thumb */
-
-	pos.x = geom.thumb_rect.p0.x;
-	for (pos.y = geom.thumb_rect.p0.y; pos.y < geom.thumb_rect.p1.y;
-	    pos.y++) {
-		rc = gfx_puttext(&pos, &fmt, "\u25a0");
-		if (rc != EOK)
-			goto error;
-	}
-
-	rc = ui_pbutton_paint(scrollbar->up_btn);
-	if (rc != EOK)
-		goto error;
-
-	rc = ui_pbutton_paint(scrollbar->down_btn);
-	if (rc != EOK)
-		goto error;
-
-	rc = gfx_update(resource->gc);
-	if (rc != EOK)
-		goto error;
-
-	return EOK;
-error:
-	return rc;
-}
-
-/** Paint scrollbar.
- *
- * @param scrollbar Scrollbar
- * @return EOK on success or an error code
- */
 errno_t ui_scrollbar_paint(ui_scrollbar_t *scrollbar)
 {
@@ -684,8 +583,5 @@
 
 	if (resource->textmode) {
-		if (scrollbar->dir == ui_sbd_horiz)
-			return ui_scrollbar_paint_text_horiz(scrollbar);
-		else
-			return ui_scrollbar_paint_text_vert(scrollbar);
+		return ui_scrollbar_paint_text(scrollbar);
 	} else {
 		return ui_scrollbar_paint_gfx(scrollbar);
Index: uspace/lib/ui/test/paint.c
===================================================================
--- uspace/lib/ui/test/paint.c	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/test/paint.c	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2022 Jiri Svoboda
  * All rights reserved.
  *
@@ -313,4 +313,40 @@
 }
 
+/** Paint text rectangle */
+PCUT_TEST(text_rect)
+{
+	errno_t rc;
+	gfx_context_t *gc = NULL;
+	ui_resource_t *resource = NULL;
+	gfx_color_t *color = NULL;
+	test_gc_t tgc;
+	gfx_rect_t rect;
+
+	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 = gfx_color_new_rgb_i16(1, 2, 3, &color);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 10;
+	rect.p0.y = 20;
+	rect.p1.x = 30;
+	rect.p1.y = 40;
+
+	/* Paint text box */
+	rc = ui_paint_text_rect(resource, &rect, color, "A");
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	gfx_color_delete(color);
+	ui_resource_destroy(resource);
+	rc = gfx_context_delete(gc);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+}
+
 static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
 {
Index: uspace/lib/ui/test/scrollbar.c
===================================================================
--- uspace/lib/ui/test/scrollbar.c	(revision 7ca721557bbbab9db7f7e937549e3e6bed609586)
+++ uspace/lib/ui/test/scrollbar.c	(revision 0d1d0ea5834bc4827a116522267acc391b94d31d)
@@ -206,5 +206,5 @@
 }
 
-/** Paint horizontal scrollbar in text mode */
+/** Paint scrollbar in text mode */
 PCUT_TEST(paint_text_horiz)
 {
@@ -235,42 +235,5 @@
 	ui_scrollbar_set_rect(scrollbar, &rect);
 
-	rc = ui_scrollbar_paint_text_horiz(scrollbar);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	ui_scrollbar_destroy(scrollbar);
-	ui_window_destroy(window);
-	ui_destroy(ui);
-}
-
-/** Paint vertical scrollbar in text mode */
-PCUT_TEST(paint_text_vert)
-{
-	ui_t *ui = NULL;
-	ui_window_t *window = NULL;
-	ui_wnd_params_t params;
-	ui_scrollbar_t *scrollbar;
-	gfx_rect_t rect;
-	errno_t rc;
-
-	rc = ui_create_disp(NULL, &ui);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	ui_wnd_params_init(&params);
-	params.caption = "Hello";
-
-	rc = ui_window_create(ui, &params, &window);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-	PCUT_ASSERT_NOT_NULL(window);
-
-	rc = ui_scrollbar_create(ui, window, ui_sbd_vert, &scrollbar);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rect.p0.x = 1;
-	rect.p0.y = 1;
-	rect.p1.x = 2;
-	rect.p1.y = 10;
-	ui_scrollbar_set_rect(scrollbar, &rect);
-
-	rc = ui_scrollbar_paint_text_vert(scrollbar);
+	rc = ui_scrollbar_paint_text(scrollbar);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
