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

구현코드
메인함수
class Desktop
{
public:
// 아이콘 숫자 기본값 10개
constexpr static auto numIcons = std::uint32_t{10};
// 아이콘 구조체. Draw메서드로 아이콘윈도우를 그린다.
struct Icon
{
Icon(std::string_view label_)
: label(label_), position(ImVec2{}), popupOpen(false),
clickCount(0){};
void Draw();
std::string label;
ImVec2 position;
bool popupOpen;
std::uint32_t clickCount;
};
public:
// 10개의 아이콘을 초기화. 아이콘 label은 Icon{num} 형식
Desktop() : icons({}), clock({})
{
icons.reserve(numIcons);
for (std::uint32_t i = 0; i < numIcons; i++)
icons.push_back(Icon{fmt::format("Icon{}", i)});
}
void Draw(std::string_view label);
private:
void DrawDesktop(); // 아이콘 10개를 그려주는 함수
void DrawTaskbar(); // 작업표시줄을 그려주는 함수
void ShowIconList(bool *open = nullptr); // 작업표시줄 윈도우키 눌렀을때 메뉴
private:
std::vector<Icon> icons;
Clock clock; // Clock 객체
};
별거 없다.
void Desktop::Draw(std::string_view label)
{
constexpr static auto window_flags =
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs;
constexpr static auto window_size = ImVec2(1280.0F, 720.0F);
constexpr static auto window_pos = ImVec2(0.0F, 0.0F);
ImGui::SetNextWindowSize(window_size);
ImGui::SetNextWindowPos(window_pos);
ImGui::Begin(label.data(), nullptr, window_flags);
DrawDesktop();
DrawTaskbar();
ImGui::End();
}
DrawDesktop
그냥 전체 아이콘 돌면서 Draw함수를 호출해주기만 한다.
void Desktop::DrawDesktop()
{
for (auto &icon : icons)
icon.Draw();
}
Icon::Draw
아이콘에 각각의 윈도우를 배정해주고 그려준다.
void Desktop::Icon::Draw()
{
constexpr static auto icon_window_flags = ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoScrollbar;
constexpr static auto button_size = ImVec2(100.0f, 50.0f);
const auto label_icon_window = fmt::format("IconWindow##{}", label);
const auto label_icon_popup = fmt::format("IconPopup##{}", label);
// 윈도우나 위젯이 최초로 생성될때만 함수를 실행시키는 플래그
// 최초라는건 컴파일 이후 처음 실행됐을때를 의미한다.
// 이후엔 상태값이 imgui.ini 파일에 저장되어 다시켰을때 같은값으로 출력된다.
ImGui::SetNextWindowPos(position, ImGuiCond_FirstUseEver);
// 항상 함수를 실행시키는 플래그. 기본값 None과 동일한 동작을한다
ImGui::SetNextWindowSize(
ImVec2(button_size.x + 35.0f, button_size.y + 35.0f),
ImGuiCond_Always);
ImGui::Begin(label_icon_window.data(), nullptr, icon_window_flags);
// 버튼을 클릭하면 팝업 띄우기
if (ImGui::Button(label.data(), button_size))
++clickCount;
if (clickCount >= 1 || popupOpen)
{
ImGui::OpenPopup(label_icon_popup.data());
clickCount = 0;
popupOpen = true;
}
if (ImGui::BeginPopupModal(label_icon_popup.data(), &popupOpen))
{
ImGui::Text("Hi");
if (ImGui::Button("Close"))
{
popupOpen = false;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::End();
}
DrawTaskbar
void WindowClass::DrawTaskbar()
{
constexpr static auto taskbar_flags =
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoTitleBar;
constexpr static auto taskbar_size = ImVec2(1280.0F, 40.0F);
constexpr static auto taskbar_pos = ImVec2(0.0F, 680.0F);
static auto open_taskbar = false;
ImGui::SetNextWindowSize(taskbar_size);
ImGui::SetNextWindowPos(taskbar_pos);
ImGui::Begin("Taskbar", nullptr, taskbar_flags);
// 작업표시줄의 윈도우버튼 같은것
if (ImGui::Button("All Icons", ImVec2(100, 30)))
{
ImGui::OpenPopup("My Programs");
open_taskbar = true;
}
if (open_taskbar)
ShowIconList(&open_taskbar);
ImGui::SameLine();
// 오른쪽 끝에 시계 표시
ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x);
static auto clock_open = false;
clock.GetTime();
const auto time = fmt::format("{}:{}", clock.hrs, clock.mins);
// 버튼에 시간을 그리고, 시계 클릭하면 아날로그 시계 그려줌
if (ImGui::Button(time.data(), ImVec2(100.0F, 30.0F)) || clock_open)
{
clock.Draw("clockWindow");
clock_open = true;
}
// 아무데나 클릭하면 시계 종료
if (clock_open && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
clock_open = false;
ImGui::End();
}
ShowIconList
void WindowClass::ShowIconList(bool *open)
{
// 한 요소의 높이를 미리 구한다.
// 함수역할: 현재 폰트 스타일로 계산된 줄간격이 포함된 한 라인의 높이
const auto selectable_height = ImGui::GetTextLineHeightWithSpacing();
// 한요소의 높이 * 전체요소수 + Taskbar의 높이
const auto popup_height = selectable_height * numIcons + 40.0F;
ImGui::SetNextWindowSize(ImVec2(100.0F, popup_height), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0.0F, 680.0F - popup_height),
ImGuiCond_Always);
if (ImGui::BeginPopupModal("My Programs", open, ImGuiWindowFlags_NoResize))
{
for (auto &icon : icons)
{
if (ImGui::Selectable(icon.label.data()))
{
icon.popupOpen = true;
ImGui::CloseCurrentPopup();
}
}
ImGui::EndPopup();
}
}
Comments