#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>

#include <algorithm>
#include <array>
#include <cstdint>
#include <string>
#include <vector>

#define USEBCM
#include "opuscmd.h"

extern "C" int OpusGetWin95VerticalRulerMetrics(
    HWND pane, int* page_top, int* page_bottom, int* top_margin,
    int* bottom_margin, int* pixels_per_inch);
extern "C" int OpusGetWin95ContinuousPageMetrics(
    HWND pane, int* page_left, int* page_top, int* page_right,
    int* page_bottom, int* page_gap, int* has_previous, int* has_next);
extern "C" int OpusScrollWin95ContinuousPages(HWND pane, int pixels);
extern "C" int OpusGetWin95ZoomPercent(HWND pane);
extern "C" int OpusGetWin95CurrentPageIndex(HWND pane);
extern "C" int OpusAdjustWin95Zoom(HWND pane, int percent_delta);
extern "C" int OpusRecenterWin95PageView(HWND pane);
extern "C" int OpusSetWin95VerticalMargin(
    HWND pane, int top_margin, int margin_pixels);
extern "C" int OpusGetWin95HorizontalRulerMetrics(
    HWND ruler, int* zero, int* active_left, int* active_right,
    int* pixels_per_inch, int* left_indent, int* first_indent,
    int* right_indent, int* default_tab, int* tab_count,
    int* tab_positions, unsigned char* tab_types, int tab_capacity);
extern "C" int OpusGetWin95HorizontalPageMargins(
    HWND ruler, int* left_margin, int* right_margin);
extern "C" int OpusAdjustWin95HorizontalMargin(
    HWND ruler, int left_margin, int delta_pixels);
extern "C" void OpusDrawWin95HorizontalRuler(HWND ruler);

namespace {

constexpr wchar_t kToolbarClass[] = L"OpusWin95Toolbar";
constexpr wchar_t kRulerOverlayClass[] = L"OpusWin95RulerOverlay";
constexpr int kToolbarBitmap = 201;
constexpr int kSpriteCell = 20;
constexpr COLORREF kButtonFace = RGB(192, 192, 192);
constexpr COLORREF kButtonShadow = RGB(128, 128, 128);
constexpr COLORREF kButtonDarkShadow = RGB(0, 0, 0);
constexpr COLORREF kButtonHighlight = RGB(255, 255, 255);
constexpr COLORREF kCaptionBlue = RGB(0, 0, 128);
constexpr UINT kComboStyle = 0x7501;
constexpr UINT kComboFont = 0x7502;
constexpr UINT kComboSize = 0x7503;
constexpr UINT kComboZoom = 0x7504;
constexpr UINT kCmdToggleStandardToolbar = 0x7101;
constexpr UINT kCmdToggleFormattingToolbar = 0x7102;
constexpr UINT_PTR kSyncTimer = 0x951;
constexpr wchar_t kOriginalPaneProcProperty[] = L"OpusWord95OriginalPaneProc";

enum class FormatGlyph {
    bold,
    italic,
    underline,
    color,
    align_left,
    align_center,
    align_right,
    align_justify,
    numbered,
    bullets,
    indent_left,
    indent_right,
    table,
    borders
};

struct SpriteButton {
    int sprite;
    UINT command;
    int group;
    bool latch;
};

struct FormatButton {
    FormatGlyph glyph;
    UINT command;
    int group;
    bool latch;
};

constexpr std::array<SpriteButton, 18> kStandardButtons{{
    {0, bcmFileNew, 0, false},
    {1, imiOpen, 0, false},
    {2, bcmSave, 0, false},
    {3, bcmPrint, 1, false},
    {4, bcmPrintPreview, 1, false},
    {5, imiSpelling, 1, false},
    {6, bcmCut, 2, false},
    {7, bcmCopy, 2, false},
    {8, bcmPaste, 2, false},
    {9, bcmCopyLooks, 2, false},
    {10, bcmUndo, 3, false},
    {11, bcmRepeat, 3, false},
    {12, bcmInsTable, 4, false},
    {13, bcmSection, 4, false},
    {15, bcmInsPic, 4, false},
    {14, bcmShowAll, 4, true},
    {15, bcmHelp, 5, false},
    {16, bcmHelp, 5, false},
}};

constexpr std::array<FormatButton, 14> kFormatButtons{{
    {FormatGlyph::bold, bcmBold, 0, true},
    {FormatGlyph::italic, bcmItalic, 0, true},
    {FormatGlyph::underline, bcmULine, 0, true},
    {FormatGlyph::color, bcmColor, 0, false},
    {FormatGlyph::align_left, bcmParaLeft, 1, true},
    {FormatGlyph::align_center, bcmParaCenter, 1, true},
    {FormatGlyph::align_right, bcmParaRight, 1, true},
    {FormatGlyph::align_justify, bcmParaBoth, 1, true},
    {FormatGlyph::numbered, imiRenumParas, 2, false},
    {FormatGlyph::bullets, imiRenumParas, 2, false},
    {FormatGlyph::indent_left, bcmUnIndent, 2, false},
    {FormatGlyph::indent_right, bcmIndent, 2, false},
    {FormatGlyph::table, bcmInsTable, 3, false},
    {FormatGlyph::borders, bcmParagraph, 3, false},
}};

struct HitResult {
    bool hit = false;
    bool format = false;
    int index = -1;
    UINT command = 0;
};

struct ToolbarState {
    HBITMAP sprite = nullptr;
    HFONT font = nullptr;
    HWND style_combo = nullptr;
    HWND font_combo = nullptr;
    HWND size_combo = nullptr;
    HWND zoom_combo = nullptr;
    HWND source_style = nullptr;
    HWND source_font = nullptr;
    HWND source_size = nullptr;
    int copied_style_count = -1;
    int copied_font_count = -1;
    int copied_size_count = -1;
    ULONGLONG suppress_sync_until = 0;
    ULONGLONG page_view_start_after = 0;
    bool style_edit_dirty = false;
    bool font_edit_dirty = false;
    bool size_edit_dirty = false;
    bool standard_visible = true;
    bool formatting_visible = true;
    bool startup_page_view_requested = false;
    int ruler_refreshes_remaining = 0;
    HitResult pressed{};
    std::array<bool, kStandardButtons.size()> standard_latched{};
    std::array<bool, kFormatButtons.size()> format_latched{};
};

HBRUSH g_menu_brush = nullptr;
HMENU g_table_menu = nullptr;
HMENU g_toolbars_menu = nullptr;
WNDPROC g_original_app_proc = nullptr;
bool g_word95_page_view_active = false;

struct VerticalRulerDragState {
    HWND pane = nullptr;
    bool active = false;
    bool top = false;
    int preview_y = 0;
    int page_offset = 0;
};

VerticalRulerDragState g_vertical_ruler_drag{};

struct HorizontalRulerDragState {
    HWND overlay = nullptr;
    HWND ruler = nullptr;
    bool active = false;
    bool left = false;
    int origin_x = 0;
    int preview_x = 0;
};

HorizontalRulerDragState g_horizontal_ruler_drag{};

struct DocumentWheelState {
    HWND pane = nullptr;
    int scroll_remainder = 0;
    int zoom_remainder = 0;
};

DocumentWheelState g_document_wheel{};

struct PageSnapshot {
    HWND pane = nullptr;
    int page_index = -1;
    int zoom_percent = 100;
    int width = 0;
    int height = 0;
    HBITMAP bitmap = nullptr;
    ULONGLONG last_used = 0;
};

std::vector<PageSnapshot> g_page_snapshots;

int dpi_for_window(HWND window) {
    using GetDpiForWindowProc = UINT(WINAPI*)(HWND);
    static const auto get_dpi = reinterpret_cast<GetDpiForWindowProc>(
        GetProcAddress(GetModuleHandleW(L"user32.dll"), "GetDpiForWindow"));
    return get_dpi != nullptr && window != nullptr ?
               static_cast<int>(get_dpi(window)) :
               96;
}

int scale(HWND window, int value) {
    return MulDiv(value, dpi_for_window(window), 96);
}

void set_window_classic(HWND window) {
    using SetWindowThemeProc = HRESULT(WINAPI*)(HWND, LPCWSTR, LPCWSTR);
    static HMODULE theme_module = LoadLibraryW(L"uxtheme.dll");
    static const auto set_theme = theme_module != nullptr ?
        reinterpret_cast<SetWindowThemeProc>(
            GetProcAddress(theme_module, "SetWindowTheme")) : nullptr;
    if (set_theme != nullptr && window != nullptr) {
        set_theme(window, L"", L"");
    }
}

void style_menu_tree(HMENU menu) {
    if (menu == nullptr) {
        return;
    }
    MENUINFO info{};
    info.cbSize = sizeof(info);
    info.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;
    info.hbrBack = g_menu_brush;
    SetMenuInfo(menu, &info);
    const int count = GetMenuItemCount(menu);
    for (int index = 0; index < count; ++index) {
        style_menu_tree(GetSubMenu(menu, index));
    }
}

void configure_word95_menus(HWND window) {
    HMENU root = GetMenu(window);
    if (root == nullptr || GetMenuItemCount(root) < 7) {
        return;
    }

    auto menu_name = [root](int index) {
        wchar_t label[80]{};
        GetMenuStringW(root, index, label,
                       static_cast<int>(sizeof(label) / sizeof(label[0])),
                       MF_BYPOSITION);
        std::wstring name;
        for (const wchar_t character : std::wstring(label)) {
            if (character != L'&') {
                name.push_back(character);
            }
        }
        return name;
    };
    auto find_named = [&menu_name, root](const wchar_t* expected) {
        const int count = GetMenuItemCount(root);
        for (int index = 0; index < count; ++index) {
            if (lstrcmpiW(menu_name(index).c_str(), expected) == 0) {
                return index;
            }
        }
        return -1;
    };
    auto find_named_in = [](HMENU menu, const wchar_t* expected) {
        const int count = menu != nullptr ? GetMenuItemCount(menu) : 0;
        for (int index = 0; index < count; ++index) {
            wchar_t label[80]{};
            GetMenuStringW(menu, index, label,
                           static_cast<int>(sizeof(label) / sizeof(label[0])),
                           MF_BYPOSITION);
            std::wstring name;
            for (const wchar_t character : std::wstring(label)) {
                if (character != L'&') {
                    name.push_back(character);
                }
            }
            if (lstrcmpiW(name.c_str(), expected) == 0) {
                return index;
            }
        }
        return -1;
    };

    // Word's menu loader can finish replacing the startup menu after this
    // layer is created, so normalize by label every time we resync.
    const int file_index = find_named(L"File");
    if (file_index >= 0 && GetMenuItemCount(root) > file_index + 4) {
        HMENU insert = GetSubMenu(root, file_index + 3);
        HMENU format = GetSubMenu(root, file_index + 4);
        if (insert != nullptr) {
            ModifyMenuW(root, file_index + 3,
                        MF_BYPOSITION | MF_POPUP | MF_STRING,
                        reinterpret_cast<UINT_PTR>(insert), L"&Insert");
        }
        if (format != nullptr) {
            ModifyMenuW(root, file_index + 4,
                        MF_BYPOSITION | MF_POPUP | MF_STRING,
                        reinterpret_cast<UINT_PTR>(format), L"F&ormat");
        }
    }
    const int utilities_index = find_named(L"Utilities");
    if (utilities_index >= 0) {
        HMENU tools = GetSubMenu(root, utilities_index);
        ModifyMenuW(root, utilities_index,
                    MF_BYPOSITION | MF_POPUP | MF_STRING,
                    reinterpret_cast<UINT_PTR>(tools), L"&Tools");
    }

    if (g_table_menu == nullptr || !IsMenu(g_table_menu)) {
        g_table_menu = CreatePopupMenu();
        if (g_table_menu != nullptr) {
            AppendMenuW(g_table_menu, MF_STRING, bcmInsTable,
                        L"&Insert Table...");
            AppendMenuW(g_table_menu, MF_STRING, imiEditTable,
                        L"&Rows and Columns...");
            AppendMenuW(g_table_menu, MF_STRING, bcmFormatTable,
                        L"Table &Properties...");
            AppendMenuW(g_table_menu, MF_SEPARATOR, 0, nullptr);
            AppendMenuW(g_table_menu, MF_STRING, bcmSelectTable,
                        L"&Select Table");
            AppendMenuW(g_table_menu, MF_STRING, bcmNextCell,
                        L"Move to &Next Cell");
            AppendMenuW(g_table_menu, MF_STRING, bcmPrevCell,
                        L"Move to Pre&vious Cell");
            AppendMenuW(g_table_menu, MF_SEPARATOR, 0, nullptr);
            AppendMenuW(g_table_menu, MF_STRING, bcmTableToText,
                        L"Convert Table to Te&xt...");
            AppendMenuW(g_table_menu, MF_STRING, imiSort,
                        L"&Sort...");
            AppendMenuW(g_table_menu, MF_STRING, imiCalculate,
                        L"&Formula/Calculate");
        }
    }
    for (int index = GetMenuItemCount(root) - 1; index >= 0; --index) {
        if (GetSubMenu(root, index) == g_table_menu) {
            RemoveMenu(root, index, MF_BYPOSITION);
        }
    }
    const int window_index = find_named(L"Window");
    if (g_table_menu != nullptr && window_index >= 0) {
        InsertMenuW(root, window_index,
                    MF_BYPOSITION | MF_POPUP | MF_STRING,
                    reinterpret_cast<UINT_PTR>(g_table_menu), L"Ta&ble");
    }

    if (g_toolbars_menu == nullptr || !IsMenu(g_toolbars_menu)) {
        g_toolbars_menu = CreatePopupMenu();
        if (g_toolbars_menu != nullptr) {
            AppendMenuW(g_toolbars_menu, MF_STRING,
                        kCmdToggleStandardToolbar, L"&Standard");
            AppendMenuW(g_toolbars_menu, MF_STRING,
                        kCmdToggleFormattingToolbar, L"&Formatting");
            AppendMenuW(g_toolbars_menu, MF_SEPARATOR, 0, nullptr);
            AppendMenuW(g_toolbars_menu, MF_STRING, bcmRuler, L"&Ruler");
            AppendMenuW(g_toolbars_menu, MF_STRING, bcmStatusArea,
                        L"&Status Bar");
            AppendMenuW(g_toolbars_menu, MF_SEPARATOR, 0, nullptr);
            AppendMenuW(g_toolbars_menu, MF_STRING, bcmCustomize,
                        L"&Customize...");
        }
    }

    const int view_index = find_named(L"View");
    HMENU view_menu = view_index >= 0 ? GetSubMenu(root, view_index) : nullptr;
    if (view_menu != nullptr && g_toolbars_menu != nullptr) {
        for (int index = GetMenuItemCount(view_menu) - 1; index >= 0;
             --index) {
            if (GetSubMenu(view_menu, index) == g_toolbars_menu ||
                find_named_in(view_menu, L"Toolbars") == index) {
                RemoveMenu(view_menu, index, MF_BYPOSITION);
            }
        }
        AppendMenuW(view_menu, MF_POPUP | MF_STRING,
                    reinterpret_cast<UINT_PTR>(g_toolbars_menu),
                    L"&Toolbars");

        if (GetMenuState(view_menu, bcmRibbon, MF_BYCOMMAND) !=
            static_cast<UINT>(-1)) {
            ModifyMenuW(view_menu, bcmRibbon,
                        MF_BYCOMMAND | MF_STRING,
                        kCmdToggleFormattingToolbar,
                        L"&Formatting Toolbar");
        }
    }

    const int normalized_window_index = find_named(L"Window");
    HMENU window_menu = normalized_window_index >= 0 ?
        GetSubMenu(root, normalized_window_index) : nullptr;
    if (window_menu != nullptr) {
        if (GetMenuState(window_menu, imiNewWnd, MF_BYCOMMAND) ==
            static_cast<UINT>(-1)) {
            AppendMenuW(window_menu, MF_STRING, imiNewWnd,
                        L"&New Window");
        }
        if (GetMenuState(window_menu, bcmArrangeWnd, MF_BYCOMMAND) ==
            static_cast<UINT>(-1)) {
            AppendMenuW(window_menu, MF_STRING, bcmArrangeWnd,
                        L"&Arrange All");
        }
        if (GetMenuState(window_menu, bcmZoomWnd, MF_BYCOMMAND) ==
            static_cast<UINT>(-1)) {
            AppendMenuW(window_menu, MF_SEPARATOR, 0, nullptr);
            AppendMenuW(window_menu, MF_STRING, bcmZoomWnd,
                        L"Ma&ximize Document");
            AppendMenuW(window_menu, MF_STRING, bcmRestoreWnd,
                        L"&Restore Document");
            AppendMenuW(window_menu, MF_STRING, bcmCloseWnd,
                        L"&Close Document");
        }
    }
}

void apply_caption_colors(HWND window) {
    using DwmSetWindowAttributeProc = HRESULT(WINAPI*)(HWND, DWORD,
                                                       LPCVOID, DWORD);
    HMODULE module = LoadLibraryW(L"dwmapi.dll");
    if (module == nullptr) {
        return;
    }
    const auto set_attribute = reinterpret_cast<DwmSetWindowAttributeProc>(
        GetProcAddress(module, "DwmSetWindowAttribute"));
    if (set_attribute != nullptr) {
        constexpr DWORD kDwmBorderColor = 34;
        constexpr DWORD kDwmCaptionColor = 35;
        constexpr DWORD kDwmTextColor = 36;
        constexpr DWORD kDwmCornerPreference = 33;
        const COLORREF border = kButtonShadow;
        const COLORREF caption = kCaptionBlue;
        const COLORREF text = RGB(255, 255, 255);
        const DWORD do_not_round = 1;
        set_attribute(window, kDwmBorderColor, &border, sizeof(border));
        set_attribute(window, kDwmCaptionColor, &caption, sizeof(caption));
        set_attribute(window, kDwmTextColor, &text, sizeof(text));
        set_attribute(window, kDwmCornerPreference, &do_not_round,
                      sizeof(do_not_round));
    }
    FreeLibrary(module);
}

ToolbarState* toolbar_state(HWND toolbar) {
    return toolbar != nullptr ? reinterpret_cast<ToolbarState*>(
        GetWindowLongPtrW(toolbar, GWLP_USERDATA)) : nullptr;
}

int toolbar_height(HWND toolbar) {
    const ToolbarState* state = toolbar_state(toolbar);
    if (state == nullptr ||
        (state->standard_visible && state->formatting_visible)) {
        return scale(toolbar, 64);
    }
    if (state->standard_visible) {
        return scale(toolbar, 33);
    }
    if (state->formatting_visible) {
        return scale(toolbar, 31);
    }
    return 0;
}

int formatting_row_top(HWND toolbar, const ToolbarState& state) {
    return scale(toolbar, state.standard_visible ? 34 : 1);
}

RECT standard_button_rect(HWND toolbar, int target) {
    const int button = scale(toolbar, 27);
    const int gap = scale(toolbar, 2);
    const int group_gap = scale(toolbar, 7);
    int x = scale(toolbar, 4);
    int previous_group = kStandardButtons[0].group;
    for (int index = 0; index <= target; ++index) {
        if (index > 0 && kStandardButtons[index].group != previous_group) {
            x += group_gap;
        }
        if (index == target) {
            return RECT{x, scale(toolbar, 2), x + button,
                        scale(toolbar, 2) + button};
        }
        x += button + gap;
        previous_group = kStandardButtons[index].group;
    }
    return RECT{};
}

int format_buttons_start(HWND toolbar) {
    return scale(toolbar, 4 + 118 + 4 + 146 + 4 + 52 + 8);
}

RECT format_button_rect(HWND toolbar, const ToolbarState& state, int target) {
    const int button = scale(toolbar, 27);
    const int gap = scale(toolbar, 2);
    const int group_gap = scale(toolbar, 7);
    int x = format_buttons_start(toolbar);
    int previous_group = kFormatButtons[0].group;
    for (int index = 0; index <= target; ++index) {
        if (index > 0 && kFormatButtons[index].group != previous_group) {
            x += group_gap;
        }
        if (index == target) {
            const int top = formatting_row_top(toolbar, state);
            return RECT{x, top, x + button, top + button};
        }
        x += button + gap;
        previous_group = kFormatButtons[index].group;
    }
    return RECT{};
}

int standard_buttons_end(HWND toolbar) {
    const RECT last = standard_button_rect(
        toolbar, static_cast<int>(kStandardButtons.size()) - 1);
    return last.right + scale(toolbar, 8);
}

void draw_classic_edge(HDC dc, RECT rect, bool sunken) {
    const HPEN top_outer = CreatePen(PS_SOLID, 1,
        sunken ? kButtonDarkShadow : kButtonHighlight);
    const HPEN top_inner = CreatePen(PS_SOLID, 1,
        sunken ? kButtonShadow : kButtonFace);
    const HPEN bottom_outer = CreatePen(PS_SOLID, 1,
        sunken ? kButtonHighlight : kButtonDarkShadow);
    const HPEN bottom_inner = CreatePen(PS_SOLID, 1,
        sunken ? kButtonFace : kButtonShadow);
    HPEN old = static_cast<HPEN>(SelectObject(dc, top_outer));
    MoveToEx(dc, rect.left, rect.bottom - 1, nullptr);
    LineTo(dc, rect.left, rect.top);
    LineTo(dc, rect.right - 1, rect.top);
    SelectObject(dc, top_inner);
    MoveToEx(dc, rect.left + 1, rect.bottom - 2, nullptr);
    LineTo(dc, rect.left + 1, rect.top + 1);
    LineTo(dc, rect.right - 2, rect.top + 1);
    SelectObject(dc, bottom_outer);
    MoveToEx(dc, rect.left, rect.bottom - 1, nullptr);
    LineTo(dc, rect.right - 1, rect.bottom - 1);
    LineTo(dc, rect.right - 1, rect.top - 1);
    SelectObject(dc, bottom_inner);
    MoveToEx(dc, rect.left + 1, rect.bottom - 2, nullptr);
    LineTo(dc, rect.right - 2, rect.bottom - 2);
    LineTo(dc, rect.right - 2, rect.top);
    SelectObject(dc, old);
    DeleteObject(top_outer);
    DeleteObject(top_inner);
    DeleteObject(bottom_outer);
    DeleteObject(bottom_inner);
}

void draw_standard_glyph(HWND toolbar, HDC dc, HDC sprite_dc,
                         const SpriteButton& spec, RECT rect, bool sunken) {
    const int glyph = scale(toolbar, 20);
    const int offset = sunken ? scale(toolbar, 1) : 0;
    const int x = rect.left + (rect.right - rect.left - glyph) / 2 + offset;
    const int y = rect.top + (rect.bottom - rect.top - glyph) / 2 + offset;
    SetStretchBltMode(dc, COLORONCOLOR);
    StretchBlt(dc, x, y, glyph, glyph, sprite_dc,
               spec.sprite * kSpriteCell, 0, kSpriteCell, kSpriteCell,
               SRCCOPY);
}

void draw_alignment(HDC dc, RECT area, FormatGlyph glyph) {
    const int width = area.right - area.left;
    const int left = area.left + 2;
    const int right = area.right - 2;
    for (int row = 0; row < 4; ++row) {
        const int y = area.top + 2 + row * 4;
        int x1 = left;
        int x2 = right;
        const int short_by = (row % 2 == 0) ? width / 4 : width / 6;
        if (glyph == FormatGlyph::align_left) {
            x2 -= short_by;
        } else if (glyph == FormatGlyph::align_center) {
            x1 += short_by / 2;
            x2 -= short_by / 2;
        } else if (glyph == FormatGlyph::align_right) {
            x1 += short_by;
        } else if (glyph == FormatGlyph::align_justify && row == 3) {
            x2 -= width / 5;
        }
        MoveToEx(dc, x1, y, nullptr);
        LineTo(dc, x2, y);
    }
}

void draw_format_glyph(HWND toolbar, HDC dc, const FormatButton& spec,
                       RECT rect, bool sunken, HDC sprite_dc) {
    const int offset = sunken ? scale(toolbar, 1) : 0;
    RECT area{rect.left + scale(toolbar, 4) + offset,
              rect.top + scale(toolbar, 4) + offset,
              rect.right - scale(toolbar, 4) + offset,
              rect.bottom - scale(toolbar, 4) + offset};
    SetBkMode(dc, TRANSPARENT);
    SetTextColor(dc, RGB(0, 0, 0));
    HFONT old_font = nullptr;
    LOGFONTW logical{};
    logical.lfHeight = -(area.bottom - area.top);
    lstrcpyW(logical.lfFaceName, L"Arial");
    if (spec.glyph == FormatGlyph::bold) {
        logical.lfWeight = FW_BOLD;
    } else if (spec.glyph == FormatGlyph::italic) {
        logical.lfItalic = TRUE;
    } else if (spec.glyph == FormatGlyph::underline) {
        logical.lfUnderline = TRUE;
    }
    if (spec.glyph == FormatGlyph::bold ||
        spec.glyph == FormatGlyph::italic ||
        spec.glyph == FormatGlyph::underline ||
        spec.glyph == FormatGlyph::color) {
        HFONT font = CreateFontIndirectW(&logical);
        old_font = static_cast<HFONT>(SelectObject(dc, font));
        DrawTextW(dc, spec.glyph == FormatGlyph::color ? L"A" :
                  spec.glyph == FormatGlyph::bold ? L"B" :
                  spec.glyph == FormatGlyph::italic ? L"I" : L"U",
                  1, &area, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        SelectObject(dc, old_font);
        DeleteObject(font);
        if (spec.glyph == FormatGlyph::color) {
            HBRUSH swatch = CreateSolidBrush(RGB(255, 255, 0));
            RECT swatch_rect{area.left + 1, area.bottom - 3,
                             area.right - 1, area.bottom};
            FillRect(dc, &swatch_rect, swatch);
            DeleteObject(swatch);
        }
        return;
    }
    if (spec.glyph == FormatGlyph::align_left ||
        spec.glyph == FormatGlyph::align_center ||
        spec.glyph == FormatGlyph::align_right ||
        spec.glyph == FormatGlyph::align_justify) {
        draw_alignment(dc, area, spec.glyph);
        return;
    }
    if (spec.glyph == FormatGlyph::numbered ||
        spec.glyph == FormatGlyph::bullets) {
        for (int row = 0; row < 3; ++row) {
            if (spec.glyph == FormatGlyph::numbered) {
                wchar_t number[2]{static_cast<wchar_t>(L'1' + row), L'\0'};
                TextOutW(dc, area.left, area.top + row * 5 - 1, number, 1);
            } else {
                HBRUSH old_brush = static_cast<HBRUSH>(SelectObject(
                    dc, GetStockObject(BLACK_BRUSH)));
                Ellipse(dc, area.left + 1, area.top + row * 5 + 1,
                        area.left + 4, area.top + row * 5 + 4);
                SelectObject(dc, old_brush);
            }
            MoveToEx(dc, area.left + 6, area.top + row * 5 + 2, nullptr);
            LineTo(dc, area.right, area.top + row * 5 + 2);
        }
        return;
    }
    if (spec.glyph == FormatGlyph::indent_left ||
        spec.glyph == FormatGlyph::indent_right) {
        for (int row = 0; row < 3; ++row) {
            MoveToEx(dc, area.left + 6, area.top + 2 + row * 5, nullptr);
            LineTo(dc, area.right, area.top + 2 + row * 5);
        }
        const bool right = spec.glyph == FormatGlyph::indent_right;
        POINT triangle[3]{{right ? area.left + 1 : area.left + 6, area.top + 6},
                          {right ? area.left + 6 : area.left + 1, area.top + 3},
                          {right ? area.left + 6 : area.left + 1, area.top + 9}};
        HBRUSH brush = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
        HBRUSH old_brush = static_cast<HBRUSH>(SelectObject(dc, brush));
        Polygon(dc, triangle, 3);
        SelectObject(dc, old_brush);
        return;
    }
    if (spec.glyph == FormatGlyph::table && sprite_dc != nullptr) {
        const int glyph = area.bottom - area.top;
        StretchBlt(dc, area.left, area.top, glyph, glyph, sprite_dc,
                   12 * kSpriteCell, 0, kSpriteCell, kSpriteCell, SRCCOPY);
        return;
    }
    if (spec.glyph == FormatGlyph::borders) {
        Rectangle(dc, area.left + 1, area.top + 1,
                  area.right - 1, area.bottom - 1);
        const int middle_x = (area.left + area.right) / 2;
        const int middle_y = (area.top + area.bottom) / 2;
        MoveToEx(dc, middle_x, area.top + 1, nullptr);
        LineTo(dc, middle_x, area.bottom - 1);
        MoveToEx(dc, area.left + 1, middle_y, nullptr);
        LineTo(dc, area.right - 1, middle_y);
    }
}

void paint_toolbar(HWND toolbar, ToolbarState& state) {
    PAINTSTRUCT paint{};
    HDC dc = BeginPaint(toolbar, &paint);
    RECT client{};
    GetClientRect(toolbar, &client);
    HBRUSH face = CreateSolidBrush(kButtonFace);
    FillRect(dc, &client, face);
    DeleteObject(face);

    if (state.standard_visible && state.formatting_visible) {
        HPEN separator = CreatePen(PS_SOLID, 1, kButtonShadow);
        HPEN highlight = CreatePen(PS_SOLID, 1, kButtonHighlight);
        HPEN old_pen = static_cast<HPEN>(SelectObject(dc, separator));
        const int row_line = scale(toolbar, 32);
        MoveToEx(dc, 0, row_line, nullptr);
        LineTo(dc, client.right, row_line);
        SelectObject(dc, highlight);
        MoveToEx(dc, 0, row_line + 1, nullptr);
        LineTo(dc, client.right, row_line + 1);
        SelectObject(dc, old_pen);
        DeleteObject(separator);
        DeleteObject(highlight);
    }

    HDC sprite_dc = CreateCompatibleDC(dc);
    HBITMAP old_bitmap = state.sprite != nullptr ?
        static_cast<HBITMAP>(SelectObject(sprite_dc, state.sprite)) : nullptr;
    if (state.standard_visible) {
        for (int index = 0;
             index < static_cast<int>(kStandardButtons.size()); ++index) {
            RECT rect = standard_button_rect(toolbar, index);
            const bool down =
                (state.pressed.hit && !state.pressed.format &&
                 state.pressed.index == index) || state.standard_latched[index];
            draw_classic_edge(dc, rect, down);
            if (state.sprite != nullptr) {
                draw_standard_glyph(toolbar, dc, sprite_dc,
                                    kStandardButtons[index], rect, down);
            }
        }
    }
    if (state.formatting_visible) {
        for (int index = 0;
             index < static_cast<int>(kFormatButtons.size()); ++index) {
            RECT rect = format_button_rect(toolbar, state, index);
            const bool down =
                (state.pressed.hit && state.pressed.format &&
                 state.pressed.index == index) || state.format_latched[index];
            draw_classic_edge(dc, rect, down);
            draw_format_glyph(toolbar, dc, kFormatButtons[index], rect, down,
                              state.sprite != nullptr ? sprite_dc : nullptr);
        }
    }
    if (old_bitmap != nullptr) {
        SelectObject(sprite_dc, old_bitmap);
    }
    DeleteDC(sprite_dc);
    EndPaint(toolbar, &paint);
}

HitResult hit_test(HWND toolbar, const ToolbarState& state, POINT point) {
    if (state.standard_visible) {
        for (int index = 0;
             index < static_cast<int>(kStandardButtons.size()); ++index) {
            RECT rect = standard_button_rect(toolbar, index);
            if (PtInRect(&rect, point)) {
                return {true, false, index, kStandardButtons[index].command};
            }
        }
    }
    if (state.formatting_visible) {
        for (int index = 0;
             index < static_cast<int>(kFormatButtons.size()); ++index) {
            RECT rect = format_button_rect(toolbar, state, index);
            if (PtInRect(&rect, point)) {
                return {true, true, index, kFormatButtons[index].command};
            }
        }
    }
    return {};
}

bool is_toolbar_descendant(HWND toolbar, HWND candidate) {
    return candidate == toolbar || IsChild(toolbar, candidate) != FALSE;
}

std::string combo_item(HWND combo, int index) {
    const LRESULT length = SendMessageA(combo, CB_GETLBTEXTLEN, index, 0);
    if (length == CB_ERR || length < 0) {
        return {};
    }
    std::vector<char> text(static_cast<std::size_t>(length) + 1);
    SendMessageA(combo, CB_GETLBTEXT, index,
                 reinterpret_cast<LPARAM>(text.data()));
    return text.data();
}

bool combo_contains(HWND combo, const char* value) {
    return SendMessageA(combo, CB_FINDSTRINGEXACT, static_cast<WPARAM>(-1),
                        reinterpret_cast<LPARAM>(value)) != CB_ERR;
}

struct ComboEnumeration {
    HWND toolbar;
    std::vector<HWND> combos;
};

BOOL CALLBACK collect_original_combos(HWND candidate, LPARAM parameter) {
    auto& enumeration = *reinterpret_cast<ComboEnumeration*>(parameter);
    if (is_toolbar_descendant(enumeration.toolbar, candidate)) {
        return TRUE;
    }
    wchar_t class_name[64]{};
    GetClassNameW(candidate, class_name,
                  static_cast<int>(sizeof(class_name) / sizeof(class_name[0])));
    if (lstrcmpiW(class_name, L"ComboBox") == 0) {
        enumeration.combos.push_back(candidate);
    }
    return TRUE;
}

void locate_source_combos(HWND toolbar, ToolbarState& state) {
    ComboEnumeration enumeration{toolbar, {}};
    EnumChildWindows(GetParent(toolbar), collect_original_combos,
                     reinterpret_cast<LPARAM>(&enumeration));
    for (HWND combo : enumeration.combos) {
        if (combo_contains(combo, "Courier New") &&
            combo_contains(combo, "Arial")) {
            state.source_font = combo;
        } else if (combo_contains(combo, "24") &&
                   combo_contains(combo, "72")) {
            state.source_size = combo;
        } else if (combo_contains(combo, "Normal") ||
                   SendMessageA(combo, CB_GETCOUNT, 0, 0) > 0) {
            state.source_style = combo;
        }
    }
}

std::wstring wide_from_ansi(const std::string& text) {
    if (text.empty()) {
        return {};
    }
    const int count = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1,
                                          nullptr, 0);
    std::vector<wchar_t> wide(static_cast<std::size_t>(count));
    MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, wide.data(), count);
    return wide.data();
}

std::string ansi_from_wide(const std::wstring& text) {
    if (text.empty()) {
        return {};
    }
    const int count = WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1,
                                          nullptr, 0, nullptr, nullptr);
    std::vector<char> ansi(static_cast<std::size_t>(count));
    WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, ansi.data(), count,
                        nullptr, nullptr);
    return ansi.data();
}

bool combo_or_child_has_focus(HWND combo) {
    const HWND focus = GetFocus();
    return focus == combo || (focus != nullptr && IsChild(combo, focus));
}

void sync_combo(HWND mirror, HWND source, int& copied_count) {
    if (mirror == nullptr || source == nullptr || !IsWindow(source)) {
        return;
    }
    const int count = static_cast<int>(SendMessageA(source, CB_GETCOUNT, 0, 0));
    if (count >= 0 && count != copied_count) {
        std::wstring mirror_text;
        const int mirror_length = GetWindowTextLengthW(mirror);
        mirror_text.resize(static_cast<std::size_t>(mirror_length) + 1);
        GetWindowTextW(mirror, &mirror_text[0], mirror_length + 1);
        SendMessageW(mirror, CB_RESETCONTENT, 0, 0);
        for (int index = 0; index < count; ++index) {
            const std::wstring item = wide_from_ansi(combo_item(source, index));
            SendMessageW(mirror, CB_ADDSTRING, 0,
                         reinterpret_cast<LPARAM>(item.c_str()));
        }
        SetWindowTextW(mirror, mirror_text.c_str());
        copied_count = count;
    }
    if (!combo_or_child_has_focus(mirror)) {
        const LRESULT selection = SendMessageA(source, CB_GETCURSEL, 0, 0);
        if (selection != CB_ERR && selection < count) {
            SendMessageW(mirror, CB_SETCURSEL, selection, 0);
        } else {
            const int length = GetWindowTextLengthA(source);
            std::vector<char> text(static_cast<std::size_t>(length) + 1);
            GetWindowTextA(source, text.data(), static_cast<int>(text.size()));
            const std::wstring source_text = wide_from_ansi(text.data());
            if (!source_text.empty()) {
                SetWindowTextW(mirror, source_text.c_str());
            }
        }
        SendMessageW(mirror, CB_SETEDITSEL, 0, MAKELPARAM(-1, 0));
    }
}

void sync_mirrors(HWND toolbar, ToolbarState& state) {
    if (state.source_font == nullptr || !IsWindow(state.source_font) ||
        state.source_size == nullptr || !IsWindow(state.source_size) ||
        state.source_style == nullptr || !IsWindow(state.source_style)) {
        locate_source_combos(toolbar, state);
    }
    sync_combo(state.style_combo, state.source_style,
               state.copied_style_count);
    sync_combo(state.font_combo, state.source_font, state.copied_font_count);
    sync_combo(state.size_combo, state.source_size, state.copied_size_count);
}

BOOL CALLBACK find_document_pane(HWND candidate, LPARAM parameter) {
    wchar_t class_name[64]{};
    GetClassNameW(candidate, class_name,
                  static_cast<int>(sizeof(class_name) / sizeof(class_name[0])));
    if (lstrcmpiW(class_name, L"OpusWwd") == 0) {
        *reinterpret_cast<HWND*>(parameter) = candidate;
        return FALSE;
    }
    return TRUE;
}

void restore_document_focus(HWND source) {
    HWND pane = nullptr;
    EnumChildWindows(GetAncestor(source, GA_ROOT), find_document_pane,
                     reinterpret_cast<LPARAM>(&pane));
    if (pane != nullptr) {
        SetFocus(pane);
    }
}

void restore_document_focus_from_root(HWND root) {
    HWND pane = nullptr;
    EnumChildWindows(root, find_document_pane,
                     reinterpret_cast<LPARAM>(&pane));
    if (pane != nullptr) {
        SetFocus(pane);
    }
}

void forward_combo(HWND mirror, HWND source, int notification,
                   bool& edit_dirty) {
    if (mirror == nullptr || source == nullptr || !IsWindow(source)) {
        return;
    }
    if (notification == CBN_SELCHANGE || notification == CBN_SELENDOK) {
        edit_dirty = false;
    }
    std::wstring wide;
    const LRESULT mirror_selection = SendMessageW(mirror, CB_GETCURSEL, 0, 0);
    if (mirror_selection != CB_ERR) {
        const LRESULT length = SendMessageW(
            mirror, CB_GETLBTEXTLEN, mirror_selection, 0);
        wide.resize(static_cast<std::size_t>(length) + 1, L'\0');
        SendMessageW(mirror, CB_GETLBTEXT, mirror_selection,
                     reinterpret_cast<LPARAM>(&wide[0]));
    } else {
        const int length = GetWindowTextLengthW(mirror);
        wide.resize(static_cast<std::size_t>(length) + 1, L'\0');
        GetWindowTextW(mirror, &wide[0], length + 1);
    }
    const std::string text = ansi_from_wide(wide.c_str());
    const LRESULT selection = SendMessageA(
        source, CB_FINDSTRINGEXACT, static_cast<WPARAM>(-1),
        reinterpret_cast<LPARAM>(text.c_str()));
    if (selection != CB_ERR) {
        SendMessageA(source, CB_SETCURSEL, selection, 0);
    }
    SetWindowTextA(source, text.c_str());
    const HWND parent = GetParent(source);
    const int control_id = GetDlgCtrlID(source);
    if (notification == CBN_SELCHANGE) {
        SendMessageW(parent, WM_COMMAND,
                     MAKEWPARAM(control_id, CBN_SELCHANGE),
                     reinterpret_cast<LPARAM>(source));
    } else if (notification == CBN_SELENDOK) {
        SendMessageW(parent, WM_COMMAND,
                     MAKEWPARAM(control_id, CBN_SELENDOK),
                     reinterpret_cast<LPARAM>(source));
        restore_document_focus(source);
    } else if (notification == CBN_EDITCHANGE) {
        // A dropdown selection can emit EDITCHANGE too; only free-form text
        // (no selected list item) needs the legacy control's focus-loss
        // commit path.
        edit_dirty = SendMessageW(mirror, CB_GETCURSEL, 0, 0) == CB_ERR;
        SendMessageW(parent, WM_COMMAND,
                     MAKEWPARAM(control_id, CBN_EDITCHANGE),
                     reinterpret_cast<LPARAM>(source));
    } else if (notification == CBN_DROPDOWN) {
        SendMessageW(parent, WM_COMMAND,
                     MAKEWPARAM(control_id, CBN_DROPDOWN),
                     reinterpret_cast<LPARAM>(source));
    } else if (notification == CBN_KILLFOCUS && edit_dirty) {
        SendMessageW(parent, WM_COMMAND,
                     MAKEWPARAM(control_id, CBN_KILLFOCUS),
                     reinterpret_cast<LPARAM>(source));
        edit_dirty = false;
    }
}

void position_combos(HWND toolbar, ToolbarState& state) {
    const int y = formatting_row_top(toolbar, state) + scale(toolbar, 1);
    // For CBS_DROPDOWN the window height also reserves the popup list. The
    // visible, closed control still uses its system edit-field height.
    const int height = scale(toolbar, 220);
    const int x_style = scale(toolbar, 4);
    const int width_style = scale(toolbar, 118);
    const int x_font = scale(toolbar, 126);
    const int width_font = scale(toolbar, 146);
    const int x_size = scale(toolbar, 276);
    const int width_size = scale(toolbar, 52);
    ShowWindow(state.style_combo,
               state.formatting_visible ? SW_SHOWNOACTIVATE : SW_HIDE);
    ShowWindow(state.font_combo,
               state.formatting_visible ? SW_SHOWNOACTIVATE : SW_HIDE);
    ShowWindow(state.size_combo,
               state.formatting_visible ? SW_SHOWNOACTIVATE : SW_HIDE);
    MoveWindow(state.style_combo, x_style, y, width_style, height, TRUE);
    MoveWindow(state.font_combo, x_font, y, width_font, height, TRUE);
    MoveWindow(state.size_combo, x_size, y, width_size, height, TRUE);

    if (state.zoom_combo != nullptr) {
        ShowWindow(state.zoom_combo,
                   state.standard_visible ? SW_SHOWNOACTIVATE : SW_HIDE);
        MoveWindow(state.zoom_combo, standard_buttons_end(toolbar),
                   scale(toolbar, 3), scale(toolbar, 82), height, TRUE);
    }
}

HWND create_combo(HWND toolbar, UINT id) {
    HWND combo = CreateWindowExW(
        0, L"COMBOBOX", L"",
        WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
            CBS_DROPDOWN | CBS_AUTOHSCROLL,
        0, 0, 10, 200, toolbar,
        reinterpret_cast<HMENU>(static_cast<UINT_PTR>(id)),
        GetModuleHandleW(nullptr), nullptr);
    set_window_classic(combo);
    return combo;
}

HWND create_zoom_combo(HWND toolbar) {
    HWND combo = CreateWindowExW(
        0, L"COMBOBOX", L"",
        WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
            CBS_DROPDOWN | CBS_AUTOHSCROLL,
        0, 0, 10, 200, toolbar,
        reinterpret_cast<HMENU>(static_cast<UINT_PTR>(kComboZoom)),
        GetModuleHandleW(nullptr), nullptr);
    set_window_classic(combo);
    SendMessageW(combo, CB_ADDSTRING, 0,
                 reinterpret_cast<LPARAM>(L"100%"));
    SendMessageW(combo, CB_ADDSTRING, 0,
                 reinterpret_cast<LPARAM>(L"Page Width"));
    SendMessageW(combo, CB_ADDSTRING, 0,
                 reinterpret_cast<LPARAM>(L"Whole Page"));
    SendMessageW(combo, CB_ADDSTRING, 0,
                 reinterpret_cast<LPARAM>(L"Print Preview"));
    SendMessageW(combo, CB_SETCURSEL, 0, 0);
    return combo;
}

void update_zoom_combo(HWND pane, int percent) {
    const HWND app = GetAncestor(pane, GA_ROOT);
    const HWND toolbar = FindWindowExW(app, nullptr, kToolbarClass, nullptr);
    ToolbarState* state = toolbar_state(toolbar);
    if (state == nullptr || state->zoom_combo == nullptr) {
        return;
    }
    const std::wstring text = std::to_wstring(percent) + L"%";
    SendMessageW(state->zoom_combo, CB_SETCURSEL,
                 static_cast<WPARAM>(-1), 0);
    SetWindowTextW(state->zoom_combo, text.c_str());
}

void update_toolbar_menu_checks(HWND app, const ToolbarState& state) {
    const UINT standard = MF_BYCOMMAND |
        (state.standard_visible ? MF_CHECKED : MF_UNCHECKED);
    const UINT formatting = MF_BYCOMMAND |
        (state.formatting_visible ? MF_CHECKED : MF_UNCHECKED);
    if (g_toolbars_menu != nullptr && IsMenu(g_toolbars_menu)) {
        CheckMenuItem(g_toolbars_menu, kCmdToggleStandardToolbar, standard);
        CheckMenuItem(g_toolbars_menu, kCmdToggleFormattingToolbar,
                      formatting);
    }
    HMENU root = GetMenu(app);
    if (root != nullptr) {
        CheckMenuItem(root, kCmdToggleStandardToolbar, standard);
        CheckMenuItem(root, kCmdToggleFormattingToolbar, formatting);
    }
}

void request_toolbar_layout(HWND app, HWND toolbar) {
    if (app == nullptr || toolbar == nullptr) {
        return;
    }
    RECT client{};
    GetClientRect(app, &client);
    const int height = toolbar_height(toolbar);
    ShowWindow(toolbar, height > 0 ? SW_SHOWNOACTIVATE : SW_HIDE);
    MoveWindow(toolbar, 0, 0, client.right - client.left, height, TRUE);
    const UINT size_type = IsZoomed(app) ? SIZE_MAXIMIZED : SIZE_RESTORED;
    SendMessageW(app, WM_SIZE, size_type,
                 MAKELPARAM(client.right - client.left,
                            client.bottom - client.top));
    InvalidateRect(app, nullptr, TRUE);
    DrawMenuBar(app);
}

void toggle_toolbar_row(HWND app, HWND toolbar, bool standard) {
    ToolbarState* state = toolbar_state(toolbar);
    if (state == nullptr) {
        return;
    }
    if (standard) {
        state->standard_visible = !state->standard_visible;
    } else {
        state->formatting_visible = !state->formatting_visible;
    }
    state->pressed = {};
    position_combos(toolbar, *state);
    update_toolbar_menu_checks(app, *state);
    request_toolbar_layout(app, toolbar);
}

void show_toolbar_context_menu(HWND toolbar, POINT screen_point) {
    ToolbarState* state = toolbar_state(toolbar);
    if (state == nullptr) {
        return;
    }
    HMENU popup = CreatePopupMenu();
    if (popup == nullptr) {
        return;
    }
    AppendMenuW(popup,
                MF_STRING |
                    (state->standard_visible ? MF_CHECKED : MF_UNCHECKED),
                kCmdToggleStandardToolbar, L"&Standard");
    AppendMenuW(popup,
                MF_STRING |
                    (state->formatting_visible ? MF_CHECKED : MF_UNCHECKED),
                kCmdToggleFormattingToolbar, L"&Formatting");
    AppendMenuW(popup, MF_STRING, bcmRuler, L"&Ruler");
    AppendMenuW(popup, MF_STRING, bcmStatusArea, L"&Status Bar");
    AppendMenuW(popup, MF_SEPARATOR, 0, nullptr);
    AppendMenuW(popup, MF_STRING, bcmCustomize, L"&Customize...");
    style_menu_tree(popup);
    const UINT command = TrackPopupMenu(
        popup, TPM_RETURNCMD | TPM_RIGHTBUTTON,
        screen_point.x, screen_point.y, 0, GetParent(toolbar), nullptr);
    DestroyMenu(popup);
    if (command != 0) {
        PostMessageW(GetParent(toolbar), WM_COMMAND,
                     MAKEWPARAM(command, 0), 0);
    }
}

WNDPROC original_pane_proc(HWND pane) {
    return reinterpret_cast<WNDPROC>(
        GetPropW(pane, kOriginalPaneProcProperty));
}

void redraw_vertical_ruler(HWND pane) {
    RECT ruler{};
    GetClientRect(pane, &ruler);
    ruler.right = std::min(ruler.right, ruler.left + scale(pane, 22));
    InvalidateRect(pane, &ruler, FALSE);
    UpdateWindow(pane);
}

bool vertical_margin_marker_at(HWND pane, POINT point, bool* top_marker,
                               int* page_offset) {
    RECT client{};
    GetClientRect(pane, &client);
    if (point.x < client.left ||
        point.x >= client.left + scale(pane, 22)) {
        return false;
    }

    int page_top = 0;
    int page_bottom = 0;
    int top_margin = 0;
    int bottom_margin = 0;
    int pixels_per_inch = 0;
    if (!OpusGetWin95VerticalRulerMetrics(
            pane, &page_top, &page_bottom, &top_margin, &bottom_margin,
            &pixels_per_inch)) {
        return false;
    }

    const int hit_radius = scale(pane, 7);
    int page_left = 0;
    int continuous_top = 0;
    int page_right = 0;
    int continuous_bottom = 0;
    int page_gap = 0;
    int has_previous = 0;
    int has_next = 0;
    OpusGetWin95ContinuousPageMetrics(
        pane, &page_left, &continuous_top, &page_right,
        &continuous_bottom, &page_gap, &has_previous, &has_next);
    const int page_step = page_bottom - page_top + page_gap;
    const std::array<int, 3> offsets{
        has_previous ? -page_step : 0,
        0,
        has_next ? page_step : 0};
    int closest_distance = hit_radius + 1;
    bool closest_top = false;
    int closest_offset = 0;
    for (std::size_t index = 0; index < offsets.size(); ++index) {
        const int offset = offsets[index];
        if ((index == 0 && !has_previous) ||
            (index == 2 && !has_next)) {
            continue;
        }
        const int top_distance = std::abs(
            point.y - (page_top + offset + top_margin));
        const int bottom_distance = std::abs(
            point.y - (page_bottom + offset - bottom_margin));
        if (top_distance < closest_distance) {
            closest_distance = top_distance;
            closest_top = true;
            closest_offset = offset;
        }
        if (bottom_distance < closest_distance) {
            closest_distance = bottom_distance;
            closest_top = false;
            closest_offset = offset;
        }
    }
    if (closest_distance > hit_radius) {
        return false;
    }
    *top_marker = closest_top;
    if (page_offset != nullptr) {
        *page_offset = closest_offset;
    }
    return true;
}

void update_vertical_margin_drag(HWND pane, int y) {
    if (!g_vertical_ruler_drag.active ||
        g_vertical_ruler_drag.pane != pane) {
        return;
    }

    int page_top = 0;
    int page_bottom = 0;
    int top_margin = 0;
    int bottom_margin = 0;
    int pixels_per_inch = 0;
    if (!OpusGetWin95VerticalRulerMetrics(
            pane, &page_top, &page_bottom, &top_margin, &bottom_margin,
            &pixels_per_inch)) {
        return;
    }

    page_top += g_vertical_ruler_drag.page_offset;
    page_bottom += g_vertical_ruler_drag.page_offset;
    const int minimum_text_height = std::max(
        scale(pane, 12), std::max(1, pixels_per_inch / 4));
    if (g_vertical_ruler_drag.top) {
        const int bottom_y = page_bottom - bottom_margin;
        y = std::max(page_top,
                     std::min(y, bottom_y - minimum_text_height));
    } else {
        const int top_y = page_top + top_margin;
        y = std::max(top_y + minimum_text_height,
                     std::min(y, page_bottom));
    }
    if (y != g_vertical_ruler_drag.preview_y) {
        g_vertical_ruler_drag.preview_y = y;
        redraw_vertical_ruler(pane);
    }
}

void cancel_vertical_margin_drag(HWND pane) {
    if (!g_vertical_ruler_drag.active ||
        g_vertical_ruler_drag.pane != pane) {
        return;
    }
    g_vertical_ruler_drag = {};
    redraw_vertical_ruler(pane);
}

PageSnapshot* find_page_snapshot(HWND pane, int page_index, int width,
                                 int height, int zoom_percent) {
    for (auto& snapshot : g_page_snapshots) {
        if (snapshot.pane == pane && snapshot.page_index == page_index &&
            snapshot.width == width && snapshot.height == height &&
            snapshot.zoom_percent == zoom_percent) {
            snapshot.last_used = GetTickCount64();
            return &snapshot;
        }
    }
    return nullptr;
}

void prune_page_snapshots(HWND pane) {
    std::size_t pane_count = 0;
    for (const auto& snapshot : g_page_snapshots) {
        if (snapshot.pane == pane) {
            ++pane_count;
        }
    }
    while (pane_count > 4) {
        auto oldest = g_page_snapshots.end();
        for (auto iterator = g_page_snapshots.begin();
             iterator != g_page_snapshots.end(); ++iterator) {
            if (iterator->pane == pane &&
                (oldest == g_page_snapshots.end() ||
                 iterator->last_used < oldest->last_used)) {
                oldest = iterator;
            }
        }
        if (oldest == g_page_snapshots.end()) {
            break;
        }
        if (oldest->bitmap != nullptr) {
            DeleteObject(oldest->bitmap);
        }
        g_page_snapshots.erase(oldest);
        --pane_count;
    }
}

void clear_page_snapshots(HWND pane) {
    for (auto iterator = g_page_snapshots.begin();
         iterator != g_page_snapshots.end();) {
        if (iterator->pane == pane) {
            if (iterator->bitmap != nullptr) {
                DeleteObject(iterator->bitmap);
            }
            iterator = g_page_snapshots.erase(iterator);
        } else {
            ++iterator;
        }
    }
}

void update_current_page_snapshot(HWND pane, HDC dc) {
    int page_left = 0;
    int page_top = 0;
    int page_right = 0;
    int page_bottom = 0;
    int page_gap = 0;
    int has_previous = 0;
    int has_next = 0;
    if (!OpusGetWin95ContinuousPageMetrics(
            pane, &page_left, &page_top, &page_right, &page_bottom,
            &page_gap, &has_previous, &has_next)) {
        return;
    }
    const int page_index = OpusGetWin95CurrentPageIndex(pane);
    const int zoom_percent = OpusGetWin95ZoomPercent(pane);
    const int width = page_right - page_left;
    const int height = page_bottom - page_top;
    if (page_index < 0 || width <= 0 || height <= 0) {
        return;
    }

    PageSnapshot* snapshot = find_page_snapshot(
        pane, page_index, width, height, zoom_percent);
    if (snapshot == nullptr) {
        PageSnapshot created{};
        created.pane = pane;
        created.page_index = page_index;
        created.zoom_percent = zoom_percent;
        created.width = width;
        created.height = height;
        created.bitmap = CreateCompatibleBitmap(dc, width, height);
        created.last_used = GetTickCount64();
        if (created.bitmap == nullptr) {
            return;
        }
        HDC memory = CreateCompatibleDC(dc);
        HBITMAP previous = static_cast<HBITMAP>(
            SelectObject(memory, created.bitmap));
        RECT background{0, 0, width, height};
        FillRect(memory, &background,
                 static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
        SelectObject(memory, previous);
        DeleteDC(memory);
        g_page_snapshots.push_back(created);
        snapshot = &g_page_snapshots.back();
        prune_page_snapshots(pane);
        snapshot = find_page_snapshot(
            pane, page_index, width, height, zoom_percent);
    }
    if (snapshot == nullptr || snapshot->bitmap == nullptr) {
        return;
    }

    RECT client{};
    RECT page{page_left, page_top, page_right, page_bottom};
    RECT visible{};
    GetClientRect(pane, &client);
    if (!IntersectRect(&visible, &page, &client)) {
        return;
    }
    HDC memory = CreateCompatibleDC(dc);
    HBITMAP previous = static_cast<HBITMAP>(
        SelectObject(memory, snapshot->bitmap));
    BitBlt(memory, visible.left - page_left, visible.top - page_top,
           visible.right - visible.left, visible.bottom - visible.top,
           dc, visible.left, visible.top, SRCCOPY);
    SelectObject(memory, previous);
    DeleteDC(memory);
}

void draw_neighbor_sheet(HDC dc, const RECT& sheet, const RECT& client,
                         const PageSnapshot* snapshot) {
    RECT visible{};
    if (!IntersectRect(&visible, &sheet, &client)) {
        return;
    }

    RECT shadow = sheet;
    OffsetRect(&shadow, 3, 3);
    RECT visible_shadow{};
    if (IntersectRect(&visible_shadow, &shadow, &client)) {
        HBRUSH shadow_brush = CreateSolidBrush(RGB(96, 96, 96));
        FillRect(dc, &visible_shadow, shadow_brush);
        DeleteObject(shadow_brush);
    }

    if (snapshot != nullptr && snapshot->bitmap != nullptr) {
        HDC memory = CreateCompatibleDC(dc);
        HBITMAP previous = static_cast<HBITMAP>(
            SelectObject(memory, snapshot->bitmap));
        BitBlt(dc, visible.left, visible.top,
               visible.right - visible.left, visible.bottom - visible.top,
               memory, visible.left - sheet.left, visible.top - sheet.top,
               SRCCOPY);
        SelectObject(memory, previous);
        DeleteDC(memory);
    } else {
        HBRUSH page_brush = CreateSolidBrush(RGB(255, 255, 255));
        FillRect(dc, &visible, page_brush);
        DeleteObject(page_brush);
    }
    HBRUSH border_brush = CreateSolidBrush(RGB(96, 96, 96));
    FrameRect(dc, &sheet, border_brush);
    DeleteObject(border_brush);
}

void draw_continuous_page_neighbors(HWND pane, HDC dc) {
    int page_left = 0;
    int page_top = 0;
    int page_right = 0;
    int page_bottom = 0;
    int page_gap = 0;
    int has_previous = 0;
    int has_next = 0;
    if (!OpusGetWin95ContinuousPageMetrics(
            pane, &page_left, &page_top, &page_right, &page_bottom,
            &page_gap, &has_previous, &has_next)) {
        return;
    }

    RECT client{};
    GetClientRect(pane, &client);
    const int page_height = page_bottom - page_top;
    if (page_right <= page_left || page_height <= 0) {
        return;
    }
    const int page_step = page_height + page_gap;
    const int page_index = OpusGetWin95CurrentPageIndex(pane);
    const int zoom_percent = OpusGetWin95ZoomPercent(pane);
    if (has_previous) {
        RECT previous{page_left, page_top - page_step,
                      page_right, page_bottom - page_step};
        draw_neighbor_sheet(
            dc, previous, client,
            find_page_snapshot(pane, page_index - 1,
                               page_right - page_left, page_height,
                               zoom_percent));
    }
    if (has_next) {
        RECT next{page_left, page_top + page_step,
                  page_right, page_bottom + page_step};
        draw_neighbor_sheet(
            dc, next, client,
            find_page_snapshot(pane, page_index + 1,
                               page_right - page_left, page_height,
                               zoom_percent));
    }
}

void draw_vertical_ruler(HWND pane, HDC dc) {
    RECT client{};
    GetClientRect(pane, &client);
    const int width = scale(pane, 22);
    RECT ruler{client.left, client.top,
               std::min(client.right, client.left + width), client.bottom};
    HBRUSH outside_brush = CreateSolidBrush(kButtonFace);
    FillRect(dc, &ruler, outside_brush);
    DeleteObject(outside_brush);

    int page_top = 0;
    int page_bottom = 0;
    int top_margin = 0;
    int bottom_margin = 0;
    int pixels_per_inch = 0;
    if (!OpusGetWin95VerticalRulerMetrics(
            pane, &page_top, &page_bottom, &top_margin, &bottom_margin,
            &pixels_per_inch) || pixels_per_inch <= 0) {
        return;
    }

    int page_left = 0;
    int continuous_top = 0;
    int page_right = 0;
    int continuous_bottom = 0;
    int page_gap = 0;
    int has_previous = 0;
    int has_next = 0;
    if (!OpusGetWin95ContinuousPageMetrics(
            pane, &page_left, &continuous_top, &page_right,
            &continuous_bottom, &page_gap, &has_previous, &has_next)) {
        page_gap = 0;
        has_previous = 0;
        has_next = 0;
    }

    int displayed_top_margin = top_margin;
    int displayed_bottom_margin = bottom_margin;
    if (g_vertical_ruler_drag.active &&
        g_vertical_ruler_drag.pane == pane) {
        if (g_vertical_ruler_drag.top) {
            displayed_top_margin = g_vertical_ruler_drag.preview_y -
                (page_top + g_vertical_ruler_drag.page_offset);
        } else {
            displayed_bottom_margin =
                page_bottom + g_vertical_ruler_drag.page_offset -
                g_vertical_ruler_drag.preview_y;
        }
    }

    const int page_step = page_bottom - page_top + page_gap;
    const std::array<int, 3> offsets{
        has_previous ? -page_step : 0,
        0,
        has_next ? page_step : 0};
    HBRUSH active_brush = CreateSolidBrush(RGB(255, 255, 255));
    for (std::size_t index = 0; index < offsets.size(); ++index) {
        if ((index == 0 && !has_previous) ||
            (index == 2 && !has_next)) {
            continue;
        }
        const int instance_top = page_top + offsets[index];
        const int instance_bottom = page_bottom + offsets[index];
        RECT writable{ruler.left,
                      instance_top + displayed_top_margin,
                      ruler.right,
                      instance_bottom - displayed_bottom_margin};
        writable.top = std::max(ruler.top, writable.top);
        writable.bottom = std::min(ruler.bottom, writable.bottom);
        if (writable.bottom > writable.top) {
            FillRect(dc, &writable, active_brush);
            DrawEdge(dc, &writable, EDGE_SUNKEN, BF_TOP | BF_BOTTOM);
        }
    }
    DeleteObject(active_brush);
    DrawEdge(dc, &ruler, EDGE_RAISED, BF_LEFT | BF_RIGHT);

    HPEN active_pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN subdued_pen = CreatePen(PS_SOLID, 1, RGB(96, 96, 96));
    HPEN previous_pen = static_cast<HPEN>(SelectObject(dc, active_pen));
    HFONT previous_font = static_cast<HFONT>(
        SelectObject(dc, GetStockObject(DEFAULT_GUI_FONT)));
    const int previous_bk = SetBkMode(dc, TRANSPARENT);
    const COLORREF previous_text = SetTextColor(dc, RGB(0, 0, 0));
    const int eighth = std::max(1, pixels_per_inch / 8);
    for (std::size_t index = 0; index < offsets.size(); ++index) {
        if ((index == 0 && !has_previous) ||
            (index == 2 && !has_next)) {
            continue;
        }
        const int instance_top = page_top + offsets[index];
        const int instance_bottom = page_bottom + offsets[index];
        const int active_top = instance_top + displayed_top_margin;
        const int active_bottom = instance_bottom - displayed_bottom_margin;
        int tick_index = 0;
        for (int y = instance_top; y < instance_bottom && y < ruler.bottom;
             y += eighth, ++tick_index) {
            if (y < ruler.top) {
                continue;
            }
            const bool writable_tick =
                y >= active_top && y <= active_bottom;
            SelectObject(dc, writable_tick ? active_pen : subdued_pen);
            int length = scale(pane, 3);
            if (tick_index % 8 == 0) {
                length = scale(pane, 9);
            } else if (tick_index % 4 == 0) {
                length = scale(pane, 7);
            } else if (tick_index % 2 == 0) {
                length = scale(pane, 5);
            }
            MoveToEx(dc, ruler.right - scale(pane, 2) - length, y, nullptr);
            LineTo(dc, ruler.right - scale(pane, 2), y);
            if (tick_index > 0 && tick_index % 8 == 0) {
                const std::wstring label = std::to_wstring(tick_index / 8);
                SetTextColor(dc, writable_tick ? RGB(0, 0, 0) :
                                                 RGB(80, 80, 80));
                TextOutW(dc, ruler.left + scale(pane, 3),
                         y - scale(pane, 6), label.c_str(),
                         static_cast<int>(label.size()));
            }
        }
    }

    SelectObject(dc, active_pen);
    SetTextColor(dc, RGB(0, 0, 0));
    const int marker_x = ruler.right - scale(pane, 2);
    const int marker_half = scale(pane, 4);
    const auto draw_margin_marker = [&](int y) {
        if (y < ruler.top || y >= ruler.bottom) {
            return;
        }
        POINT points[3]{{marker_x, y},
                        {marker_x - marker_half, y - marker_half},
                        {marker_x - marker_half, y + marker_half}};
        HBRUSH marker = CreateSolidBrush(RGB(255, 255, 255));
        HBRUSH old = static_cast<HBRUSH>(SelectObject(dc, marker));
        Polygon(dc, points, 3);
        SelectObject(dc, old);
        DeleteObject(marker);
    };
    for (std::size_t index = 0; index < offsets.size(); ++index) {
        if ((index == 0 && !has_previous) ||
            (index == 2 && !has_next)) {
            continue;
        }
        draw_margin_marker(page_top + offsets[index] +
                           displayed_top_margin);
        draw_margin_marker(page_bottom + offsets[index] -
                           displayed_bottom_margin);
    }

    SetTextColor(dc, previous_text);
    SetBkMode(dc, previous_bk);
    SelectObject(dc, previous_font);
    SelectObject(dc, previous_pen);
    DeleteObject(active_pen);
    DeleteObject(subdued_pen);
}

bool horizontal_margin_boundary_at(HWND overlay, POINT point,
                                   bool* left_boundary) {
    HWND ruler = GetParent(overlay);
    RECT client{};
    GetClientRect(overlay, &client);
    /* Keep the lower marker lane transparent so native indent/tab dragging
       continues to use the original ruler implementation. */
    if (point.y < client.top ||
        point.y >= client.bottom - scale(ruler, 7)) {
        return false;
    }

    int zero = 0;
    int active_left = 0;
    int active_right = 0;
    int pixels_per_inch = 0;
    int left_indent = 0;
    int first_indent = 0;
    int right_indent = 0;
    int default_tab = 0;
    int tab_count = 0;
    std::array<int, 1> tab_positions{};
    std::array<unsigned char, 1> tab_types{};
    if (!OpusGetWin95HorizontalRulerMetrics(
            ruler, &zero, &active_left, &active_right, &pixels_per_inch,
            &left_indent, &first_indent, &right_indent, &default_tab,
            &tab_count, tab_positions.data(), tab_types.data(), 0)) {
        return false;
    }
    const int hit_radius = scale(ruler, 5);
    const int left_distance = std::abs(point.x - active_left);
    const int right_distance = std::abs(point.x - active_right);
    if (left_distance > hit_radius && right_distance > hit_radius) {
        return false;
    }
    *left_boundary = left_distance <= right_distance;
    return true;
}

void redraw_horizontal_ruler_overlay(HWND overlay) {
    InvalidateRect(overlay, nullptr, FALSE);
    UpdateWindow(overlay);
}

void update_horizontal_margin_drag(HWND overlay, int x) {
    if (!g_horizontal_ruler_drag.active ||
        g_horizontal_ruler_drag.overlay != overlay) {
        return;
    }
    HWND ruler = g_horizontal_ruler_drag.ruler;
    int zero = 0;
    int active_left = 0;
    int active_right = 0;
    int pixels_per_inch = 0;
    int left_indent = 0;
    int first_indent = 0;
    int right_indent = 0;
    int default_tab = 0;
    int tab_count = 0;
    int left_margin = 0;
    int right_margin = 0;
    std::array<int, 1> tab_positions{};
    std::array<unsigned char, 1> tab_types{};
    if (!OpusGetWin95HorizontalRulerMetrics(
            ruler, &zero, &active_left, &active_right, &pixels_per_inch,
            &left_indent, &first_indent, &right_indent, &default_tab,
            &tab_count, tab_positions.data(), tab_types.data(), 0) ||
        !OpusGetWin95HorizontalPageMargins(
            ruler, &left_margin, &right_margin)) {
        return;
    }
    const int minimum_text_width = std::max(
        scale(ruler, 12), std::max(1, pixels_per_inch / 4));
    if (g_horizontal_ruler_drag.left) {
        x = std::max(active_left - left_margin,
                     std::min(x, active_right - minimum_text_width));
    } else {
        x = std::max(active_left + minimum_text_width,
                     std::min(x, active_right + right_margin));
    }
    if (x != g_horizontal_ruler_drag.preview_x) {
        g_horizontal_ruler_drag.preview_x = x;
        redraw_horizontal_ruler_overlay(overlay);
    }
}

void cancel_horizontal_margin_drag(HWND overlay) {
    if (!g_horizontal_ruler_drag.active ||
        g_horizontal_ruler_drag.overlay != overlay) {
        return;
    }
    g_horizontal_ruler_drag = {};
    redraw_horizontal_ruler_overlay(overlay);
}

void draw_horizontal_ruler(HWND ruler, HDC dc) {
    RECT client{};
    GetClientRect(ruler, &client);
    if (client.right <= client.left || client.bottom <= client.top) {
        return;
    }

    int zero = 0;
    int active_left = 0;
    int active_right = 0;
    int pixels_per_inch = 0;
    int left_indent = 0;
    int first_indent = 0;
    int right_indent = 0;
    int default_tab = 0;
    int tab_count = 0;
    std::array<int, 32> tab_positions{};
    std::array<unsigned char, 32> tab_types{};
    if (!OpusGetWin95HorizontalRulerMetrics(
            ruler, &zero, &active_left, &active_right, &pixels_per_inch,
            &left_indent, &first_indent, &right_indent, &default_tab,
            &tab_count, tab_positions.data(), tab_types.data(),
            static_cast<int>(tab_positions.size())) || pixels_per_inch <= 0) {
        return;
    }

    if (g_horizontal_ruler_drag.active &&
        g_horizontal_ruler_drag.ruler == ruler) {
        const int delta = g_horizontal_ruler_drag.preview_x -
                          g_horizontal_ruler_drag.origin_x;
        if (g_horizontal_ruler_drag.left) {
            active_left = g_horizontal_ruler_drag.preview_x;
            zero += delta;
            left_indent += delta;
            first_indent += delta;
            for (int index = 0; index < tab_count; ++index) {
                tab_positions[index] += delta;
            }
        } else {
            active_right = g_horizontal_ruler_drag.preview_x;
            right_indent += delta;
        }
    }

    active_left = std::max<int>(static_cast<int>(client.left),
                                std::min<int>(active_left,
                                              static_cast<int>(client.right)));
    active_right = std::max<int>(static_cast<int>(client.left),
                                 std::min<int>(active_right,
                                               static_cast<int>(client.right)));
    HBRUSH outside_brush = CreateSolidBrush(kButtonFace);
    FillRect(dc, &client, outside_brush);
    DeleteObject(outside_brush);

    RECT active{active_left, client.top, active_right, client.bottom};
    if (active.right > active.left) {
        HBRUSH active_brush = CreateSolidBrush(RGB(255, 255, 255));
        FillRect(dc, &active, active_brush);
        DeleteObject(active_brush);
        DrawEdge(dc, &active, EDGE_SUNKEN, BF_LEFT | BF_RIGHT);
    }
    DrawEdge(dc, &client, EDGE_RAISED, BF_TOP | BF_BOTTOM);

    HPEN active_pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN subdued_pen = CreatePen(PS_SOLID, 1, RGB(96, 96, 96));
    HPEN previous_pen = static_cast<HPEN>(SelectObject(dc, active_pen));
    HFONT previous_font = static_cast<HFONT>(
        SelectObject(dc, GetStockObject(DEFAULT_GUI_FONT)));
    const int previous_bk = SetBkMode(dc, TRANSPARENT);
    const COLORREF previous_text = SetTextColor(dc, RGB(0, 0, 0));

    const int scale_line = std::max(client.top + 8, client.bottom - 8);
    MoveToEx(dc, client.left, scale_line, nullptr);
    LineTo(dc, client.right, scale_line);
    const int eighth = std::max(1, pixels_per_inch / 8);
    int first_tick = (client.left - zero) / eighth;
    if (zero + first_tick * eighth > client.left) {
        --first_tick;
    }
    for (int tick = first_tick;; ++tick) {
        const int x = zero + tick * eighth;
        if (x > client.right) {
            break;
        }
        if (x < client.left) {
            continue;
        }
        const bool writable = x >= active_left && x <= active_right;
        SelectObject(dc, writable ? active_pen : subdued_pen);
        int length = 2;
        if (tick % 8 == 0) {
            length = 7;
        } else if (tick % 4 == 0) {
            length = 5;
        } else if (tick % 2 == 0) {
            length = 3;
        }
        MoveToEx(dc, x, scale_line, nullptr);
        LineTo(dc, x, scale_line - length);
        if (tick % 8 == 0) {
            const std::wstring label = std::to_wstring(tick / 8);
            SetTextColor(dc, writable ? RGB(0, 0, 0) : RGB(80, 80, 80));
            TextOutW(dc, x + 3, client.top - 1, label.c_str(),
                     static_cast<int>(label.size()));
        }
    }

    SelectObject(dc, active_pen);
    SetTextColor(dc, RGB(0, 0, 0));
    if (default_tab > 0) {
        for (int x = active_left + default_tab;
             x < active_right; x += default_tab) {
            Rectangle(dc, x - 1, client.bottom - 4,
                      x + 2, client.bottom - 2);
        }
    }

    for (int index = 0; index < tab_count; ++index) {
        const int x = tab_positions[index];
        const int top = scale_line + 1;
        const int bottom = client.bottom - 2;
        MoveToEx(dc, x, top, nullptr);
        LineTo(dc, x, bottom);
        switch (tab_types[index] & 7) {
        case 0:
            LineTo(dc, x + 5, bottom);
            break;
        case 1:
            MoveToEx(dc, x - 4, bottom, nullptr);
            LineTo(dc, x + 5, bottom);
            break;
        case 2:
            LineTo(dc, x - 5, bottom);
            break;
        default:
            MoveToEx(dc, x - 3, bottom, nullptr);
            LineTo(dc, x + 2, bottom);
            SetPixel(dc, x + 4, bottom - 1, RGB(0, 0, 0));
            break;
        }
    }

    HBRUSH marker_brush = CreateSolidBrush(RGB(255, 255, 255));
    HBRUSH previous_brush = static_cast<HBRUSH>(
        SelectObject(dc, marker_brush));
    const int marker_top = scale_line + 1;
    const int marker_bottom = client.bottom - 1;
    auto down_triangle = [&](int x) {
        POINT points[3]{{x - 5, marker_top}, {x + 5, marker_top},
                        {x, std::min(marker_bottom, marker_top + 6)}};
        Polygon(dc, points, 3);
    };
    auto up_triangle = [&](int x, bool with_base) {
        POINT points[3]{{x - 5, marker_bottom - 2},
                        {x + 5, marker_bottom - 2},
                        {x, std::max(marker_top, marker_bottom - 8)}};
        Polygon(dc, points, 3);
        if (with_base) {
            Rectangle(dc, x - 3, marker_bottom - 2,
                      x + 4, marker_bottom + 1);
        }
    };
    down_triangle(first_indent);
    up_triangle(left_indent, true);
    up_triangle(right_indent, false);
    SelectObject(dc, previous_brush);
    DeleteObject(marker_brush);

    SetTextColor(dc, previous_text);
    SetBkMode(dc, previous_bk);
    SelectObject(dc, previous_font);
    SelectObject(dc, previous_pen);
    DeleteObject(active_pen);
    DeleteObject(subdued_pen);
}

LRESULT CALLBACK ruler_overlay_proc(HWND overlay, UINT message,
                                    WPARAM w_param, LPARAM l_param) {
    switch (message) {
    case WM_NCHITTEST: {
        if (g_horizontal_ruler_drag.active &&
            g_horizontal_ruler_drag.overlay == overlay) {
            return HTCLIENT;
        }
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        ScreenToClient(overlay, &point);
        bool left_boundary = false;
        return horizontal_margin_boundary_at(
                   overlay, point, &left_boundary) ?
                   HTCLIENT : HTTRANSPARENT;
    }
    case WM_MOUSEACTIVATE:
        return MA_NOACTIVATE;
    case WM_SETCURSOR:
        SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32644)));
        return TRUE;
    case WM_LBUTTONDOWN: {
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        bool left_boundary = false;
        if (!horizontal_margin_boundary_at(
                overlay, point, &left_boundary)) {
            return 0;
        }
        HWND ruler = GetParent(overlay);
        int zero = 0;
        int active_left = 0;
        int active_right = 0;
        int pixels_per_inch = 0;
        int left_indent = 0;
        int first_indent = 0;
        int right_indent = 0;
        int default_tab = 0;
        int tab_count = 0;
        std::array<int, 1> tab_positions{};
        std::array<unsigned char, 1> tab_types{};
        if (OpusGetWin95HorizontalRulerMetrics(
                ruler, &zero, &active_left, &active_right,
                &pixels_per_inch, &left_indent, &first_indent,
                &right_indent, &default_tab, &tab_count,
                tab_positions.data(), tab_types.data(), 0)) {
            g_horizontal_ruler_drag.overlay = overlay;
            g_horizontal_ruler_drag.ruler = ruler;
            g_horizontal_ruler_drag.active = true;
            g_horizontal_ruler_drag.left = left_boundary;
            g_horizontal_ruler_drag.origin_x = left_boundary ?
                active_left : active_right;
            g_horizontal_ruler_drag.preview_x =
                g_horizontal_ruler_drag.origin_x;
            SetCapture(overlay);
            SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32644)));
        }
        return 0;
    }
    case WM_MOUSEMOVE:
        if (g_horizontal_ruler_drag.active &&
            g_horizontal_ruler_drag.overlay == overlay) {
            update_horizontal_margin_drag(overlay, GET_X_LPARAM(l_param));
            SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32644)));
            return 0;
        }
        break;
    case WM_LBUTTONUP:
        if (g_horizontal_ruler_drag.active &&
            g_horizontal_ruler_drag.overlay == overlay) {
            update_horizontal_margin_drag(overlay, GET_X_LPARAM(l_param));
            const HWND ruler = g_horizontal_ruler_drag.ruler;
            const bool left_boundary = g_horizontal_ruler_drag.left;
            const int delta = g_horizontal_ruler_drag.preview_x -
                              g_horizontal_ruler_drag.origin_x;
            g_horizontal_ruler_drag = {};
            if (GetCapture() == overlay) {
                ReleaseCapture();
            }
            const bool changed = OpusAdjustWin95HorizontalMargin(
                ruler, left_boundary ? 1 : 0, delta) != 0;
            if (!changed) {
                MessageBeep(MB_ICONEXCLAMATION);
            } else {
                HWND pane = nullptr;
                EnumChildWindows(GetAncestor(ruler, GA_ROOT),
                                 find_document_pane,
                                 reinterpret_cast<LPARAM>(&pane));
                if (pane != nullptr) {
                    clear_page_snapshots(pane);
                }
            }
            if (IsWindow(overlay)) {
                redraw_horizontal_ruler_overlay(overlay);
            }
            return 0;
        }
        break;
    case WM_CAPTURECHANGED:
        if (g_horizontal_ruler_drag.active &&
            g_horizontal_ruler_drag.overlay == overlay &&
            reinterpret_cast<HWND>(l_param) != overlay) {
            cancel_horizontal_margin_drag(overlay);
        }
        break;
    case WM_CANCELMODE:
        if (g_horizontal_ruler_drag.active &&
            g_horizontal_ruler_drag.overlay == overlay) {
            g_horizontal_ruler_drag = {};
            if (GetCapture() == overlay) {
                ReleaseCapture();
            }
            redraw_horizontal_ruler_overlay(overlay);
            return 0;
        }
        break;
    case WM_ERASEBKGND:
        return 1;
    case WM_PAINT: {
        PAINTSTRUCT paint{};
        HDC dc = BeginPaint(overlay, &paint);
        if (dc != nullptr) {
            draw_horizontal_ruler(GetParent(overlay), dc);
        }
        EndPaint(overlay, &paint);
        return 0;
    }
    }
    return DefWindowProcW(overlay, message, w_param, l_param);
}

void ensure_horizontal_ruler_overlay(HWND ruler) {
    RECT client{};
    GetClientRect(ruler, &client);
    HWND overlay = FindWindowExW(ruler, nullptr, kRulerOverlayClass, nullptr);
    if (overlay == nullptr) {
        const LONG_PTR style = GetWindowLongPtrW(ruler, GWL_STYLE);
        if ((style & WS_CLIPCHILDREN) == 0) {
            SetWindowLongPtrW(ruler, GWL_STYLE, style | WS_CLIPCHILDREN);
            SetWindowPos(ruler, nullptr, 0, 0, 0, 0,
                         SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
                         SWP_NOACTIVATE | SWP_FRAMECHANGED);
        }
        overlay = CreateWindowExW(
            WS_EX_NOACTIVATE,
            kRulerOverlayClass, L"", WS_CHILD | WS_VISIBLE,
            0, 0, client.right - client.left, client.bottom - client.top,
            ruler, nullptr, GetModuleHandleW(nullptr), nullptr);
    }
    if (overlay != nullptr) {
        SetWindowPos(overlay, HWND_TOP, 0, 0,
                     client.right - client.left, client.bottom - client.top,
                     SWP_NOACTIVATE | SWP_SHOWWINDOW);
        InvalidateRect(overlay, nullptr, FALSE);
        UpdateWindow(overlay);
    }
}

void show_document_context_menu(HWND pane, POINT screen_point) {
    HMENU popup = CreatePopupMenu();
    if (popup == nullptr) {
        return;
    }
    AppendMenuW(popup, MF_STRING, bcmUndo, L"&Undo");
    AppendMenuW(popup, MF_SEPARATOR, 0, nullptr);
    AppendMenuW(popup, MF_STRING, bcmCut, L"Cu&t");
    AppendMenuW(popup, MF_STRING, bcmCopy, L"&Copy");
    AppendMenuW(popup, MF_STRING, bcmPaste, L"&Paste");
    AppendMenuW(popup, MF_STRING, bcmSelectAll, L"Select &All");
    AppendMenuW(popup, MF_SEPARATOR, 0, nullptr);
    AppendMenuW(popup, MF_STRING, bcmCharacter, L"&Font...");
    AppendMenuW(popup, MF_STRING, bcmParagraph, L"&Paragraph...");
    AppendMenuW(popup, MF_STRING, bcmTabs, L"&Tabs...");
    AppendMenuW(popup, MF_STRING, imiRenumParas,
                L"&Bullets and Numbering...");
    AppendMenuW(popup, MF_SEPARATOR, 0, nullptr);
    AppendMenuW(popup, MF_STRING, bcmInsTable, L"Insert &Table...");
    AppendMenuW(popup, MF_STRING, bcmFormatTable, L"Table &Properties...");
    AppendMenuW(popup, MF_STRING, bcmInsPic, L"Insert &Picture...");
    AppendMenuW(popup, MF_STRING, bcmInsField, L"Insert F&ield...");
    style_menu_tree(popup);
    const HWND app = GetAncestor(pane, GA_ROOT);
    const UINT command = TrackPopupMenu(
        popup, TPM_RETURNCMD | TPM_RIGHTBUTTON,
        screen_point.x, screen_point.y, 0, app, nullptr);
    DestroyMenu(popup);
    if (command != 0) {
        PostMessageW(app, WM_COMMAND, MAKEWPARAM(command, 0), 0);
    }
}

LRESULT CALLBACK document_pane_proc(HWND pane, UINT message,
                                     WPARAM w_param, LPARAM l_param) {
    WNDPROC original = original_pane_proc(pane);
    if (message == WM_MOUSEWHEEL) {
        if (g_document_wheel.pane != pane) {
            g_document_wheel = {};
            g_document_wheel.pane = pane;
        }
        const int wheel_delta = GET_WHEEL_DELTA_WPARAM(w_param);
        if ((GET_KEYSTATE_WPARAM(w_param) & MK_CONTROL) != 0) {
            g_document_wheel.zoom_remainder += wheel_delta;
            int percent_delta = 0;
            while (g_document_wheel.zoom_remainder >= WHEEL_DELTA) {
                percent_delta += 10;
                g_document_wheel.zoom_remainder -= WHEEL_DELTA;
            }
            while (g_document_wheel.zoom_remainder <= -WHEEL_DELTA) {
                percent_delta -= 10;
                g_document_wheel.zoom_remainder += WHEEL_DELTA;
            }
            if (percent_delta != 0) {
                const int percent = OpusAdjustWin95Zoom(
                    pane, percent_delta);
                update_zoom_combo(pane, percent);
            }
            return 0;
        }

        const int scaled_delta = g_document_wheel.scroll_remainder -
            wheel_delta * scale(pane, 48);
        const int pixels = scaled_delta / WHEEL_DELTA;
        g_document_wheel.scroll_remainder =
            scaled_delta % WHEEL_DELTA;
        if (pixels != 0 &&
            OpusScrollWin95ContinuousPages(pane, pixels)) {
            return 0;
        }
    }
    if (message == WM_LBUTTONDOWN) {
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        bool top_marker = false;
        int page_offset = 0;
        if (vertical_margin_marker_at(
                pane, point, &top_marker, &page_offset)) {
            int page_top = 0;
            int page_bottom = 0;
            int top_margin = 0;
            int bottom_margin = 0;
            int pixels_per_inch = 0;
            if (OpusGetWin95VerticalRulerMetrics(
                    pane, &page_top, &page_bottom, &top_margin,
                    &bottom_margin, &pixels_per_inch)) {
                g_vertical_ruler_drag.pane = pane;
                g_vertical_ruler_drag.active = true;
                g_vertical_ruler_drag.top = top_marker;
                g_vertical_ruler_drag.page_offset = page_offset;
                g_vertical_ruler_drag.preview_y = top_marker ?
                    page_top + page_offset + top_margin :
                    page_bottom + page_offset - bottom_margin;
                SetFocus(pane);
                SetCapture(pane);
                SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32645)));
                return 0;
            }
        }
    }
    if (message == WM_MOUSEMOVE) {
        if (g_vertical_ruler_drag.active &&
            g_vertical_ruler_drag.pane == pane) {
            update_vertical_margin_drag(pane, GET_Y_LPARAM(l_param));
            SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32645)));
            return 0;
        }
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        bool top_marker = false;
        if (vertical_margin_marker_at(
                pane, point, &top_marker, nullptr)) {
            SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32645)));
            return 0;
        }
    }
    if (message == WM_LBUTTONUP && g_vertical_ruler_drag.active &&
        g_vertical_ruler_drag.pane == pane) {
        update_vertical_margin_drag(pane, GET_Y_LPARAM(l_param));
        int page_top = 0;
        int page_bottom = 0;
        int top_margin = 0;
        int bottom_margin = 0;
        int pixels_per_inch = 0;
        const bool have_metrics = OpusGetWin95VerticalRulerMetrics(
            pane, &page_top, &page_bottom, &top_margin, &bottom_margin,
            &pixels_per_inch) != 0;
        const bool top_marker = g_vertical_ruler_drag.top;
        const int preview_y = g_vertical_ruler_drag.preview_y;
        const int page_offset = g_vertical_ruler_drag.page_offset;
        g_vertical_ruler_drag = {};
        if (GetCapture() == pane) {
            ReleaseCapture();
        }
        if (have_metrics) {
            const int margin_pixels = top_marker ?
                preview_y - (page_top + page_offset) :
                page_bottom + page_offset - preview_y;
            const bool changed = OpusSetWin95VerticalMargin(
                pane, top_marker ? 1 : 0, margin_pixels) != 0;
            if (!changed) {
                MessageBeep(MB_ICONEXCLAMATION);
            } else {
                clear_page_snapshots(pane);
            }
        }
        redraw_vertical_ruler(pane);
        return 0;
    }
    if (message == WM_KEYDOWN && w_param == VK_ESCAPE &&
        g_vertical_ruler_drag.active &&
        g_vertical_ruler_drag.pane == pane) {
        g_vertical_ruler_drag = {};
        if (GetCapture() == pane) {
            ReleaseCapture();
        }
        redraw_vertical_ruler(pane);
        return 0;
    }
    if (message == WM_CAPTURECHANGED &&
        g_vertical_ruler_drag.active &&
        g_vertical_ruler_drag.pane == pane &&
        reinterpret_cast<HWND>(l_param) != pane) {
        cancel_vertical_margin_drag(pane);
    }
    if (message == WM_CANCELMODE && g_vertical_ruler_drag.active &&
        g_vertical_ruler_drag.pane == pane) {
        g_vertical_ruler_drag = {};
        if (GetCapture() == pane) {
            ReleaseCapture();
        }
        redraw_vertical_ruler(pane);
        return 0;
    }
    if (message == WM_SETCURSOR && LOWORD(l_param) == HTCLIENT) {
        POINT point{};
        GetCursorPos(&point);
        ScreenToClient(pane, &point);
        bool top_marker = false;
        if ((g_vertical_ruler_drag.active &&
             g_vertical_ruler_drag.pane == pane) ||
            vertical_margin_marker_at(
                pane, point, &top_marker, nullptr)) {
            SetCursor(LoadCursorW(nullptr, MAKEINTRESOURCEW(32645)));
            return TRUE;
        }
    }
    if (message == WM_PAINT) {
        const LRESULT result = original != nullptr ?
            CallWindowProcW(original, pane, message, w_param, l_param) :
            DefWindowProcW(pane, message, w_param, l_param);
        HDC dc = GetDC(pane);
        if (dc != nullptr) {
            update_current_page_snapshot(pane, dc);
            draw_continuous_page_neighbors(pane, dc);
            draw_vertical_ruler(pane, dc);
            ReleaseDC(pane, dc);
        }
        return result;
    }
    if (message == WM_SIZE) {
        const LRESULT result = original != nullptr ?
            CallWindowProcW(original, pane, message, w_param, l_param) :
            DefWindowProcW(pane, message, w_param, l_param);
        OpusRecenterWin95PageView(pane);
        InvalidateRect(pane, nullptr, TRUE);
        return result;
    }
    if (message == WM_RBUTTONDOWN) {
        SetFocus(pane);
        return 0;
    }
    if (message == WM_RBUTTONUP) {
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        ClientToScreen(pane, &point);
        show_document_context_menu(pane, point);
        return 0;
    }
    if (message == WM_CONTEXTMENU) {
        POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
        if (point.x == -1 && point.y == -1) {
            GetCursorPos(&point);
        }
        show_document_context_menu(pane, point);
        return 0;
    }
    if (message == WM_NCDESTROY) {
        if (g_document_wheel.pane == pane) {
            g_document_wheel = {};
        }
        clear_page_snapshots(pane);
        RemovePropW(pane, kOriginalPaneProcProperty);
        if (original != nullptr) {
            SetWindowLongPtrW(pane, GWLP_WNDPROC,
                              reinterpret_cast<LONG_PTR>(original));
        }
    }
    return original != nullptr ?
        CallWindowProcW(original, pane, message, w_param, l_param) :
        DefWindowProcW(pane, message, w_param, l_param);
}

BOOL CALLBACK subclass_document_pane(HWND candidate, LPARAM) {
    wchar_t class_name[64]{};
    GetClassNameW(candidate, class_name,
                  static_cast<int>(sizeof(class_name) / sizeof(class_name[0])));
    if (lstrcmpiW(class_name, L"OpusWwd") == 0 &&
        original_pane_proc(candidate) == nullptr) {
        SetLastError(0);
        WNDPROC original = reinterpret_cast<WNDPROC>(SetWindowLongPtrW(
            candidate, GWLP_WNDPROC,
            reinterpret_cast<LONG_PTR>(document_pane_proc)));
        if (original != nullptr || GetLastError() == 0) {
            SetPropW(candidate, kOriginalPaneProcProperty,
                     reinterpret_cast<HANDLE>(original));
            RedrawWindow(candidate, nullptr, nullptr,
                         RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
        }
    }
    return TRUE;
}

BOOL CALLBACK redraw_word95_ruler_window(HWND candidate, LPARAM) {
    wchar_t class_name[64]{};
    GetClassNameW(candidate, class_name,
                  static_cast<int>(sizeof(class_name) / sizeof(class_name[0])));
    if (lstrcmpiW(class_name, L"OpusRul") == 0 ||
        lstrcmpiW(class_name, L"OpusWwd") == 0) {
        RedrawWindow(candidate, nullptr, nullptr,
                     RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
    }
    return TRUE;
}

BOOL CALLBACK paint_word95_horizontal_ruler(HWND candidate, LPARAM) {
    wchar_t class_name[64]{};
    GetClassNameW(candidate, class_name,
                  static_cast<int>(sizeof(class_name) / sizeof(class_name[0])));
    if (lstrcmpiW(class_name, L"OpusRul") == 0) {
        ensure_horizontal_ruler_overlay(candidate);
    }
    return TRUE;
}

void subclass_all_document_panes(HWND app) {
    EnumChildWindows(app, subclass_document_pane, 0);
}

LRESULT CALLBACK app_window_proc(HWND app, UINT message,
                                 WPARAM w_param, LPARAM l_param) {
    WNDPROC original = g_original_app_proc;
    if (message == WM_COMMAND) {
        const UINT command = LOWORD(w_param);
        HWND toolbar = FindWindowExW(app, nullptr, kToolbarClass, nullptr);
        if (command == bcmPageView) {
            /* CmdPageView is a legacy toggle.  The restored shell treats the
               startup Page View choice as a stable document mode, so repeated
               selections do not accidentally drop back to flush galley view. */
            if (g_word95_page_view_active) {
                return 0;
            }
            g_word95_page_view_active = true;
        }
        if (command == kCmdToggleStandardToolbar) {
            toggle_toolbar_row(app, toolbar, true);
            return 0;
        }
        if (command == kCmdToggleFormattingToolbar) {
            toggle_toolbar_row(app, toolbar, false);
            return 0;
        }
    } else if (message == WM_INITMENUPOPUP) {
        HWND toolbar = FindWindowExW(app, nullptr, kToolbarClass, nullptr);
        ToolbarState* state = toolbar_state(toolbar);
        if (state != nullptr) {
            update_toolbar_menu_checks(app, *state);
        }
    } else if (message == WM_NCDESTROY) {
        g_original_app_proc = nullptr;
        if (original != nullptr) {
            SetWindowLongPtrW(app, GWLP_WNDPROC,
                              reinterpret_cast<LONG_PTR>(original));
        }
    }
    return original != nullptr ?
        CallWindowProcW(original, app, message, w_param, l_param) :
        DefWindowProcW(app, message, w_param, l_param);
}

bool subclass_app_window(HWND app) {
    if (g_original_app_proc != nullptr) {
        return true;
    }
    SetLastError(0);
    WNDPROC original = reinterpret_cast<WNDPROC>(SetWindowLongPtrW(
        app, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(app_window_proc)));
    if (original == nullptr && GetLastError() != 0) {
        return false;
    }
    g_original_app_proc = original;
    return true;
}

LRESULT CALLBACK toolbar_window_proc(HWND window, UINT message,
                                     WPARAM w_param, LPARAM l_param) {
    auto* state = reinterpret_cast<ToolbarState*>(
        GetWindowLongPtrW(window, GWLP_USERDATA));
    switch (message) {
    case WM_CREATE: {
        auto* created = new ToolbarState{};
        SetWindowLongPtrW(window, GWLP_USERDATA,
                          reinterpret_cast<LONG_PTR>(created));
        created->sprite = static_cast<HBITMAP>(LoadImageW(
            GetModuleHandleW(nullptr), MAKEINTRESOURCEW(kToolbarBitmap),
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION));
        LOGFONTW logical{};
        logical.lfHeight = -MulDiv(8, dpi_for_window(window), 72);
        logical.lfWeight = FW_NORMAL;
        logical.lfCharSet = DEFAULT_CHARSET;
        lstrcpyW(logical.lfFaceName, L"MS Sans Serif");
        created->font = CreateFontIndirectW(&logical);
        created->style_combo = create_combo(window, kComboStyle);
        created->font_combo = create_combo(window, kComboFont);
        created->size_combo = create_combo(window, kComboSize);
        created->zoom_combo = create_zoom_combo(window);
        SetWindowTextW(created->style_combo, L"Normal");
        SetWindowTextW(created->font_combo, L"Arial");
        SetWindowTextW(created->size_combo, L"10");
        SendMessageW(created->style_combo, WM_SETFONT,
                     reinterpret_cast<WPARAM>(created->font), FALSE);
        SendMessageW(created->font_combo, WM_SETFONT,
                     reinterpret_cast<WPARAM>(created->font), FALSE);
        SendMessageW(created->size_combo, WM_SETFONT,
                     reinterpret_cast<WPARAM>(created->font), FALSE);
        SendMessageW(created->zoom_combo, WM_SETFONT,
                     reinterpret_cast<WPARAM>(created->font), FALSE);
        position_combos(window, *created);
        sync_mirrors(window, *created);
        SetTimer(window, kSyncTimer, 350, nullptr);
        return 0;
    }
    case WM_SIZE:
        if (state != nullptr) {
            position_combos(window, *state);
        }
        return 0;
    case WM_TIMER:
        if (state != nullptr && w_param == kSyncTimer) {
            if (GetTickCount64() >= state->suppress_sync_until) {
                sync_mirrors(window, *state);
            }
            HWND app = GetParent(window);
            subclass_all_document_panes(app);
            if (state->ruler_refreshes_remaining > 0) {
                EnumChildWindows(app, redraw_word95_ruler_window, 0);
                --state->ruler_refreshes_remaining;
            }
            if (!state->startup_page_view_requested &&
                state->page_view_start_after != 0 &&
                GetTickCount64() >= state->page_view_start_after) {
                HWND pane = nullptr;
                EnumChildWindows(app, find_document_pane,
                                 reinterpret_cast<LPARAM>(&pane));
                if (pane != nullptr) {
                    state->startup_page_view_requested = true;
                    state->ruler_refreshes_remaining = 6;
                    SendMessageW(state->zoom_combo, CB_SETCURSEL, 1, 0);
                    PostMessageW(app, WM_COMMAND,
                                 MAKEWPARAM(bcmPageView, 0), 0);
                }
            }
            if (g_word95_page_view_active) {
                EnumChildWindows(app, paint_word95_horizontal_ruler, 0);
            }
        }
        return 0;
    case WM_COMMAND:
        if (state != nullptr) {
            const UINT id = LOWORD(w_param);
            const int notification = HIWORD(w_param);
            if (notification == CBN_SELCHANGE ||
                notification == CBN_SELENDOK ||
                notification == CBN_EDITCHANGE) {
                state->suppress_sync_until = GetTickCount64() + 1000;
            }
            if (id == kComboStyle) {
                forward_combo(state->style_combo, state->source_style,
                              notification, state->style_edit_dirty);
                return 0;
            }
            if (id == kComboFont) {
                forward_combo(state->font_combo, state->source_font,
                              notification, state->font_edit_dirty);
                return 0;
            }
            if (id == kComboSize) {
                forward_combo(state->size_combo, state->source_size,
                              notification, state->size_edit_dirty);
                return 0;
            }
            if (id == kComboZoom && notification == CBN_SELENDOK) {
                const LRESULT selection = SendMessageW(
                    state->zoom_combo, CB_GETCURSEL, 0, 0);
                if (selection == 1) {
                    PostMessageW(GetParent(window), WM_COMMAND,
                                 MAKEWPARAM(bcmPageView, 0), 0);
                } else if (selection == 2 || selection == 3) {
                    PostMessageW(GetParent(window), WM_COMMAND,
                                 MAKEWPARAM(bcmPrintPreview, 0), 0);
                }
                restore_document_focus_from_root(GetParent(window));
                return 0;
            }
        }
        break;
    case WM_LBUTTONDOWN:
        if (state != nullptr) {
            POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
            state->pressed = hit_test(window, *state, point);
            if (state->pressed.hit) {
                SetCapture(window);
                InvalidateRect(window, nullptr, FALSE);
            }
        }
        return 0;
    case WM_CONTEXTMENU:
        if (state != nullptr) {
            POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
            if (point.x == -1 && point.y == -1) {
                GetCursorPos(&point);
            }
            show_toolbar_context_menu(window, point);
        }
        return 0;
    case WM_RBUTTONDOWN:
        return 0;
    case WM_RBUTTONUP:
        if (state != nullptr) {
            POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
            ClientToScreen(window, &point);
            show_toolbar_context_menu(window, point);
        }
        return 0;
    case WM_LBUTTONUP:
        if (state != nullptr && state->pressed.hit) {
            POINT point{GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)};
            const HitResult released = hit_test(window, *state, point);
            const HitResult pressed = state->pressed;
            state->pressed = {};
            if (GetCapture() == window) {
                ReleaseCapture();
            }
            if (released.hit && released.format == pressed.format &&
                released.index == pressed.index) {
                if (pressed.format &&
                    kFormatButtons[pressed.index].latch) {
                    if (pressed.index >= 4 && pressed.index <= 7) {
                        for (int index = 4; index <= 7; ++index) {
                            state->format_latched[index] = false;
                        }
                    }
                    state->format_latched[pressed.index] =
                        !state->format_latched[pressed.index];
                } else if (!pressed.format &&
                           kStandardButtons[pressed.index].latch) {
                    state->standard_latched[pressed.index] =
                        !state->standard_latched[pressed.index];
                }
                PostMessageW(GetParent(window), WM_COMMAND,
                             MAKEWPARAM(pressed.command, 0), 0);
            }
            InvalidateRect(window, nullptr, FALSE);
        }
        return 0;
    case WM_CAPTURECHANGED:
        if (state != nullptr && state->pressed.hit) {
            state->pressed = {};
            InvalidateRect(window, nullptr, FALSE);
        }
        return 0;
    case WM_ERASEBKGND:
        return 1;
    case WM_PAINT:
        if (state != nullptr) {
            paint_toolbar(window, *state);
            return 0;
        }
        break;
    case WM_DESTROY:
        if (state != nullptr) {
            KillTimer(window, kSyncTimer);
            if (state->sprite != nullptr) {
                DeleteObject(state->sprite);
            }
            if (state->font != nullptr) {
                DeleteObject(state->font);
            }
            delete state;
            SetWindowLongPtrW(window, GWLP_USERDATA, 0);
        }
        break;
    }
    return DefWindowProcW(window, message, w_param, l_param);
}

bool register_toolbar_class() {
    WNDCLASSEXW window_class{};
    window_class.cbSize = sizeof(window_class);
    window_class.style = CS_DBLCLKS;
    window_class.lpfnWndProc = toolbar_window_proc;
    window_class.hInstance = GetModuleHandleW(nullptr);
    window_class.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512));
    window_class.lpszClassName = kToolbarClass;
    return RegisterClassExW(&window_class) != 0 ||
           GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

bool register_ruler_overlay_class() {
    WNDCLASSEXW window_class{};
    window_class.cbSize = sizeof(window_class);
    window_class.lpfnWndProc = ruler_overlay_proc;
    window_class.hInstance = GetModuleHandleW(nullptr);
    window_class.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512));
    window_class.lpszClassName = kRulerOverlayClass;
    return RegisterClassExW(&window_class) != 0 ||
           GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

}  // namespace

extern "C" void OpusDrawWin95HorizontalRuler(HWND ruler) {
    HDC dc = GetDC(ruler);
    if (dc != nullptr) {
        draw_horizontal_ruler(ruler, dc);
        ReleaseDC(ruler, dc);
    }
}

extern "C" HWND vhwndWin95Toolbar = nullptr;

extern "C" int OpusWin95ToolbarHeight(void) {
    return toolbar_height(vhwndWin95Toolbar);
}

extern "C" int OpusWin95ChromeActive(void) {
    return vhwndWin95Toolbar != nullptr && IsWindow(vhwndWin95Toolbar);
}

extern "C" void OpusSyncWin95Toolbar(void) {
    if (OpusWin95ChromeActive()) {
        SendMessageW(vhwndWin95Toolbar, WM_TIMER, kSyncTimer, 0);
        configure_word95_menus(GetParent(vhwndWin95Toolbar));
        style_menu_tree(GetMenu(GetParent(vhwndWin95Toolbar)));
        ToolbarState* state = toolbar_state(vhwndWin95Toolbar);
        if (state != nullptr) {
            update_toolbar_menu_checks(GetParent(vhwndWin95Toolbar), *state);
        }
        subclass_all_document_panes(GetParent(vhwndWin95Toolbar));
        DrawMenuBar(GetParent(vhwndWin95Toolbar));
    }
}

extern "C" void OpusSizeWin95Toolbar(HWND parent) {
    if (!OpusWin95ChromeActive()) {
        return;
    }
    RECT client{};
    GetClientRect(parent, &client);
    const int height = OpusWin95ToolbarHeight();
    ShowWindow(vhwndWin95Toolbar,
               height > 0 ? SW_SHOWNOACTIVATE : SW_HIDE);
    MoveWindow(vhwndWin95Toolbar, 0, 0, client.right - client.left,
               height, TRUE);
}

extern "C" int OpusCreateWin95Chrome(HWND parent) {
    if (OpusWin95ChromeActive()) {
        return TRUE;
    }
    if (!register_toolbar_class() || !register_ruler_overlay_class()) {
        return FALSE;
    }
    if (g_menu_brush == nullptr) {
        g_menu_brush = CreateSolidBrush(kButtonFace);
    }
    configure_word95_menus(parent);
    style_menu_tree(GetMenu(parent));
    DrawMenuBar(parent);
    apply_caption_colors(parent);
    set_window_classic(parent);

    vhwndWin95Toolbar = CreateWindowExW(
        0, kToolbarClass, L"",
        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
        0, 0, 1, scale(parent, 64), parent, nullptr,
        GetModuleHandleW(nullptr), nullptr);
    if (vhwndWin95Toolbar == nullptr) {
        return FALSE;
    }
    if (!subclass_app_window(parent)) {
        DestroyWindow(vhwndWin95Toolbar);
        vhwndWin95Toolbar = nullptr;
        return FALSE;
    }
    subclass_all_document_panes(parent);
    OpusSizeWin95Toolbar(parent);
    ToolbarState* state = toolbar_state(vhwndWin95Toolbar);
    if (state != nullptr) {
        update_toolbar_menu_checks(parent, *state);
    }
    SetWindowPos(vhwndWin95Toolbar, HWND_TOP, 0, 0, 0, 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    return TRUE;
}

extern "C" void OpusRequestWin95PageView(HWND parent) {
    HWND pane = nullptr;
    EnumChildWindows(parent, find_document_pane,
                     reinterpret_cast<LPARAM>(&pane));
    if (pane == nullptr) {
        return;
    }

    HWND toolbar = FindWindowExW(parent, nullptr, kToolbarClass, nullptr);
    ToolbarState* state = toolbar_state(toolbar);
    if (state != nullptr) {
        state->page_view_start_after = GetTickCount64() + 750;
        state->startup_page_view_requested = false;
    }
}
