Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to force a given aspect ratio #164

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions slop.1
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Sets the padding size for the selection, this can be negative.
.BR \-t ", " \-\-tolerance=\fIFLOAT\fR
How far in pixels the mouse can move after clicking, and still be detected as a normal click instead of a click-and-drag. Setting this to 0 will disable window selections. Alternatively setting it to 9999999 would force a window selection.
.TP
.BR \-a ", " \-\-aspectratio=\fIFLOAT,FLOAT\fR
Set the selection rectangle's aspect ratio, for example `16,9'.
.TP
.BR \-c ", " \-\-color=\fIFLOAT,FLOAT,FLOAT,FLOAT\fR
Sets the selection rectangle's color. Supports RGB or RGBA input. Depending on the system's window manager/OpenGL support, the opacity may be ignored.
.TP
Expand Down
28 changes: 28 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@

using namespace slop;

glm::vec2 parseAspectRatio( std::string value ) {
std::string valuecopy = value;
glm::vec2 found;
std::string::size_type sz;
try {
found[0] = std::stof(value,&sz);
value = value.substr(sz+1);
found[1] = std::stof(value,&sz);
if (value.size() != sz) {
throw std::runtime_error("dur");
}
} catch ( ... ) {
throw std::invalid_argument("Unable to parse value `" + valuecopy + "` as a aspect ratio. Should be in the format width,height. Like 16,9.");
}
return found;
}

glm::vec4 parseColor( std::string value ) {
std::string valuecopy = value;
glm::vec4 found;
Expand Down Expand Up @@ -65,6 +82,15 @@ SlopOptions* getOptions( cxxopts::Options& options ) {
if ( options.count( "tolerance" ) > 0 ) {
foo->tolerance = options["tolerance"].as<float>();
}
glm::vec2 aspectRatio = glm::vec2(foo->x_ratio, foo->y_ratio);
if ( options.count( "aspectratio" ) > 0) {
aspectRatio = parseAspectRatio( options["aspectratio"].as<std::string>() );
if (aspectRatio.x == 0 || aspectRatio.y == 0) {
throw std::invalid_argument("--aspectratio must not contain zero values");
}
}
foo->x_ratio = aspectRatio.x;
foo->y_ratio = aspectRatio.y;
glm::vec4 color = glm::vec4( foo->r, foo->g, foo->b, foo->a );
if ( options.count( "color" ) > 0 ) {
color = parseColor( options["color"].as<std::string>() );
Expand Down Expand Up @@ -173,6 +199,7 @@ void printHelp() {
std::cout << " Alternatively setting it to 999999 would.\n";
std::cout << " only allow for window selections.\n";
std::cout << " (default=`2')\n";
std::cout << " -a, --aspectratio=FLOAT,FLOAT Set the selection rectangle's aspect ratio.\n";
std::cout << " -D, --nodrag Select region with two clicks instead of\n";
std::cout << " click and drag\n";
std::cout << " -c, --color=FLOAT,FLOAT,FLOAT,FLOAT\n";
Expand Down Expand Up @@ -238,6 +265,7 @@ int app( int argc, char** argv ) {
("b,bordersize", "Sets the selection rectangle's thickness.", cxxopts::value<float>())
("p,padding", "Sets the padding size for the selection, this can be negative.", cxxopts::value<float>())
("t,tolerance", "How far in pixels the mouse can move after clicking, and still be detected as a normal click instead of a click-and-drag. Setting this to 0 will disable window selections. Alternatively setting it to 9999999 would force a window selection.", cxxopts::value<float>())
("a,aspectratio", "Sets the selection rectangle's aspect ratio.", cxxopts::value<std::string>())
("D,nodrag", "Select region with two clicks instead of click and drag")
("c,color", "Sets the selection rectangle's color. Supports RGB or RGBA input. Depending on the system's window manager/OpenGL support, the opacity may be ignored.", cxxopts::value<std::string>())
("r,shader", "This sets the vertex shader, and fragment shader combo to use when drawing the final framebuffer to the screen. This obviously only works when OpenGL is enabled. The shaders are loaded from ~/.config/maim. See https://github.com/naelstrof/slop for more information on how to create your own shaders.", cxxopts::value<std::string>())
Expand Down
6 changes: 6 additions & 0 deletions src/slop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ slop::SlopOptions::SlopOptions() {
padding = 0;
shaders = slop_default_shaders;
highlight = false;
x_ratio = 0;
y_ratio = 0;
r = 0.5;
g = 0.5;
b = 0.5;
Expand Down Expand Up @@ -354,6 +356,8 @@ extern "C" struct slop_options slop_options_default() {
options.padding = 0;
options.shaders = slop_default_shaders;
options.highlight = false;
options.x_ratio = 0;
options.y_ratio = 0;
options.r = 0.5;
options.g = 0.5;
options.b = 0.5;
Expand All @@ -380,6 +384,8 @@ extern "C" struct slop_selection slop_select( struct slop_options* options ) {
realOptions.padding = options->padding;
realOptions.shaders = options->shaders;
realOptions.highlight = options->highlight;
realOptions.x_ratio = options->x_ratio;
realOptions.y_ratio = options->y_ratio;
realOptions.r = options->r;
realOptions.g = options->g;
realOptions.b = options->b;
Expand Down
4 changes: 4 additions & 0 deletions src/slop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ struct slop_options {
int nokeyboard;
int nodecorations;
char* shaders;
float x_ratio;
float y_ratio;
float r;
float g;
float b;
Expand Down Expand Up @@ -69,6 +71,8 @@ class SlopOptions {
bool nokeyboard;
bool nodecorations;
char* shaders;
float x_ratio;
float y_ratio;
float r;
float g;
float b;
Expand Down
78 changes: 60 additions & 18 deletions src/slopstates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ slop::SlopMemory::SlopMemory( SlopOptions* options, Rectangle* rect ) {
state = (SlopState*)new SlopStart();
nextState = NULL;
tolerance = options->tolerance;
aspectRatio = glm::vec2(options->x_ratio, options->y_ratio);
nodrag = options->nodrag;
nodecorations = options->nodecorations;
rectangle = rect;
Expand Down Expand Up @@ -103,24 +104,47 @@ void slop::SlopStartDrag::update( SlopMemory& memory, double dt ) {
memory.setState( (SlopState*)new SlopEndDrag() );
}

// Query X server once only during update function
glm::vec2 mousePos = mouse->getMousePos();

// Determine which cursor to use
char a = startPoint.y > mouse->getMousePos().y;
char b = startPoint.x > mouse->getMousePos().x;
char a = startPoint.y > mousePos.y;
char b = startPoint.x > mousePos.x;
char c = (a << 1) | b;

// -1 to invert, 1 to leave as is
glm::vec2 invert;
switch ( c ) {
case 0: mouse->setCursor( XC_lr_angle );
invert = glm::vec2(1, 1);
break;
case 1: mouse->setCursor( XC_ll_angle );
invert = glm::vec2(-1, 1);
break;
case 2: mouse->setCursor( XC_ur_angle );
invert = glm::vec2(1, -1);
break;
case 3: mouse->setCursor( XC_ul_angle );
invert = glm::vec2(-1, -1);
break;
}

glm::vec2 widthHeight = mousePos - startPoint;
float scale = glm::max(glm::abs(widthHeight.x) / memory.aspectRatio.x,
glm::abs(widthHeight.y) / memory.aspectRatio.y);

glm::vec2 rectEndPoint;
if (memory.aspectRatio == glm::vec2(0, 0)) {
rectEndPoint = glm::vec2(mousePos);
} else {
rectEndPoint = glm::vec2(startPoint + memory.aspectRatio*scale*invert);
}

// Compensate for edges of screen, depending on the mouse position in relation to the start point.
int lx = mouse->getMousePos().x < startPoint.x;
int ly = mouse->getMousePos().y < startPoint.y;
memory.rectangle->setPoints(startPoint+glm::vec2(1*lx,1*ly), mouse->getMousePos()+glm::vec2(1*(!lx), 1*(!ly)));
int lx = mousePos.x < startPoint.x;
int ly = mousePos.y < startPoint.y;

memory.rectangle->setPoints(startPoint+glm::vec2(1*lx,1*ly), rectEndPoint+glm::vec2(1*(!lx), 1*(!ly)));

if ( !memory.nodrag && !mouse->getButton( 1 ) ) {
memory.setState( (SlopState*)new SlopEndDrag() );
Expand All @@ -129,7 +153,7 @@ void slop::SlopStartDrag::update( SlopMemory& memory, double dt ) {

if ( keyboard ) {
if ( keyboard->getKey(XK_space) ) {
memory.setState( (SlopState*)new SlopStartMove( startPoint, mouse->getMousePos() ) );
memory.setState( (SlopState*)new SlopStartMove(startPoint, rectEndPoint) );
return;
}
int arrows[2];
Expand All @@ -152,15 +176,30 @@ void slop::SlopStartDrag::update( SlopMemory& memory, double dt ) {
}

void slop::SlopEndDrag::onEnter( SlopMemory& memory ) {
// Clip rectangle on edges of screen.
// p1(x,y), p2(z,w) with default format as p2_x x p2_y+p1_x+p1_y
glm::vec4 rect = memory.rectangle->getRect();
glm::vec2 p1, p2;
p1.x = glm::min(int(rect.x), WidthOfScreen(x11->screen));
p1.x = glm::max(int(rect.x), 0);
p1.y = glm::min(int(rect.y), HeightOfScreen(x11->screen));
p1.y = glm::max(int(rect.y), 0);
p2.x = glm::min(int(rect.x + rect.z), WidthOfScreen(x11->screen));
p2.y = glm::min(int(rect.y + rect.w), HeightOfScreen(x11->screen));
memory.rectangle->setPoints(p1, p2);

memory.running = false;
}

slop::SlopStartMove::SlopStartMove( glm::vec2 oldPoint, glm::vec2 newPoint ) {
// oldPoint is where drag was started and newPoint where move was
startPoint = oldPoint;
// This vector is the diagonal of the rectangle
// it will be used to move the startPoint along with mousePos
diagonal = newPoint - oldPoint;
// This vector is the diagonal of the rectangle between mouse and oldPoint.
// It will be used to move the startPoint along with mousePos.
// Cause of aspect ratio feature, it isn't necessarily the same as diagonal.
mouseDiagonal = mouse->getMousePos() - oldPoint;
}
void slop::SlopStartMove::onEnter( SlopMemory& memory ) {
// redundant because of update()
Expand All @@ -170,21 +209,24 @@ void slop::SlopStartMove::onEnter( SlopMemory& memory ) {
mouse->setCursor( XC_fleur );
}
void slop::SlopStartMove::update( SlopMemory& memory, double dt ) {
// Unclear why it has to be - and not +
startPoint = mouse->getMousePos() - diagonal;

int lx = mouse->getMousePos().x < startPoint.x;
int ly = mouse->getMousePos().y < startPoint.y;
memory.rectangle->setPoints(startPoint+glm::vec2(1*lx,1*ly), mouse->getMousePos()+glm::vec2(1*(!lx), 1*(!ly)));
glm::vec2 mousePos = mouse->getMousePos();

// It needs to be - instead + because:
// - left upper corner of screen is (x,y) = (0,0);
// - y axis is inverted (0,0) x
// +---->
// | + (4,1)
// y v
startPoint = mousePos - mouseDiagonal;

int lx = mousePos.x < startPoint.x;
int ly = mousePos.y < startPoint.y;
memory.rectangle->setPoints(startPoint+glm::vec2(1*lx,1*ly),
startPoint+diagonal+glm::vec2(1*(!lx), 1*(!ly)));

// space or mouse1 released, return to drag
// if mouse1 is released then drag will end also
if ( !keyboard->getKey(XK_space) or (!mouse->getButton( 1 ) && !memory.nodrag) ) {
// clip rectangle on edges of screen.
startPoint.x = glm::min((int)startPoint.x, WidthOfScreen(x11->screen));
startPoint.x = glm::max((int)startPoint.x, 0);
startPoint.y = glm::min((int)startPoint.y, HeightOfScreen(x11->screen));
startPoint.y = glm::max((int)startPoint.y, 0);
memory.setState( (SlopState*) new SlopStartDrag(startPoint) );
}
}
2 changes: 2 additions & 0 deletions src/slopstates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class SlopEndDrag : SlopState {
class SlopStartMove : SlopState {
private:
glm::vec2 diagonal;
glm::vec2 mouseDiagonal;
public:
SlopStartMove( glm::vec2 oldPoint, glm::vec2 newPoint );
virtual void onEnter( SlopMemory& memory );
Expand All @@ -84,6 +85,7 @@ class SlopMemory {
SlopMemory( SlopOptions* options, Rectangle* rect );
~SlopMemory();
Window selectedWindow;
glm::vec2 aspectRatio;
bool running;
float tolerance;
bool nodecorations;
Expand Down