[imgui] 9. Desktop 구현

[imgui] 9. Desktop 구현

2023년 7월 11일
imgui

목표 #

  • Windows 처럼 여러 창을 띄워둘 수 있는 Desktop 구현
  • 윈도우 버튼에서 모든 애플리케이션을 실행할 수 있다.
  • 시계 기능

Desktop


구현코드 #

github 링크

메인함수 #

 1class Desktop
 2{
 3public:
 4    // 아이콘 숫자 기본값 10개
 5    constexpr static auto numIcons = std::uint32_t{10};
 6
 7    // 아이콘 구조체. Draw메서드로 아이콘윈도우를 그린다.
 8    struct Icon
 9    {
10        Icon(std::string_view label_)
11            : label(label_), position(ImVec2{}), popupOpen(false),
12              clickCount(0){};
13
14        void Draw();
15
16        std::string label;
17        ImVec2 position;
18        bool popupOpen;
19        std::uint32_t clickCount;
20    };
21
22public:
23    // 10개의 아이콘을 초기화. 아이콘 label은 Icon{num} 형식
24    Desktop() : icons({}), clock({})
25    {
26        icons.reserve(numIcons);
27        for (std::uint32_t i = 0; i < numIcons; i++)
28            icons.push_back(Icon{fmt::format("Icon{}", i)});
29    }
30    void Draw(std::string_view label);
31
32private:
33    void DrawDesktop();     // 아이콘 10개를 그려주는 함수
34    void DrawTaskbar();     // 작업표시줄을 그려주는 함수
35
36    void ShowIconList(bool *open = nullptr);    // 작업표시줄 윈도우키 눌렀을때 메뉴
37
38private:
39    std::vector<Icon> icons;
40    Clock clock;            // Clock 객체
41};

별거 없다.

 1void Desktop::Draw(std::string_view label)
 2{
 3    constexpr static auto window_flags =
 4        ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
 5        ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar |
 6        ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs;
 7    constexpr static auto window_size = ImVec2(1280.0F, 720.0F);
 8    constexpr static auto window_pos = ImVec2(0.0F, 0.0F);
 9
10    ImGui::SetNextWindowSize(window_size);
11    ImGui::SetNextWindowPos(window_pos);
12
13    ImGui::Begin(label.data(), nullptr, window_flags);
14
15    DrawDesktop();
16    DrawTaskbar();
17
18    ImGui::End();
19
20}

DrawDesktop #

그냥 전체 아이콘 돌면서 Draw함수를 호출해주기만 한다.

1void Desktop::DrawDesktop()
2{
3    for (auto &icon : icons)
4        icon.Draw();
5}

Icon::Draw #

아이콘에 각각의 윈도우를 배정해주고 그려준다.

 1void Desktop::Icon::Draw()
 2{
 3    constexpr static auto icon_window_flags = ImGuiWindowFlags_NoCollapse |
 4                                          ImGuiWindowFlags_NoScrollbar;
 5
 6    constexpr static auto button_size = ImVec2(100.0f, 50.0f);
 7
 8    const auto label_icon_window = fmt::format("IconWindow##{}", label);
 9    const auto label_icon_popup = fmt::format("IconPopup##{}", label);
10    
11    // 윈도우나 위젯이 최초로 생성될때만 함수를 실행시키는 플래그 
12    // 최초라는건 컴파일 이후 처음 실행됐을때를 의미한다. 
13    // 이후엔 상태값이 imgui.ini 파일에 저장되어 다시켰을때 같은값으로 출력된다. 
14    ImGui::SetNextWindowPos(position, ImGuiCond_FirstUseEver);
15
16    // 항상 함수를 실행시키는 플래그. 기본값 None과 동일한 동작을한다
17    ImGui::SetNextWindowSize(
18        ImVec2(button_size.x + 35.0f, button_size.y + 35.0f),
19        ImGuiCond_Always);
20
21    ImGui::Begin(label_icon_window.data(), nullptr, icon_window_flags);
22    // 버튼을 클릭하면 팝업 띄우기
23    if (ImGui::Button(label.data(), button_size))
24        ++clickCount;
25    if (clickCount >= 1 || popupOpen)
26    {
27        ImGui::OpenPopup(label_icon_popup.data());
28        clickCount = 0;
29        popupOpen = true;
30    }
31
32    if (ImGui::BeginPopupModal(label_icon_popup.data(), &popupOpen))
33    {
34        ImGui::Text("Hi");
35        if (ImGui::Button("Close"))
36        {
37            popupOpen = false;
38            ImGui::CloseCurrentPopup();
39        }
40        ImGui::EndPopup();
41    }
42    ImGui::End();
43}

DrawTaskbar #

 1void WindowClass::DrawTaskbar()
 2{
 3    constexpr static auto taskbar_flags =
 4        ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
 5        ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar |
 6        ImGuiWindowFlags_NoTitleBar;
 7    constexpr static auto taskbar_size = ImVec2(1280.0F, 40.0F);
 8    constexpr static auto taskbar_pos = ImVec2(0.0F, 680.0F);
 9
10    static auto open_taskbar = false;
11
12    ImGui::SetNextWindowSize(taskbar_size);
13    ImGui::SetNextWindowPos(taskbar_pos);
14
15    ImGui::Begin("Taskbar", nullptr, taskbar_flags);
16
17    // 작업표시줄의 윈도우버튼 같은것
18    if (ImGui::Button("All Icons", ImVec2(100, 30)))
19    {
20        ImGui::OpenPopup("My Programs");
21        open_taskbar = true;
22    }
23
24    if (open_taskbar)
25        ShowIconList(&open_taskbar);
26
27    ImGui::SameLine();
28
29    // 오른쪽 끝에 시계 표시
30    ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x);
31
32    static auto clock_open = false;
33    clock.GetTime();
34    const auto time = fmt::format("{}:{}", clock.hrs, clock.mins);
35
36    // 버튼에 시간을 그리고, 시계 클릭하면 아날로그 시계 그려줌
37    if (ImGui::Button(time.data(), ImVec2(100.0F, 30.0F)) || clock_open)
38    {
39        clock.Draw("clockWindow");
40        clock_open = true;
41    }
42
43    // 아무데나 클릭하면 시계 종료
44    if (clock_open && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
45        clock_open = false;
46
47    ImGui::End();
48}

ShowIconList #

 1void WindowClass::ShowIconList(bool *open)
 2{
 3    // 한 요소의 높이를 미리 구한다.
 4    // 함수역할: 현재 폰트 스타일로 계산된 줄간격이 포함된 한 라인의 높이
 5    const auto selectable_height = ImGui::GetTextLineHeightWithSpacing();
 6    // 한요소의 높이 * 전체요소수 + Taskbar의 높이
 7    const auto popup_height = selectable_height * numIcons + 40.0F;
 8
 9    ImGui::SetNextWindowSize(ImVec2(100.0F, popup_height), ImGuiCond_Always);
10    ImGui::SetNextWindowPos(ImVec2(0.0F, 680.0F - popup_height),
11                            ImGuiCond_Always);
12
13    if (ImGui::BeginPopupModal("My Programs", open, ImGuiWindowFlags_NoResize))
14    {
15        for (auto &icon : icons)
16        {
17            if (ImGui::Selectable(icon.label.data()))
18            {
19                icon.popupOpen = true;
20                ImGui::CloseCurrentPopup();
21            }
22        }
23
24        ImGui::EndPopup();
25    }
26}
comments powered by Disqus