diff --git a/vpr/main.ui b/vpr/main.ui index 4bb2986dc23..d6b4b31e079 100644 --- a/vpr/main.ui +++ b/vpr/main.ui @@ -13,16 +13,6 @@ - - BlockNames - 0 - - - - 0 - - - False @@ -113,6 +103,35 @@ 5 + + + True + False + Toggle NoC Display + + + False + True + 6 + + + + + True + False + 0 + + None + NoC Links + NoC Link Usage + + + + False + True + 7 + + Block Outline @@ -126,7 +145,7 @@ False True - 6 + 8 @@ -142,12 +161,22 @@ False True - 7 + 9 + + 5 + 0 + + + + 0 + + + test False @@ -239,6 +268,12 @@ + + + + + + False @@ -535,59 +570,6 @@ - - False - - - True - False - - - SearchType - True - False - 0 - - Block ID - Block Name - Net ID - Net Name - RR Node ID - - - - 0 - 0 - - - - - True - True - search - gtk-find - Search... - - - 1 - 0 - - - - - Search - True - True - True - - - 2 - 0 - - - - - True False @@ -601,52 +583,42 @@ True False - - - True - False - True - True - - - 0 - 1 - 4 - 3 - - + True True False + end - - Window + + Zoom Fit True True True 0 - 1 + 0 - - Zoom Fit + + Window True True True + start 0 - 0 + 1 4 - 1 + 0 + 2 @@ -657,7 +629,7 @@ 0 - 4 + 5 4 @@ -667,112 +639,165 @@ True True True + end right 4 - 4 + 5 - + True - True - False - True - SearchPopover - - - True - False - center - gtk-find - - + False + True + True 0 - 0 + 2 + 4 + 3 - + + SearchType True - True - False - True - BlockPopover - - - True - False - Block Settings - - + False + 0 + + Block ID + Block Name + Net ID + Net Name + RR Node ID + - 1 + 0 0 - + + Search True True - False True - NetPopover - - - True - False - Net Settings - - - 2 + 3 0 - + True True - False - True - RoutingPopover - - - True - False - Routing Options - - + search + True + gtk-find + Search... + Completion - 3 + 1 0 + 2 - + True - True - False - True - MiscPopover + False + True - + True - False - Misc. + True + False + True + BlockPopover + + + True + False + Block Settings + + + + 0 + 0 + + + + + True + True + False + True + NetPopover + + + True + False + Net Settings + + + + + 1 + 0 + + + + + True + True + False + True + RoutingPopover + + + True + False + Routing Options + + + + + 2 + 0 + + + + + True + True + False + True + MiscPopover + + + True + False + Misc. + + + + + 3 + 0 + - 4 - 0 + 0 + 1 + 4 @@ -781,6 +806,45 @@ + + + + + + + + False + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index 6fc4beb6e14..ae48bdbc7b9 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -28,42 +28,6 @@ gint label_left_start_col = 0; gint box_left_start_col = 0; gint button_row = 2; // 2 is the row num of the window button in main.ui, add buttons starting from this row -void button_for_displaying_noc() { - GObject* main_window = application.get_object(application.get_main_window_id().c_str()); - GObject* main_window_grid = application.get_object("InnerGrid"); - t_draw_state* draw_state = get_draw_state_vars(); - - // if the user did not turn on the "noc" option then we don't give the option to display the noc to the user - if (!draw_state->show_noc_button) { - return; - } - - // if we are here then the user turned the "noc" option on, so create a button to allow the user to display the noc - - //combo box for toggle_noc_display - GtkWidget* toggle_noc_display_widget = gtk_combo_box_text_new(); - GtkWidget* toggle_noc_display_label = gtk_label_new("Toggle NoC Display:"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "None"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "NoC Links"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "NoC Link Usage"); - - gtk_combo_box_set_active((GtkComboBox*)toggle_noc_display_widget, 0); // default set to None which has an index 0 - gtk_widget_set_name(toggle_noc_display_widget, "toggle_noc_display"); - - //attach to the grid - gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_label, label_left_start_col, button_row++, box_width, box_height); - gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_widget, box_left_start_col, button_row++, box_width, box_height); - - // show the newy added check box - gtk_widget_show_all((GtkWidget*)main_window); - - //connect signals - g_signal_connect_swapped(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), - "changed", - G_CALLBACK(toggle_noc_display), - toggle_noc_display_widget); -} - void delete_button(const char* button_name) { GObject* main_window_grid = application.get_object("InnerGrid"); GList* list_of_widgets = gtk_container_get_children(GTK_CONTAINER(main_window_grid)); diff --git a/vpr/src/draw/buttons.h b/vpr/src/draw/buttons.h index 5dcba6f11fc..853ad4cb50b 100644 --- a/vpr/src/draw/buttons.h +++ b/vpr/src/draw/buttons.h @@ -9,8 +9,6 @@ # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" -void button_for_displaying_noc(); - void delete_button(const char* button_name); GtkWidget* find_button(const char* button_name); #endif /* NO_GRAPHICS */ diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index daff060d12b..f05c48ca990 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "vtr_assert.h" #include "vtr_ndoffsetmatrix.h" @@ -282,6 +283,7 @@ static void default_setup(ezgl::application* app) { basic_button_setup(app); net_button_setup(app); block_button_setup(app); + search_setup(app); } /* function below intializes the interface window with a set of buttons and links @@ -301,7 +303,6 @@ static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, //Hiding unused functionality hide_widget("RoutingMenuButton", app); hide_crit_path_button(app); - button_for_displaying_noc(); } /* function below intializes the interface window with a set of buttons and links @@ -356,7 +357,6 @@ static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, default_setup(app); routing_button_setup(app); hide_crit_path_button(app); - button_for_displaying_noc(); } /* function below intializes the interface window with a set of buttons and links @@ -670,19 +670,33 @@ bool draw_if_net_highlighted(ClusterNetId inet) { if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { return true; } - return false; } -# if defined(X11) && !defined(__MINGW32__) -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* key_name) { - //VTR_LOG("Key press %c (%d)\n", key_pressed, keysym); +/** + * @brief cbk function for key press + * + * At the moment, only does something if user is currently typing in searchBar and + * hits enter, at which point it runs autocomplete + */ +void act_on_key_press(ezgl::application* app, GdkEventKey* /*event*/, char* key_name) { std::string key(key_name); + GtkWidget* searchBar = GTK_WIDGET(app->get_object("TextInput")); + std::string text(gtk_entry_get_text(GTK_ENTRY(searchBar))); + t_draw_state* draw_state = get_draw_state_vars(); + if (gtk_widget_is_focus(searchBar)) { + if (key == "Return") { + enable_autocomplete(app); + gtk_editable_set_position(GTK_EDITABLE(searchBar), text.length()); + return; + } + } + if (draw_state->justEnabled) { + draw_state->justEnabled = false; + } else { + gtk_entry_set_completion(GTK_ENTRY(searchBar), nullptr); + } } -# else -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* /*key_name*/) { -} -# endif void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y) { // std::cout << "User clicked the "; diff --git a/vpr/src/draw/draw_toggle_functions.cpp b/vpr/src/draw/draw_toggle_functions.cpp index eb06fb0f000..a7e95ffde0e 100644 --- a/vpr/src/draw/draw_toggle_functions.cpp +++ b/vpr/src/draw/draw_toggle_functions.cpp @@ -406,15 +406,18 @@ void toggle_expansion_cost_cbk(GtkComboBoxText* self, ezgl::application* app) { app->refresh_drawing(); } -void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_noc_display button - * which is written in button.cpp */ +/** + * @brief cbk fn to toggle Network-On-Chip (Noc) visibility + * alters draw_state->draw_noc to reflect new state + * Reacts to main.ui created combo box, setup in ui_setup.cpp + * + * @param self ptr to combo box + * @param app ezgl application + */ +void toggle_noc_cbk(GtkComboBoxText* self, ezgl::application* app) { t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_noc_display"; - auto toggle_crit_path = find_button(button_name.c_str()); - gchar* combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_crit_path)); + gchar* combo_box_content = gtk_combo_box_text_get_active_text(self); if (strcmp(combo_box_content, "None") == 0) { draw_state->draw_noc = DRAW_NO_NOC; } else if (strcmp(combo_box_content, "NoC Links") == 0) @@ -423,7 +426,7 @@ void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /* draw_state->draw_noc = DRAW_NOC_LINK_USAGE; g_free(combo_box_content); - application.refresh_drawing(); + app->refresh_drawing(); } /** diff --git a/vpr/src/draw/draw_toggle_functions.h b/vpr/src/draw/draw_toggle_functions.h index c0c433843f7..7461e309cf2 100644 --- a/vpr/src/draw/draw_toggle_functions.h +++ b/vpr/src/draw/draw_toggle_functions.h @@ -107,11 +107,10 @@ void toggle_crit_path_cbk(GtkComboBoxText* self, ezgl::application* app); * Draws different router expansion costs based on user input. Changes value of draw_state->show_router_expansion_cost. */ void toggle_expansion_cost_cbk(GtkComboBoxText* self, ezgl::application* app); -/* Callback function for runtime created toggle_noc_display - * in button.cpp. +/* Callback function for main.ui created ToggleNocBox in ui_setup.cpp * Controls if the NoC on chip should be visualized and whether the link usage * in the NoC should be visualized. Changes value of draw_state->draw_noc */ -void toggle_noc_display(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); +void toggle_noc_cbk(GtkComboBoxText* self, ezgl::application* app); /* Callback function for main.ui created netMaxFanout widget in button.cpp. * Sets draw_state->draw_net_max_fanout to its corresponding value in the UI. */ diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index db989a59777..9fd29f29ff2 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -217,6 +217,7 @@ struct t_draw_state { bool show_noc_button = false; e_draw_noc draw_noc = DRAW_NO_NOC; std::shared_ptr noc_usage_color_map = nullptr; // color map used to display noc link bandwidth usage + bool justEnabled = false; //Whether auto-complete was just enabled std::vector list_of_breakpoints; diff --git a/vpr/src/draw/search_bar.cpp b/vpr/src/draw/search_bar.cpp index 02592fc8c1a..fcc6771c9e9 100644 --- a/vpr/src/draw/search_bar.cpp +++ b/vpr/src/draw/search_bar.cpp @@ -1,5 +1,19 @@ -#ifndef NO_GRAPHICS +/** + * @file search_bar.cpp + * @author Sebastian Lievano + * @brief Contains search/auto-complete related functions + * @version 0.1 + * @date 2022-07-20 + * + * This file essentially follows the whole search process, from searching, finding the match, + * and finally highlighting the searched for item. Additionally, auto-complete related stuff is found + * here. + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef NO_GRAPHICS # include # include @@ -52,6 +66,7 @@ extern std::string rr_highlight_message; void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app) { auto& device_ctx = g_vpr_ctx.device(); auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& atom_ctx = g_vpr_ctx.atom(); // get ID from search bar GtkEntry* text_entry = (GtkEntry*)app->get_object("TextInput"); @@ -59,16 +74,9 @@ void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app) { std::string user_input = text; std::stringstream ss(user_input); - GObject* combo_box = (GObject*)app->get_object("SearchType"); - gchar* type = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box)); - //Checking that a type is selected - if (type && type[0] == '\0') { - warning_dialog_box("Please select a search type"); - app->refresh_drawing(); + auto search_type = get_search_type(app); + if (search_type == "") return; - } - - std::string search_type(type); // reset deselect_all(); @@ -99,14 +107,38 @@ void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app) { return; } - highlight_blocks((ClusterBlockId)block_id); + highlight_cluster_block((ClusterBlockId)block_id); } else if (search_type == "Block Name") { + /* If the block exists in atom netlist, proceeding with highlighting process. + * if highlight atom block fn returns false, that means that the block can't be highlighted + * We've already confirmed the block exists in the netlist, so that means that at this zoom lvl, + * the subblock is not shown. Therefore highlight the clb mapping. + * + * If the block does not exist in the atom netlist, we will check the CLB netlist to see if + * they searched for a cluster block*/ std::string block_name = ""; ss >> block_name; - highlight_blocks((std::string)block_name); + AtomBlockId atom_blk_id = atom_ctx.nlist.find_block(block_name); + if (atom_blk_id != AtomBlockId::INVALID()) { + ClusterBlockId cluster_block_id = atom_ctx.lookup.atom_clb(atom_blk_id); + if (!highlight_atom_block(atom_blk_id, cluster_block_id, app)) { + highlight_cluster_block(cluster_block_id); + } + return; + } + + //Continues if atom block not found (Checking if user searched a clb) + ClusterBlockId cluster_block_id = ClusterBlockId::INVALID(); + cluster_block_id = cluster_ctx.clb_nlist.find_block(block_name); + + if (cluster_block_id == ClusterBlockId::INVALID()) { + warning_dialog_box("Invalid Block Name"); + return; //name not exist + } + highlight_cluster_block(cluster_block_id); //found block } else if (search_type == "Net ID") { @@ -124,10 +156,18 @@ void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app) { } else if (search_type == "Net Name") { + //in this case, all nets (clb and non-clb) are contained in the atom netlist + //So we only need to search this one std::string net_name = ""; ss >> net_name; + AtomNetId atom_net_id = atom_ctx.nlist.find_net(net_name); - highlight_nets((std::string)net_name); + if (atom_net_id == AtomNetId::INVALID()) { + warning_dialog_box("Invalid Net Name"); + return; //name not exist + } + ClusterNetId clb_net_id = atom_ctx.lookup.clb_net(atom_net_id); + highlight_nets(clb_net_id); } else @@ -229,7 +269,12 @@ void auto_zoom_rr_node(int rr_node_id) { (application.get_canvas(application.get_main_canvas_id()))->get_camera().set_world(zoom_view); } -void highlight_blocks(ClusterBlockId clb_index) { +/** + * @brief Highlights the given cluster block + * + * @param clb_index Cluster Index to be highlighted + */ +void highlight_cluster_block(ClusterBlockId clb_index) { char msg[vtr::bufsize]; auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); @@ -257,45 +302,80 @@ void highlight_blocks(ClusterBlockId clb_index) { application.refresh_drawing(); } -void highlight_nets(ClusterNetId net_id) { - t_trace* tptr; - auto& route_ctx = g_vpr_ctx.routing(); +/** + * @brief Finds and highlights the atom block. Returns true if block shows, false if not + * + * @param atom_blk AtomBlockId being searched for + * @param cl_blk ClusterBlock containing atom_blk + * @param app ezgl:: application used + * @return true | If sub-block can be highlighted + * @return false | If sub-block not found (impossible in search case) or not shown at current zoom lvl + */ +bool highlight_atom_block(AtomBlockId atom_blk, ClusterBlockId cl_blk, ezgl::application* app) { + auto& atom_ctx = g_vpr_ctx.atom(); + auto& cl_ctx = g_vpr_ctx.clustering(); + t_pb* pb = cl_ctx.clb_nlist.block_pb(cl_blk); - t_draw_state* draw_state = get_draw_state_vars(); + //Getting the pb* for the atom block + auto atom_block_pb = find_atom_block_in_pb(atom_ctx.nlist.block_name(atom_blk), pb); + if (!atom_block_pb) return false; //If no block found, returning false - if (int(route_ctx.trace.size()) == 0) return; + //Ensuring that block is drawn at current zoom lvl, returning false if not + auto atom_block_depth = atom_block_pb->pb_graph_node->pb_type->depth; + t_draw_state* draw_state = get_draw_state_vars(); + int max_depth = draw_state->show_blk_internal; + if (atom_block_depth > max_depth) return false; - for (tptr = route_ctx.trace[net_id].head; tptr != nullptr; tptr = tptr->next) { - draw_state->net_color[net_id] = ezgl::MAGENTA; - } + //Highlighting block + get_selected_sub_block_info().set(atom_block_pb, cl_blk); + app->refresh_drawing(); + return true; } -void highlight_nets(std::string net_name) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - ClusterNetId net_id = ClusterNetId::INVALID(); - net_id = cluster_ctx.clb_nlist.find_net(net_name); - - if (net_id == ClusterNetId::INVALID()) { - warning_dialog_box("Invalid Net Name"); - return; //name not exist +/** + * @brief Recursively looks through pb graph to find block w. given name + * + * @param name name of block being searched for + * @param pb current node to be examined + * @return t_pb* t_pb ptr of block w. name "name". Returns nullptr if nothing found + */ +t_pb* find_atom_block_in_pb(std::string name, t_pb* pb) { + //Checking if block is one being searched for + std::string pbName(pb->name); + if (pbName == name) + return pb; + //If block has no children, returning + if (pb->child_pbs == nullptr) + return nullptr; + int num_child_types = pb->get_num_child_types(); + //Iterating through all child types + for (int i = 0; i < num_child_types; ++i) { + if (pb->child_pbs[i] == nullptr) continue; + int num_children_of_type = pb->get_num_children_of_type(i); + //Iterating through all of pb's children of given type + for (int j = 0; j < num_children_of_type; ++j) { + t_pb* child_pb = &pb->child_pbs[i][j]; + //If child exists, recursively calling function on it + if (child_pb->name != nullptr) { + t_pb* subtree_result = find_atom_block_in_pb(name, child_pb); + //If a result is found, returning it to top of recursive calls + if (subtree_result != nullptr) { + return subtree_result; + } + } + } } - - highlight_nets(net_id); //found net + return nullptr; } -void highlight_blocks(std::string block_name) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - ClusterBlockId block_id = ClusterBlockId::INVALID(); - block_id = cluster_ctx.clb_nlist.find_block(block_name); +void highlight_nets(ClusterNetId net_id) { + auto& route_ctx = g_vpr_ctx.routing(); - if (block_id == ClusterBlockId::INVALID()) { - warning_dialog_box("Invalid Block Name"); - return; //name not exist - } + t_draw_state* draw_state = get_draw_state_vars(); - highlight_blocks(block_id); //found block + //If routing does not exist return + if (int(route_ctx.trace.size()) == 0) return; + draw_state->net_color[net_id] = ezgl::MAGENTA; } void warning_dialog_box(const char* message) { @@ -339,34 +419,164 @@ void warning_dialog_box(const char* message) { void search_type_changed(GtkComboBox* self, ezgl::application* app) { auto type = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(self)); GtkEntry* searchBar = GTK_ENTRY(app->get_object("TextInput")); + GtkEntryCompletion* completion = GTK_ENTRY_COMPLETION(app->get_object("Completion")); + GtkTreeModel* netNames = GTK_TREE_MODEL(app->get_object("NetNames")); + GtkTreeModel* blockNames = GTK_TREE_MODEL(app->get_object("BlockNames")); //Ensuring a valid type was selected if (!type) return; if (type[0] == '\0') return; std::string searchType(type); - //Setting active completion model to blockCompleter if type selected is block Name + + /* + * If search type is name, connecting search bar to completion, + * and connecting completion to the appropriate model (blocks or nets) + * Additionally, visibility of key length setter is toggled by these changes + */ if (searchType == "Block Name") { - GtkEntryCompletion* blockCompleter = GTK_ENTRY_COMPLETION(app->get_object("BlockNameCompleter")); - gtk_entry_set_completion(searchBar, blockCompleter); - } else { //If not, setting to null + gtk_entry_completion_set_model(completion, blockNames); + } else if (searchType == "Net Name") { + gtk_entry_completion_set_model(completion, netNames); + } else { //setting to null if option does not require auto-complete + gtk_entry_completion_set_model(completion, NULL); gtk_entry_set_completion(searchBar, nullptr); } } /** - * @brief loads block names into gtk list store item used for completion + * @brief A non-default matching function. As opposed to simply searching for a prefix(default), + * searches string for presence of a substring. Case-insensitive * - * @param app ezgl application + * @param completer the GtkEntryCompletion being used + * @param key a normalized and case-folded key representing the text + * @param iter GtkTreeIter pointing at the current entry being compared + * @param user_data null + * @return true | if the string pointed to by iter contains key (case-insensitive) + * @return false | if the string pointed to does not contain key */ -void load_block_names(ezgl::application* app) { - auto blockStorage = GTK_LIST_STORE(app->get_object("BlockNames")); - auto& cluster_ctx = g_vpr_ctx.clustering(); - GtkTreeIter iter; - //Getting and storing all block names - for (ClusterBlockId id : cluster_ctx.clb_nlist.blocks()) { - gtk_list_store_append(blockStorage, &iter); - gtk_list_store_set(blockStorage, &iter, - 0, (cluster_ctx.clb_nlist.block_name(id)).c_str(), -1); +gboolean customMatchingFunction( + GtkEntryCompletion* completer, + const gchar* key, + GtkTreeIter* iter, + gpointer /*user data*/ +) { + GtkTreeModel* model = gtk_entry_completion_get_model(completer); + const gchar* text; + gtk_tree_model_get(model, iter, 0, &text, -1); + //Removing case information + g_utf8_casefold(text, -1); + g_utf8_normalize(text, -1, G_NORMALIZE_DEFAULT); + std::string cppText(text); + //If substring not found, returning false; + return (cppText.find(key, 0) != std::string::npos); +} + +/** + * @brief Creates a GdkEvent that simulates user pressing key "key". + * Currently used to fool GtkEntryCompletion into showing options w/o receiving a new input + * + * @param key character value + * @param window GdkWindow + * @return GdkEvent Keypress event + */ +GdkEvent simulate_keypress(char key, GdkWindow* window) { + int charVal = (int)key; + //Creating event and adding properties + GdkEvent new_event; + new_event.key.type = GDK_KEY_PRESS; + new_event.key.window = window; + new_event.key.send_event = TRUE; + new_event.key.time = GDK_CURRENT_TIME; + new_event.key.keyval = gdk_unicode_to_keyval(charVal); + new_event.key.state = GDK_KEY_PRESS_MASK; + new_event.key.length = 0; + new_event.key.string = 0; + new_event.key.hardware_keycode = 0; + new_event.key.group = 0; + return new_event; +} + +/** + * @brief Turns on autocomplete + * + * This function enables the auto-complete fuctionality for the search bar. + * Normally, this is pretty simple, but the idea is to have auto-complete appear as soon + * as the user hits the "Enter" key. To accomplish this, a fake Gdk event is created + * to simulate the user hitting a key. + * + * This was done for usability reasons; if this is not done, user will need to input another key before seeing + * autocomplete results. Considering the enter is supposed to be a search, we want to search for the users + * key, not the key + another char + * + * PERFORMANCE DATA + * Correlation between key length and time is shaky; there might be some correlation to + * how many strings are similar to it. All tests are performed with the key "1" - pretty common + * Tests are searched three times then average + * MODEL 1: EARCH + TSENG.BLIF + * NETS 1483 + * NET SRCH. 19392 + * BLOCKS 1835 + * BLOCK SRCH. 21840 + * For second model (much larger, much longer CPU times) observed large dropoff in times from one char to two chars (about 2 times faster) but after stayed consistent + * Maybe when I ahve more time, will make a cute graph or something, no time right now + * MODEL 2: Strativix arch + MES_NOC (TITAN) + * NETS 577696 + * NET SRCH. 4.93438e+06 + * BLOCKS 572148 + * BLOCKS SRCH. 4.8654e+06 + * Obviously much slower w. more nets/blocks. However, it only performs a single search after each enter key press, pretty bearable considering its searching in strings + * @param app ezgl app + */ +void enable_autocomplete(ezgl::application* app) { + GtkEntryCompletion* completion = GTK_ENTRY_COMPLETION(app->get_object("Completion")); + GtkEntry* searchBar = GTK_ENTRY(app->get_object("TextInput")); + auto draw_state = get_draw_state_vars(); + + std::string searchType = get_search_type(app); + if (searchType == "") + return; + //Checking to make sure that we are on a mode that uses auto-complete + if (gtk_entry_completion_get_model(completion) == NULL) { + std::cout << "NO MODEL SELECTED" << std::endl; + return; } + + //Getting input text + std::string oldText(gtk_entry_get_text(searchBar)); + + //Turning on completion + gtk_entry_set_completion(searchBar, completion); + gtk_entry_completion_complete(completion); + + //Setting min key length to either 0 or 1 less than key length (max option) + gtk_entry_completion_set_minimum_key_length(completion, std::max(0, (int)(oldText.length() - 1))); + + draw_state->justEnabled = true; + + //If string len is 0, reutrning + if (oldText.length() == 0) return; + + gtk_widget_grab_focus(GTK_WIDGET(searchBar)); + std::string newText = (oldText.length() > 1) ? oldText.substr(0, oldText.length() - 1) : ""; + gtk_entry_set_text(searchBar, newText.c_str()); + + //Creating a false event to insert the last character into the string + auto window = gtk_widget_get_parent_window(GTK_WIDGET(searchBar)); + GdkEvent new_event = simulate_keypress(oldText.back(), window); + gdk_event_put(&new_event); +} + +//Returns current search type. Returns empty string if fails +std::string get_search_type(ezgl::application* app) { + GObject* combo_box = (GObject*)app->get_object("SearchType"); + gchar* type = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box)); + //Checking that a type is selected + if (!type || (type && type[0] == '\0')) { + warning_dialog_box("Please select a search type"); + app->refresh_drawing(); + return ""; + } + std::string searchType(type); + return searchType; } -#endif /* NO_GRAPHICS */ +#endif /* NO_GRAPHICS */ \ No newline at end of file diff --git a/vpr/src/draw/search_bar.h b/vpr/src/draw/search_bar.h index 50588156a71..92f51470601 100644 --- a/vpr/src/draw/search_bar.h +++ b/vpr/src/draw/search_bar.h @@ -13,12 +13,17 @@ void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app); bool highlight_rr_nodes(int hit_node); void auto_zoom_rr_node(int rr_node_id); -void highlight_blocks(ClusterBlockId clb_index); +void highlight_cluster_block(ClusterBlockId clb_index); void highlight_nets(ClusterNetId net_id); void highlight_nets(std::string net_name); -void highlight_blocks(std::string block_name); -void load_block_names(ezgl::application* app); +void highlight_atom_block(AtomBlockId block_id); + +gboolean customMatchingFunction( + GtkEntryCompletion* completer, + const gchar* key, + GtkTreeIter* iter, + gpointer user_data); //Function to manage entry completions when search type is changed void search_type_changed(GtkComboBox* /*self*/, ezgl::application* app); @@ -26,6 +31,20 @@ void search_type_changed(GtkComboBox* /*self*/, ezgl::application* app); /*function below pops up a dialog box with no button, showing the input warning message*/ void warning_dialog_box(const char* message); +//Returns pb ptr of given atom block name +t_pb* find_atom_block_in_pb(std::string name, t_pb* pb); + +//Highlights atom block in cluster block +bool highlight_atom_block(AtomBlockId atom_blk, ClusterBlockId cl_blk, ezgl::application* app); + +//Turns on autocomplete/suggestions +void enable_autocomplete(ezgl::application* app); + +//Simulates key press event +GdkEvent simulate_keypress(char key, GdkWindow* window); + +//Returns current search type +std::string get_search_type(ezgl::application* app); #endif /* NO_GRAPHICS */ -#endif /* SEARCH_BAR_H */ +#endif /* SEARCH_BAR_H */ \ No newline at end of file diff --git a/vpr/src/draw/ui_setup.cpp b/vpr/src/draw/ui_setup.cpp index d12bbacaeeb..54b8c6d8404 100644 --- a/vpr/src/draw/ui_setup.cpp +++ b/vpr/src/draw/ui_setup.cpp @@ -80,7 +80,7 @@ void net_button_setup(ezgl::application* app) { * @brief sets up block related buttons, connects their signals * * Connects signals and sets init. values for blk internals spin button, - * blk pin util combo box, and placement macros combo box created in + * blk pin util combo box,placement macros combo box, and noc combo bx created in * main.ui. Found in Block Settings dropdown * @param app */ @@ -100,6 +100,15 @@ void block_button_setup(ezgl::application* app) { //Toggle Placement Macros GtkComboBoxText* placement_macros = GTK_COMBO_BOX_TEXT(app->get_object("TogglePlacementMacros")); g_signal_connect(placement_macros, "changed", G_CALLBACK(placement_macros_cbk), app); + + //Toggle NoC Display (based on startup cmd --noc on) + if (!draw_state->show_noc_button) { + hide_widget("NocLabel", app); + hide_widget("ToggleNocBox", app); + } else { + GtkComboBoxText* toggleNocBox = GTK_COMBO_BOX_TEXT(app->get_object("ToggleNocBox")); + g_signal_connect(toggleNocBox, "changed", G_CALLBACK(toggle_noc_cbk), app); + } } /** @@ -138,6 +147,19 @@ void routing_button_setup(ezgl::application* app) { g_signal_connect(toggle_router_util, "changed", G_CALLBACK(toggle_router_util_cbk), app); } +/** + * @brief Loads required data for search autocomplete, sets up special completion fn + * + * @param app ezgl app + */ +void search_setup(ezgl::application* app) { + load_block_names(app); + load_net_names(app); + //Setting custom matching function for entry completion (searches whole string instead of start) + GtkEntryCompletion* wildcardComp = GTK_ENTRY_COMPLETION(app->get_object("Completion")); + gtk_entry_completion_set_match_func(wildcardComp, (GtkEntryCompletionMatchFunc)customMatchingFunction, NULL, NULL); +} + /** * @brief connects critical path button to its cbk fn * @@ -169,4 +191,48 @@ void hide_widget(std::string widgetName, ezgl::application* app) { gtk_widget_hide(widget); } +/** + * @brief loads atom and cluster lvl names into gtk list store item used for completion + * + * @param app ezgl application used for ui + */ +void load_block_names(ezgl::application* app) { + auto blockStorage = GTK_LIST_STORE(app->get_object("BlockNames")); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& atom_ctx = g_vpr_ctx.atom(); + GtkTreeIter iter; + int i = 0; + for (ClusterBlockId id : cluster_ctx.clb_nlist.blocks()) { + gtk_list_store_append(blockStorage, &iter); + gtk_list_store_set(blockStorage, &iter, + 0, (cluster_ctx.clb_nlist.block_name(id)).c_str(), -1); + i++; + } + for (AtomBlockId id : atom_ctx.nlist.blocks()) { + gtk_list_store_append(blockStorage, &iter); + gtk_list_store_set(blockStorage, &iter, + 0, (atom_ctx.nlist.block_name(id)).c_str(), -1); + i++; + } +} + +/** + * @brief loads atom net names into gtk list store item used for completion + * + * @param app ezgl application used for ui + */ +void load_net_names(ezgl::application* app) { + auto netStorage = GTK_LIST_STORE(app->get_object("NetNames")); + auto& atom_ctx = g_vpr_ctx.atom(); + GtkTreeIter iter; + //Loading net names + int i = 0; + for (AtomNetId id : atom_ctx.nlist.nets()) { + gtk_list_store_append(netStorage, &iter); + gtk_list_store_set(netStorage, &iter, + 0, (atom_ctx.nlist.net_name(id)).c_str(), -1); + i++; + } +} + #endif /* NO_GRAPHICS */ diff --git a/vpr/src/draw/ui_setup.h b/vpr/src/draw/ui_setup.h index d37e816851c..69b8115e4f8 100644 --- a/vpr/src/draw/ui_setup.h +++ b/vpr/src/draw/ui_setup.h @@ -18,10 +18,13 @@ void basic_button_setup(ezgl::application* app); void net_button_setup(ezgl::application* app); void block_button_setup(ezgl::application* app); +void search_setup(ezgl::application* app); void routing_button_setup(ezgl::application* app); void crit_path_button_setup(ezgl::application* app); void hide_crit_path_button(ezgl::application* app); +void load_block_names(ezgl::application* app); +void load_net_names(ezgl::application* app); void hide_widget(std::string widgetName, ezgl::application* app); void show_widget(std::string widgetName, ezgl::application* app);