[imgui] 9. Desktop 구현
2023년 7월 11일
목표 #
- Windows 처럼 여러 창을 띄워둘 수 있는 Desktop 구현
- 윈도우 버튼에서 모든 애플리케이션을 실행할 수 있다.
- 시계 기능

구현코드 #
메인함수 #
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}