Skip to content

Commit

Permalink
Button layout rectangle rotation (OpenStickCommunity#1015)
Browse files Browse the repository at this point in the history
Added rotation to rectangles using the angleStart property.
Renamed GP_SHAPE_DIAMOND to GP_SHAPE_LINE now that rectangles can rotate.
  • Loading branch information
mikepparks authored May 17, 2024
1 parent d0ae969 commit 681ead5
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 46 deletions.
8 changes: 4 additions & 4 deletions headers/buttonlayouts.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@
}

#define BUTTON_GROUP_KEYBOARD_ANGLED {\
{GP_ELEMENT_DIR_BUTTON, {8, 37, 7, 7, 1, 1, GAMEPAD_MASK_LEFT, GP_SHAPE_DIAMOND}},\
{GP_ELEMENT_DIR_BUTTON, {23, 24, 7, 7, 1, 1, GAMEPAD_MASK_UP, GP_SHAPE_DIAMOND}},\
{GP_ELEMENT_DIR_BUTTON, {23, 50, 7, 7, 1, 1, GAMEPAD_MASK_DOWN, GP_SHAPE_DIAMOND}},\
{GP_ELEMENT_DIR_BUTTON, {37, 37, 7, 7, 1, 1, GAMEPAD_MASK_RIGHT, GP_SHAPE_DIAMOND}}\
{GP_ELEMENT_DIR_BUTTON, {8, 37, 16, 45, 1, 1, GAMEPAD_MASK_LEFT, GP_SHAPE_SQUARE, 45}},\
{GP_ELEMENT_DIR_BUTTON, {23, 24, 31, 32, 1, 1, GAMEPAD_MASK_UP, GP_SHAPE_SQUARE, 45}},\
{GP_ELEMENT_DIR_BUTTON, {23, 50, 31, 58, 1, 1, GAMEPAD_MASK_DOWN, GP_SHAPE_SQUARE, 45}},\
{GP_ELEMENT_DIR_BUTTON, {37, 37, 45, 45, 1, 1, GAMEPAD_MASK_RIGHT, GP_SHAPE_SQUARE, 45}}\
}

#define BUTTON_GROUP_VEWLIX {\
Expand Down
2 changes: 1 addition & 1 deletion headers/display/GPGFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GPGFX {
void drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color, uint8_t filled);
void drawArc(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled, double startAngle, double endAngle, uint8_t closed);
void drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled);
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled);
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0);
void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority);
private:
Expand Down
2 changes: 1 addition & 1 deletion headers/interfaces/i2c/displaybase.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class GPGFX_DisplayBase {

virtual void drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled) {}

virtual void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled) {}
virtual void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0) {}

virtual void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0) {}

Expand Down
2 changes: 1 addition & 1 deletion headers/interfaces/i2c/ssd1306/obd_ssd1306.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class GPGFX_OBD_SSD1306 : public GPGFX_DisplayBase {

void drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled);

void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled);
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0);

void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority);

Expand Down
2 changes: 1 addition & 1 deletion headers/interfaces/i2c/ssd1306/tiny_ssd1306.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GPGFX_TinySSD1306 : public GPGFX_DisplayBase {

void drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled);

void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled);
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0);

void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0);

Expand Down
2 changes: 1 addition & 1 deletion proto/enums.proto
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ enum GPShape_Type

GP_SHAPE_ELLIPSE = 0;
GP_SHAPE_SQUARE = 1;
GP_SHAPE_DIAMOND = 2;
GP_SHAPE_LINE = 2;
GP_SHAPE_POLYGON = 3;
GP_SHAPE_ARC = 4;
};
Expand Down
4 changes: 2 additions & 2 deletions src/display/GPGFX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ void GPGFX::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_
this->displayDriver->drawLine(x1, y1, x2, y2, color, filled);
}

void GPGFX::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled) {
this->displayDriver->drawRectangle(x, y, width, height, color, filled);
void GPGFX::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle) {
this->displayDriver->drawRectangle(x, y, width, height, color, filled, rotationAngle);
}

void GPGFX::drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation) {
Expand Down
22 changes: 4 additions & 18 deletions src/display/ui/elements/GPButton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,26 +128,12 @@ void GPButton::draw() {
uint16_t turboX = baseX + (width - turboW) / 2;
uint16_t turboY = baseY + (height - turboH) / 2;

getRenderer()->drawRectangle(baseX, baseY, sizeX+offsetX, sizeY, this->strokeColor, state);
if (this->_inputType == GP_ELEMENT_BTN_BUTTON && (getGamepad()->turboState.buttons & this->_inputMask)) {
getRenderer()->drawRectangle(turboX, turboY, turboX+turboW, turboY+turboH, 1, 0);
}
} else if (this->_shape == GP_SHAPE_DIAMOND) {
uint16_t size = (this->_sizeX) * scaleX + this->getViewport().left;
if (state) {
int i;
for (i = 0; i < size; i++) {
getRenderer()->drawLine(baseX - i, baseY - size + i, baseX + i, baseY - size + i, this->strokeColor, 0);
getRenderer()->drawLine(baseX - i, baseY + size - i, baseX + i, baseY + size - i, this->strokeColor, 0);
}
getRenderer()->drawLine(baseX - size, baseY, baseX + size, baseY, this->strokeColor, 0); // Fill in the middle
}
getRenderer()->drawLine(baseX - size, baseY, baseX, baseY - size, this->strokeColor, 0);
getRenderer()->drawLine(baseX, baseY - size, baseX + size, baseY, this->strokeColor, 0);
getRenderer()->drawLine(baseX + size, baseY, baseX, baseY + size, this->strokeColor, 0);
getRenderer()->drawLine(baseX, baseY + size, baseX - size, baseY, this->strokeColor, 0);
getRenderer()->drawRectangle(baseX, baseY, sizeX+offsetX, sizeY, this->strokeColor, state, this->_angle);
if (this->_inputType == GP_ELEMENT_BTN_BUTTON && (getGamepad()->turboState.buttons & this->_inputMask)) {
getRenderer()->drawRectangle(turboX, turboY, turboX+turboW, turboY+turboH, 1, 0, this->_angle);
}
} else if (this->_shape == GP_SHAPE_LINE) {
getRenderer()->drawLine(baseX, baseY, this->_sizeX, this->_sizeY, this->strokeColor, 0);
} else if (this->_shape == GP_SHAPE_POLYGON) {
uint16_t scaledSize = (uint16_t)((double)this->_sizeX * scaleX);
uint16_t baseRadius = (uint16_t)scaledSize;
Expand Down
10 changes: 3 additions & 7 deletions src/display/ui/elements/GPShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,9 @@ void GPShape::draw() {
uint16_t width = this->_sizeX - baseX;
uint16_t height = this->_sizeY - baseY;

getRenderer()->drawRectangle(baseX, baseY, sizeX+offsetX, sizeY, this->strokeColor, this->fillColor);
} else if (this->_shape == GP_SHAPE_DIAMOND) {
uint16_t size = (this->_sizeX) * scaleX + this->getViewport().left;
getRenderer()->drawLine(baseX - size, baseY, baseX, baseY - size, this->strokeColor, 0);
getRenderer()->drawLine(baseX, baseY - size, baseX + size, baseY, this->strokeColor, 0);
getRenderer()->drawLine(baseX + size, baseY, baseX, baseY + size, this->strokeColor, 0);
getRenderer()->drawLine(baseX, baseY + size, baseX - size, baseY, this->strokeColor, 0);
getRenderer()->drawRectangle(baseX, baseY, sizeX+offsetX, sizeY, this->strokeColor, this->fillColor, this->_angle);
} else if (this->_shape == GP_SHAPE_LINE) {
getRenderer()->drawLine(baseX, baseY, this->_sizeX, this->_sizeY, this->strokeColor, 0);
} else if (this->_shape == GP_SHAPE_POLYGON) {
uint16_t scaledSize = (uint16_t)((double)this->_sizeX * scaleX);
uint16_t baseRadius = (uint16_t)scaledSize;
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/i2c/ssd1306/obd_ssd1306.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void GPGFX_OBD_SSD1306::drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, ui
obdPreciseEllipse(&obd, x, y, radiusX, radiusY, color, filled);
}

void GPGFX_OBD_SSD1306::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled) {
void GPGFX_OBD_SSD1306::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle) {
obdRectangle(&obd, x, y, width, height, color, filled);
}

Expand Down
65 changes: 56 additions & 9 deletions src/interfaces/i2c/ssd1306/tiny_ssd1306.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,64 @@ void GPGFX_TinySSD1306::drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, ui
}
}

void GPGFX_TinySSD1306::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled) {
//printf("Rect %d, %d, %d, %d, %d, %d\n", x, y, width, height, color, filled);
drawLine(x, y, x, height, color, filled);
drawLine(x, y, width, y, color, filled);
drawLine(width, height, x, height, color, filled);
drawLine(width, height, width, y, color, filled);
void GPGFX_TinySSD1306::drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle) {
// Calculate center point of the rectangle
double centerX = (x + width) / 2.0;
double centerY = (y + height) / 2.0;

// Calculate half width and half height for easier calculations
double halfWidth = (width - x) / 2.0;
double halfHeight = (height - y) / 2.0;

// Convert rotation angle to radians
double angleRad = rotationAngle * M_PI / 180.0;

// Pre-calculate sine and cosine of the rotation angle
double cosA = cos(angleRad);
double sinA = sin(angleRad);

// Calculate rotated coordinates for each corner of the rectangle
double x0 = centerX + cosA * (-halfWidth) - sinA * (-halfHeight);
double y0 = centerY + sinA * (-halfWidth) + cosA * (-halfHeight);

double x1 = centerX + cosA * (halfWidth) - sinA * (-halfHeight);
double y1 = centerY + sinA * (halfWidth) + cosA * (-halfHeight);

double x2 = centerX + cosA * (halfWidth) - sinA * (halfHeight);
double y2 = centerY + sinA * (halfWidth) + cosA * (halfHeight);

double x3 = centerX + cosA * (-halfWidth) - sinA * (halfHeight);
double y3 = centerY + sinA * (-halfWidth) + cosA * (halfHeight);

// Round coordinates to nearest integer
uint16_t x0_rounded = (uint16_t)round(x0);
uint16_t y0_rounded = (uint16_t)round(y0);
uint16_t x1_rounded = (uint16_t)round(x1);
uint16_t y1_rounded = (uint16_t)round(y1);
uint16_t x2_rounded = (uint16_t)round(x2);
uint16_t y2_rounded = (uint16_t)round(y2);
uint16_t x3_rounded = (uint16_t)round(x3);
uint16_t y3_rounded = (uint16_t)round(y3);

// Draw lines between rotated coordinates
drawLine(x0_rounded, y0_rounded, x1_rounded, y1_rounded, color, filled);
drawLine(x1_rounded, y1_rounded, x2_rounded, y2_rounded, color, filled);
drawLine(x2_rounded, y2_rounded, x3_rounded, y3_rounded, color, filled);
drawLine(x3_rounded, y3_rounded, x0_rounded, y0_rounded, color, filled);

if (filled) {
for (uint8_t i = 1; i < (height-y); i++) {
drawLine(x, y+i, width, y+i, color, filled);
}
// Calculate the number of lines needed for the filling
uint16_t numLines = (uint16_t)round(sqrt(halfWidth * halfWidth + halfHeight * halfHeight) * 2);

for (uint16_t i = 0; i <= numLines; i++) {
double t = (double)i / numLines;
double xStart = (1 - t) * x0 + t * x3;
double yStart = (1 - t) * y0 + t * y3;
double xEnd = (1 - t) * x1 + t * x2;
double yEnd = (1 - t) * y1 + t * y2;

drawLine((uint16_t)round(xStart), (uint16_t)round(yStart), (uint16_t)round(xEnd), (uint16_t)round(yEnd), color, filled);
}
}
}

Expand Down

0 comments on commit 681ead5

Please sign in to comment.