예제 #1
0
	graphics_system::graphics_system(core::engine& engine)
	: engine_{engine}, window_{nullptr, [](SDL_Window*){}}, context_{nullptr}, width_{800}, height_{600},
	fullscreen_{false}, clear_color_{glm::vec4{0.4f, 0.6f, 0.9f, 1.f}},
	shader_manager_{std::make_unique<graphics::shader_manager>(engine_)},
	texture_manager_{std::make_unique<graphics::texture_manager>(engine_)} {
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,1);
		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,8);

		auto window_mask = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullscreen_ ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
		name_ = "Behaviour Trees";
		window_ = std::unique_ptr<SDL_Window, void(*)(SDL_Window*)>(
			SDL_CreateWindow(name_.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width_, height_, window_mask),
			SDL_DestroyWindow);

		if (!window_) {
			throw std::runtime_error{"could not create window"};
		}

		auto width = 0;
		auto height = 0;
		SDL_GetWindowSize(window_.get(), &width, &height);
		width_ = width;
		height_ = height;

		try {
			context_ = SDL_GL_CreateContext(window_.get());
		} catch (const std::runtime_error& ex) {
			throw std::runtime_error{std::string{"could not create opengl context with version 4.3. "} + ex.what()};
		}

		SDL_GL_SetSwapInterval(1);

		glewExperimental = GL_TRUE;
		if (glewInit() != GLEW_OK) {
			throw std::runtime_error("requested opengl 4.3 features are not available");
		}

		utils::log << "OpenGL version " << std::string{reinterpret_cast<const char*>(glGetString(GL_VERSION))} << std::endl;

		if(GLEW_KHR_debug){
			glDebugMessageCallback(
				+[](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void*) {
					std::cerr << std::string(message,length) << " (source: " << source << ", type: " <<type<< ", id: "
						<< id <<", severity: " << severity << ")" <<std::endl;
				}, nullptr);
		}
		else{
			utils::log(utils::LOG_WARNING) << "no opengL debug log available." << std::endl;
		}
		clear_color(clear_color_);
	}
예제 #2
0
void test_clear_color()
{
    uint8_t expected_color[3] = {0, 0, 0};
    Color color = create_color(0, 1, 2);
    clear_color(&color);
    
    assert(color.r == expected_color[0]);
    assert(color.g == expected_color[1]);
    assert(color.b == expected_color[2]);

    printf("Clear Color Passed\n");
}
예제 #3
0
파일: winio.cpp 프로젝트: pgengler/pinot
/* Display a message on the statusbar, and set disable_cursorpos to
 * true, so that the message won't be immediately overwritten if
 * constant cursor position display is on. */
void statusbar(const char *msg, ...)
{
	va_list ap;
	char *bar, *foo;
	size_t start_x;
	bool old_whitespace;

	va_start(ap, msg);

	/* Curses mode is turned off.  If we use wmove() now, it will muck
	 * up the terminal settings.  So we just use vfprintf(). */
	if (isendwin()) {
		vfprintf(stderr, msg, ap);
		va_end(ap);
		return;
	}

	blank_statusbar();

	old_whitespace = ISSET(WHITESPACE_DISPLAY);
	UNSET(WHITESPACE_DISPLAY);
	bar = charalloc(mb_cur_max() * (COLS - 3));
	vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap);
	va_end(ap);
	foo = display_string(bar, 0, COLS - 4, false);
	free(bar);
	if (old_whitespace) {
		SET(WHITESPACE_DISPLAY);
	}
	start_x = (COLS - strlenpt(foo) - 4) / 2;

	wmove(bottomwin, 0, start_x);
	set_color(bottomwin, interface_colors[STATUS_BAR]);
	waddstr(bottomwin, "[ ");
	waddstr(bottomwin, foo);
	free(foo);
	waddstr(bottomwin, " ]");
	clear_color(bottomwin, interface_colors[STATUS_BAR]);
	wnoutrefresh(bottomwin);
	reset_cursor();
	wnoutrefresh(edit);
	/* Leave the cursor at its position in the edit window, not in
	 * the statusbar. */

	disable_cursorpos = true;

	/* If we're doing quick statusbar blanking, and constant cursor
	 * position display is off, blank the statusbar after only one
	 * keystroke.  Otherwise, blank it after twenty-six keystrokes, as
	 * Pico does. */
	statusblank = ISSET(QUICK_BLANK) && !ISSET(CONST_UPDATE) ? 1 : 26;
}
예제 #4
0
void test_set_color()
{
    Color expected_color = create_color(255, 255, 255);
    Color color = create_color(0, 1, 2);
    clear_color(&color);
    set_color(&color, &expected_color);
    
    assert(color.r == expected_color.r);
    assert(color.g == expected_color.g);
    assert(color.b == expected_color.b);

    printf("Set Color Passed\n");
}
예제 #5
0
void test_set_rgb_color()
{
    uint8_t expected_color[3] = {255, 255, 255};
    Color color = create_color(0, 1, 2);
    clear_color(&color);
    set_color_rgb(&color, 255, 255, 255);
    
    assert(color.r == expected_color[0]);
    assert(color.g == expected_color[1]);
    assert(color.b == expected_color[2]);

    printf("Set RGB Color Passed\n");
}
예제 #6
0
파일: winio.cpp 프로젝트: pgengler/pinot
/* Write a shortcut key to the help area at the bottom of the window.
 * keystroke is e.g. "^G" and desc is e.g. "Get Help".  We are careful
 * to write at most len characters, even if len is very small and
 * keystroke and desc are long.  Note that waddnstr(,,(size_t)-1) adds
 * the whole string!  We do not bother padding the entry with blanks. */
void onekey(const std::string& keystroke, const std::string& desc, size_t len)
{
	size_t keystroke_len = keystroke.length() + 1;

	set_color(bottomwin, interface_colors[KEY_COMBO]);
	waddnstr(bottomwin, keystroke.c_str(), actual_x(keystroke.c_str(), len));
	clear_color(bottomwin, interface_colors[KEY_COMBO]);

	if (len > keystroke_len) {
		len -= keystroke_len;
	} else {
		len = 0;
	}

	if (len > 0) {
		waddch(bottomwin, ' ');
		waddnstr(bottomwin, desc.c_str(), actual_x(desc.c_str(), len));
	}
}
예제 #7
0
	void render_process::process(const render_state_ptr& state)
	{
		state_ = state;
		switch (state_->cmd_) {
		case cmd_draw:
		case cmd_draw_index:
			{
				draw();
				break;
			}
		case cmd_clear_color:
			{
				clear_color();
				break;
			}
		default:
			{
				assert(0);
				break;
			}
		}
	}
예제 #8
0
파일: winio.cpp 프로젝트: pgengler/pinot
/* edit_draw() takes care of the job of actually painting a line into
 * the edit window.  fileptr is the line to be painted, at row line of
 * the window.  converted is the actual string to be written to the
 * window, with tabs and control characters replaced by strings of
 * regular characters.  start is the column number of the first
 * character of this page.  That is, the first character of converted
 * corresponds to character number actual_x(fileptr->data, start) of the
 * line. */
void edit_draw(filestruct *fileptr, const char *converted, int line, size_t start)
{
	size_t startpos = actual_x(fileptr->data, start);
	/* The position in fileptr->data of the leftmost character
	 * that displays at least partially on the window. */
	size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
	/* The position in fileptr->data of the first character that is
	 * completely off the window to the right.
	 *
	 * Note that endpos might be beyond the null terminator of the
	 * string. */

	assert(openfile != openfiles.end() && fileptr != NULL && converted != NULL);
	assert(strlenpt(converted) <= COLS);

	/* Just paint the string in any case (we'll add color or reverse on
	 * just the text that needs it). */
	mvwaddstr(edit, line, 0, converted);
	/* Tell ncurses to really redraw the line without trying to optimize
	 * for what it thinks is already there, because it gets it wrong in
	 * the case of a wide character in column zero. */
#ifndef USE_SLANG
	wredrawln(edit, line, 1);
#endif

	/* If color syntaxes are available and turned on, we need to display
	 * them. */
	if (!openfile->colorstrings.empty() && !ISSET(NO_COLOR_SYNTAX)) {
		/* Set up multi-line color data for this line if it's not yet calculated  */
		if (fileptr->multidata.empty() && openfile->syntax && openfile->syntax->nmultis > 0) {
			fileptr->multidata.resize(openfile->syntax->nmultis, -1); // assume that '-1' applies until we know otherwise
		}
		for (auto tmpcolor : openfile->colorstrings) {
			int x_start;
			/* Starting column for mvwaddnstr.  Zero-based. */
			int paintlen = 0;
			/* Number of chars to paint on this line.  There are
			 * COLS characters on a whole line. */
			size_t index;
			/* Index in converted where we paint. */
			regmatch_t startmatch;
			/* Match position for start_regex. */
			regmatch_t endmatch;
			/* Match position for end_regex. */

			if (tmpcolor->bright) {
				wattron(edit, A_BOLD);
			}
			if (tmpcolor->underline) {
				wattron(edit, A_UNDERLINE);
			}
			wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
			/* Two notes about regexec().  A return value of zero means
			 * that there is a match.  Also, rm_eo is the first
			 * non-matching character after the match. */

			/* First case,tmpcolor is a single-line expression. */
			if (tmpcolor->end == NULL) {
				size_t k = 0;

				/* We increment k by rm_eo, to move past the end of the
				 * last match.  Even though two matches may overlap, we
				 * want to ignore them, so that we can highlight e.g. C
				 * strings correctly. */
				while (k < endpos) {
					/* Note the fifth parameter to regexec().  It says
					 * not to match the beginning-of-line character
					 * unless k is zero.  If regexec() returns
					 * REG_NOMATCH, there are no more matches in the
					 * line. */
					if (regexec(tmpcolor->start, &fileptr->data[k], 1, &startmatch, (k == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH) {
						break;
					}


					/* Translate the match to the beginning of the
					 * line. */
					startmatch.rm_so += k;
					startmatch.rm_eo += k;

					/* Skip over a zero-length regex match. */
					if (startmatch.rm_so == startmatch.rm_eo) {
						startmatch.rm_eo++;
					} else if (startmatch.rm_so < endpos && startmatch.rm_eo > startpos) {
						x_start = (startmatch.rm_so <= startpos) ? 0 : strnlenpt(fileptr->data, startmatch.rm_so) - start;

						index = actual_x(converted, x_start);

						paintlen = actual_x(converted + index, strnlenpt(fileptr->data, startmatch.rm_eo) - start - x_start);

						assert(0 <= x_start && 0 <= paintlen);

						mvwaddnstr(edit, line, x_start, converted + index, paintlen);
					}
					k = startmatch.rm_eo;
				}
			} else if (!fileptr->multidata.empty() && fileptr->multidata[tmpcolor->id] != CNONE) {
				/* This is a multi-line regex.  There are two steps.
				 * First, we have to see if the beginning of the line is
				 * colored by a start on an earlier line, and an end on
				 * this line or later.
				 *
				 * We find the first line before fileptr matching the
				 * start.  If every match on that line is followed by an
				 * end, then go to step two.  Otherwise, find the next
				 * line after start_line matching the end.  If that line
				 * is not before fileptr, then paint the beginning of
				 * this line. */
				const filestruct *start_line = fileptr->prev;
				/* The first line before fileptr matching start. */
				regoff_t start_col;
				/* Where it starts in that line. */
				const filestruct *end_line;
				short md = fileptr->multidata[tmpcolor->id];

				if (md == -1) {
					fileptr->multidata[tmpcolor->id] = CNONE;    /* until we find out otherwise */
				} else if (md == CNONE) {
					unset_formatting(tmpcolor);
					continue;
				} else if (md == CWHOLELINE) {
					mvwaddnstr(edit, line, 0, converted, -1);
					unset_formatting(tmpcolor);
					continue;
				} else if (md == CBEGINBEFORE) {
					regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0);
					paintlen = actual_x(converted, strnlenpt(fileptr->data, endmatch.rm_eo) - start);
					mvwaddnstr(edit, line, 0, converted, paintlen);
					unset_formatting(tmpcolor);
					continue;
				}

				while (start_line != NULL && regexec(tmpcolor->start, start_line->data, 1, &startmatch, 0) == REG_NOMATCH) {
					/* If there is an end on this line, there is no need
					 * to look for starts on earlier lines. */
					if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0) == 0) {
						goto step_two;
					}
					start_line = start_line->prev;
				}

				/* If the found start has been qualified as an end earlier, believe it and skip to the next step. */
				if (start_line != NULL && !start_line->multidata.empty() && start_line->multidata[tmpcolor->id] == CBEGINBEFORE) {
					goto step_two;
				}

				/* Skip over a zero-length regex match. */
				if (startmatch.rm_so == startmatch.rm_eo) {
					startmatch.rm_eo++;
				} else {
					/* No start found, so skip to the next step. */
					if (start_line == NULL) {
						goto step_two;
					}
					/* Now start_line is the first line before fileptr
					 * containing a start match.  Is there a start on
					 * this line not followed by an end on this line? */
					start_col = 0;
					while (true) {
						start_col += startmatch.rm_so;
						startmatch.rm_eo -= startmatch.rm_so;
						if (regexec(tmpcolor->end, start_line->data + start_col + startmatch.rm_eo, 0, NULL, (start_col + startmatch.rm_eo == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH) {
							/* No end found after this start. */
							break;
						}
						start_col++;
						if (regexec(tmpcolor->start, start_line->data + start_col, 1, &startmatch, REG_NOTBOL) == REG_NOMATCH) {
							/* No later start on this line. */
							goto step_two;
						}
					}
					/* Indeed, there is a start not followed on this
					 * line by an end. */

					/* We have already checked that there is no end
					 * before fileptr and after the start.  Is there an
					 * end after the start at all?  We don't paint
					 * unterminated starts. */
					end_line = fileptr;
					while (end_line != NULL && regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0) == REG_NOMATCH) {
						end_line = end_line->next;
					}

					/* No end found, or it is too early. */
					if (end_line == NULL || (end_line == fileptr && endmatch.rm_eo <= startpos)) {
						goto step_two;
					}

					/* Now paint the start of fileptr.  If the start of
					 * fileptr is on a different line from the end,
					 * paintlen is -1, meaning that everything on the
					 * line gets painted.  Otherwise, paintlen is the
					 * expanded location of the end of the match minus
					 * the expanded location of the beginning of the
					 * page. */
					if (end_line != fileptr) {
						paintlen = -1;
						fileptr->multidata[tmpcolor->id] = CWHOLELINE;
					} else {
						paintlen = actual_x(converted, strnlenpt(fileptr->data, endmatch.rm_eo) - start);
						fileptr->multidata[tmpcolor->id] = CBEGINBEFORE;
					}
					mvwaddnstr(edit, line, 0, converted, paintlen);
					/* If the whole line has been painted, don't bother looking for any more starts. */
					if (paintlen < 0) {
						continue;
					}
step_two:
					/* Second step, we look for starts on this line. */
					start_col = 0;

					while (start_col < endpos) {
						if (regexec(tmpcolor->start, fileptr->data + start_col, 1, &startmatch, (start_col == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH || start_col + startmatch.rm_so >= endpos) {
							/* No more starts on this line. */
							break;
						}
						/* Translate the match to be relative to the
						 * beginning of the line. */
						startmatch.rm_so += start_col;
						startmatch.rm_eo += start_col;

						x_start = (startmatch.rm_so <= startpos) ? 0 : strnlenpt(fileptr->data, startmatch.rm_so) - start;

						index = actual_x(converted, x_start);

						if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo, 1, &endmatch, (startmatch.rm_eo == 0) ? 0 : REG_NOTBOL) == 0) {
							/* Translate the end match to be relative to the beginning of the line. */
							endmatch.rm_so += startmatch.rm_eo;
							endmatch.rm_eo += startmatch.rm_eo;
							/* There is an end on this line.  But does
							 * it appear on this page, and is the match
							 * more than zero characters long? */
							if (endmatch.rm_eo > startpos && endmatch.rm_eo > startmatch.rm_so) {
								paintlen = actual_x(converted + index, strnlenpt(fileptr->data, endmatch.rm_eo) - start - x_start);

								assert(0 <= x_start && x_start < COLS);

								mvwaddnstr(edit, line, x_start, converted + index, paintlen);
								if (paintlen > 0) {
									fileptr->multidata[tmpcolor->id] = CSTARTENDHERE;
								}

							}
						} else {
							/* There is no end on this line.  But we
							 * haven't yet looked for one on later
							 * lines. */
							end_line = fileptr->next;

							while (end_line != NULL && regexec(tmpcolor->end, end_line->data, 0, NULL, 0) == REG_NOMATCH) {
								end_line = end_line->next;
							}

							if (end_line != NULL) {
								assert(0 <= x_start && x_start < COLS);

								mvwaddnstr(edit, line, x_start, converted + index, -1);
								/* We painted to the end of the line, so
								 * don't bother checking any more
								 * starts. */
								fileptr->multidata[tmpcolor->id] = CENDAFTER;
								break;
							}
						}
						start_col = startmatch.rm_so + 1;
					}
				}
			}
			unset_formatting(tmpcolor);
		}
	}

	/* If the mark is on, we need to display it. */
	if (openfile->mark_set && (fileptr->lineno <=
	                           openfile->mark_begin->lineno || fileptr->lineno <=
	                           openfile->current->lineno) && (fileptr->lineno >=
	                                   openfile->mark_begin->lineno || fileptr->lineno >=
	                                   openfile->current->lineno)) {
		/* fileptr is at least partially selected. */
		const filestruct *top;
		/* Either current or mark_begin, whichever is first. */
		size_t top_x;
		/* current_x or mark_begin_x, corresponding to top. */
		const filestruct *bot;
		size_t bot_x;
		int x_start;
		/* Starting column for mvwaddnstr().  Zero-based. */
		int paintlen;
		/* Number of characters to paint on this line.  There are
		 * COLS characters on a whole line. */
		size_t index;
		/* Index in converted where we paint. */

		mark_order(&top, &top_x, &bot, &bot_x, NULL);

		if (top->lineno < fileptr->lineno || top_x < startpos) {
			top_x = startpos;
		}
		if (bot->lineno > fileptr->lineno || bot_x > endpos) {
			bot_x = endpos;
		}

		/* The selected bit of fileptr is on this page. */
		if (top_x < endpos && bot_x > startpos) {
			assert(startpos <= top_x);

			/* x_start is the expanded location of the beginning of the
			 * mark minus the beginning of the page. */
			x_start = strnlenpt(fileptr->data, top_x) - start;

			/* If the end of the mark is off the page, paintlen is -1,
			 * meaning that everything on the line gets painted.
			 * Otherwise, paintlen is the expanded location of the end
			 * of the mark minus the expanded location of the beginning
			 * of the mark. */
			if (bot_x >= endpos) {
				paintlen = -1;
			} else
				paintlen = strnlenpt(fileptr->data, bot_x) - (x_start + start);

			/* If x_start is before the beginning of the page, shift
			 * paintlen x_start characters to compensate, and put
			 * x_start at the beginning of the page. */
			if (x_start < 0) {
				paintlen += x_start;
				x_start = 0;
			}

			assert(x_start >= 0 && x_start <= strlen(converted));

			index = actual_x(converted, x_start);

			if (paintlen > 0) {
				paintlen = actual_x(converted + index, paintlen);
			}

			set_color(edit, interface_colors[FUNCTION_TAG]);
			mvwaddnstr(edit, line, x_start, converted + index, paintlen);
			clear_color(edit, interface_colors[FUNCTION_TAG]);
		}
	}
}
예제 #9
0
파일: winio.cpp 프로젝트: pgengler/pinot
void titlebar(const char *path)
{
	int space = COLS;
	/* The space we have available for display. */
	size_t verlen = strlenpt(PACKAGE_STRING) + 1;
	/* The length of the version message in columns, plus one for
	 * padding. */
	const char *prefix;
	/* "DIR:", "File:", or "New Buffer".  Goes before filename. */
	size_t prefixlen;
	/* The length of the prefix in columns, plus one for padding. */
	const char *state;
	/* "Modified", "View", or "".  Shows the state of this
	 * buffer. */
	ssize_t statelen = 0;
	/* The length of the state in columns, or the length of
	 * "Modified" if the state is blank and we're not in the file
	 * browser. */
	char *exppath = NULL;
	/* The filename, expanded for display. */
	bool newfie = false;
	/* Do we say "New Buffer"? */
	bool dots = false;
	/* Do we put an ellipsis before the path? */

	set_color(topwin, interface_colors[TITLE_BAR]);

	blank_titlebar();

	/* space has to be at least 4: two spaces before the version message,
	 * at least one character of the version message, and one space
	 * after the version message. */
	if (space < 4) {
		space = 0;
	} else {
		/* Limit verlen to 1/3 the length of the screen in columns,
		 * minus three columns for spaces. */
		if (verlen > (COLS / 3) - 3) {
			verlen = (COLS / 3) - 3;
		}
	}

	if (space >= 4) {
		/* Add a space after the version message, and account for both
		 * it and the two spaces before it. */
		mvwaddnstr(topwin, 0, 2, PACKAGE_STRING, actual_x(PACKAGE_STRING, verlen));
		verlen += 3;

		/* Account for the full length of the version message. */
		space -= verlen;
	}

	/* Don't display the state if we're in the file browser. */
	if (path != NULL) {
		state = "";
	} else {
		state = openfile->modified ? _("Modified") : ISSET(VIEW_MODE) ? _("View") : "";
	}

	statelen = strlenpt((*state == '\0' && path == NULL) ? _("Modified") : state);

	/* If possible, add a space before state. */
	if (space > 0 && statelen < space) {
		statelen++;
	} else {
		goto the_end;
	}

	/* path should be a directory if we're in the file browser. */
	if (path != NULL) {
		prefix = _("DIR:");
	} else {
		if (openfile->filename[0] == '\0') {
			prefix = _("New Buffer");
			newfie = true;
		} else {
			prefix = _("File:");
		}
	}

	prefixlen = strnlenpt(prefix, space - statelen) + 1;

	/* If newfie is false, add a space after prefix. */
	if (!newfie && prefixlen + statelen < space) {
		prefixlen++;
	}

	/* If we're not in the file browser, set path to the current
	 * filename. */
	if (path == NULL) {
		path = openfile->filename.c_str();
	}

	/* Account for the full lengths of the prefix and the state. */
	if (space >= prefixlen + statelen) {
		space -= prefixlen + statelen;
	} else {
		space = 0;
	}
	/* space is now the room we have for the filename. */

	if (!newfie) {
		size_t lenpt = strlenpt(path), start_col;

		/* Don't set dots to true if we have fewer than eight columns
		 * (i.e. one column for padding, plus seven columns for a
		 * filename). */
		dots = (space >= 8 && lenpt >= space);

		if (dots) {
			start_col = lenpt - space + 3;
			space -= 3;
		} else {
			start_col = 0;
		}

		exppath = display_string(path, start_col, space, false);
	}

	/* If dots is true, we will display something like "File:
	 * ...ename". */
	if (dots) {
		mvwaddnstr(topwin, 0, verlen - 1, prefix, actual_x(prefix, prefixlen));
		if (space <= -3 || newfie) {
			goto the_end;
		}
		waddch(topwin, ' ');
		waddnstr(topwin, "...", space + 3);
		if (space <= 0) {
			goto the_end;
		}
		waddstr(topwin, exppath);
	} else {
		size_t exppathlen = newfie ? 0 : strlenpt(exppath);
		/* The length of the expanded filename. */

		/* There is room for the whole filename, so we center it. */
		mvwaddnstr(topwin, 0, verlen + ((space - exppathlen) / 3), prefix, actual_x(prefix, prefixlen));
		if (!newfie) {
			waddch(topwin, ' ');
			waddstr(topwin, exppath);
		}
	}

the_end:
	free(exppath);

	if (state[0] != '\0') {
		if (statelen >= COLS - 1) {
			mvwaddnstr(topwin, 0, 0, state, actual_x(state, COLS));
		} else {
			assert(COLS - statelen - 1 >= 0);

			mvwaddnstr(topwin, 0, COLS - statelen - 1, state, actual_x(state, statelen));
		}
	}

	clear_color(topwin, interface_colors[TITLE_BAR]);

	wnoutrefresh(topwin);
	reset_cursor();
	wnoutrefresh(edit);
}