| // Copyright 2021 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MINIOS_DRAW_UTILS_H_ |
| #define MINIOS_DRAW_UTILS_H_ |
| |
| #include <absl/container/flat_hash_map.h> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include <base/files/file.h> |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/strings/string_split.h> |
| #include <base/time/time.h> |
| #include <base/timer/timer.h> |
| #include <gtest/gtest_prod.h> |
| |
| #include "minios/process_manager.h" |
| |
| namespace minios { |
| |
| // Dropdown Menu Colors. |
| extern const char kMenuBlack[]; |
| extern const char kMenuBlue[]; |
| extern const char kMenuGrey[]; |
| extern const char kMenuDropdownFrameNavy[]; |
| extern const char kMenuDropdownBackgroundBlack[]; |
| extern const char kMenuButtonFrameGrey[]; |
| |
| // Dimension Constants |
| extern const int kButtonHeight; |
| extern const int kButtonMargin; |
| extern const int kDefaultMessageWidth; |
| extern const int kMonospaceGlyphHeight; |
| extern const int kMonospaceGlyphWidth; |
| extern const int kDefaultButtonWidth; |
| extern const int kSmallCanvasSize; |
| extern const int kProgressBarYScale; |
| extern const int kProgressBarHeight; |
| |
| // Frecon constants |
| extern const char kScreens[]; |
| extern const int kFreconScalingFactor; |
| extern const int kCanvasSize; |
| extern const int kFreconNoOffset; |
| |
| extern const char kDetachablePath[]; |
| |
| class DrawInterface { |
| public: |
| virtual ~DrawInterface() = default; |
| |
| virtual bool Init() = 0; |
| |
| // Show dynamic text using pre-rendered glyphs. Colors 'white', 'grey' and |
| // 'black'. Returns true on success. |
| virtual bool ShowText(const std::string& text, |
| int glyph_offset_h, |
| int glyph_offset_v, |
| const std::string& color) = 0; |
| // Shows image at offsets given a full file path. Returns true on success. |
| virtual bool ShowImage(const base::FilePath& image_name, |
| int offset_x, |
| int offset_y) = 0; |
| // Shows a box at given offsets. Color should be given as a hex string. |
| // Returns true on success. |
| virtual bool ShowBox(int offset_x, |
| int offset_y, |
| int size_x, |
| int size_y, |
| const std::string& color) = 0; |
| |
| // Shows message image at the given offset. All message tokens are in |
| // `/etc/screens`. Falls back to English if chosen locale is not available. |
| virtual bool ShowMessage(const std::string& message_token, |
| int offset_x, |
| int offset_y) = 0; |
| |
| // Shows title and uses title offsets. |
| virtual void ShowInstructions(const std::string& message_token) = 0; |
| |
| // Shows the title and corresponding description using offsets from |
| // `constants` to place. |
| virtual void ShowInstructionsWithTitle(const std::string& message_token) = 0; |
| |
| // Returns whether device has a detachable keyboard. |
| virtual bool IsDetachable() const = 0; |
| |
| // Show button, focus changes the button color to indicate selection. Returns |
| // false on error. |
| virtual void ShowButton(const std::string& message_token, |
| int offset_y, |
| bool is_selected, |
| int inner_width, |
| bool is_text) = 0; |
| |
| // Shows stepper icons given a list of steps. Currently icons available in |
| // 'kScreens' only go up to 3. Steps can be a number '1', 'error', or 'done'. |
| // Defaults to done if requested icon not found. |
| virtual void ShowStepper(const std::vector<std::string>& steps) = 0; |
| |
| // Shows advanced options button at the bottom of the screen. |
| virtual void ShowAdvancedOptionsButton(bool focused) = 0; |
| |
| // Shows power button at the bottom of the screen. |
| virtual void ShowPowerButton(bool focused) = 0; |
| |
| // Clears screen and shows footer and language drop down menu. |
| virtual void MessageBaseScreen() = 0; |
| |
| // Shows the language dropdown button. |
| virtual void ShowLanguageDropdown(int current_index) = 0; |
| |
| // Find the index of currently selected locale. |
| virtual int FindLocaleIndex() const = 0; |
| |
| // Shows language menu drop down button on base screen. Button is highlighted |
| // if it is currently selected. |
| virtual void ShowLanguageMenu(bool is_selected) = 0; |
| |
| // Does all the reloading needed when the locale is changed, including |
| // repainting the screen. Called after `LanguageDropdown` is done. |
| virtual void LocaleChange(int selected_locale) = 0; |
| |
| // Show an empty progress bar. |
| virtual void ShowProgressBar() = 0; |
| |
| // Show progress bar at percentage given. |
| virtual void ShowProgressPercentage(double progress) = 0; |
| |
| // Show indeterminate progress bar. |
| virtual void ShowIndeterminateProgressBar() = 0; |
| |
| // Hide/Stop indeterminate progress bar. |
| virtual void HideIndeterminateProgressBar() = 0; |
| |
| // Returns number of locales. |
| virtual int GetSupportedLocalesSize() const = 0; |
| |
| // Returns the default button width, read from constants. |
| virtual int GetDefaultButtonWidth() const = 0; |
| |
| // Returns the frecon canvas size. |
| virtual int GetFreconCanvasSize() const = 0; |
| |
| // Returns the screen assets path. |
| virtual base::FilePath GetScreensPath() const = 0; |
| |
| // Returns whether the current locale is read from right to left. |
| virtual bool IsLocaleRightToLeft() const = 0; |
| |
| // Show a closed drop down menu at the specified location. |
| virtual void ShowDropDownClosed(int offset_x, |
| int offset_y, |
| int text_x, |
| const std::string& message, |
| const std::string& icon_label, |
| bool is_selected) = 0; |
| }; |
| |
| // `DrawUtils` contains all the different components needed to show MiniOS |
| // Screens. |
| class DrawUtils : public DrawInterface { |
| public: |
| // The period corresponding to 66.67 fps. |
| static constexpr base::TimeDelta kAnimationPeriod = base::Milliseconds(15); |
| |
| explicit DrawUtils(std::shared_ptr<ProcessManagerInterface> process_manager) |
| : process_manager_(process_manager), |
| screens_path_(root_.Append(kScreens)) {} |
| ~DrawUtils() override = default; |
| |
| DrawUtils(const DrawUtils&) = delete; |
| DrawUtils& operator=(const DrawUtils&) = delete; |
| |
| bool Init() override; |
| |
| bool ShowText(const std::string& text, |
| int glyph_offset_h, |
| int glyph_offset_v, |
| const std::string& color) override; |
| |
| bool ShowImage(const base::FilePath& image_name, |
| int offset_x, |
| int offset_y) override; |
| |
| bool ShowBox(int offset_x, |
| int offset_y, |
| int size_x, |
| int size_y, |
| const std::string& color) override; |
| |
| bool ShowMessage(const std::string& message_token, |
| int offset_x, |
| int offset_y) override; |
| |
| void ShowInstructions(const std::string& message_token) override; |
| |
| void ShowInstructionsWithTitle(const std::string& message_token) override; |
| |
| bool IsDetachable() const override; |
| |
| bool IsLocaleRightToLeft() const override; |
| |
| void ShowButton(const std::string& message_token, |
| int offset_y, |
| bool is_selected, |
| int inner_width, |
| bool is_text) override; |
| |
| void ShowStepper(const std::vector<std::string>& steps) override; |
| |
| void MessageBaseScreen() override; |
| |
| void ShowLanguageDropdown(int current_index) override; |
| |
| int FindLocaleIndex() const override; |
| |
| void ShowLanguageMenu(bool is_selected) override; |
| |
| void ShowAdvancedOptionsButton(bool focused) override; |
| |
| void ShowPowerButton(bool focused) override; |
| |
| void LocaleChange(int selected_locale) override; |
| |
| void ShowProgressBar() override; |
| |
| void ShowProgressPercentage(double progress) override; |
| |
| void ShowIndeterminateProgressBar() override; |
| |
| void HideIndeterminateProgressBar() override; |
| |
| int GetSupportedLocalesSize() const override { |
| return supported_locales_.size(); |
| } |
| |
| int GetDefaultButtonWidth() const override { return default_button_width_; } |
| |
| int GetFreconCanvasSize() const override { return frecon_canvas_size_; } |
| |
| base::FilePath GetScreensPath() const override { return screens_path_; } |
| |
| // Override the root directory for testing. Default is '/'. |
| void SetRootForTest(const std::string& test_root) { |
| root_ = base::FilePath(test_root); |
| screens_path_ = base::FilePath(root_).Append(kScreens); |
| is_detachable_ = base::PathExists(root_.Append(kDetachablePath)); |
| } |
| |
| // Override the current locale without using the language menu. |
| void SetLanguageForTest(const std::string& test_locale) { |
| locale_ = test_locale; |
| // Reload locale dependent dimension constants. |
| ReadDimensionConstants(); |
| } |
| // Draw closed drop down at `offset_x offset_y`. Place `message` at `text_x` |
| // alongside `icon_label` which should be an image file name. |
| void ShowDropDownClosed(int offset_x, |
| int offset_y, |
| int text_x, |
| const std::string& message, |
| const std::string& icon_label, |
| bool is_selected) override; |
| |
| protected: |
| FRIEND_TEST(DrawUtilsTest, InstructionsWithTitle); |
| FRIEND_TEST(DrawUtilsTest, ReadDimension); |
| FRIEND_TEST(DrawUtilsTest, GetDimension); |
| FRIEND_TEST(DrawUtilsTest, GetLangConsts); |
| FRIEND_TEST(DrawUtilsTest, GetLangConstsError); |
| FRIEND_TEST(DrawUtilsTest, CheckRightToLeft); |
| FRIEND_TEST(DrawUtilsTest, CheckDetachable); |
| FRIEND_TEST(DrawUtilsTest, GetHwidFromCommand); |
| FRIEND_TEST(DrawUtilsTest, GetHwidFromDefault); |
| FRIEND_TEST(DrawUtilsTest, GetFreconConstFile); |
| FRIEND_TEST(DrawUtilsTest, GetFreconConstNoInt); |
| FRIEND_TEST(DrawUtilsTest, GetFreconConstNoFile); |
| FRIEND_TEST(DrawUtilsTestMocks, ShowFooter); |
| FRIEND_TEST(DrawUtilsTestMocks, ShowInvalidVersion); |
| FRIEND_TEST(DrawUtilsTestMocks, ShowLeftToRightVersion); |
| FRIEND_TEST(DrawUtilsTestMocks, ShowRightToLeftVersion); |
| |
| // Shows a progress bar (box of a predetermined location) at the given offset |
| // with the given size. Color should be given as a hex string. Acts as a No-op |
| // if offset is outside the bounds of the canvas. Will also clamp progress bar |
| // to the bounds of the canvas. |
| void ShowProgressBar(int offset_x, int size_x, const std::string& color); |
| // Initialize the segments and offsets for the head and tail of the |
| // indeterminate progress bar. |
| void InitIndeterminateProgressBar(); |
| // Reset the offsets for the head and tail of the indeterminate progress bar |
| // to starting positions. |
| void ResetIndeterminateProgressBar(); |
| // Draw the next segment of the indeterminate progress bar. |
| void DrawIndeterminateProgressBar(); |
| |
| // Clears full screen except the footer. |
| void ClearMainArea(); |
| |
| // Clears screen including the footer. |
| void ClearScreen(); |
| |
| // Shows footer with basic instructions and chromebook model. |
| void ShowFooter(); |
| |
| // Read dimension constants for current locale into memory. Must be updated |
| // every time the language changes. |
| void ReadDimensionConstants(); |
| |
| // Sets the height or width of an image given the token. Returns false on |
| // error. |
| bool GetDimension(const std::string& token, int* token_dimension) const; |
| |
| // Read the language constants into memory. Does not change |
| // based on the current locale. Returns false on failure. |
| bool ReadLangConstants(); |
| |
| // Sets the width of language token for a given locale. Returns false on |
| // error. |
| bool GetLangConstants(const std::string& locale, int* lang_width) const; |
| |
| // Gets frecon constants defined at initialization by Upstart job. |
| void GetFreconConstants(); |
| |
| // Get hardware Id from crossystem. Set hwid to `CHROMEBOOK` as default. |
| void ReadHardwareId(); |
| |
| // Show minios version in UI. |
| void ShowVersion(); |
| |
| // Show non navigational buttons. These buttons don't have a box, and can have |
| // icons or arrows next to them. |
| void ShowControlButton(const std::optional<std::string>& icon, |
| const std::string& token, |
| int x_offset, |
| int y_offset, |
| int button_width, |
| bool show_arrow, |
| bool focused); |
| |
| std::shared_ptr<ProcessManagerInterface> process_manager_; |
| |
| // Timer for animating the indeterminate progress bar. |
| base::RepeatingTimer timer_; |
| |
| int frecon_canvas_size_{1080}; |
| int frecon_scale_factor_{1}; |
| // This is always half of `frecon_canvas_size` since offsets are always |
| // relative to the center of the screen and thus go from |
| // `-frecon_offset_limit` to `+frecon_offset_limit`. |
| int frecon_offset_limit_{540}; |
| // Default button width. Changes for each locale. |
| int default_button_width_{80}; |
| // Default root directory. |
| base::FilePath root_{"/"}; |
| |
| // Default screens path, set in init. |
| base::FilePath screens_path_; |
| |
| // Default and fall back locale directory. |
| std::string locale_{"en-US"}; |
| |
| // Key value pairs that store token name and measurements. |
| base::StringPairs image_dimensions_; |
| |
| // Key value pairs that store language widths. |
| absl::flat_hash_map<std::string, int> language_widths_; |
| |
| // List of all supported locales. |
| std::vector<std::string> supported_locales_; |
| |
| // Hardware Id read from crossystem. |
| std::string hwid_; |
| |
| // X-offsets for the current head and tail of the indeterminate progress bar. |
| int indeterminate_progress_bar_head_; |
| int indeterminate_progress_bar_tail_; |
| // Per frame segment size for the head and tail of the indeterminate progress |
| // bar. |
| int segment_size_head_; |
| int segment_size_tail_; |
| |
| // Whether the device has a detachable keyboard. |
| bool is_detachable_{false}; |
| |
| // The version parsed from cmdline, nullopt on failure. |
| std::optional<std::string> minios_version_; |
| }; |
| |
| } // namespace minios |
| |
| #endif // MINIOS_DRAW_UTILS_H_ |