void dc_draw_window(bool show_prompt) { uint cmd_lines; // Number of lines for the command string uint buffer_lines; // Number of lines from the buffer to draw uint i; // The current row we're drawing uint j; // The current row of the command string we're drawing SCP_string out_str; // The command string + prompt character SCP_string::iterator str_it; // Iterator to out_str out_str = dc_prompt + dc_command_buf; cmd_lines = (out_str.size() / DCOLS) + 1; if (show_prompt) { buffer_lines = DROWS - cmd_lines; } else { buffer_lines = DROWS; } // Ensure the window is not bigger than the buffer CLAMP(DROWS, DROWS_MIN, DBROWS); CLAMP(DCOLS, DCOLS_MIN, DBCOLS); // Ensure we don't scroll too far dc_scroll_x = MIN(dc_scroll_x, (DBCOLS - DCOLS)); if (dc_buffer.size() >= buffer_lines) { dc_scroll_y = MIN(dc_scroll_y, (dc_buffer.size() - buffer_lines)); } else { dc_scroll_y = 0; // Disallow vscroll until the buffer is larger than the window } // Draw the buffer strings for (i = 0; i < buffer_lines; ++i) { if ((i + dc_scroll_y) < dc_buffer.size()) { gr_string(0, ((i * row_height) + row_height), dc_buffer[i + dc_scroll_y].substr(dc_scroll_x).c_str(), GR_RESIZE_NONE); } } // Draw the command string w/ padding only if the prompt is active. if (show_prompt) { i += 1; // 1 line between the output and the input text j = 0; gr_set_color_fast(&Color_bright); for (str_it = out_str.begin(); str_it < out_str.end(); ++str_it) { if (j == (DCOLS - 1)) { // Insert a newline char at every place the string needs to return the 'carriage' str_it = out_str.insert(str_it, '\n'); j = 0; } else { ++j; } } gr_string(0, ((i * row_height) + row_height), out_str.c_str(), GR_RESIZE_NONE); dc_draw_cursor(out_str, 0, ((i * row_height))); gr_set_color_fast(&Color_normal); } }
void debug_console(void (*_func)(void)) { int done = 0; while( key_inkey() ) { os_poll(); } if ( !debug_inited ) { dc_init(); } dc_draw(TRUE); while (!done) { // poll the os os_poll(); int k = key_inkey(); switch( k ) { case KEY_SHIFTED+KEY_ENTER: case KEY_ESC: done = TRUE; break; case KEY_BACKSP: if (!dc_command_buf.empty()) { dc_command_buf.erase(dc_command_buf.size() - 1); } break; case KEY_F3: case KEY_UP: if (last_oldcommand < (dc_history.end() - 1)) { ++last_oldcommand; } dc_command_buf = *last_oldcommand; break; case KEY_DOWN: if (last_oldcommand > dc_history.begin()) { --last_oldcommand; } dc_command_buf = *last_oldcommand; break; case KEY_PAGEUP: if (dc_scroll_y > 1) { dc_scroll_y--; } break; case KEY_PAGEDOWN: if (dc_scroll_y < (DBROWS - DROWS)) { dc_scroll_y++; } else { dc_scroll_y = (DBROWS - DROWS); } break; case KEY_ENTER: dc_scroll_y = (DBROWS - DROWS); // Set the scroll to look at the bottom last_oldcommand = dc_history.begin(); // Reset the last oldcommand lastline = 0; // Reset the line counter // Clear the command line on the window, but don't print the prompt until the command has processed // Stuff a copy of the command line onto the history // Search for the command // If not found: // abort, // dc_printf("Error: Invalid or Missing command %s", cmd.c_str()), and // dc_printf(dc_prompt) when ready for input // Call the function for that command, and strip the cmd token from the command line string if (dc_command_buf.empty()) { dc_printf("No command given.\n"); break; } // Else, continue to process the cmd_line // z64: Thread Note: Maybe lock a mutex here to allow a previous DCF to finish/abort before starting a new one // z64: We'll just assume we won't be here unless a command has finished... dc_history.push_front(dc_command_buf); // Push the command onto the history queue last_oldcommand = dc_history.begin(); // Reset oldcommand while (dc_history.size() > DCMDS) { dc_history.pop_back(); // Keep the commands less than or equal to DCMDS } dc_command_str = dc_command_buf; // Xfer to the command string for processing dc_command_buf.resize(0); // Nullify the buffer dc_printf("%s%s\n", dc_prompt, dc_command_str.c_str()); // Print the command w/ prompt. dc_draw(FALSE); // Redraw the console without the command line. dc_do_command(&dc_command_str); // Try to do the command break; default: // Not any of the control key codes, so it's probably a letter or number. ubyte c = (ubyte)key_to_ascii(k); if ((c != 255) && (dc_command_buf.size() < MAX_CLI_LEN)) { dc_command_buf.push_back(c); } } // Do the passed function if ( _func ) { _func(); } // All done, and ready for new entry dc_draw(TRUE); } while( key_inkey() ) { os_poll(); } }
void dc_putc(char c) { SCP_string* line_str = &(dc_buffer.back()); SCP_string temp_str; int i; int w; if (c == ' ') { /** * Push c onto the temp_str and get its gr_string width * * If we run out of room on the line, or * If we run out of room on the screen, change c to a '\n' and let subsequent block handle it, * Else, push the space onto the line and bail */ temp_str = *line_str; temp_str.push_back(c); gr_get_string_size(&w, NULL, temp_str.c_str()); if ((temp_str.size() >= DBCOLS) || (w > gr_screen.max_w)) { c = '\n'; } else { lastwhite = temp_str.size(); *line_str = temp_str; return; } } if (c == '\t') { /** * Calculate how many spaces to put in to align tabs, * Append temp_str with the spaces and get its gr_string width * * If we run out of room on the line, or * If we run out of room on the screen, change c to a '\n' and let subsequent block handle it, * Else, copy temp_str onto the line, update the lastwhite index, and bail */ i = DTABS - (line_str->size() % DTABS); temp_str = *line_str; temp_str.append(i, ' '); gr_get_string_size(&w, NULL, temp_str.c_str()); if ((temp_str.size() >= DBCOLS) || (w > gr_screen.max_w)) { c = '\n'; } else { lastwhite = temp_str.size(); *line_str = temp_str; return; } } if (c == '\n') { /** * Trash whatever char happens to be past (DBCOLS - 1), * Push a blank line onto the dc_buffer from the bottom, * Increment the scroller, if needed, * Trash the topmost line(s) in the buffer, * Reset the lastwhite index, * Increment the lastline counter, and finally * bail */ if (line_str->size() > DBCOLS) { line_str->resize(DBCOLS); } dc_buffer.push_back(""); if ((dc_buffer.size() > DROWS) && (dc_scroll_y < SCROLL_Y_MAX)) { dc_scroll_y++; } while (dc_buffer.size() > DBROWS) { dc_buffer.pop_front(); } lastwhite = 0; lastline++; return; } // By this point, c is probably a writable character temp_str = *line_str; temp_str.push_back(c); gr_get_string_size(&w, NULL, temp_str.c_str()); if ((temp_str.size() >= DBCOLS) || (w > gr_screen.max_w)) { /** * Word wrapping * Save the word, clear the line of the word, push new line with the word on it * Update scroll_y, if needed, * Pop off old lines, and finally * Push new character onto the new line */ temp_str = line_str->substr(lastwhite); line_str->resize(lastwhite); dc_buffer.push_back(temp_str); line_str = &dc_buffer.back(); if ((dc_buffer.size() > DROWS) && (dc_scroll_y < SCROLL_Y_MAX)) { dc_scroll_y++; } while (dc_buffer.size() > DBROWS) { dc_buffer.pop_front(); } lastwhite = 0; lastline++; line_str->push_back(c); return; } // Else, just push the char onto the line line_str->push_back(c); }