I'm trying to run this code through Eclipse. It has no errors when compiling and opens up Terminal (as I set it to) when it runs, but nothing shows up in the Terminal even though (supposedly) I have coded it to display a box. Could anyone let me know what I need to do so that it displays properly?
Thanks
#include <iostream>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
void set_difficulty(int level,int &v);
void SetMenuBox(WINDOW*&);
int main(){
int speed = 0;
chtype a=219;
initscr(); //initialize screen
WINDOW *win = newwin(20,40,15,20); //create new window (row,col,x,y) where (x,y) is top left corner
wrefresh(stdscr); //refresh standard screen
start_color(); //enable color changes
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with black outline
init_pair(2,COLOR_GREEN,COLOR_BLACK);
attron(COLOR_PAIR(1)); //use the color pair
wattron(win,COLOR_PAIR(1));
wrefresh(win);
wborder(stdscr,0,0,0,0,0,0,0,0); //create border around win using lines
wborder(win,a,a,a,a,a,a,a,a); //create border around standard window
wrefresh(stdscr);
wrefresh(win);
wmove(win,2,18); //move cursor
wprintw(win,"MENU"); //print "MENU" at cursor
wmove(win,5,2);
wprintw(win,"Select Difficulty:");
wmove(win,7,2);
wprintw(win,"1==Easy");
wmove(win,9,2);
wprintw(win,"2==Medium");
wmove(win,11,2);
wprintw(win,"3==Hard");
wmove(win,13,2);
wprintw(win,"0==EXIT");
wmove(win,18,19);
wrefresh(win); //the character typed will be green not blue
int d=wgetch(win); //get character from win, d is the ascii number
sleep(500); //pause for 1000 ms
wmove(win,28,25);
while(d<48||d>51){ //keeps getting character until an allowable
wborder(win,32,32,32,32,32,32,32,32); //character is selected
mvwdelch(win,18,19);
wborder(win,a,a,a,a,a,a,a,a);
wmove(win,18,19);
wrefresh(win);
d = wgetch(win);
sleep(500);
}
if(d==48)
return 0;
else if(d>48&&d<=51){
set_difficulty(d,speed);
}
wrefresh(win);
sleep(1000);
wclear(win);
SetMenuBox(win);
wrefresh(win);
wmove(win,15,18);
wprintw(win,"%d",speed);
wrefresh(win);
sleep(1000);
//endwin(); //close window
return 0;
}
void set_difficulty(int level,int &v){
switch (level){
case 49:
v = 2500;
break;
case 50:
v = 1750;
break;
case 51:
v = 1250;
break;
}
}
void SetMenuBox(WINDOW *&w){
chtype a = 219;
delwin(w);
wrefresh(stdscr);
w = newwin(30,40,15,20);
wrefresh(stdscr);
wrefresh(w);
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with blue outline
attron(COLOR_PAIR(1)); //use the color pair
wattron(w,COLOR_PAIR(1));
wrefresh(w);
wborder(w,a,a,a,a,a,a,a,a);
wrefresh(w);
}
Related
I'm trying to print a sub-menu associated with a main menu shown with ncurses.
This is the way i've organized it :
do{} while (); loop with wgetch gets keypad input from user
if user presses the enter key, the subMenu entry is shown after clearing the whole screen.
Unfortunately, I can't make it past the 2nd step, the sub-menu never shows up on screen.
#include <ncurses.h>
#include <iostream>
#include <string>
int main()
{
std::string nameMainMenuExample = "/parent1/folder";
std::string nameSubMenuExample = "/folder/file";
// initialize ncurses
WINDOW *win;
win = initscr();
raw();
curs_set(0);
cbreak();
box(win, 0, 0);
refresh();
wrefresh(win);
keypad(win, true);
// end initialize ncurses
int highlight = 0;
int choice;
// PRESS 'a' to ESCAPE LOOP
do {
mvwprintw(win, 1, 1, nameMainMenuExample.c_str());
switch (choice) {
case KEY_UP:
--highlight;
if (highlight == -1) {
highlight = 0;
}
break;
case KEY_DOWN:
++highlight;
if (highlight == 1) {
highlight = 0;
}
break;
case KEY_ENTER: // Enter key pressed
clear();
mvwprintw(win, 1, 1, nameSubMenuExample.c_str());
refresh();
break;
default:
break;
}
} while ((choice = wgetch(win)) != 97); // random choice a == 97
endwin();
return 0;
}
I just expect the sub menu to be printed on screen after ncurses clears the screen of the main menu.
Thanks
If you wanted to activate the submenu on the enter key, you should be checking the value wgetch returned against KEY_ENTER (which is something like 16777221 numerically), not 10.
You're mixing calls to different windows (clear and refresh use stdscr) and the one your wgetch call uses is getting its own wrefresh. Since the menu-window is not being refreshed, it never appears, and since wgetch does a wrefresh, that may additionally obscure things.
Start by making the wrefresh calls apply to the windows you want to be repainted.
Using ncurses in C++, ENTER key value is just '\n'
For example:
case '\n':
clear();
mvwprintw(win, 1, 1, nameSubMenuExample.c_str());
refresh();
break;
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to create a scribble clone for a uni project.
My lines are basically a lot of dots. If I draw too quick, the line breaks and I have single dots.
Also, I can't figure out how to draw lines ONLY when a mouse button is pressed.
I tried to put mouseMoved into a while loop until mouseButton is released but that didn't seem to work. I ended up in an infinite loop.
Here is my code so far:
while (window.isOpen())
{
while (window.pollEvent(event))
{
int mouseButtonX = event.mouseButton.x;
int mouseButtonY = event.mouseButton.y;
int mouseMoveX = event.mouseMove.x;
int mouseMoveY = event.mouseMove.y;
setBrushSize(5);
brush.setRadius(brushSize);
brush.setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
brush.setFillColor(sf::Color::Transparent);
brush.setOutlineColor(sf::Color::Green);
brush.setOutlineThickness(2);
switch (event.type) {
case (sf::Event::Closed):
window.close();
break;
case (sf::Event::KeyPressed):
if (event.key.control && event.key.code == sf::Keyboard::X) {
cout << "closing";
window.close();
}
if (event.key.code == sf::Keyboard::R) {
cout << "printed";
brushColor = setBrushColor(255, 0, 0);
}
if (event.key.code == sf::Keyboard::G) {
brushColor = setBrushColor(0, 255, 0);
}
if (event.key.code == sf::Keyboard::B) {
brushColor = setBrushColor(0, 0, 255);
}
if (event.key.code == sf::Keyboard::C) {
for (int i = 0; i < points.size(); i++) {
points.clear();
}
it = 0;
}
break;
case(sf::Event::MouseButtonPressed):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseButtonX - brushSize, mouseButtonY - brushSize);
it++;
cout << "drawPoint: Pressed X = " << mouseButtonX << " Y = " << mouseButtonY << endl;
break;
case(sf::Event::MouseMoved):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
it++;
cout << "drawPoint: Moved X = " << mouseMoveX << " Y = " << mouseMoveY << endl;
break;
}
}
window.clear(sf::Color(255, 247, 204));
window.draw(SkechyT);
window.draw(close);
window.draw(brush);
window.draw(color);
window.draw(clear);
for (int i = 0; i < points.size(); i++) {
window.draw(points[i]);
}
//window.draw(point);
window.display();
}
}
int getBrushSize() {
return brushSize;
}
void setBrushSize(int num) {
brushSize = num;
}
sf::Color setBrushColor(int r, int g, int b) {
return sf::Color(r, g, b);
}
~Visualizer();
};
While you can modify a sf::VertexArray on the fly (basically building a vector drawing app), you can also use a sf::RenderTexture as an actual drawing canvas.
Considering you tried drawing lots of small points, I'd assume you're aiming for the latter. What's important here is the fact that you don't necessarily have to clear render textures between drawing calls and can therefore preserve whatever has been drawn before.
Combined with the original goal – drawing – this becomes very easy.
All you have to do is draw the changes (e.g. when moving the cursor), finalize the render texture (by calling display()), and then presenting it using any drawable (like sf::Sprite.
I've quickly scribbled together the following example, which should show the concept rather well (and you won't run into an endless loop other than the actual main loop):
#include <SFML/Graphics.hpp>
#include <vector>
int main(int argc, char **argv) {
sf::RenderWindow window(sf::VideoMode(800, 600), L"SFML Drawing – C to clear, PageUp/PageDown to pick colors", sf::Style::Default);
// Set a specific frame rate, since we don't want to
// worry about vsync or the time between drawing iterations
window.setVerticalSyncEnabled(false);
window.setFramerateLimit(100);
// First we'll use a canvas to basically store our image
sf::RenderTexture canvas;
canvas.create(800, 600);
canvas.clear(sf::Color::White);
// Next we'll need a sprite as a helper to draw our canvas
sf::Sprite sprite;
sprite.setTexture(canvas.getTexture(), true);
// Define some colors to use
// These are all with very low alpha so we
// can (over-)draw based on how fast we move the cursor
const std::vector<sf::Color> colors = {
sf::Color(255, 0, 0, 8),
sf::Color(255, 255, 0, 8),
sf::Color(0, 255, 0, 8),
sf::Color(0, 255, 255, 8),
sf::Color(0, 0, 255, 8),
sf::Color(255, 0, 255, 8)
};
// We'll need something to actually draw
// For simplicity, I'm just drawing a circle shape
// but you could also draw a line, rectangle, or something more complex
const float brush_size = 25;
sf::CircleShape brush(brush_size, 24);
brush.setOrigin(brush_size, brush_size); // Center on the circle's center
sf::Vector2f lastPos;
bool isDrawing = false;
unsigned int color = 0;
// Apply some default color
brush.setFillColor(colors[color]);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::C:
// Clear our canvas
canvas.clear(sf::Color::White);
canvas.display();
break;
case sf::Keyboard::PageUp:
// Get next color
color = (color + 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
case sf::Keyboard::PageDown:
// Get previous color
color = (color - 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
}
break;
case sf::Event::Resized:
{
// Window got resized, update the view to the new size
sf::View view(window.getView());
const sf::Vector2f size(window.getSize().x, window.getSize().y);
view.setSize(size); // Set the size
view.setCenter(size / 2.f); // Set the center, moving our drawing to the top left
window.setView(view); // Apply the view
break;
}
case sf::Event::MouseButtonPressed:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left) {
isDrawing = true;
// Store the cursor position relative to the canvas
lastPos = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
// Now let's draw our brush once, so we can
// draw dots without actually draging the mouse
brush.setPosition(lastPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
}
break;
case sf::Event::MouseButtonReleased:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left)
isDrawing = false;
break;
case sf::Event::MouseMoved:
if (isDrawing)
{
// Calculate the cursor position relative to the canvas
const sf::Vector2f newPos(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)));
// I'm only using the new position here
// but you could also use `lastPos` to draw a
// line or rectangle instead
brush.setPosition(newPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
break;
}
}
}
// Clear the window
window.clear(sf::Color(64, 64, 64));
// Draw our canvas
window.draw(sprite);
// Show the window
window.display();
}
return 0;
}
Once running, you can start drawing using the left mouse button. C will clear the canvas and Page Up and Page Down allow you to pick a different color:
Edit: And just to mention it, in the example above, rather than drawing a circle, you can just draw a sf::VertexArray with sf::Lines and two vertices: lastPos and newPos. This way you'll always draw a continuous line. (But you'd obviously have to save/update lastPos with the value of newPos once you're done.)
I have two windows, one at the top, and one at the bottom (and I will be adding a third window later that will be between those two windows). I draw a horizontal line for the bottom window and then I start drawing the top window, and the bottom window gets erased!
The constructor display() is called automatically and than the function displayMessage() is called by my code.
Here is the code for display():
display::display()
{
//initialize window
initscr(); //start curses mode
cbreak(); //Disable line buffering
curs_set(0); //Don't show curser
refresh(); //Now refresh screen
//setup bottom bar
bottomBar = newwin(2, 80, 22, 0); //create new window
whline(bottomBar, '_', 80); //draw line
wrefresh(bottomBar); //refresh
//setup top bar
topBar = newwin(0, 80, 0, 0); //create new window
wattron(topBar, A_UNDERLINE); //text is to be underlined
}
Here is the code for displayMessage():
void display::displayMessage(string message)
{
//do some other necessary stuff
int length = message.length(); //get length of message
wmove(topBar, 0, 0); //move curser back to beginning
//getch();
wrefresh(topBar); //refresh
//getch();
whline(topBar, '_',80); //draw line for bottom
//getch();
wmove(topBar, 0, 40 - length/2 - 1); //move cursor to center text
wprintw(topBar,message.c_str()); //print message
wrefresh(topBar); //refresh
}
In addition here is the code snippets that call those two:
//initialize stuff
pomodoro instance;
while(true) //loop forever, or until user
{
for (int i = 0; i < 3; i++) //loop thru 4 pomodoros
{
//work
instance.Display.displayMessage("**Time to work!**");
instance.playAlarm();
//waitForUser();
//timer(config.workTime);
//break
return 0; //doing development right now
This line is a problem:
topBar = newwin(0, 80, 0, 0); //create new window
because the first parameter is zero. The manual page explains:
If either nlines or ncols is zero, they default to
LINES - begin_y and
COLS - begin_x.
So the zero-parameter makes your windows overlap (a lot).
So I'm learning SDL and I'm trying to make a basic menu. The menu consists of "Start", below it "Load" and below it "Quit". None of them have a function, they're just for show.
What I'm doing is adding a box that surrounds the selected option. I tried to make it so whenever up or down is pressed on the keyboard, the counter will be incremented or lowered by one and the box will move up or down. However, every time I press one of the buttons the counter goes to huge numbers. I know that because I wrote alongside code that displays the counter on the screen.
I would really appreciate any help with what I'm doing wrong.
screenshot: http://i.imgur.com/6Io8cLj.png
PS: I'm using a header file with a function apply_surface() so I'll add it first.
Start of head.h:
#ifndef CYOP_H_HEADER
#define CYOP_H_HEADER
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
using namespace std;
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
Uint32 colorkey = SDL_MapRGB( source->format, 0, 0xFF, 0xFF );
SDL_SetColorKey(source, SDL_SRCCOLORKEY, colorkey);
SDL_BlitSurface(source, NULL, destination, &offset);
}
#endif
Start of main.cpp:
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "head.h"
#include <string>
#include <sstream>
using namespace std;
// Text rendering parts
TTF_Font *font = NULL;
SDL_Color color = {255, 0, 0};
int cur=0; // Current Menu Item (0 is start, 1 is Load, 2 is Quit)
string str = "Counter: ";
string num;
string strc = str+num;
bool quitp = false; //Quit Program bool
ostringstream convert;
SDL_Surface* background = NULL;
SDL_Surface* start = NULL;
SDL_Surface* load = NULL;
SDL_Surface* quit = NULL;
SDL_Surface* screen = NULL;
SDL_Surface* select = NULL;
SDL_Surface* message = NULL;
SDL_Event event;
void selected(int n)
/*Function that is supposed to reload all images again,
only the "select" picture at a different place**/
{
convert << cur;
num=convert.str();
strc=str+num;
message = TTF_RenderText_Solid(font, strc.c_str(), color); // Renders "Counter: *number
of cur **/
int arr[3]={50, 100, 150};
apply_surface(0,0,background,screen);
apply_surface(60,50,start,screen);
apply_surface(60,100,load,screen);
apply_surface(60,150,quit,screen);
apply_surface(0, 0, message, screen);
apply_surface(60, arr[n], select, screen);
SDL_Flip(screen);
}
int main(int argc, char* args[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
screen = SDL_SetVideoMode(300, 300, 32, SDL_SWSURFACE);
font = TTF_OpenFont("grasping.ttf", 28);
message = TTF_RenderText_Solid(font, strc.c_str(), color);
background = IMG_Load ("background.bmp");
start = IMG_Load ("start1.bmp");
load = IMG_Load ("load1.bmp");
quit = IMG_Load ("quit1.bmp");
select = IMG_Load ("select.bmp");
apply_surface(0,0,background,screen);
apply_surface(60,50,start,screen);
apply_surface(60,100,load,screen);
apply_surface(60,150,quit,screen);
apply_surface(60, 50, select, screen);
apply_surface(0, 0, message, screen);
SDL_Flip(screen);
while(quitp==false)
{
if(SDL_PollEvent(&event));
{
if (event.type == SDL_QUIT)
{
quitp = true;
}
if (event.type == SDL_KEYDOWN)
{
SDLKey keyPressed = event.key.keysym.sym;
switch (keyPressed)
{
case SDLK_DOWN:
cur++;
break;
case SDLK_UP:
cur--;
break;
default: break;
}selected(cur);
}// Closing if(event.type == SDL_KEYDOWN)
}// Closing if(SDL_PollEvent)
} // Closing main while loop
SDL_Quit();
return 0;
}
There are two problems:
The first is a classic rookie mistake:
if(SDL_PollEvent(&event));
What you meant to do here is this:
if(SDL_PollEvent(&event))
Amazing what a difference one character makes!
The second issue is this:
However, every time I press one of the buttons the counter goes to
huge numbers. I know that because I wrote alongside code that displays
the counter on the screen.
You need to look a little more closely at that screenshot. The number it's printing out is 123456789101112. See the pattern there?
cur = 1, strc = "Counter: 1"
cur = 2, strc = "Counter: 12"
cur = 3, strc = "Counter: 123"
cur = 4, strc = "Counter: 1234"
..etc
The way you're using the string stream just appends the number each time. The easy solutions here are to either not use the same string stream each time, or to reset it to the empty string.
I've got some code (below) that uses SDL_ttf and would like to:
Be able to render text (from the TTF) in alignment (to a buffer or array as well) like a console would (having each character printed in it's individual cell).
Be able to utilize a blinking cursor (possibly render and un-render an underscore, maybe?)
Be able to let the user input text from the keyboard and render each char on the screen right when it is typed (using SDLK_charhere).
Getting back to #1: I'm thinking about getting the width of the previous character printed on the screen (from the TTF) and using its width (in pixels) to print the next character right after the previous character, plus 2 pixels. <-- PLEASE TELL ME IF THE SPACING BETWEEN CHARS IN A REGULAR WIN32 CONSOLE IS A DIFFERENT SIZE IN PIXELS.
Here's the code that needs to be modified:
#include "include/SDL/SDL.h"
#include "include/SDL/SDL_ttf.h"
int currentX = 0;
int currentY = 0;
int newW;
int newH;
SDL_Surface* screen;
SDL_Surface* fontSurface;
SDL_Color fColor;
SDL_Rect fontRect;
SDL_Event event;
TTF_Font* font;
//Initialize the font, set to white
void fontInit(){
TTF_Init();
font = TTF_OpenFont("dos.ttf", 12);
fColor.r = 0; // 255
fColor.g = 204; // 255
fColor.b = 0; //255
}
//Print the designated string at the specified coordinates
void PrintStr(char *c, int x, int y){
fontSurface = TTF_RenderText_Solid(font, c, fColor);
fontRect.x = x;
fontRect.y = y;
SDL_BlitSurface(fontSurface, NULL, screen, &fontRect);
SDL_Flip(screen);
}
int main(int argc, char** argv)
{
// Initialize the SDL library with the Video subsystem
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
//Create the screen
screen = SDL_SetVideoMode(320, 480, 0, SDL_SWSURFACE);
//Initialize fonts
fontInit();
PrintStr("", 0, 0);
do {
// Process the events
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
// Escape forces us to quit the app
case SDLK_ESCAPE:
event.type = SDL_QUIT;
break;
default:
break;
}
break;
default:
break;
}
}
SDL_Delay(10);
} while (event.type != SDL_QUIT);
// Cleanup
SDL_Quit();
return 0;
}
This isn't a trivial thing to do, but it sounds like a good learning project! You're maybe going to need a few thousand lines of code rather than the few tens you have up there. Perhaps start by considering these questions and their answers.
Do you want a fixed width font, or a variable width font?
How can you buffer the rendered text in an intelligent way? (glyphs or lines for eg.)
How can you buffer the text itself in an intelligent way?
How can you translate key presses into text?
What is translating and driving all this?
All these will need to be considered along with the most important question of all:
Do I want to do this?
If you do do this, it will teach you a lot about programming, but it might not give you the best full screen console you're looking for.