/** * Click and drag absolute: move to a relative coordinate within the window * windowname, clamped. */ bool clickAndDragAbsolute(std::string window_name, nlohmann::json action){ //populate the window variables. int x_start, x_end, y_start, y_end, mouse_button; bool no_clamp = false; bool success = populateClickAndDragValues(action, window_name, x_start, x_end, y_start, y_end, mouse_button, no_clamp); //if we couldn't populate the values, do nothing (window doesn't exist) if(!success){ std::cout << "Click and drag unsuccessful due to failure to populate click and drag values." << std::endl; return false; } int start_x_position = action.value("start_x", -1); int start_y_position = action.value("start_y", -1); int end_x_position = action.value("end_x", -1); int end_y_position = action.value("end_y", -1); if (start_x_position == end_x_position && start_y_position == end_y_position){ std::cout << "Error, the click and drag action did not specify movement." << std::endl; return false; } if(end_x_position == -1 || end_y_position == -1){ std::cout << "ERROR: the click and drag action must include an ending position" << std::endl; return false; } //get the mouse into starting position if they are specified. if(start_x_position != -1 && start_y_position != -1){ start_x_position = start_x_position + x_start; start_y_position = start_y_position + y_start; //don't move out of the window. clamp(start_x_position, x_start, x_end); clamp(start_y_position, y_start, y_end); mouse_move(window_name, start_x_position, start_y_position,x_start, x_end, y_start, y_end, false); } end_x_position = end_x_position + x_start; end_y_position = end_y_position + y_start; //clamp the end position so we don't exit the window. clamp(end_x_position, x_start, x_end); clamp(end_y_position, y_start, y_end); //These functions won't do anything if the window doesn't exist. mouseDown(window_name,mouse_button); mouse_move(window_name, end_x_position, end_y_position,x_start, x_end, y_start, y_end, false); mouseUp(window_name,mouse_button); return true; }
/** * This function sets the window variables (using populateWindowData), and * mouse_button (pressed) destination (an x,y tuple we are dragging to), and * no_clamp (which is currently disabled/false). returns false on failure. * It is on the programmer to check. */ bool populateClickAndDragValues(nlohmann::json action, std::string window_name, int& window_left, int& window_right, int& window_top, int& window_bottom, int& mouse_button, bool& no_clamp){ int height, width; //Get the window dimensions. populateWindowData(window_name,height,width,window_left,window_right,window_top,window_bottom); // if(command.find("no clamp") != std::string::npos){ // std::cout << "Multiple windows are not yet supported. (No 'no clamp' option available)" << std::endl; // no_clamp = false; // } std::string mouse_button_string = action.value("mouse_button", "left"); if(mouse_button_string == "left"){ mouse_button = 1; } else if (mouse_button_string == "middle"){ mouse_button = 2; } else if (mouse_button_string == "right"){ mouse_button = 3; } else{ //default. mouse_button = 1; } return true; }
bool ReadTexturesFromJson(const nlohmann::json& json_textures, const filesystem::path& base_path, ID3D11Device* device, std::vector<TextureIdentifier>* textures) { const auto& json_textures_array = json_textures.value("textures", nlohmann::json::array({})); if (!json_textures_array.is_array()) { DXFW_TRACE(__FILE__, __LINE__, false, "Invalid textures JSON %S", json_textures_array.dump().c_str()); return false; } for (const auto& json_texture : json_textures_array) { if (!json_texture.is_object()) { DXFW_TRACE(__FILE__, __LINE__, false, "Invalid textures entry %S", json_texture.dump().c_str()); continue; } const auto& json_texture_name_it = json_texture.find("name"); if (json_texture_name_it == json_texture.end() || !json_texture_name_it->is_string()) { DXFW_TRACE(__FILE__, __LINE__, false, "Invalid texture name %S", json_texture_name_it->dump().c_str()); continue; } const auto& json_texture_path_it = json_texture.find("filename"); if (json_texture_path_it == json_texture.end() || !(json_texture_path_it->is_string() || json_texture_path_it->is_array())) { DXFW_TRACE(__FILE__, __LINE__, false, "Invalid texture filename(s) %S", json_texture_path_it->dump().c_str()); continue; } TextureIdentifier identifier; identifier.Hash = std::hash<std::string>()(*json_texture_name_it); if (json_texture_path_it->is_string()) { identifier.Texture = ReadSingleTexture(identifier.Hash, *json_texture_path_it, base_path, device); } else { // Array identifier.Texture = ReadMipmapTexture(identifier.Hash, *json_texture_path_it, base_path, device); } if (!identifier.Texture.IsValid()) { DXFW_TRACE(__FILE__, __LINE__, false, "Error creating texture %S", json_texture_name_it->dump().c_str()); continue; } textures->emplace_back(std::move(identifier)); } return true; }
/** * This function defines which actions are inherently bound for a GUI/window. **/ bool isWindowedAction(const nlohmann::json action){ std::string action_str = action.value("action", ""); if (action_str == ""){ std::cout << "ERROR: poorly formatted action (no 'action' type specified)" << std::endl; return false; } else{ if(action_str.find("screenshot") != std::string::npos){ return true; } else if(action_str.find("type") != std::string::npos){ return true; } else if(action_str.find("key") != std::string::npos){ return true; } else if(action_str.find("click and drag") != std::string::npos){ return true; } else if(action_str.find("click") != std::string::npos){ return true; } else if(action_str.find("move mouse") != std::string::npos){ return true; } else if(action_str.find("center") != std::string::npos){ return true; } else if(action_str.find("origin") != std::string::npos){ return true; } else{ return false; } } }
void IO::from_json(const nlohmann::json& j, IO::CPParam& p) { for(const auto& pair: CPParam::str2section){ p.*pair.second = j.value(pair.first, CPParam::Section{}); } }
void Difference::PrepareGrade(const nlohmann::json& j) { std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; std::cout << "PREPARE GRADE" << std::endl; // -------------------------------------------------------- //std::cout << "json " << j.dump(4) << std::endl; if (j.find("max_char_changes") != j.end()) { std::cout << "MAX CHAR CHANGES" << std::endl; int max_char_changes = j.value("max_char_changes", -1); assert (max_char_changes > 0); int min_char_changes = j.value("min_char_changes",0); assert (min_char_changes >= 0); assert (min_char_changes < max_char_changes); assert (total_char > 0); if (max_char_changes > total_char) { std::cout << "WARNING! max_char_changes > total_char)" << std::endl; max_char_changes = total_char; if (min_char_changes > max_char_changes) { min_char_changes = max_char_changes-1; } assert (min_char_changes >= 0); } assert (max_char_changes <= total_char); int char_changes = char_added + char_deleted; std::cout << "char_changes=" << char_changes << " min=" << min_char_changes << " max=" << max_char_changes << std::endl; int min_max_diff = max_char_changes-min_char_changes; int lower_bar = std::max(0,min_char_changes-min_max_diff); int upper_bar = max_char_changes + min_max_diff; assert (0 <= lower_bar && lower_bar <= min_char_changes && min_char_changes <= max_char_changes && max_char_changes <= upper_bar); float grade; if (char_changes < lower_bar) { std::cout << "too few char changes (zero credit)" << std::endl; messages.push_back(std::make_pair(MESSAGE_FAILURE,"ERROR! Approx " + std::to_string(char_changes) + " characters added and/or deleted. Significantly fewer character changes than allowed.")); } else if (char_changes < min_char_changes) { std::cout << "less than min char changes (partial credit)" << std::endl; float numer = min_char_changes - char_changes; float denom = min_max_diff; std::cout << "numer " << numer << " denom= " << denom << std::endl; assert (denom > 0); grade = 1 - numer/denom; messages.push_back(std::make_pair(MESSAGE_FAILURE,"ERROR! Approx " + std::to_string(char_changes) + " characters added and/or deleted. Fewer character changes than allowed.")); } else if (char_changes < max_char_changes) { messages.push_back(std::make_pair(MESSAGE_SUCCESS,"Approx " + std::to_string(char_changes) + " characters added and/or deleted. Character changes within allowed range.")); std::cout << "between min and max char changes (full credit)" << std::endl; grade = 1.0; } else if (char_changes < upper_bar) { std::cout << "more than max char changes (partial credit)" << std::endl; float numer = char_changes - max_char_changes; float denom = min_max_diff; assert (denom > 0); grade = 1 - numer/denom; std::cout << "numer " << numer << " denom= " << denom << std::endl; messages.push_back(std::make_pair(MESSAGE_FAILURE,"ERROR! Approx " + std::to_string(char_changes) + " characters added and/or deleted. More character changes than allowed.")); } else { std::cout << "too many char changes (zero credit)" << std::endl; messages.push_back(std::make_pair(MESSAGE_FAILURE,"ERROR! Approx " + std::to_string(char_changes) + " characters added and/or deleted. Significantly more character changes than allowed.")); grade = 0.0; } std::cout << "grade " << grade << std::endl; assert (grade >= -0.00001 & grade <= 1.00001); this->setGrade(grade); } // -------------------------------------------------------- else if (this->extraStudentOutputOk) { // only missing lines (deletions) are a problem int count_of_missing_lines = 0; for (int x = 0; x < this->changes.size(); x++) { int num_b_lines = this->changes[x].b_changes.size(); if (num_b_lines > 0) { count_of_missing_lines += num_b_lines; } } int output_length = this->output_length_b; std::cout << "COMPARE outputlength=" << output_length << " missinglines=" << count_of_missing_lines << std::endl; assert (count_of_missing_lines <= output_length); float grade = 1.0; if (output_length > 0) { //std::cout << "SES [ESOO] calculating grade " << this->distance << "/" << output_length << std::endl; //grade -= (this->distance / (float) output_length ); grade -= count_of_missing_lines / float(output_length); std::cout << "grade: missing_lines [ " << count_of_missing_lines << "] / output_length " << output_length << "]\n"; //std::cout << "SES [ESOO] calculated grade = " << std::setprecision(1) << std::fixed << std::setw(5) << grade << " " << std::setw(5) << (int)floor(5*grade) << std::endl; if (grade < 1.0 && this->only_whitespace_changes) { std::cout << "ONLY WHITESPACE DIFFERENCES! adjusting grade: " << grade << " -> "; // FIXME: Ugly, but with rounding, this will be only a -1 point grade for this test case grade = std::max(grade,0.99f); std::cout << grade << std::endl; } else { std::cout << "MORE THAN JUST WHITESPACE DIFFERENCES! " << std::endl; } } else { assert (output_length == 0); std::cout << "NO OUTPUT, GRADE IS ZERO" << std::endl; grade = 0; } std::cout << "this test grade = " << grade << std::endl; this->setGrade(grade); } // -------------------------------------------------------- else { // both missing lines (deletions) and extra lines are a deduction int max_output_length = std::max(this->output_length_a, this->output_length_b); float grade = 1.0; if (max_output_length == 0) { grade = 0; } else { //std::cout << "SES calculating grade " << this->distance << "/" << max_output_length << std::endl; grade -= (this->distance / (float) max_output_length ); std::cout << "grade: this->distance [ " << this->distance << "] / max_output_length " << max_output_length << "]\n"; //std::cout << "SES calculated grade = " << grade << std::endl; } this->setGrade(grade); } // =================================================== std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; }
void Vipster::IO::from_json(const nlohmann::json &j, IO::PWConfig& c) { c.atoms = j.value("atomfmt", IO::PWConfig::AtomFmt::Current); c.cell = j.value("cellfmt", IO::PWConfig::CellFmt::Current); }
/** * The 'delta' version of the click and drag command. This function moves an xy * distance from a startpoint. This distance is 'wrapping', so if it is outside * of the window, we mouseup, return to the start position, mousedown, and then * move again. We give a one pixel border at each side of the window and clamp * using that value to avoid accidental resizing. */ bool clickAndDragDelta(std::string window_name, nlohmann::json action){ //get the values of the student's window. int x_start, x_end, y_start, y_end, mouse_button; bool no_clamp = false; bool success = populateClickAndDragValues(action, window_name, x_start, x_end, y_start, y_end, mouse_button, no_clamp); //if we can't populate the click and drag values, do nothing. if(!success){ std::cout << "Could not populate the click and drag values."<< std::endl; return false; } //Define the corners of our window. (We use vectors as 2d points.) std::vector<int> upper_left, upper_right, lower_left, lower_right; upper_left.push_back(x_start); upper_left.push_back(y_start); upper_right.push_back(x_end); upper_right.push_back(y_start); lower_left.push_back(x_start); lower_left.push_back(y_end); lower_right.push_back(x_end); lower_right.push_back(y_end); //delta version, 2 values movement x and movement y. int amt_x_movement_remaining = action.value("x_distance", 0); int amt_y_movement_remaining = action.value("y_distance", 0); std::string start_location = action.value("start_location", "center"); //This shouldn't fail unless there isn't a mouse. std::string mouse_location_string = output_of_system_command("xdotool getmouselocation"); std::vector<int> xy = extractIntsFromString(mouse_location_string); //if the mouse isn't detected, fail. if(xy.size() < 2){ std::cout << "Mouse coordinates couldn't be found. Mouse undetected." << std::endl; return false; } //get the current mouse location int start_mouse_x = xy[0]; int start_mouse_y = xy[1]; //clamp the mouse within the screen (and move in by a pixel). clamp(start_mouse_x, x_start+1, x_end-1); clamp(start_mouse_y, y_start+1, y_end-1); //get the center of the window int width = x_end - x_start; int height = y_end - y_start; int x_middle = x_start + (width/2); int y_middle = y_start+(height/2); //NOTE: check my arithmetic. /** * The process that this algorithm goes through is as follows: * 1) Determine the slope of the dragged line and its distance. * 2) while we have not traversed the necessary distance * 3) project a line from the current mouse position towards the end * position with length equal to the remaining distance. * 4) Now that we have a line segment defined, find where/if it intersects * any of the window's edges * 5) if it does intersect, cut it off at the point of intersection, and only * drag that far. Else, if it doesn't intersect, we can assume we are * inside of the window, due to the clamp, and can drag. * 6) update remaining distance and continue to loop. */ //rise / run float slope=(float)amt_y_movement_remaining/(float)amt_x_movement_remaining; float total_distance_needed = sqrt(pow(amt_x_movement_remaining, 2) + pow (amt_y_movement_remaining, 2)); //remaining distance needed. float remaining_distance_needed = total_distance_needed; int action_start_x = (start_location == "current") ? start_mouse_x : x_middle; int action_start_y = (start_location == "current") ? start_mouse_y : y_middle; std::cout << "start x " << start_mouse_x << " our x " << action_start_x; std::cout << "start y " << start_mouse_y << " our y " << action_start_y; //The functions called within this loop will not fire if the window doesn't // exist. This check just short circuits to avoid additional printing. while(remaining_distance_needed >= 1 && windowExists(window_name)){ int curr_x = action_start_x; int curr_y = action_start_y; int moved_mouse_x, moved_mouse_y; //reset the mouse to the start location. mouse_move(window_name, action_start_x, action_start_y, x_start, x_end, y_start, y_end, false); //determine how far we've come. float fraction_of_distance_remaining = remaining_distance_needed / total_distance_needed; //project in the direction of the move to find the end of our line segment. float projected_x = action_start_x + (amt_x_movement_remaining * fraction_of_distance_remaining); float projected_y = action_start_y + (amt_y_movement_remaining * fraction_of_distance_remaining); //we are using vectors as 2d points. std::vector<int> current_point, projected_point; current_point.push_back(curr_x); current_point.push_back(curr_y); projected_point.push_back(projected_x); projected_point.push_back(projected_y); std::vector<float> intersection_point; intersection_point=getLineIntersectionPoint(current_point,projected_point, upper_left, upper_right); /** * TODO make this block smaller. * These if statements just test all edges of the window against our * projected line. */ //found is just a quick short-circuit to keep the code from ballooning. bool found = false; if(intersection_point.size() != 0){ //TOP std::cout << "intersected top" << std::endl; moved_mouse_x = (int)intersection_point[0]; moved_mouse_y = (int)intersection_point[1]; found = true; } if(!found) //RIGHT { intersection_point = getLineIntersectionPoint(current_point, projected_point, upper_right, lower_right); if(intersection_point.size() != 0){ std::cout << "intersected right" << std::endl; moved_mouse_x = (int)intersection_point[0]; moved_mouse_y = (int)intersection_point[1]; found = true; } } if(!found) //BOTTOM { intersection_point = getLineIntersectionPoint(current_point, projected_point, lower_right, lower_left); if(intersection_point.size() != 0){ std::cout << "intersected bottom" << std::endl; moved_mouse_x = (int)intersection_point[0]; moved_mouse_y = (int)intersection_point[1]; found = true; } } if(!found) //LEFT { intersection_point = getLineIntersectionPoint(current_point, projected_point, lower_left, upper_left); if(intersection_point.size() != 0){ std::cout << "intersected left" << std::endl; moved_mouse_x = (int)intersection_point[0]; moved_mouse_y = (int)intersection_point[1]; found = true; } } //if we didn't intersect, we are inside of the box (guaranteed by clamp) // so we can move freely. if(!found) { std::cout << "No intersection at all"<< std::endl; moved_mouse_x = projected_x; moved_mouse_y = projected_y; } //the distance we can move float distance_of_move = sqrt(pow(moved_mouse_x - action_start_x, 2) + pow (moved_mouse_y - action_start_y, 2)); //we are moving distance_of_move remaining_distance_needed -= distance_of_move; std::cout << "after the move, we had " << remaining_distance_needed << " distance left " << std::endl; mouseDown(window_name,mouse_button); //click mouse_move(window_name, moved_mouse_x, moved_mouse_y,x_start, x_end, //drag y_start, y_end, false); mouseUp(window_name,mouse_button); //release } //end loop. //to preserve backwards compatibility. if(start_location != "current"){ //put the mouse back where we found it. mouse_move(window_name, start_mouse_x, start_mouse_y, x_start, x_end, y_start, y_end,false); } return true; }