diff --git a/.gitignore b/.gitignore index b351203..115d9f3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ graphics-service/build .vs .vscode .vscode/* -api-service/__pycache__ \ No newline at end of file +api-service/__pycache__ +build \ No newline at end of file diff --git a/graphics-service/inc/Calculator.h b/graphics-service/inc/Calculator.h new file mode 100644 index 0000000..75eaee5 --- /dev/null +++ b/graphics-service/inc/Calculator.h @@ -0,0 +1,336 @@ +#ifndef CALCUALTOR +#define CALCULATOR +#define RAYGUI_IMPLEMENTATION + +#include +#include "Widget.h" + +#include +#include +#include +#include "Constants.h" +#include +#include +#include +#include +using namespace std; + +class Calculator : public Widget { + +private: + std::string text; + Vector2 mousePoint; + Texture2D plusButton; + bool Button1Pressed; + int offset; + int lastOperatorIndex; + stack operators; + stack operands; + +public: + Calculator(uint32_t x, uint32_t y, uint32_t w, uint32_t h, std::string n) : + Widget (x, y, w, h, n) { + // Calls widget's constructor + //render = false; + text = ""; + mousePoint = { 0.0f , 0.0f }; + Image plusIcon = LoadImage( "../resources/images/plus_operator.png" ); + ImageResize( &plusIcon, 50, 50); + plusButton = LoadTextureFromImage(plusIcon); + UnloadImage(plusIcon); + Button1Pressed = false; + offset = 25; + + } +private: + void spawnButton(int x, int y, int w,int h, std::string buttonText){ + DrawRectangleLines(x,y,w,h,SKYBLUE); + int buttonOffset = (50 - MeasureText(buttonText.c_str(),30))/2; + DrawText(buttonText.c_str(), buttonOffset+x, 10 + y, 30, SKYBLUE); + } +private: + bool buttonInteract(int x, int y, int w,int h, std::string buttonText){ + + if (CheckCollisionPointRec(mousePoint, (Rectangle){x,y,w,h})){ + + DrawRectangle(x,y,w,h,SKYBLUE); + int buttonOffset = (50 - MeasureText(buttonText.c_str(),30))/2; + DrawText(buttonText.c_str(), buttonOffset+x, 10 + y, 30, BLACK); + + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) return true; + else return false; + + } + + + } + + +private: +int precedence(char op){ + if(op == '+'||op == '-') return 1; + if(op == '*'||op == '/') return 2; + if(op == '^') return 3; + return 0; +} + +// Function to perform arithmetic operations. +private: + float applyOp(float a, float b, char op){ + + if ( op == '+') return a+b; + else if ( op == '-') return a-b; + else if (op == '*') return a*b; + else if (op == '/') return a/b; + else if (op == '^') return pow(a,b); + +} + +// Function that returns value of +// expression after evaluation. +private: +float evaluate(string tokens){ + int i; + + // stack to store integer values. + stack values; + + // stack to store operators. + stack ops; + + for(i = 0; i < tokens.length(); i++){ + + // Current token is a whitespace, + // skip it. + if(tokens[i] == ' ') + continue; + + // Current token is an opening + // brace, push it to 'ops' + else if(tokens[i] == '('){ + ops.push(tokens[i]); + } + + // Current token is a number, push + // it to stack for numbers. + else if(isdigit(tokens[i]) ){ + float val = 0.0f; + std::string tokenVal = ""; + // There may be more than one + // digits in number. + while(i < tokens.length() && (isdigit(tokens[i]) || tokens[i] == '.')) + { + tokenVal += tokens[i]; + + i++; + } + val = std::stof(tokenVal); + values.push(val); + + // right now the i points to + // the character next to the digit, + // since the for loop also increases + // the i, we would skip one + // token position; we need to + // decrease the value of i by 1 to + // correct the offset. + i--; + } + + // Closing brace encountered, solve + // entire brace. + else if(tokens[i] == ')') + { + while(!ops.empty() && ops.top() != '(') + { + float val2 = values.top(); + values.pop(); + + float val1 = values.top(); + values.pop(); + + char op = ops.top(); + ops.pop(); + + values.push(applyOp(val1, val2, op)); + } + + // pop opening brace. + if(!ops.empty()) + ops.pop(); + } + + // Current token is an operator. + else + { + // While top of 'ops' has same or greater + // precedence to current token, which + // is an operator. Apply operator on top + // of 'ops' to top two elements in values stack. + while(!ops.empty() && precedence(ops.top()) + >= precedence(tokens[i])){ + float val2 = values.top(); + values.pop(); + + float val1 = values.top(); + values.pop(); + + char op = ops.top(); + ops.pop(); + + values.push(applyOp(val1, val2, op)); + } + + // Push current token to 'ops'. + ops.push(tokens[i]); + } + } + + // Entire expression has been parsed at this + // point, apply remaining ops to remaining + // values. + while(!ops.empty()){ + float val2 = values.top(); + values.pop(); + + float val1 = values.top(); + values.pop(); + + char op = ops.top(); + ops.pop(); + + values.push(applyOp(val1, val2, op)); + } + + // Top of 'values' contains result, return it. + return values.top(); +} + + +// +private: + void draw() override { + + // Put code here for drawing! + int32_t middle_x = pos_x + (width / 2); //posx => parameter in Widget + int32_t middle_y = pos_y ; + + mousePoint = GetMousePosition(); + + //checks if mouse is over the caluclator widget , the if block can be removed if the calc needs to be static + bool isHovering = CheckCollisionPointRec(mousePoint, (Rectangle){pos_x, pos_y, CALC_W, CALC_H }) ; + + + + int hoverTextWidth; + std::string text_display = "CALCULATOR"; + + hoverTextWidth = MeasureText(text_display.c_str(), 20); + uint32_t x_cord = middle_x - (hoverTextWidth / 2); + + + DrawText(text_display.c_str(), x_cord + 10, middle_y + 40, 20, SKYBLUE); + + DrawRectangleLines(x_cord, middle_y + 20, hoverTextWidth + 20, 50, SKYBLUE); + + + + + + int textWidth = MeasureText(text.c_str(), 30); + + uint32_t x_cord = middle_x - (textWidth / 2); + DrawText(text.c_str(), x_cord, middle_y + 20, 30, SKYBLUE); + + + Rectangle button_op1 = {x_cord , middle_y + 80, 50, 50}; + + + //column 1 + spawnButton(offset +pos_x, middle_y + 100 , 50,50, "1"); + spawnButton(offset +pos_x, middle_y + 150 , 50,50, "4"); + spawnButton(offset +pos_x, middle_y + 200 , 50,50, "7"); + spawnButton(offset +pos_x, middle_y + 250 , 50,50, "+"); + spawnButton(offset +pos_x, middle_y + 300 , 50,50, "-"); + spawnButton(offset +pos_x, middle_y + 350 , 50,50, "^"); + spawnButton(offset +pos_x, middle_y + 400 , 50,50, "CE"); + + //column 2 + spawnButton(offset +pos_x + 50, middle_y + 100 , 50,50, "2"); + spawnButton(offset +pos_x + 50, middle_y + 150 , 50,50, "5"); + spawnButton(offset +pos_x + 50, middle_y + 200 , 50,50, "8"); + spawnButton(offset +pos_x + 50, middle_y + 250 , 50,50, "0"); + spawnButton(offset +pos_x + 50, middle_y + 300 , 50,50, "/"); + spawnButton(offset +pos_x + 50, middle_y + 350 , 50,50, "*"); + spawnButton(offset +pos_x + 50, middle_y + 400 , 50,50, "C"); + + //column 3 + spawnButton(offset +pos_x + 100, middle_y + 100 , 50,50, "3"); + spawnButton(offset +pos_x + 100, middle_y + 150 , 50,50, "6"); + spawnButton(offset +pos_x + 100, middle_y + 200 , 50,50, "9"); + spawnButton(offset +pos_x + 100, middle_y + 250 , 50,50, "("); + spawnButton(offset +pos_x + 100, middle_y + 300 , 50,50, ")"); + spawnButton(offset +pos_x + 100, middle_y + 350 , 50,50, "."); + spawnButton(offset +pos_x + 100, middle_y + 400 , 50,50, "="); + + //****************************hover************************* + + //column 1 + if(buttonInteract(offset +pos_x, middle_y + 100 , 50,50, "1")){text += "1";} + if(buttonInteract(offset +pos_x, middle_y + 150 , 50,50, "4")){text += "4";} + if(buttonInteract(offset +pos_x, middle_y + 200 , 50,50, "7")){text += "7";} + if(buttonInteract(offset +pos_x, middle_y + 250 , 50,50, "+") && (isalnum(text.c_str()[text.length()-1]) || text.c_str()[text.length()-1] == ')' ) ) + { text += "+"; } + if(buttonInteract(offset +pos_x, middle_y + 300 , 50,50, "-") && (isalnum(text.c_str()[text.length()-1]) || text.c_str()[text.length()-1] == ')' )) + { text += "-"; } + if(buttonInteract(offset +pos_x, middle_y + 350 , 50,50, "^") && (isalnum(text.c_str()[text.length()-1]) || + text.c_str()[text.length()-1] == ')' )) + { text += "^"; } + if(buttonInteract(offset +pos_x, middle_y + 400 , 50,50, "CE")) + { text = ""; } + + //column 2 + if(buttonInteract(offset +pos_x + 50, middle_y + 100 , 50,50, "2")){text += "2";} + if(buttonInteract(offset +pos_x + 50, middle_y + 150 , 50,50, "5")){text += "5";} + if(buttonInteract(offset +pos_x + 50, middle_y + 200 , 50,50, "8")){text += "8";} + if(buttonInteract(offset +pos_x + 50, middle_y + 250 , 50,50, "0")){text += "0";} + if(buttonInteract(offset +pos_x + 50, middle_y + 300 , 50,50, "/") && (isalnum(text.c_str()[text.length()-1]) || text.c_str()[text.length()-1] == ')' )) + { text += "/"; } + if(buttonInteract(offset +pos_x + 50, middle_y + 350 , 50,50, "*" ) && isalnum(text.c_str()[text.length()-1])) + { text += "*"; } + if(buttonInteract(offset +pos_x + 50, middle_y + 400 , 50,50, "C")) + {text = text.substr(0, text.length() -1);} + + //column 3 + if(buttonInteract(offset +pos_x + 100, middle_y + 100 , 50,50, "3")){text += "3";} + if(buttonInteract(offset +pos_x + 100, middle_y + 150 , 50,50, "6")){text += "6";} + if(buttonInteract(offset +pos_x + 100, middle_y + 200 , 50,50, "9")){text += "9";} + + if(buttonInteract(offset +pos_x + 100, middle_y + 250 , 50,50, "(") && + !isalnum(text.c_str()[text.length()-1])) + { text += "("; } + if(buttonInteract(offset +pos_x + 100, middle_y + 300 , 50,50, ")") && + isalnum(text.c_str()[text.length()-1])) + { text += ")"; } + if(buttonInteract(offset +pos_x + 100, middle_y + 350 , 50,50, ".") && + isalnum(text.c_str()[text.length()-1])) + { text += "."; } + if(buttonInteract(offset +pos_x + 100, middle_y + 400 , 50,50, "=")){ + + float resultEval = evaluate(text); + + int int_resultEval = round(resultEval * 100); + std::string str_resultEval = std::to_string(int_resultEval); + text = str_resultEval.substr(0, str_resultEval.length() - 2) + "." + + str_resultEval.substr( str_resultEval.length() - 2, str_resultEval.length() - 1); + + } + + + } + +private: + +}; + +#endif \ No newline at end of file diff --git a/graphics-service/inc/Constants.h b/graphics-service/inc/Constants.h index 2b8cfc6..08bfd92 100644 --- a/graphics-service/inc/Constants.h +++ b/graphics-service/inc/Constants.h @@ -33,9 +33,14 @@ #define POLY_MIN -180 #define POLY_SCALE POLY_MAX - POLY_MIN +//Calcuator widget Constants +#define CALC_W 200 +#define CALC_H 500 +#define CALC_X WEATHER_X +#define CALC_Y WEATHER_Y + WEATHER_H + 50 // Shader Information #define GLSL_VERSION 100 // Color scheme -#define MAIN_COLOR SKY_BLUE \ No newline at end of file +#define MAIN_COLOR SKYBLUE \ No newline at end of file diff --git a/graphics-service/inc/WeatherWidget.h b/graphics-service/inc/WeatherWidget.h index bae6b0c..1ffd659 100644 --- a/graphics-service/inc/WeatherWidget.h +++ b/graphics-service/inc/WeatherWidget.h @@ -20,6 +20,7 @@ class WeatherWidget : public Widget { Widget (x, y, w, h, n) { Image weatherIcons = LoadImage("../resources/Adjusted-Weather-Icons.png"); + ImageResize(&weatherIcons, IMAGE_SIZE_X, IMAGE_SIZE_Y); icons = LoadTextureFromImage(weatherIcons); UnloadImage(weatherIcons); @@ -57,14 +58,26 @@ class WeatherWidget : public Widget { temperature = "Loading..."; weatherConditions = "Loading..."; } - // Obtains rectangle for weather icon - Rectangle rect = iconMap["Clear"]; + + + // Obtains rectangle for weather icon + // so far doesn't change icon with weather conditions + + + Rectangle rect = iconMap[weatherConditions.c_str()]; + Rectangle rect2 = iconMap["Thunderstorm"]; // Position for icon on screen Vector2 icon_pos {pos_x, pos_y + 30}; - DrawTextureRec(icons, rect, icon_pos, WHITE); - DrawText(temperature.c_str(), pos_x + 80, pos_y + 60, 30, SKYBLUE); - DrawText(weatherConditions.c_str(), pos_x, pos_y + 100, 30, SKYBLUE); + //Renders the final weather report + DrawTextureRec(icons, rect, icon_pos, WHITE); + //renders another icon on top of the actual icon ******test***** + BeginBlendMode(1); + // Draw here for + // DrawTextureRec(icons, rect2, icon_pos, WHITE ); + EndBlendMode(); + DrawText(temperature.c_str(), pos_x + ICON_SIZE_X , pos_y + 60, 30, SKYBLUE); + DrawText(weatherConditions.c_str(), pos_x, pos_y+ ICON_SIZE_Y + 20, 30, SKYBLUE); DrawText(city.c_str(), pos_x, pos_y, 30, SKYBLUE); } diff --git a/graphics-service/src/Game.cpp b/graphics-service/src/Game.cpp index a4ef10f..d082603 100644 --- a/graphics-service/src/Game.cpp +++ b/graphics-service/src/Game.cpp @@ -7,6 +7,7 @@ #include "TimeWidget.h" #include "WeatherWidget.h" #include "NewsWidget.h" +#include "Calculator.h" Game::Game(int width, int height, std::string title) { InitWindow(width, height, title.c_str()); @@ -19,9 +20,11 @@ Game::Game(int width, int height, std::string title) { TimeWidget* timeWidget = new TimeWidget(TIME_X, TIME_Y, TIME_W, TIME_H, "Time Widget"); NewsWidget* newsWidget = new NewsWidget(NEWS_X, NEWS_Y, NEWS_W, NEWS_H, "News Widget"); WeatherWidget* weatherWidget = new WeatherWidget(WEATHER_X, WEATHER_Y, WEATHER_W, WEATHER_H, "Weather Widget"); + Calculator* calculatorWidget = new Calculator(CALC_X, CALC_Y, CALC_W, CALC_H, "Calculator Widget"); widgets.push_back(timeWidget); widgets.push_back(newsWidget); widgets.push_back(weatherWidget); + widgets.push_back(calculatorWidget); } Game::~Game() noexcept { diff --git a/graphics-service/src/Utility.cpp b/graphics-service/src/Utility.cpp index e8d1ccc..69c8fd9 100644 --- a/graphics-service/src/Utility.cpp +++ b/graphics-service/src/Utility.cpp @@ -67,6 +67,6 @@ void get_http_request(bool* finished, const string url, Json::Value* storage) { void draw_loading_wheel(uint32_t x, uint32_t y, uint32_t r) { DrawCircleSectorLines( - Vector2{x, y}, r, 0.0, 0.5, 1, MAIN_COLOR - ) + Vector2{x, y}, r, 0.0, 0.5, 1, MAIN_COLOR + ); }