diff --git a/CMakeLists.txt b/CMakeLists.txt index 98a4ba0..0cbe74f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,7 @@ file(MAKE_DIRECTORY ${TOOLS_DATA_DIR}) set(OUTPUT_NAME cc3dsfs) add_executable(CMakeBin2C tools/bin2c.cpp) -add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/3dscapture.cpp source/conversions.cpp source/ConnectionMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp) +add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/3dscapture.cpp source/conversions.cpp source/ConnectionMenu.cpp source/OptionSelectionMenu.cpp source/MainMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp) add_dependencies(${OUTPUT_NAME} FTD3XX_BUILD_PROJECT CMakeBin2C) target_link_libraries(${OUTPUT_NAME} PRIVATE sfml-graphics sfml-audio sfml-window sfml-system ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB}) target_link_directories(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}) diff --git a/include/ConnectionMenu.hpp b/include/ConnectionMenu.hpp index 81ca7a8..94a31ae 100755 --- a/include/ConnectionMenu.hpp +++ b/include/ConnectionMenu.hpp @@ -1,55 +1,24 @@ #ifndef __CONNECTIONMENU_HPP #define __CONNECTIONMENU_HPP -#include -#include +#include "OptionSelectionMenu.hpp" -#include "TextRectangle.hpp" #include "capture_structs.hpp" -#include "sfml_gfx_structs.hpp" -#define CONNECTION_NUM_ELEMENTS_PER_SCREEN 4 -#define CONNECTION_NUM_PAGE_ELEMENTS 3 -#define CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN (CONNECTION_NUM_ELEMENTS_PER_SCREEN + CONNECTION_NUM_PAGE_ELEMENTS) -#define CONNECTION_NUM_VERTICAL_SLICES (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - (CONNECTION_NUM_PAGE_ELEMENTS - 1)) - -class ConnectionMenu { +class ConnectionMenu : public OptionSelectionMenu { public: ConnectionMenu(bool font_load_success, sf::Font &text_font); ~ConnectionMenu(); - bool poll(SFEvent &event_data); - void draw(float scaling_factor, sf::RenderTarget &window); void prepare(float scaling_factor, int view_size_x, int view_size_y); void insert_data(DevicesList *devices_list); int selected_index = -1; +protected: + void reset_output_option(); + void set_output_option(int index); + int get_num_options(); + std::string get_string_option(int index); + void class_setup(); private: - struct ConnectionMenuData { - int page = 0; - int option_selected = -1; - bool enabled_labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; - int menu_width; - int menu_height; - int pos_x; - int pos_y; - }; - std::chrono::time_point last_action_time; - const float action_timeout = 0.1; - int loaded_page = 0; - int option_selected = -1; - TextRectangle *labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; - bool selectable_labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; - ConnectionMenuData future_data; - ConnectionMenuData loaded_data; DevicesList *devices_list; - - bool can_execute_action(); - void up_code(); - void down_code(); - void left_code(); - void right_code(); - void prepare_options(); - void option_selection_handling(); - void decrement_selected_option(); - void increment_selected_option(); }; #endif diff --git a/include/MainMenu.hpp b/include/MainMenu.hpp new file mode 100755 index 0000000..129181f --- /dev/null +++ b/include/MainMenu.hpp @@ -0,0 +1,42 @@ +#ifndef __MAINMENU_HPP +#define __MAINMENU_HPP + +#include "OptionSelectionMenu.hpp" +#include + +#include "TextRectangle.hpp" +#include "sfml_gfx_structs.hpp" +#include "display_structs.hpp" + +#define NUM_TOTAL_MAIN_MENU_OPTIONS 4 + +#define MAIN_NUM_ELEMENTS_PER_SCREEN 5 +#define MAIN_NUM_PAGE_ELEMENTS 3 +#define MAIN_NUM_ELEMENTS_DISPLAYED_PER_SCREEN (MAIN_NUM_ELEMENTS_PER_SCREEN + MAIN_NUM_PAGE_ELEMENTS) +#define MAIN_NUM_VERTICAL_SLICES (MAIN_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - (MAIN_NUM_PAGE_ELEMENTS - 1)) + +enum MainMenuOutAction{ + MAIN_MENU_NO_ACTION, + MAIN_MENU_OPEN, + MAIN_MENU_CLOSE_MENU, + MAIN_MENU_QUIT_APPLICATION, +}; + +class MainMenu : public OptionSelectionMenu { +public: + MainMenu(bool font_load_success, sf::Font &text_font); + ~MainMenu(); + void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info, bool connected); + void insert_data(ScreenType s_type, bool is_fullscreen); + MainMenuOutAction selected_index = MainMenuOutAction::MAIN_MENU_NO_ACTION; +protected: + void reset_output_option(); + void set_output_option(int index); + int get_num_options(); + std::string get_string_option(int index); + void class_setup(); +private: + int options_indexes[NUM_TOTAL_MAIN_MENU_OPTIONS]; + int num_enabled_options; +}; +#endif diff --git a/include/OptionSelectionMenu.hpp b/include/OptionSelectionMenu.hpp new file mode 100755 index 0000000..ae2ff77 --- /dev/null +++ b/include/OptionSelectionMenu.hpp @@ -0,0 +1,72 @@ +#ifndef __OPTIONSELECTIONMENU_HPP +#define __OPTIONSELECTIONMENU_HPP + +#include +#include + +#include "TextRectangle.hpp" +#include "sfml_gfx_structs.hpp" + +class OptionSelectionMenu { +public: + OptionSelectionMenu(); + ~OptionSelectionMenu(); + bool poll(SFEvent &event_data); + void draw(float scaling_factor, sf::RenderTarget &window); + void reset_data(); + std::chrono::time_point last_input_processed_time; +protected: + int num_elements_per_screen = 1; + int num_page_elements = 3; + int num_elements_displayed_per_screen = num_elements_per_screen + num_page_elements; + int num_vertical_slices = (num_elements_displayed_per_screen - (num_page_elements - 1)); + int num_elements_start_id = 0; + int num_page_elements_start_id = num_elements_per_screen + num_elements_start_id; + int prev_page_id = num_page_elements_start_id; + int info_page_id = num_page_elements_start_id + 1; + int next_page_id = num_page_elements_start_id + 2; + int min_elements_text_scaling_factor = 3; + int width_factor_menu = 1; + int width_divisor_menu = 1; + int base_height_factor_menu = 1; + int base_height_divisor_menu = 1; + float min_text_size = 0.3; + virtual void reset_output_option(); + virtual void set_output_option(int index); + virtual int get_num_options(); + virtual std::string get_string_option(int index); + virtual void class_setup(); + void initialize(bool font_load_success, sf::Font &text_font); + void prepare_options(); + void base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y); + struct MenuData { + int page = 0; + int option_selected = -1; + int menu_width; + int menu_height; + int pos_x; + int pos_y; + }; + MenuData future_data; + TextRectangle **labels; + bool *future_enabled_labels; +private: + std::chrono::time_point last_action_time; + const float action_timeout = 0.1; + int loaded_page = 0; + int option_selected = -1; + bool *selectable_labels; + bool *loaded_enabled_labels; + MenuData loaded_data; + + void prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int index, float text_scaling_factor); + bool can_execute_action(); + void up_code(); + void down_code(); + void left_code(); + void right_code(); + void option_selection_handling(); + void decrement_selected_option(); + void increment_selected_option(); +}; +#endif diff --git a/include/display_structs.hpp b/include/display_structs.hpp new file mode 100755 index 0000000..d2cce57 --- /dev/null +++ b/include/display_structs.hpp @@ -0,0 +1,46 @@ +#ifndef __DISPLAY_STRUCTS_HPP +#define __DISPLAY_STRUCTS_HPP + +#include "utils.hpp" +#include "hw_defs.hpp" + +enum ScreenType { TOP, BOTTOM, JOINT }; +enum Crop { DEFAULT_3DS, SPECIAL_DS, SCALED_DS, NATIVE_DS, SCALED_GBA, NATIVE_GBA, SCALED_GB, NATIVE_GB, SCALED_SNES, NATIVE_SNES, NATIVE_NES, CROP_END }; +enum ParCorrection { PAR_NORMAL, PAR_SNES_HORIZONTAL, PAR_SNES_VERTICAL, PAR_END }; +enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END }; +enum OffsetAlgorithm { NO_DISTANCE, HALF_DISTANCE, MAX_DISTANCE, OFF_ALGO_END }; +enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE }; + +struct ScreenInfo { + bool is_blurred; + Crop crop_kind; + double scaling; + bool is_fullscreen; + BottomRelativePosition bottom_pos; + OffsetAlgorithm subscreen_offset_algorithm, subscreen_attached_offset_algorithm, total_offset_algorithm_x, total_offset_algorithm_y; + int top_rotation, bot_rotation; + bool show_mouse; + bool v_sync_enabled; + bool async; + int top_scaling, bot_scaling; + bool bfi; + double bfi_divider; + double menu_scaling_factor; + bool rounded_corners_fix; + ParCorrection top_par; + ParCorrection bot_par; +}; + +struct DisplayData { + bool split = false; +}; + +#pragma pack(push, 1) + +struct PACKED VideoOutputData { + uint8_t screen_data[IN_VIDEO_SIZE][4]; +}; + +#pragma pack(pop) + +#endif diff --git a/include/frontend.hpp b/include/frontend.hpp index fdf8f6e..d9733e5 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -9,60 +9,17 @@ #include "utils.hpp" #include "audio_data.hpp" #include "capture_structs.hpp" -#include "hw_defs.hpp" #include "TextRectangle.hpp" #include "sfml_gfx_structs.hpp" #include "ConnectionMenu.hpp" - -enum Crop { DEFAULT_3DS, SPECIAL_DS, SCALED_DS, NATIVE_DS, SCALED_GBA, NATIVE_GBA, SCALED_GB, NATIVE_GB, SCALED_SNES, NATIVE_SNES, NATIVE_NES, CROP_END }; -enum ParCorrection { PAR_NORMAL, PAR_SNES_HORIZONTAL, PAR_SNES_VERTICAL, PAR_END }; -enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END }; -enum OffsetAlgorithm { NO_DISTANCE, HALF_DISTANCE, MAX_DISTANCE, OFF_ALGO_END }; -enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE }; - -struct ScreenInfo { - bool is_blurred; - Crop crop_kind; - double scaling; - bool is_fullscreen; - BottomRelativePosition bottom_pos; - OffsetAlgorithm subscreen_offset_algorithm, subscreen_attached_offset_algorithm, total_offset_algorithm_x, total_offset_algorithm_y; - int top_rotation, bot_rotation; - bool show_mouse; - bool v_sync_enabled; - bool async; - int top_scaling, bot_scaling; - bool bfi; - double bfi_divider; - double menu_scaling_factor; - bool rounded_corners_fix; - ParCorrection top_par; - ParCorrection bot_par; -}; - -struct DisplayData { - bool split = false; - CurrMenuType curr_menu = DEFAULT_MENU_TYPE; -}; - -#pragma pack(push, 1) - -struct PACKED VideoOutputData { - uint8_t screen_data[IN_VIDEO_SIZE][4]; -}; - -#pragma pack(pop) - -void reset_screen_info(ScreenInfo &info); -bool load_screen_info(std::string key, std::string value, std::string base, ScreenInfo &info); -std::string save_screen_info(std::string base, const ScreenInfo &info); +#include "MainMenu.hpp" +#include "display_structs.hpp" class WindowScreen { public: - enum ScreenType { TOP, BOTTOM, JOINT }; ScreenInfo m_info; - WindowScreen(WindowScreen::ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, AudioData* audio_data, std::mutex* events_access); + WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, AudioData* audio_data, std::mutex* events_access); ~WindowScreen(); void build(); @@ -112,8 +69,10 @@ private: std::chrono::time_point last_window_creation_time; const float mouse_timeout = 5.0f; const float v_sync_timeout = 5.0f; + CurrMenuType curr_menu = DEFAULT_MENU_TYPE; CurrMenuType loaded_menu; ConnectionMenu *connection_menu; + MainMenu *main_menu; sf::Texture in_tex; @@ -126,7 +85,7 @@ private: sf::RectangleShape m_in_rect_top, m_in_rect_bot; out_rect_data m_out_rect_top, m_out_rect_bot; - WindowScreen::ScreenType m_stype; + ScreenType m_stype; std::queue events_queue; @@ -153,6 +112,7 @@ private: void poll_window(); bool common_poll(SFEvent &event_data); bool main_poll(SFEvent &event_data); + bool no_menu_poll(SFEvent &event_data); void prepare_screen_rendering(); bool window_needs_work(); void window_factory(bool is_main_thread); @@ -178,6 +138,7 @@ private: sf::Vector2f getShownScreenSize(bool is_top, Crop &crop_kind); void crop(); void setWinSize(bool is_main_thread); + void setup_main_menu(); void update_connection(); }; @@ -189,6 +150,9 @@ struct FrontendData { bool reload; }; +void reset_screen_info(ScreenInfo &info); +bool load_screen_info(std::string key, std::string value, std::string base, ScreenInfo &info); +std::string save_screen_info(std::string base, const ScreenInfo &info); void get_par_size(float &width, float &height, float multiplier_factor, ParCorrection &correction_factor); void get_par_size(int &width, int &height, float multiplier_factor, ParCorrection &correction_factor); void default_sleep(); diff --git a/include/sfml_gfx_structs.hpp b/include/sfml_gfx_structs.hpp index 6f49c77..52e09f7 100755 --- a/include/sfml_gfx_structs.hpp +++ b/include/sfml_gfx_structs.hpp @@ -5,7 +5,7 @@ #include enum JoystickDirection {JOY_DIR_NONE, JOY_DIR_UP, JOY_DIR_DOWN, JOY_DIR_LEFT, JOY_DIR_RIGHT}; -enum JoystickAction {JOY_ACTION_NONE, JOY_ACTION_CONFIRM, JOY_ACTION_NEGATE}; +enum JoystickAction {JOY_ACTION_NONE, JOY_ACTION_CONFIRM, JOY_ACTION_NEGATE, JOY_ACTION_MENU}; struct out_rect_data { sf::RectangleShape out_rect; diff --git a/include/utils.hpp b/include/utils.hpp index 9375104..1d5aef8 100755 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -21,6 +21,7 @@ #define USB_CHECKS_PER_SECOND ((USB_FPS + (USB_FPS / 12)) * USB_NUM_CHECKS) bool is_big_endian(void); +std::string get_float_str_decimals(float value, int decimals); class ConsumerMutex { public: diff --git a/source/ConnectionMenu.cpp b/source/ConnectionMenu.cpp index ae94238..e3a1fb4 100755 --- a/source/ConnectionMenu.cpp +++ b/source/ConnectionMenu.cpp @@ -1,355 +1,51 @@ #include "ConnectionMenu.hpp" -#define CONNECTION_NUM_PAGE_ELEMENTS_START_ID CONNECTION_NUM_ELEMENTS_PER_SCREEN -#define CONNECTION_PREV_PAGE_ID (CONNECTION_NUM_PAGE_ELEMENTS_START_ID) -#define CONNECTION_INFO_PAGES_ID (CONNECTION_NUM_PAGE_ELEMENTS_START_ID + 1) -#define CONNECTION_NEXT_PAGE_ID (CONNECTION_NUM_PAGE_ELEMENTS_START_ID + 2) - -ConnectionMenu::ConnectionMenu(bool font_load_success, sf::Font &text_font) { - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { - this->labels[i] = new TextRectangle(font_load_success, text_font); - this->labels[i]->setProportionalBox(false); - this->labels[i]->setText(std::to_string(i)); - this->labels[i]->setShowText(true); - this->selectable_labels[i] = true; - this->future_data.enabled_labels[i] = true; - } - this->last_action_time = std::chrono::high_resolution_clock::now(); - this->selectable_labels[CONNECTION_INFO_PAGES_ID] = false; +ConnectionMenu::ConnectionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ + this->initialize(font_load_success, text_font); } ConnectionMenu::~ConnectionMenu() { - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) - delete this->labels[i]; } -bool ConnectionMenu::can_execute_action() { - auto curr_time = std::chrono::high_resolution_clock::now(); - const std::chrono::duration diff = curr_time - this->last_action_time; - if(diff.count() > this->action_timeout) - return true; - return false; +void ConnectionMenu::class_setup() { + this->num_elements_per_screen = 4; + this->num_page_elements = 3; + this->num_elements_displayed_per_screen = num_elements_per_screen + num_page_elements; + this->num_vertical_slices = (num_elements_displayed_per_screen - (num_page_elements - 1)); + this->num_elements_start_id = 0; + this->num_page_elements_start_id = num_elements_per_screen + num_elements_start_id; + this->prev_page_id = num_page_elements_start_id; + this->info_page_id = num_page_elements_start_id + 1; + this->next_page_id = num_page_elements_start_id + 2; + this->min_elements_text_scaling_factor = num_elements_per_screen; + this->width_factor_menu = 16; + this->width_divisor_menu = 9; + this->base_height_factor_menu = 10; + this->base_height_divisor_menu = 6; + this->min_text_size = 0.3; } void ConnectionMenu::insert_data(DevicesList *devices_list) { - this->selected_index = -1; - this->future_data.option_selected = -1; - this->future_data.page = 0; this->devices_list = devices_list; this->prepare_options(); } -void ConnectionMenu::decrement_selected_option() { - do { - this->future_data.option_selected -= 1; - if(this->future_data.option_selected <= 0) { - this->future_data.option_selected = 0; - return; - } - if(this->future_data.option_selected >= CONNECTION_NUM_ELEMENTS_PER_SCREEN) { - this->future_data.option_selected = CONNECTION_NUM_ELEMENTS_PER_SCREEN - 1; - } - } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])); +void ConnectionMenu::reset_output_option() { + this->selected_index = -1; } -void ConnectionMenu::increment_selected_option() { - int starting_value = this->future_data.option_selected; - if(starting_value < 0){ - this->future_data.option_selected = 0; - return; - } - do { - this->future_data.option_selected += 1; - if(this->future_data.option_selected >= CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN) { - this->future_data.option_selected = starting_value; - return; - } - } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])); +void ConnectionMenu::set_output_option(int index) { + this->selected_index = index; } -void ConnectionMenu::prepare_options() { - int num_pages = 1 + ((this->devices_list->numValidDevices - 1) / CONNECTION_NUM_ELEMENTS_PER_SCREEN); - if(this->future_data.page >= num_pages) - this->future_data.page = num_pages - 1; - int start = this->future_data.page * CONNECTION_NUM_ELEMENTS_PER_SCREEN; - int total_elements = this->devices_list->numValidDevices - start; - if(total_elements > CONNECTION_NUM_ELEMENTS_PER_SCREEN) - total_elements = CONNECTION_NUM_ELEMENTS_PER_SCREEN; - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { - this->future_data.enabled_labels[i] = false; - this->labels[i]->setShowText(false); - } - for(int i = 0; i < total_elements; i++) { - this->future_data.enabled_labels[i] = true; - this->labels[i]->setText(std::string(&this->devices_list->serialNumbers[SERIAL_NUMBER_SIZE * (i + start)])); - this->labels[i]->setShowText(true); - } - if(num_pages > 1) { - this->future_data.enabled_labels[CONNECTION_INFO_PAGES_ID] = true; - this->labels[CONNECTION_INFO_PAGES_ID]->setText(std::to_string(this->future_data.page + 1) + "/" + std::to_string(num_pages)); - this->labels[CONNECTION_INFO_PAGES_ID]->setShowText(true); - if(this->future_data.page > 0) { - this->future_data.enabled_labels[CONNECTION_PREV_PAGE_ID] = true; - this->labels[CONNECTION_PREV_PAGE_ID]->setText("<"); - this->labels[CONNECTION_PREV_PAGE_ID]->setShowText(true); - } - if(this->future_data.page < (num_pages - 1)) { - this->future_data.enabled_labels[CONNECTION_NEXT_PAGE_ID] = true; - this->labels[CONNECTION_NEXT_PAGE_ID]->setText(">"); - this->labels[CONNECTION_NEXT_PAGE_ID]->setShowText(true); - } - } - if(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])) { - this->future_data.option_selected = -1; - } +int ConnectionMenu::get_num_options() { + return this->devices_list->numValidDevices; } -void ConnectionMenu::option_selection_handling() { - int old_loaded_page = this->future_data.page; - if(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])) { - this->future_data.option_selected = -1; - return; - } - if(!this->can_execute_action()) - return; - if(this->future_data.option_selected < CONNECTION_NUM_ELEMENTS_PER_SCREEN) { - this->selected_index = this->future_data.option_selected + (CONNECTION_NUM_ELEMENTS_PER_SCREEN * this->future_data.page); - this->last_action_time = std::chrono::high_resolution_clock::now(); - } - else if((this->future_data.option_selected == CONNECTION_PREV_PAGE_ID) && this->future_data.page > 0) - this->future_data.page--; - else if((this->future_data.option_selected == CONNECTION_NEXT_PAGE_ID) && this->future_data.page < ((this->devices_list->numValidDevices - 1) / CONNECTION_NUM_ELEMENTS_PER_SCREEN)) - this->future_data.page++; - if(old_loaded_page != this->future_data.page) { - this->prepare_options(); - this->last_action_time = std::chrono::high_resolution_clock::now(); - } -} - -void ConnectionMenu::up_code() { - if(!this->can_execute_action()) - return; - this->decrement_selected_option(); - this->last_action_time = std::chrono::high_resolution_clock::now(); -} - -void ConnectionMenu::down_code() { - if(!this->can_execute_action()) - return; - this->increment_selected_option(); - this->last_action_time = std::chrono::high_resolution_clock::now(); -} - -void ConnectionMenu::left_code() { - if(!this->can_execute_action()) - return; - if(this->selectable_labels[CONNECTION_PREV_PAGE_ID] && this->future_data.enabled_labels[CONNECTION_PREV_PAGE_ID]) { - if(this->future_data.option_selected == CONNECTION_PREV_PAGE_ID) - this->option_selection_handling(); - else { - this->future_data.option_selected = CONNECTION_PREV_PAGE_ID; - this->last_action_time = std::chrono::high_resolution_clock::now(); - } - } -} - -void ConnectionMenu::right_code() { - if(!this->can_execute_action()) - return; - if(this->selectable_labels[CONNECTION_NEXT_PAGE_ID] && this->future_data.enabled_labels[CONNECTION_NEXT_PAGE_ID]) { - if(this->future_data.option_selected == CONNECTION_NEXT_PAGE_ID) - this->option_selection_handling(); - else { - this->future_data.option_selected = CONNECTION_NEXT_PAGE_ID; - this->last_action_time = std::chrono::high_resolution_clock::now(); - } - } -} - -bool ConnectionMenu::poll(SFEvent &event_data) { - bool consumed = true; - switch (event_data.type) { - case sf::Event::TextEntered: - switch (event_data.unicode) { - default: - consumed = false; - break; - } - - break; - - case sf::Event::KeyPressed: - switch (event_data.code) { - case sf::Keyboard::Up: - this->up_code(); - break; - case sf::Keyboard::Down: - this->down_code(); - break; - case sf::Keyboard::PageUp: - this->up_code(); - break; - case sf::Keyboard::PageDown: - this->down_code(); - break; - case sf::Keyboard::Left: - this->left_code(); - break; - case sf::Keyboard::Right: - this->right_code(); - break; - case sf::Keyboard::Enter: - this->option_selection_handling(); - break; - default: - consumed = false; - break; - } - - break; - case sf::Event::MouseMoved: - this->future_data.option_selected = -1; - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { - if(!(this->selectable_labels[i] && this->future_data.enabled_labels[i])) - continue; - if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { - this->future_data.option_selected = i; - break; - } - } - break; - case sf::Event::MouseButtonPressed: - this->future_data.option_selected = -1; - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { - if(!(this->selectable_labels[i] && this->future_data.enabled_labels[i])) - continue; - if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { - this->future_data.option_selected = i; - break; - } - } - if(this->future_data.option_selected == -1) - break; - if(event_data.mouse_button == sf::Mouse::Left) - this->option_selection_handling(); - break; - case sf::Event::JoystickButtonPressed: - switch(get_joystick_action(event_data.joystickId, event_data.joy_button)) { - case JOY_ACTION_CONFIRM: - this->option_selection_handling(); - break; - case JOY_ACTION_NEGATE: - this->option_selection_handling(); - break; - default: - consumed = false; - break; - } - break; - case sf::Event::JoystickMoved: - switch(get_joystick_direction(event_data.joystickId, event_data.axis, event_data.position)) { - case JOY_DIR_UP: - this->up_code(); - break; - case JOY_DIR_DOWN: - this->down_code(); - break; - case JOY_DIR_LEFT: - this->left_code(); - break; - case JOY_DIR_RIGHT: - this->right_code(); - break; - default: - consumed = false; - break; - } - break; - default: - consumed = false; - break; - } - return consumed; -} - -void ConnectionMenu::draw(float scaling_factor, sf::RenderTarget &window) { - sf::RectangleShape menu_rectangle(sf::Vector2f(this->loaded_data.menu_width, this->loaded_data.menu_height)); - menu_rectangle.setFillColor(sf::Color(30, 30, 60, 192)); - menu_rectangle.setPosition(this->loaded_data.pos_x, this->loaded_data.pos_y); - window.draw(menu_rectangle); - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { - if(this->loaded_data.enabled_labels[i]) - this->labels[i]->draw(window); - } +std::string ConnectionMenu::get_string_option(int index) { + return std::string(&this->devices_list->serialNumbers[SERIAL_NUMBER_SIZE * index]); } void ConnectionMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y) { - int num_elements = 1; - for(int i = 1; i < CONNECTION_NUM_ELEMENTS_PER_SCREEN; i++) - if(this->future_data.enabled_labels[i]) - num_elements++; - bool has_bottom = false; - for(int i = 0; i < CONNECTION_NUM_PAGE_ELEMENTS; i++) - if(this->future_data.enabled_labels[i + CONNECTION_NUM_PAGE_ELEMENTS_START_ID]) - has_bottom = true; - if(has_bottom) - num_elements += 1; - const float base_height = (CONNECTION_NUM_VERTICAL_SLICES * (BASE_PIXEL_FONT_HEIGHT * 8)) / 6; - int max_width = (view_size_x * 9) / 10; - int max_height = (view_size_y * 9) / 10; - float max_scaling_factor = max_height / base_height; - if(menu_scaling_factor > max_scaling_factor) - menu_scaling_factor = max_scaling_factor; - if(menu_scaling_factor < 0.3) - menu_scaling_factor = 0.3; - int num_elements_text_scaling_factor = num_elements; - if(num_elements_text_scaling_factor < 3) - num_elements_text_scaling_factor = 3; - float text_scaling_factor = (menu_scaling_factor * CONNECTION_NUM_VERTICAL_SLICES) / num_elements_text_scaling_factor; - int menu_height = base_height * menu_scaling_factor; - int menu_width = (menu_height * 16) / 9; - if(menu_width > max_width) - menu_width = max_width; - int pos_x = (view_size_x - menu_width) / 2; - int pos_y = (view_size_y - menu_height) / 2; - int slice_y_size = menu_height / num_elements; - int slice_x_size = menu_width / CONNECTION_NUM_PAGE_ELEMENTS; - int num_rendered_y = 0; - for(int i = 0; i < CONNECTION_NUM_ELEMENTS_PER_SCREEN; i++) { - if(!this->future_data.enabled_labels[i]) - continue; - this->labels[i]->setTextFactor(text_scaling_factor); - int x_size = menu_width; - int y_size = slice_y_size; - if(i == (num_elements - 1)) - y_size = menu_height - (slice_y_size * (num_elements - 1)); - this->labels[i]->setSize(x_size, y_size); - this->labels[i]->setPosition(pos_x, pos_y + (slice_y_size * i)); - if(i == this->future_data.option_selected) - this->labels[i]->setRectangleKind(TEXT_KIND_SELECTED); - else - this->labels[i]->setRectangleKind(TEXT_KIND_NORMAL); - this->labels[i]->prepareRenderText(); - ++num_rendered_y; - } - for(int i = 0; i < CONNECTION_NUM_PAGE_ELEMENTS; i++) { - int index = i + CONNECTION_NUM_PAGE_ELEMENTS_START_ID; - if(!this->future_data.enabled_labels[index]) - continue; - this->labels[index]->setTextFactor(text_scaling_factor); - int x_size = slice_x_size; - if(i == (CONNECTION_NUM_PAGE_ELEMENTS - 1)) - x_size = menu_width - (slice_x_size * (CONNECTION_NUM_PAGE_ELEMENTS - 1)); - int y_size = slice_y_size; - if(num_rendered_y == (num_elements - 1)) - y_size = menu_height - (slice_y_size * (num_elements - 1)); - this->labels[index]->setSize(x_size, y_size); - this->labels[index]->setPosition(pos_x + (slice_x_size * i), pos_y + (slice_y_size * num_rendered_y)); - if(index == this->future_data.option_selected) - this->labels[index]->setRectangleKind(TEXT_KIND_SELECTED); - else - this->labels[index]->setRectangleKind(TEXT_KIND_NORMAL); - this->labels[index]->prepareRenderText(); - } - this->loaded_data = this->future_data; + this->base_prepare(menu_scaling_factor, view_size_x, view_size_y); } diff --git a/source/MainMenu.cpp b/source/MainMenu.cpp new file mode 100755 index 0000000..2480885 --- /dev/null +++ b/source/MainMenu.cpp @@ -0,0 +1,99 @@ +#include "MainMenu.hpp" + +#define MAIN_NUM_PAGE_ELEMENTS_START_ID MAIN_NUM_ELEMENTS_PER_SCREEN +#define MAIN_PREV_PAGE_ID (MAIN_NUM_PAGE_ELEMENTS_START_ID) +#define MAIN_INFO_PAGES_ID (MAIN_NUM_PAGE_ELEMENTS_START_ID + 1) +#define MAIN_NEXT_PAGE_ID (MAIN_NUM_PAGE_ELEMENTS_START_ID + 2) + +static std::string main_menu_option_strings[NUM_TOTAL_MAIN_MENU_OPTIONS] = {"Disconnect", "Connect", "Close Menu", "Quit Application"}; +static bool usable_fullscreen[NUM_TOTAL_MAIN_MENU_OPTIONS] = {true, false, true, true}; +static bool usable_normal_screen[NUM_TOTAL_MAIN_MENU_OPTIONS] = {true, false, true, true}; +static bool usable_joint_screen[NUM_TOTAL_MAIN_MENU_OPTIONS] = {true, false, true, true}; +static bool usable_top_screen[NUM_TOTAL_MAIN_MENU_OPTIONS] = {true, false, true, true}; +static bool usable_bottom_screen[NUM_TOTAL_MAIN_MENU_OPTIONS] = {true, false, true, true}; +static MainMenuOutAction main_menu_out_actions[NUM_TOTAL_MAIN_MENU_OPTIONS] = {MAIN_MENU_OPEN, MAIN_MENU_NO_ACTION, MAIN_MENU_CLOSE_MENU, MAIN_MENU_QUIT_APPLICATION}; + +MainMenu::MainMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ + this->initialize(font_load_success, text_font); + this->num_enabled_options = 0; +} + +MainMenu::~MainMenu() { +} + +void MainMenu::class_setup() { + this->num_elements_per_screen = 5; + this->num_page_elements = 3; + this->num_elements_displayed_per_screen = num_elements_per_screen + num_page_elements; + this->num_vertical_slices = (num_elements_displayed_per_screen - (num_page_elements - 1)); + this->num_elements_start_id = 0; + this->num_page_elements_start_id = num_elements_per_screen + num_elements_start_id; + this->prev_page_id = num_page_elements_start_id; + this->info_page_id = num_page_elements_start_id + 1; + this->next_page_id = num_page_elements_start_id + 2; + this->min_elements_text_scaling_factor = this->num_vertical_slices; + this->width_factor_menu = 16; + this->width_divisor_menu = 9; + this->base_height_factor_menu = 12; + this->base_height_divisor_menu = 6; + this->min_text_size = 0.3; +} + +void MainMenu::insert_data(ScreenType s_type, bool is_fullscreen) { + bool *fullscreen_enabled_ptr = usable_fullscreen; + if(!is_fullscreen) + fullscreen_enabled_ptr = usable_normal_screen; + bool *screen_type_enabled_ptr = usable_joint_screen; + if(s_type == ScreenType::TOP) + screen_type_enabled_ptr = usable_top_screen; + if(s_type == ScreenType::BOTTOM) + screen_type_enabled_ptr = usable_bottom_screen; + this->num_enabled_options = 0; + for(int i = 0; i < NUM_TOTAL_MAIN_MENU_OPTIONS; i++) { + if(fullscreen_enabled_ptr[i] && screen_type_enabled_ptr[i]) { + this->options_indexes[this->num_enabled_options] = i; + this->num_enabled_options++; + } + } + this->prepare_options(); +} + +void MainMenu::reset_output_option() { + this->selected_index = MainMenuOutAction::MAIN_MENU_NO_ACTION; +} + +void MainMenu::set_output_option(int index) { + this->selected_index = main_menu_out_actions[this->options_indexes[index]]; +} + +int MainMenu::get_num_options() { + return this->num_enabled_options; +} + +std::string MainMenu::get_string_option(int index) { + return main_menu_option_strings[this->options_indexes[index]]; +} + +void MainMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info, bool connected) { + int num_pages = 1 + ((this->get_num_options() - 1) / this->num_elements_per_screen); + if(this->future_data.page >= num_pages) + this->future_data.page = num_pages - 1; + int start = this->future_data.page * this->num_elements_per_screen; + for(int i = 0; i < this->num_elements_per_screen; i++) { + if(!this->future_enabled_labels[i]) + continue; + int option_index = this->options_indexes[start + i]; + switch(main_menu_out_actions[option_index]) { + case MAIN_MENU_OPEN: + if(connected) + this->labels[i]->setText(main_menu_option_strings[option_index]); + else + this->labels[i]->setText(main_menu_option_strings[option_index + 1]); + break; + default: + break; + } + } + + this->base_prepare(menu_scaling_factor, view_size_x, view_size_y); +} diff --git a/source/OptionSelectionMenu.cpp b/source/OptionSelectionMenu.cpp new file mode 100755 index 0000000..0830464 --- /dev/null +++ b/source/OptionSelectionMenu.cpp @@ -0,0 +1,401 @@ +#include "OptionSelectionMenu.hpp" + +OptionSelectionMenu::OptionSelectionMenu() { +} + +OptionSelectionMenu::~OptionSelectionMenu() { + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) + delete this->labels[i]; + delete []this->labels; + delete []this->selectable_labels; + delete []this->future_enabled_labels; + delete []this->loaded_enabled_labels; +} + +void OptionSelectionMenu::initialize(bool font_load_success, sf::Font &text_font) { + this->class_setup(); + this->labels = new TextRectangle*[this->num_elements_displayed_per_screen]; + this->selectable_labels = new bool[this->num_elements_displayed_per_screen]; + this->future_enabled_labels = new bool[this->num_elements_displayed_per_screen]; + this->loaded_enabled_labels = new bool[this->num_elements_displayed_per_screen]; + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { + this->labels[i] = new TextRectangle(font_load_success, text_font); + this->labels[i]->setProportionalBox(false); + this->labels[i]->setText(std::to_string(i)); + this->labels[i]->setShowText(true); + this->selectable_labels[i] = true; + this->future_enabled_labels[i] = true; + } + this->future_data.menu_width = 1; + this->future_data.menu_height = 1; + this->future_data.pos_x = 0; + this->future_data.pos_y = 0; + this->last_action_time = std::chrono::high_resolution_clock::now(); + this->last_input_processed_time = std::chrono::high_resolution_clock::now(); + this->selectable_labels[this->info_page_id] = false; +} + +void OptionSelectionMenu::class_setup() { + this->num_elements_per_screen = 1; + this->num_page_elements = 3; + this->num_elements_displayed_per_screen = num_elements_per_screen + num_page_elements; + this->num_vertical_slices = (num_elements_displayed_per_screen - (num_page_elements - 1)); + this->num_elements_start_id = 0; + this->num_page_elements_start_id = num_elements_per_screen + num_elements_start_id; + this->prev_page_id = num_page_elements_start_id; + this->info_page_id = num_page_elements_start_id + 1; + this->next_page_id = num_page_elements_start_id + 2; + this->min_elements_text_scaling_factor = 3; + this->width_factor_menu = 1; + this->width_divisor_menu = 1; + this->base_height_factor_menu = 1; + this->base_height_divisor_menu = 1; + this->min_text_size = 0.3; +} + +bool OptionSelectionMenu::can_execute_action() { + this->last_input_processed_time = std::chrono::high_resolution_clock::now(); + auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - this->last_action_time; + if(diff.count() > this->action_timeout) + return true; + return false; +} + +void OptionSelectionMenu::reset_data() { + this->last_input_processed_time = std::chrono::high_resolution_clock::now(); + this->reset_output_option(); + this->future_data.option_selected = -1; + this->future_data.page = 0; +} + +void OptionSelectionMenu::decrement_selected_option() { + do { + this->future_data.option_selected -= 1; + if(this->future_data.option_selected <= 0) { + this->future_data.option_selected = 0; + return; + } + if((this->future_data.option_selected < (this->num_page_elements_start_id + this->num_page_elements)) && (this->future_data.option_selected >= num_page_elements_start_id)) { + this->future_data.option_selected = this->num_page_elements_start_id - 1; + } + } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_enabled_labels[this->future_data.option_selected])); +} + +void OptionSelectionMenu::increment_selected_option() { + int starting_value = this->future_data.option_selected; + if(starting_value < 0){ + this->future_data.option_selected = 0; + return; + } + do { + this->future_data.option_selected += 1; + if(this->future_data.option_selected >= this->num_elements_displayed_per_screen) { + this->future_data.option_selected = starting_value; + return; + } + } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_enabled_labels[this->future_data.option_selected])); +} + +void OptionSelectionMenu::reset_output_option() { +} + +void OptionSelectionMenu::set_output_option(int index) { +} + +int OptionSelectionMenu::get_num_options() { + return this->num_elements_per_screen; +} + +std::string OptionSelectionMenu::get_string_option(int index) { + return "Sample Text"; +} + +void OptionSelectionMenu::prepare_options() { + int num_pages = 1 + ((this->get_num_options() - 1) / this->num_elements_per_screen); + if(this->future_data.page >= num_pages) + this->future_data.page = num_pages - 1; + int start = this->future_data.page * this->num_elements_per_screen; + int total_elements = this->get_num_options() - start; + if(total_elements > this->num_elements_per_screen) + total_elements = this->num_elements_per_screen; + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { + this->future_enabled_labels[i] = false; + this->labels[i]->setShowText(false); + } + for(int i = 0; i < total_elements; i++) { + this->future_enabled_labels[i] = true; + this->labels[i]->setText(this->get_string_option(i + start)); + this->labels[i]->setShowText(true); + } + if(num_pages > 1) { + this->future_enabled_labels[this->info_page_id] = true; + this->labels[this->info_page_id]->setText(std::to_string(this->future_data.page + 1) + "/" + std::to_string(num_pages)); + this->labels[this->info_page_id]->setShowText(true); + if(this->future_data.page > 0) { + this->future_enabled_labels[this->prev_page_id] = true; + this->labels[this->prev_page_id]->setText("<"); + this->labels[this->prev_page_id]->setShowText(true); + } + if(this->future_data.page < (num_pages - 1)) { + this->future_enabled_labels[this->next_page_id] = true; + this->labels[this->next_page_id]->setText(">"); + this->labels[this->next_page_id]->setShowText(true); + } + } + if(!(this->selectable_labels[this->future_data.option_selected] && this->future_enabled_labels[this->future_data.option_selected])) { + this->future_data.option_selected = -1; + } +} + +void OptionSelectionMenu::option_selection_handling() { + int old_loaded_page = this->future_data.page; + if(!(this->selectable_labels[this->future_data.option_selected] && this->future_enabled_labels[this->future_data.option_selected])) { + this->future_data.option_selected = -1; + return; + } + if(!this->can_execute_action()) + return; + if(this->future_data.option_selected < this->num_elements_per_screen) { + this->set_output_option(this->future_data.option_selected + (this->num_elements_per_screen * this->future_data.page)); + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + else if((this->future_data.option_selected == this->prev_page_id) && this->future_data.page > 0) + this->future_data.page--; + else if((this->future_data.option_selected == this->next_page_id) && this->future_data.page < ((this->get_num_options() - 1) / this->num_elements_per_screen)) + this->future_data.page++; + if(old_loaded_page != this->future_data.page) { + this->prepare_options(); + this->last_action_time = std::chrono::high_resolution_clock::now(); + } +} + +void OptionSelectionMenu::up_code() { + if(!this->can_execute_action()) + return; + this->decrement_selected_option(); + this->last_action_time = std::chrono::high_resolution_clock::now(); +} + +void OptionSelectionMenu::down_code() { + if(!this->can_execute_action()) + return; + this->increment_selected_option(); + this->last_action_time = std::chrono::high_resolution_clock::now(); +} + +void OptionSelectionMenu::left_code() { + if(!this->can_execute_action()) + return; + if(this->selectable_labels[this->prev_page_id] && this->future_enabled_labels[this->prev_page_id]) { + if(this->future_data.option_selected == this->prev_page_id) + this->option_selection_handling(); + else { + this->future_data.option_selected = this->prev_page_id; + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + } +} + +void OptionSelectionMenu::right_code() { + if(!this->can_execute_action()) + return; + if(this->selectable_labels[this->next_page_id] && this->future_enabled_labels[this->next_page_id]) { + if(this->future_data.option_selected == this->next_page_id) + this->option_selection_handling(); + else { + this->future_data.option_selected = this->next_page_id; + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + } +} + +bool OptionSelectionMenu::poll(SFEvent &event_data) { + bool consumed = true; + switch (event_data.type) { + case sf::Event::TextEntered: + switch (event_data.unicode) { + default: + consumed = false; + break; + } + + break; + + case sf::Event::KeyPressed: + switch (event_data.code) { + case sf::Keyboard::Up: + this->up_code(); + break; + case sf::Keyboard::Down: + this->down_code(); + break; + case sf::Keyboard::PageUp: + this->up_code(); + break; + case sf::Keyboard::PageDown: + this->down_code(); + break; + case sf::Keyboard::Left: + this->left_code(); + break; + case sf::Keyboard::Right: + this->right_code(); + break; + case sf::Keyboard::Enter: + this->option_selection_handling(); + break; + default: + consumed = false; + break; + } + + break; + case sf::Event::MouseMoved: + this->future_data.option_selected = -1; + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { + if(!(this->selectable_labels[i] && this->future_enabled_labels[i])) + continue; + if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { + this->future_data.option_selected = i; + this->last_input_processed_time = std::chrono::high_resolution_clock::now(); + break; + } + } + break; + case sf::Event::MouseButtonPressed: + this->future_data.option_selected = -1; + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { + if(!(this->selectable_labels[i] && this->future_enabled_labels[i])) + continue; + if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { + this->future_data.option_selected = i; + break; + } + } + if(this->future_data.option_selected == -1) + break; + if(event_data.mouse_button == sf::Mouse::Left) + this->option_selection_handling(); + break; + case sf::Event::JoystickButtonPressed: + switch(get_joystick_action(event_data.joystickId, event_data.joy_button)) { + case JOY_ACTION_CONFIRM: + this->option_selection_handling(); + break; + case JOY_ACTION_NEGATE: + this->option_selection_handling(); + break; + default: + consumed = false; + break; + } + break; + case sf::Event::JoystickMoved: + switch(get_joystick_direction(event_data.joystickId, event_data.axis, event_data.position)) { + case JOY_DIR_UP: + this->up_code(); + break; + case JOY_DIR_DOWN: + this->down_code(); + break; + case JOY_DIR_LEFT: + this->left_code(); + break; + case JOY_DIR_RIGHT: + this->right_code(); + break; + default: + consumed = false; + break; + } + break; + default: + consumed = false; + break; + } + return consumed; +} + +void OptionSelectionMenu::draw(float scaling_factor, sf::RenderTarget &window) { + sf::RectangleShape menu_rectangle(sf::Vector2f(this->loaded_data.menu_width, this->loaded_data.menu_height)); + menu_rectangle.setFillColor(sf::Color(30, 30, 60, 192)); + menu_rectangle.setPosition(this->loaded_data.pos_x, this->loaded_data.pos_y); + window.draw(menu_rectangle); + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { + if(this->loaded_enabled_labels[i]) + this->labels[i]->draw(window); + } +} + +void OptionSelectionMenu::prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int index, float text_scaling_factor) { + this->labels[index]->setTextFactor(text_scaling_factor); + int x_base_pos = (this->future_data.menu_width * x_multiplier) / x_divisor; + int y_base_pos = (this->future_data.menu_height * y_multiplier) / y_divisor; + int x_size = ((this->future_data.menu_width * (x_multiplier + 1)) / x_divisor) - x_base_pos; + int y_size = ((this->future_data.menu_height * (y_multiplier + 1)) / y_divisor) - y_base_pos; + this->labels[index]->setSize(x_size, y_size); + this->labels[index]->setPosition(this->future_data.pos_x + x_base_pos, this->future_data.pos_y + y_base_pos); + if(index == this->future_data.option_selected) + this->labels[index]->setRectangleKind(TEXT_KIND_SELECTED); + else + this->labels[index]->setRectangleKind(TEXT_KIND_NORMAL); + this->labels[index]->prepareRenderText(); +} + +void OptionSelectionMenu::base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y) { + int num_elements = 0; + for(int i = 0; i < this->num_elements_per_screen; i++) + if(this->future_enabled_labels[i]) + num_elements++; + bool has_bottom = false; + for(int i = 0; i < this->num_page_elements; i++) + if(this->future_enabled_labels[i + this->num_page_elements_start_id]) + has_bottom = true; + if(has_bottom) + num_elements += 1; + const float base_height = (this->num_vertical_slices * BASE_PIXEL_FONT_HEIGHT * 10) / 9; + int max_width = (view_size_x * 9) / 10; + int max_height = (view_size_y * 9) / 10; + float max_scaling_factor = max_height / base_height; + float final_menu_scaling_factor = (menu_scaling_factor * this->base_height_factor_menu) / this->base_height_divisor_menu; + if(menu_scaling_factor > max_scaling_factor) + menu_scaling_factor = max_scaling_factor; + if(final_menu_scaling_factor > max_scaling_factor) + final_menu_scaling_factor = max_scaling_factor; + if(menu_scaling_factor < this->min_text_size) + menu_scaling_factor = this->min_text_size; + if(final_menu_scaling_factor < this->min_text_size) + final_menu_scaling_factor = this->min_text_size; + int num_elements_text_scaling_factor = num_elements; + if(num_elements_text_scaling_factor < this->min_elements_text_scaling_factor) + num_elements_text_scaling_factor = this->min_elements_text_scaling_factor; + float text_scaling_factor = (menu_scaling_factor * this->num_vertical_slices) / num_elements_text_scaling_factor; + this->future_data.menu_height = base_height * final_menu_scaling_factor; + this->future_data.menu_width = (this->future_data.menu_height * this->width_factor_menu) / this->width_divisor_menu; + if(this->future_data.menu_width > max_width) + this->future_data.menu_width = max_width; + this->future_data.pos_x = (view_size_x - this->future_data.menu_width) / 2; + this->future_data.pos_y = (view_size_y - this->future_data.menu_height) / 2; + int slice_y_size = this->future_data.menu_height / num_elements; + int slice_x_size = this->future_data.menu_width / this->num_page_elements; + int num_rendered_y = 0; + for(int i = 0; i < this->num_elements_per_screen; i++) { + int index = i; + if(this->future_enabled_labels[index]) { + this->prepare_text_slices(0, 1, num_rendered_y, num_elements, index, text_scaling_factor); + ++num_rendered_y; + } + } + for(int i = 0; i < this->num_page_elements; i++) { + int index = i + this->num_page_elements_start_id; + if(this->future_enabled_labels[index]){ + this->prepare_text_slices(i, this->num_page_elements, num_rendered_y, num_elements, index, text_scaling_factor); + } + } + if(has_bottom) + ++num_rendered_y; + this->loaded_data = this->future_data; + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) + this->loaded_enabled_labels[i] = this->future_enabled_labels[i]; +} diff --git a/source/TextRectangle.cpp b/source/TextRectangle.cpp index d92cc69..a5d2c7f 100755 --- a/source/TextRectangle.cpp +++ b/source/TextRectangle.cpp @@ -93,14 +93,17 @@ void TextRectangle::prepareRenderText() { } void TextRectangle::setText(std::string text) { + if(this->future_data.printed_text != text) + this->future_data.render_text = true; this->future_data.printed_text = text; - this->future_data.render_text = true; } void TextRectangle::setShowText(bool show_text) { this->future_data.show_text = show_text; if(!this->future_data.show_text) this->startTimer(false); + if(this->future_data.show_text) + this->future_data.render_text = true; } void TextRectangle::draw(sf::RenderTarget &window) { @@ -214,6 +217,7 @@ void TextRectangle::updateText(int x_limit) { this->actual_text.setFillColor(sf::Color::White); // set the text style //this->actual_text.setStyle(sf::Text::Bold); + this->actual_text.setPosition(0, 0); this->setTextWithLineWrapping(x_limit); sf::FloatRect globalBounds; if(this->loaded_data.proportional_box) { diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index 34afdd6..44d7442 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -1,7 +1,6 @@ #include "frontend.hpp" #include -#include #include "font_ttf.h" #define LEFT_ROUNDED_PADDING 5 @@ -23,7 +22,7 @@ static std::string crop_names[] = {"3DS", "16:10", "Scaled DS", "Native DS", "Sc static std::string par_width_names[] = {"1:1", "SNES Horizontal", "SNES Vertical"}; -WindowScreen::WindowScreen(WindowScreen::ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, AudioData* audio_data, std::mutex* events_access) { +WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, AudioData* audio_data, std::mutex* events_access) { this->m_stype = stype; this->events_access = events_access; this->m_prepare_save = 0; @@ -34,6 +33,7 @@ WindowScreen::WindowScreen(WindowScreen::ScreenType stype, CaptureStatus* captur this->font_load_success = this->text_font.loadFromMemory(font_ttf, font_ttf_len); this->notification = new TextRectangle(this->font_load_success, this->text_font); this->connection_menu = new ConnectionMenu(this->font_load_success, this->text_font); + this->main_menu = new MainMenu(this->font_load_success, this->text_font); this->in_tex.create(IN_VIDEO_WIDTH, IN_VIDEO_HEIGHT); this->m_in_rect_top.setTexture(&this->in_tex); this->m_in_rect_bot.setTexture(&this->in_tex); @@ -45,9 +45,9 @@ WindowScreen::WindowScreen(WindowScreen::ScreenType stype, CaptureStatus* captur this->done_display = true; this->saved_buf = new VideoOutputData; this->win_title = NAME; - if(this->m_stype == WindowScreen::ScreenType::TOP) + if(this->m_stype == ScreenType::TOP) this->win_title += "_top"; - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) + if(this->m_stype == ScreenType::BOTTOM) this->win_title += "_bot"; this->last_connected_status = false; this->capture_status = capture_status; @@ -57,6 +57,7 @@ WindowScreen::~WindowScreen() { delete this->saved_buf; delete this->notification; delete this->connection_menu; + delete this->main_menu; } void WindowScreen::build() { @@ -64,7 +65,7 @@ void WindowScreen::build() { sf::Vector2f bot_screen_size = sf::Vector2f(BOT_WIDTH_3DS, HEIGHT_3DS); int width = TOP_WIDTH_3DS; - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) + if(this->m_stype == ScreenType::BOTTOM) width = BOT_WIDTH_3DS; this->reload(); @@ -93,333 +94,396 @@ void WindowScreen::reload() { bool WindowScreen::common_poll(SFEvent &event_data) { double old_scaling = 0.0; bool consumed = true; - switch (event_data.type) { - case sf::Event::Closed: - this->m_prepare_quit = true; - break; - - case sf::Event::TextEntered: - switch (event_data.unicode) { - case 's': - this->m_info.is_fullscreen = false; - this->display_data->split = !this->display_data->split; - break; - - case 'f': - this->m_info.is_fullscreen = !this->m_info.is_fullscreen; - this->create_window(true); - break; - - case 'a': - this->m_info.async = !this->m_info.async; - this->print_notification_on_off("Async", this->m_info.async); - break; - - case 'v': - this->m_info.v_sync_enabled = !this->m_info.v_sync_enabled; - this->print_notification_on_off("VSync", this->m_info.v_sync_enabled); - break; - - case 'z': - old_scaling = this->m_info.menu_scaling_factor; - this->m_info.menu_scaling_factor -= 0.1; - if(this->m_info.menu_scaling_factor < 0.35) - this->m_info.menu_scaling_factor = 0.3; - if(old_scaling != this->m_info.menu_scaling_factor) { - this->print_notification_float("Menu Scaling", this->m_info.menu_scaling_factor, 1); - } - break; - - - case 'x': - old_scaling = this->m_info.menu_scaling_factor; - this->m_info.menu_scaling_factor += 0.1; - if(this->m_info.menu_scaling_factor > 4.95) - this->m_info.menu_scaling_factor = 5.0; - if(old_scaling != this->m_info.menu_scaling_factor) { - this->print_notification_float("Menu Scaling", this->m_info.menu_scaling_factor, 1); - } - break; - - case '-': - if(this->m_info.is_fullscreen) - break; - old_scaling = this->m_info.scaling; - this->m_info.scaling -= 0.5; - if (this->m_info.scaling < 1.25) - this->m_info.scaling = 1.0; - if(old_scaling != this->m_info.scaling) { - this->print_notification_float("Scaling", this->m_info.scaling, 1); - this->future_operations.call_screen_settings_update = true; - } - break; - - case '0': - if(this->m_info.is_fullscreen) - break; - old_scaling = this->m_info.scaling; - this->m_info.scaling += 0.5; - if (this->m_info.scaling > 44.75) - this->m_info.scaling = 45.0; - if(old_scaling != this->m_info.scaling) { - this->print_notification_float("Scaling", this->m_info.scaling, 1); - this->future_operations.call_screen_settings_update = true; - } - break; - default: - consumed = false; - break; - } - - break; - - case sf::Event::KeyPressed: - switch (event_data.code) { - case sf::Keyboard::Escape: + switch(event_data.type) { + case sf::Event::Closed: this->m_prepare_quit = true; break; + + case sf::Event::TextEntered: + switch(event_data.unicode) { + case 's': + if(this->curr_menu != CONNECT_MENU_TYPE) + this->curr_menu = DEFAULT_MENU_TYPE; + this->m_info.is_fullscreen = false; + this->display_data->split = !this->display_data->split; + break; + + case 'f': + if(this->curr_menu != CONNECT_MENU_TYPE) + this->curr_menu = DEFAULT_MENU_TYPE; + this->m_info.is_fullscreen = !this->m_info.is_fullscreen; + this->create_window(true); + break; + + case 'a': + this->m_info.async = !this->m_info.async; + this->print_notification_on_off("Async", this->m_info.async); + break; + + case 'v': + this->m_info.v_sync_enabled = !this->m_info.v_sync_enabled; + this->print_notification_on_off("VSync", this->m_info.v_sync_enabled); + break; + + case 'z': + old_scaling = this->m_info.menu_scaling_factor; + this->m_info.menu_scaling_factor -= 0.1; + if(this->m_info.menu_scaling_factor < 0.35) + this->m_info.menu_scaling_factor = 0.3; + if(old_scaling != this->m_info.menu_scaling_factor) { + this->print_notification_float("Menu Scaling", this->m_info.menu_scaling_factor, 1); + } + break; + + + case 'x': + old_scaling = this->m_info.menu_scaling_factor; + this->m_info.menu_scaling_factor += 0.1; + if(this->m_info.menu_scaling_factor > 4.95) + this->m_info.menu_scaling_factor = 5.0; + if(old_scaling != this->m_info.menu_scaling_factor) { + this->print_notification_float("Menu Scaling", this->m_info.menu_scaling_factor, 1); + } + break; + + case '-': + if(this->m_info.is_fullscreen) + break; + old_scaling = this->m_info.scaling; + this->m_info.scaling -= 0.5; + if (this->m_info.scaling < 1.25) + this->m_info.scaling = 1.0; + if(old_scaling != this->m_info.scaling) { + this->print_notification_float("Scaling", this->m_info.scaling, 1); + this->future_operations.call_screen_settings_update = true; + } + break; + + case '0': + if(this->m_info.is_fullscreen) + break; + old_scaling = this->m_info.scaling; + this->m_info.scaling += 0.5; + if (this->m_info.scaling > 44.75) + this->m_info.scaling = 45.0; + if(old_scaling != this->m_info.scaling) { + this->print_notification_float("Scaling", this->m_info.scaling, 1); + this->future_operations.call_screen_settings_update = true; + } + break; + default: + consumed = false; + break; + } + + break; + + case sf::Event::KeyPressed: + switch(event_data.code) { + case sf::Keyboard::Escape: + this->m_prepare_quit = true; + break; + default: + consumed = false; + break; + } + + break; + case sf::Event::MouseMoved: + if(this->m_info.is_fullscreen) { + this->m_info.show_mouse = true; + this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); + } + consumed = false; + break; + case sf::Event::MouseButtonPressed: + if(this->m_info.is_fullscreen) { + this->m_info.show_mouse = true; + this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); + } + consumed = false; + break; + case sf::Event::MouseButtonReleased: + if(this->m_info.is_fullscreen) { + this->m_info.show_mouse = true; + this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); + } + consumed = false; + break; + case sf::Event::JoystickButtonPressed: + consumed = false; + break; + case sf::Event::JoystickMoved: + consumed = false; + break; default: consumed = false; break; - } + } + return consumed; +} - break; - case sf::Event::MouseMoved: - if(this->m_info.is_fullscreen) { - this->m_info.show_mouse = true; - this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); - } - consumed = false; - break; - case sf::Event::MouseButtonPressed: - if(this->m_info.is_fullscreen) { - this->m_info.show_mouse = true; - this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); - } - consumed = false; - break; - case sf::Event::MouseButtonReleased: - if(this->m_info.is_fullscreen) { - this->m_info.show_mouse = true; - this->last_mouse_action_time = std::chrono::high_resolution_clock::now(); - } - consumed = false; - break; - case sf::Event::JoystickButtonPressed: - consumed = false; - break; - case sf::Event::JoystickMoved: - consumed = false; - break; - default: - consumed = false; - break; +void WindowScreen::setup_main_menu() { + if(this->curr_menu != MAIN_MENU_TYPE) { + this->curr_menu = MAIN_MENU_TYPE; + this->main_menu->reset_data(); + this->main_menu->insert_data(this->m_stype, this->m_info.is_fullscreen); + } +} + +bool WindowScreen::no_menu_poll(SFEvent &event_data) { + bool consumed = true; + switch(event_data.type) { + case sf::Event::TextEntered: + switch(event_data.unicode) { + default: + consumed = false; + break; + } + break; + case sf::Event::KeyPressed: + switch(event_data.code) { + case sf::Keyboard::Enter: + this->setup_main_menu(); + break; + default: + consumed = false; + break; + } + break; + case sf::Event::MouseMoved: + consumed = false; + break; + case sf::Event::MouseButtonPressed: + if(event_data.mouse_button == sf::Mouse::Right) + this->setup_main_menu(); + else + consumed = false; + break; + case sf::Event::MouseButtonReleased: + consumed = false; + break; + case sf::Event::JoystickButtonPressed:switch(get_joystick_action(event_data.joystickId, event_data.joy_button)) { + case JOY_ACTION_MENU: + this->setup_main_menu(); + break; + default: + consumed = false; + break; + } + break; + case sf::Event::JoystickMoved: + consumed = false; + break; + default: + consumed = false; + break; } return consumed; } bool WindowScreen::main_poll(SFEvent &event_data) { bool consumed = true; - switch (event_data.type) { - case sf::Event::TextEntered: - switch (event_data.unicode) { - case 'c': - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) { - if(this->m_info.crop_kind == Crop::DEFAULT_3DS) - this->m_info.crop_kind = Crop::NATIVE_DS; - else - this->m_info.crop_kind = Crop::DEFAULT_3DS; + switch(event_data.type) { + case sf::Event::TextEntered: + switch(event_data.unicode) { + case 'c': + if(this->m_stype == ScreenType::BOTTOM) { + if(this->m_info.crop_kind == Crop::DEFAULT_3DS) + this->m_info.crop_kind = Crop::NATIVE_DS; + else + this->m_info.crop_kind = Crop::DEFAULT_3DS; + } + else { + this->m_info.crop_kind = static_cast((this->m_info.crop_kind + 1) % Crop::CROP_END); + } + this->print_notification("Crop: " + crop_names[this->m_info.crop_kind]); + this->prepare_size_ratios(false, false); + this->future_operations.call_crop = true; + + break; + + case 'b': + this->m_info.is_blurred = !this->m_info.is_blurred; + this->future_operations.call_blur = true; + this->print_notification_on_off("Blur", this->m_info.is_blurred); + break; + + case 'i': + this->m_info.bfi = !this->m_info.bfi; + this->print_notification_on_off("BFI", this->m_info.bfi); + break; + + case 'o': + this->m_prepare_open = true; + break; + + case 't': + this->m_info.bottom_pos = static_cast((this->m_info.bottom_pos + 1) % (BottomRelativePosition::BOT_REL_POS_END)); + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + break; + + case '6': + this->m_info.subscreen_offset_algorithm = static_cast((this->m_info.subscreen_offset_algorithm + 1) % (OffsetAlgorithm::OFF_ALGO_END)); + this->future_operations.call_screen_settings_update = true; + break; + + case '7': + this->m_info.subscreen_attached_offset_algorithm = static_cast((this->m_info.subscreen_attached_offset_algorithm + 1) % (OffsetAlgorithm::OFF_ALGO_END)); + this->future_operations.call_screen_settings_update = true; + break; + + case '4': + this->m_info.total_offset_algorithm_x = static_cast((this->m_info.total_offset_algorithm_x + 1) % (OffsetAlgorithm::OFF_ALGO_END)); + this->future_operations.call_screen_settings_update = true; + break; + + case '5': + this->m_info.total_offset_algorithm_y = static_cast((this->m_info.total_offset_algorithm_y + 1) % (OffsetAlgorithm::OFF_ALGO_END)); + this->future_operations.call_screen_settings_update = true; + break; + + case 'y': + this->prepare_size_ratios(true, false); + this->future_operations.call_screen_settings_update = true; + break; + + case 'u': + this->prepare_size_ratios(false, true); + this->future_operations.call_screen_settings_update = true; + break; + + case '8': + this->m_info.top_rotation = (this->m_info.top_rotation + 270) % 360; + this->m_info.bot_rotation = (this->m_info.bot_rotation + 270) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + + break; + + case '9': + this->m_info.top_rotation = (this->m_info.top_rotation + 90) % 360; + this->m_info.bot_rotation = (this->m_info.bot_rotation + 90) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + break; + + case 'h': + this->m_info.top_rotation = (this->m_info.top_rotation + 270) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + + break; + + case 'j': + this->m_info.top_rotation = (this->m_info.top_rotation + 90) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + + break; + + case 'k': + this->m_info.bot_rotation = (this->m_info.bot_rotation + 270) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + + break; + + case 'l': + this->m_info.bot_rotation = (this->m_info.bot_rotation + 90) % 360; + this->prepare_size_ratios(false, false); + this->future_operations.call_rotate = true; + + break; + + case 'r': + if(this->m_info.is_fullscreen) + break; + this->m_info.rounded_corners_fix = !this->m_info.rounded_corners_fix; + this->future_operations.call_screen_settings_update = true; + this->print_notification_on_off("Extra Padding", this->m_info.rounded_corners_fix); + + break; + + case '2': + if(this->m_stype == ScreenType::BOTTOM) + break; + this->m_info.top_par = static_cast((this->m_info.top_par + 1) % (ParCorrection::PAR_END)); + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + this->print_notification("Top PAR: " + par_width_names[this->m_info.top_par]); + + break; + + case '3': + if(this->m_stype == ScreenType::TOP) + break; + this->m_info.bot_par = static_cast((this->m_info.bot_par + 1) % (ParCorrection::PAR_END)); + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + this->print_notification("Bottom PAR: " + par_width_names[this->m_info.bot_par]); + + break; + + case 'm': + audio_data->change_audio_mute(); + break; + + case ',': + audio_data->change_audio_volume(false); + break; + + case '.': + audio_data->change_audio_volume(true); + break; + + default: + consumed = false; + break; } - else { - this->m_info.crop_kind = static_cast((this->m_info.crop_kind + 1) % Crop::CROP_END); + + break; + + case sf::Event::KeyPressed: + switch(event_data.code) { + case sf::Keyboard::F1: + case sf::Keyboard::F2: + case sf::Keyboard::F3: + case sf::Keyboard::F4: + this->m_prepare_load = event_data.code - sf::Keyboard::F1 + 1; + break; + + case sf::Keyboard::F5: + case sf::Keyboard::F6: + case sf::Keyboard::F7: + case sf::Keyboard::F8: + this->m_prepare_save = event_data.code - sf::Keyboard::F5 + 1; + break; + default: + consumed = false; + break; } - this->print_notification("Crop: " + crop_names[this->m_info.crop_kind]); - this->prepare_size_ratios(false, false); - this->future_operations.call_crop = true; break; - - case 'b': - this->m_info.is_blurred = !this->m_info.is_blurred; - this->future_operations.call_blur = true; - this->print_notification_on_off("Blur", this->m_info.is_blurred); - break; - - case 'i': - this->m_info.bfi = !this->m_info.bfi; - this->print_notification_on_off("BFI", this->m_info.bfi); - break; - - case 'o': - this->m_prepare_open = true; - break; - - case 't': - this->m_info.bottom_pos = static_cast((this->m_info.bottom_pos + 1) % (BottomRelativePosition::BOT_REL_POS_END)); - this->prepare_size_ratios(false, false); - this->future_operations.call_screen_settings_update = true; - break; - - case '6': - this->m_info.subscreen_offset_algorithm = static_cast((this->m_info.subscreen_offset_algorithm + 1) % (OffsetAlgorithm::OFF_ALGO_END)); - this->future_operations.call_screen_settings_update = true; - break; - - case '7': - this->m_info.subscreen_attached_offset_algorithm = static_cast((this->m_info.subscreen_attached_offset_algorithm + 1) % (OffsetAlgorithm::OFF_ALGO_END)); - this->future_operations.call_screen_settings_update = true; - break; - - case '4': - this->m_info.total_offset_algorithm_x = static_cast((this->m_info.total_offset_algorithm_x + 1) % (OffsetAlgorithm::OFF_ALGO_END)); - this->future_operations.call_screen_settings_update = true; - break; - - case '5': - this->m_info.total_offset_algorithm_y = static_cast((this->m_info.total_offset_algorithm_y + 1) % (OffsetAlgorithm::OFF_ALGO_END)); - this->future_operations.call_screen_settings_update = true; - break; - - case 'y': - this->prepare_size_ratios(true, false); - this->future_operations.call_screen_settings_update = true; - break; - - case 'u': - this->prepare_size_ratios(false, true); - this->future_operations.call_screen_settings_update = true; - break; - - case '8': - this->m_info.top_rotation = (this->m_info.top_rotation + 270) % 360; - this->m_info.bot_rotation = (this->m_info.bot_rotation + 270) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - - break; - - case '9': - this->m_info.top_rotation = (this->m_info.top_rotation + 90) % 360; - this->m_info.bot_rotation = (this->m_info.bot_rotation + 90) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - break; - - case 'h': - this->m_info.top_rotation = (this->m_info.top_rotation + 270) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - - break; - - case 'j': - this->m_info.top_rotation = (this->m_info.top_rotation + 90) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - - break; - - case 'k': - this->m_info.bot_rotation = (this->m_info.bot_rotation + 270) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - - break; - - case 'l': - this->m_info.bot_rotation = (this->m_info.bot_rotation + 90) % 360; - this->prepare_size_ratios(false, false); - this->future_operations.call_rotate = true; - - break; - - case 'r': - if(this->m_info.is_fullscreen) - break; - this->m_info.rounded_corners_fix = !this->m_info.rounded_corners_fix; - this->future_operations.call_screen_settings_update = true; - this->print_notification_on_off("Extra Padding", this->m_info.rounded_corners_fix); - - break; - - case '2': - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) - break; - this->m_info.top_par = static_cast((this->m_info.top_par + 1) % (ParCorrection::PAR_END)); - this->prepare_size_ratios(false, false); - this->future_operations.call_screen_settings_update = true; - this->print_notification("Top PAR: " + par_width_names[this->m_info.top_par]); - - break; - - case '3': - if(this->m_stype == WindowScreen::ScreenType::TOP) - break; - this->m_info.bot_par = static_cast((this->m_info.bot_par + 1) % (ParCorrection::PAR_END)); - this->prepare_size_ratios(false, false); - this->future_operations.call_screen_settings_update = true; - this->print_notification("Bottom PAR: " + par_width_names[this->m_info.bot_par]); - - break; - - case 'm': - audio_data->change_audio_mute(); - break; - - case ',': - audio_data->change_audio_volume(false); - break; - - case '.': - audio_data->change_audio_volume(true); - break; - - default: + case sf::Event::MouseMoved: consumed = false; break; - } - - break; - - case sf::Event::KeyPressed: - switch (event_data.code) { - case sf::Keyboard::F1: - case sf::Keyboard::F2: - case sf::Keyboard::F3: - case sf::Keyboard::F4: - this->m_prepare_load = event_data.code - sf::Keyboard::F1 + 1; + case sf::Event::MouseButtonPressed: + consumed = false; break; - - case sf::Keyboard::F5: - case sf::Keyboard::F6: - case sf::Keyboard::F7: - case sf::Keyboard::F8: - this->m_prepare_save = event_data.code - sf::Keyboard::F5 + 1; + case sf::Event::MouseButtonReleased: + consumed = false; + break; + case sf::Event::JoystickButtonPressed: + consumed = false; + break; + case sf::Event::JoystickMoved: + consumed = false; break; default: consumed = false; break; - } - - break; - case sf::Event::MouseMoved: - consumed = false; - break; - case sf::Event::MouseButtonPressed: - consumed = false; - break; - case sf::Event::MouseButtonReleased: - consumed = false; - break; - case sf::Event::JoystickButtonPressed: - consumed = false; - break; - case sf::Event::JoystickMoved: - consumed = false; - break; - default: - consumed = false; - break; } return consumed; } @@ -442,20 +506,46 @@ void WindowScreen::poll() { return; continue; } - switch(this->loaded_menu) { - case DEFAULT_MENU_TYPE: + if(this->loaded_menu != CONNECT_MENU_TYPE) { if(this->main_poll(event_data)) continue; - break; - case CONNECT_MENU_TYPE: - if(this->connection_menu->poll(event_data)) { - if(this->check_connection_menu_result() != -1) - return; - continue; - } - break; - default: - break; + } + switch(this->loaded_menu) { + case DEFAULT_MENU_TYPE: + if(this->no_menu_poll(event_data)) + continue; + break; + case CONNECT_MENU_TYPE: + if(this->connection_menu->poll(event_data)) { + if(this->check_connection_menu_result() != -1) + return; + continue; + } + break; + case MAIN_MENU_TYPE: + if(this->main_menu->poll(event_data)) { + switch(this->main_menu->selected_index) { + case MAIN_MENU_OPEN: + this->m_prepare_open = true; + break; + case MAIN_MENU_CLOSE_MENU: + this->curr_menu = DEFAULT_MENU_TYPE; + return; + break; + case MAIN_MENU_QUIT_APPLICATION: + this->m_prepare_quit = true; + this->curr_menu = DEFAULT_MENU_TYPE; + return; + break; + default: + break; + } + this->main_menu->selected_index = MAIN_MENU_NO_ACTION; + continue; + } + break; + default: + break; } } } @@ -512,7 +602,7 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { return; bool should_be_open = this->display_data->split; - if(this->m_stype == WindowScreen::ScreenType::JOINT) + if(this->m_stype == ScreenType::JOINT) should_be_open = !should_be_open; if(this->m_win.isOpen() ^ should_be_open) { if(this->m_win.isOpen()) @@ -520,7 +610,7 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { else this->open(); } - this->loaded_menu = this->display_data->curr_menu; + this->loaded_menu = this->curr_menu; loaded_operations = future_operations; if(this->m_win.isOpen() || this->loaded_operations.call_create) { WindowScreen::reset_operations(future_operations); @@ -543,6 +633,9 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { case CONNECT_MENU_TYPE: this->connection_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y); break; + case MAIN_MENU_TYPE: + this->main_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info, this->capture_status->connected); + break; default: break; } @@ -560,7 +653,8 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { } void WindowScreen::setup_connection_menu(DevicesList *devices_list) { - this->display_data->curr_menu = CONNECT_MENU_TYPE; + this->curr_menu = CONNECT_MENU_TYPE; + this->connection_menu->reset_data(); this->connection_menu->insert_data(devices_list); } @@ -569,7 +663,7 @@ int WindowScreen::check_connection_menu_result() { } void WindowScreen::end_connection_menu() { - this->display_data->curr_menu = DEFAULT_MENU_TYPE; + this->curr_menu = DEFAULT_MENU_TYPE; } void WindowScreen::update_connection() { @@ -666,21 +760,7 @@ void WindowScreen::print_notification_on_off(std::string base_text, bool value) } void WindowScreen::print_notification_float(std::string base_text, float value, int decimals) { - float approx_factor = pow(0.1, decimals) * (0.5); - int int_part = (int)(value + approx_factor); - int dec_part = (int)((value + approx_factor - int_part) * pow(10, decimals)); - std::string status_text = std::to_string(int_part); - - if(decimals > 0) { - if(!dec_part) { - status_text += "."; - for(int i = 0; i < decimals; i++) - status_text += "0"; - } - else - status_text += "." + std::to_string(dec_part); - } - this->print_notification(base_text + ": " + status_text); + this->print_notification(base_text + ": " + get_float_str_decimals(value, decimals)); } void WindowScreen::poll_window() { @@ -791,16 +871,16 @@ std::string WindowScreen::title_factory() { } void WindowScreen::pre_texture_conversion_processing() { - if(this->loaded_menu != DEFAULT_MENU_TYPE) + if(this->loaded_menu == CONNECT_MENU_TYPE) return; //Place preprocessing window-specific effects here this->in_tex.update((uint8_t*)this->saved_buf, IN_VIDEO_WIDTH, IN_VIDEO_HEIGHT, 0, 0); } void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top) { - if((is_top && this->m_stype == WindowScreen::ScreenType::BOTTOM) || ((!is_top) && this->m_stype == WindowScreen::ScreenType::TOP)) + if((is_top && this->m_stype == ScreenType::BOTTOM) || ((!is_top) && this->m_stype == ScreenType::TOP)) return; - if(this->loaded_menu != DEFAULT_MENU_TYPE) + if(this->loaded_menu == CONNECT_MENU_TYPE) return; rect_data.out_tex.clear(); @@ -821,18 +901,21 @@ void WindowScreen::display_data_to_window(bool actually_draw) { this->m_win.clear(); this->window_bg_processing(); - switch(this->loaded_menu) { - case DEFAULT_MENU_TYPE: - if(this->m_stype != WindowScreen::ScreenType::BOTTOM) + if(this->loaded_menu != CONNECT_MENU_TYPE) { + if(this->m_stype != ScreenType::BOTTOM) this->m_win.draw(this->m_out_rect_top.out_rect); - if(this->m_stype != WindowScreen::ScreenType::TOP) + if(this->m_stype != ScreenType::TOP) this->m_win.draw(this->m_out_rect_bot.out_rect); - break; - case CONNECT_MENU_TYPE: - this->connection_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); - break; - default: - break; + } + switch(this->loaded_menu) { + case CONNECT_MENU_TYPE: + this->connection_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); + break; + case MAIN_MENU_TYPE: + this->main_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); + break; + default: + break; } this->notification->draw(this->m_win); this->m_win.display(); @@ -888,9 +971,9 @@ void WindowScreen::set_position_screens(sf::Vector2f &curr_top_screen_size, sf:: bot_screen_height = curr_bot_screen_size.x; } - if(this->m_stype == WindowScreen::ScreenType::TOP) + if(this->m_stype == ScreenType::TOP) bot_screen_width = bot_screen_height = 0; - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) + if(this->m_stype == ScreenType::BOTTOM) top_screen_width = top_screen_height = 0; int greatest_width = top_screen_width; @@ -900,7 +983,7 @@ void WindowScreen::set_position_screens(sf::Vector2f &curr_top_screen_size, sf:: if(greatest_height < bot_screen_height) greatest_height = bot_screen_height; - if(this->m_stype == WindowScreen::ScreenType::JOINT) { + if(this->m_stype == ScreenType::JOINT) { switch(this->loaded_info.bottom_pos) { case UNDER_TOP: bot_screen_x = apply_offset_algo(greatest_width - bot_screen_width, this->loaded_info.subscreen_offset_algorithm); @@ -1002,7 +1085,7 @@ void WindowScreen::calc_scaling_resize_screens(sf::Vector2f &own_screen_size, sf int own_width = own_screen_size.x; get_par_size(own_width, own_height, own_scaling, own_par); other_scaling = prepare_screen_ratio(other_screen_size, other_rotation, own_width, own_height, own_rotation, other_par); - if(this->m_stype == WindowScreen::ScreenType::JOINT) { + if(this->m_stype == ScreenType::JOINT) { // Due to size differences, it may be possible that // the chosen screen might be able to increase its // scaling even more without compromising the other one... @@ -1020,11 +1103,11 @@ void WindowScreen::prepare_size_ratios(bool top_increase, bool bot_increase) { sf::Vector2f top_screen_size = getShownScreenSize(true, this->m_info.crop_kind); sf::Vector2f bot_screen_size = getShownScreenSize(false, this->m_info.crop_kind); - if(this->m_stype == WindowScreen::ScreenType::TOP) { + if(this->m_stype == ScreenType::TOP) { bot_increase = true; top_increase = false; } - if(this->m_stype == WindowScreen::ScreenType::BOTTOM) { + if(this->m_stype == ScreenType::BOTTOM) { bot_increase = false; top_increase = true; } @@ -1035,9 +1118,9 @@ void WindowScreen::prepare_size_ratios(bool top_increase, bool bot_increase) { } bool prioritize_top = (!bot_increase) && (top_increase || (this->m_info.bottom_pos == UNDER_TOP) || (this->m_info.bottom_pos == RIGHT_TOP)); if(prioritize_top) - calc_scaling_resize_screens(top_screen_size, bot_screen_size, this->m_info.top_scaling, this->m_info.bot_scaling, this->m_info.top_rotation, this->m_info.bot_rotation, top_increase, try_mantain_ratio, this->m_stype == WindowScreen::ScreenType::BOTTOM, this->m_info.top_par, this->m_info.bot_par); + calc_scaling_resize_screens(top_screen_size, bot_screen_size, this->m_info.top_scaling, this->m_info.bot_scaling, this->m_info.top_rotation, this->m_info.bot_rotation, top_increase, try_mantain_ratio, this->m_stype == ScreenType::BOTTOM, this->m_info.top_par, this->m_info.bot_par); else - calc_scaling_resize_screens(bot_screen_size, top_screen_size, this->m_info.bot_scaling, this->m_info.top_scaling, this->m_info.bot_rotation, this->m_info.top_rotation, bot_increase, try_mantain_ratio, this->m_stype == WindowScreen::ScreenType::TOP, this->m_info.bot_par, this->m_info.top_par); + calc_scaling_resize_screens(bot_screen_size, top_screen_size, this->m_info.bot_scaling, this->m_info.top_scaling, this->m_info.bot_rotation, this->m_info.top_rotation, bot_increase, try_mantain_ratio, this->m_stype == ScreenType::TOP, this->m_info.bot_par, this->m_info.top_par); } int WindowScreen::get_fullscreen_offset_x(int top_width, int top_height, int bot_width, int bot_height) { diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 820964b..90099b4 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -218,9 +218,9 @@ static void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data curr_fps_array = new double[FPS_WINDOW_SIZE]; memset(out_buf, 0, sizeof(VideoOutputData)); - WindowScreen top_screen(WindowScreen::ScreenType::TOP, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); - WindowScreen bot_screen(WindowScreen::ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); - WindowScreen joint_screen(WindowScreen::ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); + WindowScreen top_screen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); + WindowScreen bot_screen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); + WindowScreen joint_screen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, audio_data, &events_access); frontend_data.top_screen = &top_screen; frontend_data.bot_screen = &bot_screen; frontend_data.joint_screen = &joint_screen; diff --git a/source/frontend.cpp b/source/frontend.cpp index 69b41f1..fab8955 100755 --- a/source/frontend.cpp +++ b/source/frontend.cpp @@ -227,6 +227,8 @@ JoystickAction get_joystick_action(uint32_t joystickId, uint32_t joy_button) { return JOY_ACTION_CONFIRM; if((joy_button == 2) || (joy_button == 3)) return JOY_ACTION_NEGATE; + if((joy_button == 4) || (joy_button == 5)) + return JOY_ACTION_MENU; return JOY_ACTION_NONE; } diff --git a/source/utils.cpp b/source/utils.cpp index b7f3523..753b6a8 100755 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -4,6 +4,7 @@ #include #include #include +#include bool is_big_endian(void) { union { @@ -14,6 +15,24 @@ bool is_big_endian(void) { return value.c[0] == 1; } +std::string get_float_str_decimals(float value, int decimals) { + float approx_factor = pow(0.1, decimals) * (0.5); + int int_part = (int)(value + approx_factor); + int dec_part = (int)((value + approx_factor - int_part) * pow(10, decimals)); + std::string return_text = std::to_string(int_part); + + if(decimals > 0) { + if(!dec_part) { + return_text += "."; + for(int i = 0; i < decimals; i++) + return_text += "0"; + } + else + return_text += "." + std::to_string(dec_part); + } + + return return_text; +} //============================================================================ ConsumerMutex::ConsumerMutex() {