From a36e7e674196fb9fefc8aac33f560d6b8a019e58 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 24 Jun 2026 21:29:39 +0400 Subject: [PATCH] Make IV editor table toolbar button context-aware --- .../SourceFiles/iv/editor/iv_editor_box.cpp | 51 ++++++++++++++++++- .../iv/editor/iv_editor_widget.cpp | 37 ++++++++++++++ .../SourceFiles/iv/editor/iv_editor_widget.h | 8 +-- 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/iv/editor/iv_editor_box.cpp b/Telegram/SourceFiles/iv/editor/iv_editor_box.cpp index 0730e51a47..86e0cfa94c 100644 --- a/Telegram/SourceFiles/iv/editor/iv_editor_box.cpp +++ b/Telegram/SourceFiles/iv/editor/iv_editor_box.cpp @@ -207,6 +207,8 @@ private: void showTextStyleMenu(not_null button); void fillListStyleMenu(not_null menu); void showListStyleMenu(not_null button); + void fillTableStyleMenu(not_null menu); + void showTableStyleMenu(not_null button); void applyBlockText(); void updateFromEditorState(); @@ -223,6 +225,7 @@ private: Ui::IconButton *_linkButton = nullptr; Ui::IconButton *_emojiButton = nullptr; Ui::IconButton *_listButton = nullptr; + Ui::IconButton *_tableButton = nullptr; base::unique_qptr _menu; }; @@ -534,11 +537,20 @@ void Toolbar::buildPills() { showListStyleMenu(listStyle); }); _listButton = listStyle; - addPillButton( + const auto tableStyle = addPillButton( controls, ToolbarActionId::Table, &st::ivEditorToolbarTableIcon, - [=] { insertType(State::InsertBlockType::Table); }); + nullptr); + tableStyle->setIsMenuButton(true); + tableStyle->setClickedCallback([=] { + if (_editor && _editor->currentTableRangeAtCaret()) { + showTableStyleMenu(tableStyle); + } else { + insertType(State::InsertBlockType::Table); + } + }); + _tableButton = tableStyle; _linkButton = addPillButton( controls, ToolbarActionId::Link, @@ -838,6 +850,32 @@ void Toolbar::showListStyleMenu(not_null button) { _menu->popup(button->mapToGlobal(QPoint(0, button->height()))); } +void Toolbar::fillTableStyleMenu(not_null menu) { + if (!_editor) { + return; + } + const auto range = _editor->currentTableRangeAtCaret(); + if (!range) { + return; + } + _editor->fillTableChangeMenu(menu, *range); +} + +void Toolbar::showTableStyleMenu(not_null button) { + if (_menu) { + return; + } + auto menu = base::make_unique_q( + this, + st::popupMenuWithIcons); + fillTableStyleMenu(not_null(menu.get())); + if (menu->empty()) { + return; + } + _menu = std::move(menu); + _menu->popup(button->mapToGlobal(QPoint(0, button->height()))); +} + void Toolbar::updateFromEditorState() { for (const auto &pb : _stateButtons) { const auto &state = _toolbarState[pb.format]; @@ -861,6 +899,15 @@ void Toolbar::updateFromEditorState() { ? ToolbarButtonState::Active : ToolbarButtonState::Inactive); } + if (_tableButton) { + const auto inTable = _editor + && _editor->currentTableRangeAtCaret().has_value(); + SetupToolbarButton( + not_null(_tableButton), + inTable + ? ToolbarButtonState::Active + : ToolbarButtonState::Inactive); + } } void Toolbar::setEmojiColumnOpen(bool open) { diff --git a/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp b/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp index d21295351c..f78aebbfdd 100644 --- a/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp +++ b/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp @@ -4588,6 +4588,43 @@ State::ListSelectionInfo Widget::listSelectionInfo( return _state->listSelectionInfo(range); } +std::optional +Widget::currentTableRangeAtCaret() const { + const auto activeLeaf = _state->activePreparedLeafSource(); + if (!activeLeaf + || activeLeaf->kind != PreparedEditLeafKind::TableCellText + || activeLeaf->tableRowIndex < 0 + || activeLeaf->tableCellIndex < 0) { + return std::nullopt; + } + const auto path = _state->convertBlockPath(activeLeaf->block); + const auto block = path + ? BlockFromPath(_state->richPage(), *path) + : nullptr; + if (!block || block->kind != RichPage::BlockKind::Table) { + return std::nullopt; + } + const auto grid = BuildTableGrid(*block); + for (const auto &cell : grid.cells) { + if (cell.rowIndex != activeLeaf->tableRowIndex + || cell.cellIndex != activeLeaf->tableCellIndex) { + continue; + } + auto range = PreparedEditTableCellRange{ + .block = activeLeaf->block, + .rowFrom = cell.rowFrom, + .rowTill = cell.rowTill, + .columnFrom = cell.columnFrom, + .columnTill = cell.columnTill, + }; + if (range.empty() || !_state->tableSelectionInfo(range).valid) { + return std::nullopt; + } + return range; + } + return std::nullopt; +} + void Widget::showListContextMenu( const PreparedListItemRange &range, QPoint globalPos) { diff --git a/Telegram/SourceFiles/iv/editor/iv_editor_widget.h b/Telegram/SourceFiles/iv/editor/iv_editor_widget.h index 818ed09935..aa1a7ead37 100644 --- a/Telegram/SourceFiles/iv/editor/iv_editor_widget.h +++ b/Telegram/SourceFiles/iv/editor/iv_editor_widget.h @@ -177,6 +177,8 @@ public: [[nodiscard]] ActiveBlockInfo activeBlockInfo() const; [[nodiscard]] std::optional currentListRangeAtCaret() const; + [[nodiscard]] std::optional + currentTableRangeAtCaret() const; [[nodiscard]] std::optional currentListItemRangeAtCaret(); [[nodiscard]] State::ListSelectionInfo listSelectionInfo( @@ -187,6 +189,9 @@ public: void fillListItemChangeMenu( not_null menu, const Markdown::PreparedEditListItemRange &range); + void fillTableChangeMenu( + not_null menu, + const Markdown::PreparedEditTableCellRange &range); void setInlineFieldExternalInteractionActive(bool active); void setTopContentPadding(int value); @@ -668,9 +673,6 @@ private: void showTableContextMenu( const Markdown::PreparedEditTableCellRange &range, QPoint globalPos); - void fillTableChangeMenu( - not_null menu, - const Markdown::PreparedEditTableCellRange &range); void applyTableChange(Fn change); [[nodiscard]] std::optional simpleMediaBlockPathFromHit( const Markdown::PreparedEditHit &hit) const;