From bee474f6e9339a513b75df38dfb66edafc2674cc Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 11 Jan 2018 22:33:26 +0300
Subject: [PATCH] Remove history_item and layout from pch.

Also move some code to separate modules.
Also create history item views by Window::Controller.
---
 Telegram/SourceFiles/apiwrap.cpp              |   2 +-
 Telegram/SourceFiles/app.cpp                  |  26 ++---
 Telegram/SourceFiles/app.h                    |  63 +++++++---
 Telegram/SourceFiles/boxes/confirm_box.cpp    |   1 +
 .../SourceFiles/boxes/edit_caption_box.cpp    |   1 +
 .../SourceFiles/boxes/local_storage_box.cpp   |   1 +
 Telegram/SourceFiles/boxes/send_files_box.cpp |   1 +
 Telegram/SourceFiles/calls/calls_panel.cpp    |   1 +
 Telegram/SourceFiles/calls/calls_top_bar.cpp  |   1 +
 .../SourceFiles/chat_helpers/bot_keyboard.h   |   6 +-
 .../chat_helpers/gifs_list_widget.cpp         |   1 +
 .../chat_helpers/stickers_list_widget.h       |   1 +
 .../SourceFiles/core/click_handler_types.cpp  |   3 +-
 Telegram/SourceFiles/data/data_feed.cpp       |   1 +
 .../data/data_search_controller.cpp           |   1 +
 Telegram/SourceFiles/data/data_session.h      |   2 +
 .../SourceFiles/dialogs/dialogs_entry.cpp     |   1 +
 .../dialogs/dialogs_inner_widget.cpp          |   1 +
 .../SourceFiles/dialogs/dialogs_layout.cpp    |   1 +
 Telegram/SourceFiles/facades.cpp              |  18 ++-
 Telegram/SourceFiles/facades.h                |   4 +-
 .../admin_log/history_admin_log_inner.cpp     |  42 ++++---
 .../admin_log/history_admin_log_inner.h       |  29 ++---
 .../admin_log/history_admin_log_item.cpp      |  21 ++--
 .../admin_log/history_admin_log_item.h        |  27 ++++-
 .../admin_log/history_admin_log_section.h     |   8 +-
 .../history/feed/history_feed_section.cpp     |   2 +-
 Telegram/SourceFiles/history/history.cpp      |  12 +-
 Telegram/SourceFiles/history/history.h        |  10 +-
 .../history/history_inner_widget.cpp          |  31 ++---
 .../history/history_inner_widget.h            |  29 ++---
 Telegram/SourceFiles/history/history_item.cpp |  54 +--------
 Telegram/SourceFiles/history/history_item.h   | 108 +++---------------
 Telegram/SourceFiles/history/history_media.h  |   2 +
 .../history/history_media_grouped.cpp         |   3 +-
 .../history/history_media_pointer.cpp         |  38 ++++++
 .../history/history_media_pointer.h           |  45 ++++++++
 .../history/history_media_types.cpp           |   1 +
 .../SourceFiles/history/history_message.cpp   |  11 +-
 .../SourceFiles/history/history_message.h     |   8 +-
 .../SourceFiles/history/history_service.cpp   |   8 ++
 .../SourceFiles/history/history_service.h     |   6 +
 .../SourceFiles/history/history_widget.cpp    |   2 +-
 .../view/history_view_cursor_state.cpp        |  33 ++++++
 .../history/view/history_view_cursor_state.h  |  63 ++++++++++
 .../history/view/history_view_element.cpp     | 104 +++++++++++++++++
 .../history/view/history_view_element.h       |  80 +++++++++++++
 .../history/view/history_view_list_widget.cpp |  33 +++---
 .../history/view/history_view_list_widget.h   |  33 +++---
 .../history/view/history_view_message.cpp     |  92 +--------------
 .../history/view/history_view_message.h       |  65 +----------
 .../view/history_view_service_message.cpp     |   8 ++
 .../view/history_view_service_message.h       |  11 ++
 Telegram/SourceFiles/info/info_wrap_widget.h  |   4 +
 .../info/media/info_media_list_widget.h       |   1 +
 .../info/profile/info_profile_values.h        |   4 +
 .../inline_bot_layout_internal.cpp            |   1 +
 .../inline_bots/inline_results_widget.cpp     |   1 +
 Telegram/SourceFiles/layout.cpp               |  13 +++
 Telegram/SourceFiles/layout.h                 |  51 ++-------
 Telegram/SourceFiles/mainwidget.cpp           |   2 +-
 Telegram/SourceFiles/mainwindow.cpp           |   4 -
 Telegram/SourceFiles/mainwindow.h             |   2 -
 .../media/player/media_player_cover.cpp       |   1 +
 .../media/player/media_player_widget.cpp      |   2 +
 .../media/view/media_clip_controller.cpp      |   1 +
 Telegram/SourceFiles/mediaview.cpp            |   1 +
 .../SourceFiles/overview/overview_layout.cpp  |   6 +
 .../SourceFiles/overview/overview_layout.h    |   8 +-
 Telegram/SourceFiles/ui/countryinput.h        |   1 +
 Telegram/SourceFiles/ui/images.cpp            |   1 +
 Telegram/SourceFiles/ui/text_options.cpp      |   1 +
 .../window/notifications_manager_default.cpp  |  11 ++
 .../window/notifications_manager_default.h    |  12 +-
 .../window/themes/window_theme_editor.cpp     |   1 +
 .../SourceFiles/window/window_controller.cpp  |  15 +++
 .../SourceFiles/window/window_controller.h    |  13 +++
 Telegram/gyp/telegram_sources.txt             |   6 +
 78 files changed, 794 insertions(+), 525 deletions(-)
 create mode 100644 Telegram/SourceFiles/history/history_media_pointer.cpp
 create mode 100644 Telegram/SourceFiles/history/history_media_pointer.h
 create mode 100644 Telegram/SourceFiles/history/view/history_view_cursor_state.cpp
 create mode 100644 Telegram/SourceFiles/history/view/history_view_cursor_state.h
 create mode 100644 Telegram/SourceFiles/history/view/history_view_element.cpp
 create mode 100644 Telegram/SourceFiles/history/view/history_view_element.h

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 06ecd59e8..431e34122 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -1617,7 +1617,7 @@ void ApiWrap::resolveWebPages() {
 		if (i.value() > 0) continue;
 		if (i.key()->pendingTill <= t) {
 			auto j = items.constFind(i.key());
-			if (j != items.cend() && !j.value().isEmpty()) {
+			if (j != items.cend() && !j.value().empty()) {
 				for_const (auto item, j.value()) {
 					if (item->id > 0) {
 						if (item->channelId() == NoChannel) {
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 10c5b47cd..87cb65941 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -89,7 +89,7 @@ namespace {
 	using SentData = QMap<uint64, QPair<PeerId, QString>>;
 	SentData sentData;
 
-	HistoryView::Message *hoveredItem = nullptr,
+	HistoryView::Element *hoveredItem = nullptr,
 		*pressedItem = nullptr,
 		*hoveredLinkItem = nullptr,
 		*pressedLinkItem = nullptr,
@@ -1835,7 +1835,7 @@ namespace {
 		}
 	}
 
-	void messageViewDestroyed(not_null<HistoryView::Message*> view) {
+	void messageViewDestroyed(not_null<HistoryView::Element*> view) {
 		if (::hoveredItem == view) {
 			hoveredItem(nullptr);
 		}
@@ -2182,43 +2182,43 @@ namespace {
 		clearAllImages();
 	}
 
-	void hoveredItem(HistoryView::Message *item) {
+	void hoveredItem(HistoryView::Element *item) {
 		::hoveredItem = item;
 	}
 
-	HistoryView::Message *hoveredItem() {
+	HistoryView::Element *hoveredItem() {
 		return ::hoveredItem;
 	}
 
-	void pressedItem(HistoryView::Message *item) {
+	void pressedItem(HistoryView::Element *item) {
 		::pressedItem = item;
 	}
 
-	HistoryView::Message *pressedItem() {
+	HistoryView::Element *pressedItem() {
 		return ::pressedItem;
 	}
 
-	void hoveredLinkItem(HistoryView::Message *item) {
+	void hoveredLinkItem(HistoryView::Element *item) {
 		::hoveredLinkItem = item;
 	}
 
-	HistoryView::Message *hoveredLinkItem() {
+	HistoryView::Element *hoveredLinkItem() {
 		return ::hoveredLinkItem;
 	}
 
-	void pressedLinkItem(HistoryView::Message *item) {
+	void pressedLinkItem(HistoryView::Element *item) {
 		::pressedLinkItem = item;
 	}
 
-	HistoryView::Message *pressedLinkItem() {
+	HistoryView::Element *pressedLinkItem() {
 		return ::pressedLinkItem;
 	}
 
-	void mousedItem(HistoryView::Message *item) {
+	void mousedItem(HistoryView::Element *item) {
 		::mousedItem = item;
 	}
 
-	HistoryView::Message *mousedItem() {
+	HistoryView::Element *mousedItem() {
 		return ::mousedItem;
 	}
 
@@ -2484,7 +2484,7 @@ namespace {
 
 	QString phoneFromSharedContact(int32 userId) {
 		auto i = ::sharedContactItems.constFind(userId);
-		if (i != ::sharedContactItems.cend() && !i->isEmpty()) {
+		if (i != ::sharedContactItems.cend() && !i->empty()) {
 			if (auto media = (*i->cbegin())->getMedia()) {
 				if (media->type() == MediaTypeContact) {
 					return static_cast<HistoryContact*>(media)->phone();
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index c0bd75b79..b0ad996f2 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -9,20 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "core/basic_types.h"
 #include "history/history.h"
-#include "history/history_item.h"
-#include "layout.h"
 
 class Messenger;
 class MainWindow;
 class MainWidget;
 class LocationCoords;
 struct LocationData;
+class HistoryItem;
 
 namespace HistoryView {
 class Message;
 } // namespace HistoryView
 
-using HistoryItemsMap = OrderedSet<HistoryItem*>;
+using HistoryItemsMap = base::flat_set<not_null<HistoryItem*>>;
 using PhotoItems = QHash<PhotoData*, HistoryItemsMap>;
 using DocumentItems = QHash<DocumentData*, HistoryItemsMap>;
 using WebPageItems = QHash<WebPageData*, HistoryItemsMap>;
@@ -33,6 +32,42 @@ using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
 using PhotosData = QHash<PhotoId, PhotoData*>;
 using DocumentsData = QHash<DocumentId, DocumentData*>;
 
+enum RoundCorners {
+	SmallMaskCorners = 0x00, // for images
+	LargeMaskCorners,
+
+	BoxCorners,
+	MenuCorners,
+	BotKbOverCorners,
+	StickerCorners,
+	StickerSelectedCorners,
+	SelectedOverlaySmallCorners,
+	SelectedOverlayLargeCorners,
+	DateCorners,
+	DateSelectedCorners,
+	ForwardCorners,
+	MediaviewSaveCorners,
+	EmojiHoverCorners,
+	StickerHoverCorners,
+	BotKeyboardCorners,
+	PhotoSelectOverlayCorners,
+
+	Doc1Corners,
+	Doc2Corners,
+	Doc3Corners,
+	Doc4Corners,
+
+	InShadowCorners, // for photos without bg
+	InSelectedShadowCorners,
+
+	MessageInCorners, // with shadow
+	MessageInSelectedCorners,
+	MessageOutCorners,
+	MessageOutSelectedCorners,
+
+	RoundCornersCount
+};
+
 namespace App {
 	MainWindow *wnd();
 	MainWidget *main();
@@ -199,7 +234,7 @@ namespace App {
 	void historyClearItems();
 	void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);
 	void historyUnregDependency(HistoryItem *dependent, HistoryItem *dependency);
-	void messageViewDestroyed(not_null<HistoryView::Message*> view);
+	void messageViewDestroyed(not_null<HistoryView::Element*> view);
 
 	void historyRegRandom(uint64 randomId, const FullMsgId &itemId);
 	void historyUnregRandom(uint64 randomId);
@@ -208,16 +243,16 @@ namespace App {
 	void historyUnregSentData(uint64 randomId);
 	void histSentDataByItem(uint64 randomId, PeerId &peerId, QString &text);
 
-	void hoveredItem(HistoryView::Message *item);
-	HistoryView::Message *hoveredItem();
-	void pressedItem(HistoryView::Message *item);
-	HistoryView::Message *pressedItem();
-	void hoveredLinkItem(HistoryView::Message *item);
-	HistoryView::Message *hoveredLinkItem();
-	void pressedLinkItem(HistoryView::Message *item);
-	HistoryView::Message *pressedLinkItem();
-	void mousedItem(HistoryView::Message *item);
-	HistoryView::Message *mousedItem();
+	void hoveredItem(HistoryView::Element *item);
+	HistoryView::Element *hoveredItem();
+	void pressedItem(HistoryView::Element *item);
+	HistoryView::Element *pressedItem();
+	void hoveredLinkItem(HistoryView::Element *item);
+	HistoryView::Element *hoveredLinkItem();
+	void pressedLinkItem(HistoryView::Element *item);
+	HistoryView::Element *pressedLinkItem();
+	void mousedItem(HistoryView::Element *item);
+	HistoryView::Element *mousedItem();
 	void clearMousedItems();
 
 	const style::font &monofont();
diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp
index 5504ad2f5..20d58e425 100644
--- a/Telegram/SourceFiles/boxes/confirm_box.cpp
+++ b/Telegram/SourceFiles/boxes/confirm_box.cpp
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "mainwindow.h"
 #include "apiwrap.h"
 #include "application.h"
+#include "history/history_item.h"
 #include "ui/widgets/checkbox.h"
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/labels.h"
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index 7e9a43055..8371a3616 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "window/window_controller.h"
 #include "mainwidget.h"
+#include "layout.h"
 #include "styles/style_history.h"
 #include "styles/style_boxes.h"
 
diff --git a/Telegram/SourceFiles/boxes/local_storage_box.cpp b/Telegram/SourceFiles/boxes/local_storage_box.cpp
index 770e4db93..ca621bda1 100644
--- a/Telegram/SourceFiles/boxes/local_storage_box.cpp
+++ b/Telegram/SourceFiles/boxes/local_storage_box.cpp
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "mainwindow.h"
 #include "auth_session.h"
+#include "layout.h"
 
 LocalStorageBox::LocalStorageBox(QWidget *parent)
 : _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) {
diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp
index 9884a82f7..539729027 100644
--- a/Telegram/SourceFiles/boxes/send_files_box.cpp
+++ b/Telegram/SourceFiles/boxes/send_files_box.cpp
@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "window/window_controller.h"
 #include "styles/style_history.h"
 #include "styles/style_boxes.h"
+#include "layout.h"
 
 namespace {
 
diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp
index f8aa4ee4d..c0667c2aa 100644
--- a/Telegram/SourceFiles/calls/calls_panel.cpp
+++ b/Telegram/SourceFiles/calls/calls_panel.cpp
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "observer_peer.h"
 #include "platform/platform_specific.h"
 #include "window/main_window.h"
+#include "layout.h"
 
 namespace Calls {
 namespace {
diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp
index 7b09123ba..cd9371485 100644
--- a/Telegram/SourceFiles/calls/calls_top_bar.cpp
+++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "observer_peer.h"
 #include "boxes/abstract_box.h"
 #include "base/timer.h"
+#include "layout.h"
 
 namespace Calls {
 namespace {
diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.h b/Telegram/SourceFiles/chat_helpers/bot_keyboard.h
index 562782513..58ef69d3c 100644
--- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.h
+++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.h
@@ -9,14 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "ui/widgets/tooltip.h"
 
+namespace style {
+struct BotKeyboardButton;
+} // namespace style
+
 class ReplyKeyboard;
 
 class BotKeyboard
 	: public TWidget
 	, public Ui::AbstractTooltipShower
 	, public ClickHandlerHost {
-	Q_OBJECT
-
 public:
 	BotKeyboard(QWidget *parent);
 
diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
index dd8ec4932..8b1fac79c 100644
--- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "mainwindow.h"
 #include "window/window_controller.h"
+#include "history/view/history_view_cursor_state.h"
 
 namespace ChatHelpers {
 namespace {
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
index 090eeb96c..ac881e38f 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
@@ -17,6 +17,7 @@ class Controller;
 
 namespace Ui {
 class LinkButton;
+class RippleAnimation;
 } // namespace Ui
 
 namespace ChatHelpers {
diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp
index 8f9918c28..9cb807c6f 100644
--- a/Telegram/SourceFiles/core/click_handler_types.cpp
+++ b/Telegram/SourceFiles/core/click_handler_types.cpp
@@ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "messenger.h"
 #include "platform/platform_specific.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
+#include "history/history_item.h"
 #include "boxes/confirm_box.h"
 #include "base/qthelp_regex.h"
 #include "base/qthelp_url.h"
diff --git a/Telegram/SourceFiles/data/data_feed.cpp b/Telegram/SourceFiles/data/data_feed.cpp
index 4dc519a81..f65e7f75b 100644
--- a/Telegram/SourceFiles/data/data_feed.cpp
+++ b/Telegram/SourceFiles/data/data_feed.cpp
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_feed.h"
 
 #include "dialogs/dialogs_key.h"
+#include "history/history_item.h"
 
 namespace Data {
 
diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp
index 8ca86dd81..894a6cd03 100644
--- a/Telegram/SourceFiles/data/data_search_controller.cpp
+++ b/Telegram/SourceFiles/data/data_search_controller.cpp
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "auth_session.h"
 #include "data/data_session.h"
 #include "data/data_messages.h"
+#include "history/history_item.h"
 
 namespace Api {
 namespace {
diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h
index f20c884ec..4cb9d4b89 100644
--- a/Telegram/SourceFiles/data/data_session.h
+++ b/Telegram/SourceFiles/data/data_session.h
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "chat_helpers/stickers.h"
 #include "dialogs/dialogs_key.h"
 
+struct HistoryMessageGroup;
+
 namespace Data {
 
 class Feed;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
index 8a4bcab35..28e4f0b60 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "dialogs/dialogs_indexed_list.h"
 #include "mainwidget.h"
 #include "styles/style_dialogs.h"
+#include "history/history_item.h"
 
 namespace Dialogs {
 namespace {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 02eebb62b..49db8f558 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "dialogs/dialogs_layout.h"
 #include "dialogs/dialogs_search_from_controllers.h"
 #include "history/feed/history_feed_section.h"
+#include "history/history_item.h"
 #include "styles/style_dialogs.h"
 #include "styles/style_chat_helpers.h"
 #include "styles/style_window.h"
diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
index 38ce0c7e0..2f129986f 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/empty_userpic.h"
 #include "ui/text_options.h"
 #include "lang/lang_keys.h"
+#include "history/history_item.h"
 
 namespace Dialogs {
 namespace Layout {
diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index 2ca6e2ad8..332da2957 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -22,13 +22,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "window/layer_widget.h"
 #include "lang/lang_keys.h"
 #include "base/observer.h"
+#include "history/history_item.h"
 #include "history/history_media.h"
 #include "styles/style_history.h"
 #include "data/data_session.h"
 
-Q_DECLARE_METATYPE(ClickHandlerPtr);
-Q_DECLARE_METATYPE(Qt::MouseButton);
-
 namespace App {
 namespace internal {
 
@@ -175,11 +173,9 @@ void showSettings() {
 }
 
 void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
-	if (auto w = wnd()) {
-		qRegisterMetaType<ClickHandlerPtr>();
-		qRegisterMetaType<Qt::MouseButton>();
-		QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button));
-	}
+	crl::on_main(wnd(), [handler, button] {
+		handler->onClick(button);
+	});
 }
 
 void logOutDelayed() {
@@ -266,14 +262,16 @@ void showPeerHistory(
 		const PeerId &peer,
 		MsgId msgId) {
 	auto ms = getms();
-	LOG(("Show Peer Start"));
 	if (auto m = App::main()) {
 		m->ui_showPeerHistory(
 			peer,
 			Window::SectionShow::Way::ClearStack,
 			msgId);
 	}
-	LOG(("Show Peer End: %1").arg(getms() - ms));
+}
+
+void showPeerHistoryAtItem(not_null<const HistoryItem*> item) {
+	showPeerHistory(item->history()->peer->id, item->id);
 }
 
 PeerData *getPeerForMouseAction() {
diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h
index d46b48430..a762c52f5 100644
--- a/Telegram/SourceFiles/facades.h
+++ b/Telegram/SourceFiles/facades.h
@@ -189,6 +189,7 @@ inline void showPeerProfile(const History *history) {
 }
 
 void showPeerHistory(const PeerId &peer, MsgId msgId);
+void showPeerHistoryAtItem(not_null<const HistoryItem*> item);
 
 inline void showPeerHistory(const PeerData *peer, MsgId msgId) {
 	showPeerHistory(peer->id, msgId);
@@ -198,9 +199,6 @@ inline void showPeerHistory(
 		MsgId msgId) {
 	showPeerHistory(history->peer->id, msgId);
 }
-inline void showPeerHistoryAtItem(const HistoryItem *item) {
-	showPeerHistory(item->history()->peer->id, item->id);
-}
 inline void showChatsList() {
 	showPeerHistory(PeerId(0), 0);
 }
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
index d28e26c0a..592cd4c42 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp
@@ -14,12 +14,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/admin_log/history_admin_log_section.h"
 #include "history/admin_log/history_admin_log_filter.h"
 #include "history/view/history_view_service_message.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "chat_helpers/message_field.h"
 #include "mainwindow.h"
 #include "mainwidget.h"
 #include "messenger.h"
 #include "apiwrap.h"
+#include "layout.h"
 #include "window/window_controller.h"
 #include "auth_session.h"
 #include "ui/widgets/popup_menu.h"
@@ -115,7 +116,7 @@ void InnerWidget::enumerateUserpics(Method method) {
 	// -1 means we didn't find an attached to next message yet.
 	int lowestAttachedItemTop = -1;
 
-	auto userpicCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto userpicCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		// Skip all service messages.
 		const auto message = view->data()->toHistoryMessage();
 		if (!message) return true;
@@ -161,7 +162,7 @@ void InnerWidget::enumerateDates(Method method) {
 	// -1 means we didn't find a same-day with previous message yet.
 	auto lowestInOneDayItemBottom = -1;
 
-	auto dateCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto dateCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		const auto item = view->data();
 		if (lowestInOneDayItemBottom < 0 && item->isInOneDayWithPrevious()) {
 			lowestInOneDayItemBottom = itembottom - item->marginBottom();
@@ -527,18 +528,25 @@ void InnerWidget::addEvents(Direction direction, const QVector<MTPChannelAdminLo
 	addToItems.reserve(oldItemsCount + events.size() * 2);
 	for_const (auto &event, events) {
 		Assert(event.type() == mtpc_channelAdminLogEvent);
-		auto &data = event.c_channelAdminLogEvent();
-		if (_itemsByIds.find(data.vid.v) != _itemsByIds.cend()) {
+		const auto &data = event.c_channelAdminLogEvent();
+		const auto id = data.vid.v;
+		if (_itemsByIds.find(id) != _itemsByIds.cend()) {
 			continue;
 		}
 
 		auto count = 0;
-		GenerateItems(_history, _idManager, data, [this, id = data.vid.v, &addToItems, &count](OwnedItem item) {
+		const auto addOne = [&](OwnedItem item) {
 			_itemsByIds.emplace(id, item.get());
 			_itemsByData.emplace(item->data(), item.get());
 			addToItems.push_back(std::move(item));
 			++count;
-		});
+		};
+		GenerateItems(
+			_controller,
+			_history,
+			_idManager,
+			data,
+			addOne);
 		if (count > 1) {
 			// Reverse the inner order of the added messages, because we load events
 			// from bottom to top but inside one event they go from top to bottom.
@@ -659,7 +667,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
 			}
 			p.translate(0, -top);
 
-			enumerateUserpics([&](not_null<Message*> view, int userpicTop) {
+			enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
 				// stop the enumeration if the userpic is below the painted rect
 				if (userpicTop >= clip.top() + clip.height()) {
 					return false;
@@ -677,7 +685,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
 
 			auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
 			auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
-			enumerateDates([&](not_null<Message*> view, int itemtop, int dateTop) {
+			enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
 				// stop the enumeration if the date is above the painted rect
 				if (dateTop + dateHeight <= clip.top()) {
 					return false;
@@ -737,7 +745,7 @@ void InnerWidget::clearAfterFilterChange() {
 	updateSize();
 }
 
-auto InnerWidget::viewForItem(const HistoryItem *item) -> Message* {
+auto InnerWidget::viewForItem(const HistoryItem *item) -> Element* {
 	if (item) {
 		const auto i = _itemsByData.find(item);
 		if (i != _itemsByData.end()) {
@@ -1359,7 +1367,7 @@ void InnerWidget::updateSelected() {
 		if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) {
 			if (auto message = item->toHistoryMessage()) {
 				if (message->hasFromPhoto()) {
-					enumerateUserpics([&](not_null<Message*> view, int userpicTop) {
+					enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
 						// stop enumeration if the userpic is below our point
 						if (userpicTop > point.y()) {
 							return false;
@@ -1541,18 +1549,18 @@ void InnerWidget::performDrag() {
 	//} // TODO
 }
 
-int InnerWidget::itemTop(not_null<const Message*> item) const {
-	return _itemsTop + item->y();
+int InnerWidget::itemTop(not_null<const Element*> view) const {
+	return _itemsTop + view->y();
 }
 
-void InnerWidget::repaintItem(const Message *item) {
-	if (!item) {
+void InnerWidget::repaintItem(const Element *view) {
+	if (!view) {
 		return;
 	}
-	update(0, itemTop(item), width(), item->data()->height());
+	update(0, itemTop(view), width(), view->data()->height());
 }
 
-QPoint InnerWidget::mapPointToItem(QPoint point, const Message *view) const {
+QPoint InnerWidget::mapPointToItem(QPoint point, const Element *view) const {
 	if (!view) {
 		return QPoint();
 	}
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h
index 39b706fbc..152164e70 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "history/view/history_view_cursor_state.h"
 #include "history/admin_log/history_admin_log_item.h"
 #include "history/admin_log/history_admin_log_section.h"
 #include "ui/widgets/tooltip.h"
@@ -23,7 +24,7 @@ class Controller;
 } // namespace Window
 
 namespace HistoryView {
-class Message;
+class Element;
 } // namespace HistoryView
 
 namespace AdminLog {
@@ -90,7 +91,7 @@ protected:
 	int resizeGetHeight(int newWidth) override;
 
 private:
-	using Message = HistoryView::Message;
+	using Element = HistoryView::Element;
 	enum class Direction {
 		Up,
 		Down,
@@ -112,9 +113,9 @@ private:
 	void mouseActionCancel();
 	void updateSelected();
 	void performDrag();
-	int itemTop(not_null<const Message*> item) const;
-	void repaintItem(const Message *item);
-	QPoint mapPointToItem(QPoint point, const Message *item) const;
+	int itemTop(not_null<const Element*> view) const;
+	void repaintItem(const Element *view);
+	QPoint mapPointToItem(QPoint point, const Element *view) const;
 	void handlePendingHistoryResize();
 
 	void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
@@ -146,7 +147,7 @@ private:
 	void clearAfterFilterChange();
 	void clearAndRequestLog();
 	void addEvents(Direction direction, const QVector<MTPChannelAdminLogEvent> &events);
-	Message *viewForItem(const HistoryItem *item);
+	Element *viewForItem(const HistoryItem *item);
 
 	void toggleScrollDateShown();
 	void repaintScrollDateCallback();
@@ -158,7 +159,7 @@ private:
 	// This function finds all history items that are displayed and calls template method
 	// for each found message (in given direction) in the passed history with passed top offset.
 	//
-	// Method has "bool (*Method)(Message *item, int itemtop, int itembottom)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
 	// if it returns false the enumeration stops immidiately.
 	template <EnumItemsDirection direction, typename Method>
 	void enumerateItems(Method method);
@@ -166,7 +167,7 @@ private:
 	// This function finds all userpics on the left that are displayed and calls template method
 	// for each found userpic (from the top to the bottom) using enumerateItems() method.
 	//
-	// Method has "bool (*Method)(not_null<HistoryMessage*> message, int userpicTop)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
 	// if it returns false the enumeration stops immidiately.
 	template <typename Method>
 	void enumerateUserpics(Method method);
@@ -183,8 +184,8 @@ private:
 	not_null<ChannelData*> _channel;
 	not_null<History*> _history;
 	std::vector<OwnedItem> _items;
-	std::map<uint64, not_null<Message*>> _itemsByIds;
-	std::map<not_null<HistoryItem*>, not_null<Message*>, std::less<>> _itemsByData;
+	std::map<uint64, not_null<Element*>> _itemsByIds;
+	std::map<not_null<HistoryItem*>, not_null<Element*>, std::less<>> _itemsByData;
 	int _itemsTop = 0;
 	int _itemsHeight = 0;
 
@@ -192,14 +193,14 @@ private:
 	int _minHeight = 0;
 	int _visibleTop = 0;
 	int _visibleBottom = 0;
-	Message *_visibleTopItem = nullptr;
+	Element *_visibleTopItem = nullptr;
 	int _visibleTopFromItem = 0;
 
 	bool _scrollDateShown = false;
 	Animation _scrollDateOpacity;
 	SingleQueuedInvokation _scrollDateCheck;
 	base::Timer _scrollDateHideTimer;
-	Message *_scrollDateLastItem = nullptr;
+	Element *_scrollDateLastItem = nullptr;
 	int _scrollDateLastItemTop = 0;
 
 	// Up - max, Down - min.
@@ -218,12 +219,12 @@ private:
 	TextSelectType _mouseSelectType = TextSelectType::Letters;
 	QPoint _dragStartPosition;
 	QPoint _mousePosition;
-	Message *_mouseActionItem = nullptr;
+	Element *_mouseActionItem = nullptr;
 	HistoryCursorState _mouseCursorState = HistoryDefaultCursorState;
 	uint16 _mouseTextSymbol = 0;
 	bool _pressWasInactive = false;
 
-	Message *_selectedItem = nullptr;
+	Element *_selectedItem = nullptr;
 	TextSelection _selectedText;
 	bool _wasSelectedText = false; // was some text selected in current drag action
 	Qt::CursorShape _cursor = style::cur_default;
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
index f3701f0da..c481ab3b3 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/admin_log/history_admin_log_item.h"
 
 #include "history/admin_log/history_admin_log_inner.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "history/history_service.h"
 #include "history/history_message.h"
 #include "lang/lang_keys.h"
@@ -282,11 +282,11 @@ TextWithEntities GenerateParticipantChangeText(not_null<ChannelData*> channel, c
 
 } // namespace
 
-OwnedItem::OwnedItem(not_null<HistoryItem*> data)
+OwnedItem::OwnedItem(
+	not_null<Window::Controller*> controller,
+	not_null<HistoryItem*> data)
 : _data(data)
-, _view(std::make_unique<HistoryView::Message>(
-	data,
-	HistoryView::Context::AdminLog)) {
+, _view(_data->createView(controller, HistoryView::Context::AdminLog)) {
 }
 
 OwnedItem::OwnedItem(OwnedItem &&other)
@@ -307,7 +307,12 @@ OwnedItem::~OwnedItem() {
 	}
 }
 
-void GenerateItems(not_null<History*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda<void(OwnedItem item)> callback) {
+void GenerateItems(
+		not_null<Window::Controller*> controller,
+		not_null<History*> history,
+		LocalIdManager &idManager,
+		const MTPDchannelAdminLogEvent &event,
+		base::lambda<void(OwnedItem item)> callback) {
 	Expects(history->peer->isChannel());
 
 	auto id = event.vid.v;
@@ -315,8 +320,8 @@ void GenerateItems(not_null<History*> history, LocalIdManager &idManager, const
 	auto channel = history->peer->asChannel();
 	auto &action = event.vaction;
 	auto date = event.vdate;
-	auto addPart = [&callback](not_null<HistoryItem*> item) {
-		return callback(OwnedItem(item));
+	auto addPart = [&](not_null<HistoryItem*> item) {
+		return callback(OwnedItem(controller, item));
 	};
 
 	using Flag = MTPDmessage::Flag;
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h
index 6531250c4..245f3b251 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h
@@ -7,36 +7,51 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+namespace Window {
+class Controller;
+} // namespace Window
+
+namespace HistoryView {
+class Element;
+} // namespace HistoryView
+
 namespace AdminLog {
 
 class OwnedItem;
 class LocalIdManager;
 
-void GenerateItems(not_null<History*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda<void(OwnedItem item)> callback);
+void GenerateItems(
+	not_null<Window::Controller*> controller,
+	not_null<History*> history,
+	LocalIdManager &idManager,
+	const MTPDchannelAdminLogEvent &event,
+	base::lambda<void(OwnedItem item)> callback);
 
 // Smart pointer wrapper for HistoryItem* that destroys the owned item.
 class OwnedItem {
 public:
-	explicit OwnedItem(not_null<HistoryItem*> data);
+	OwnedItem(
+		not_null<Window::Controller*> controller,
+		not_null<HistoryItem*> data);
 	OwnedItem(const OwnedItem &other) = delete;
 	OwnedItem &operator=(const OwnedItem &other) = delete;
 	OwnedItem(OwnedItem &&other);
 	OwnedItem &operator=(OwnedItem &&other);
 	~OwnedItem();
 
-	HistoryView::Message *get() const {
+	HistoryView::Element *get() const {
 		return _view.get();
 	}
-	HistoryView::Message *operator->() const {
+	HistoryView::Element *operator->() const {
 		return get();
 	}
-	operator HistoryView::Message*() const {
+	operator HistoryView::Element*() const {
 		return get();
 	}
 
 private:
 	HistoryItem *_data = nullptr;
-	std::unique_ptr<HistoryView::Message> _view;
+	std::unique_ptr<HistoryView::Element> _view;
 
 };
 
diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h
index 31c493f19..1f5d8a757 100644
--- a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h
+++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.h
@@ -123,7 +123,7 @@ private:
 
 class SectionMemento : public Window::SectionMemento {
 public:
-	using Message = HistoryView::Message;
+	using Element = HistoryView::Element;
 
 	SectionMemento(not_null<ChannelData*> channel) : _channel(channel) {
 	}
@@ -159,7 +159,7 @@ public:
 
 	void setItems(
 			std::vector<OwnedItem> &&items,
-			std::map<uint64, not_null<Message*>> &&itemsByIds,
+			std::map<uint64, not_null<Element*>> &&itemsByIds,
 			bool upLoaded,
 			bool downLoaded) {
 		_items = std::move(items);
@@ -179,7 +179,7 @@ public:
 	std::vector<OwnedItem> takeItems() {
 		return std::move(_items);
 	}
-	std::map<uint64, not_null<Message*>> takeItemsByIds() {
+	std::map<uint64, not_null<Element*>> takeItemsByIds() {
 		return std::move(_itemsByIds);
 	}
 	LocalIdManager takeIdManager() {
@@ -204,7 +204,7 @@ private:
 	std::vector<not_null<UserData*>> _admins;
 	std::vector<not_null<UserData*>> _adminsCanEdit;
 	std::vector<OwnedItem> _items;
-	std::map<uint64, not_null<Message*>> _itemsByIds;
+	std::map<uint64, not_null<Element*>> _itemsByIds;
 	bool _upLoaded = false;
 	bool _downLoaded = true;
 	LocalIdManager _idManager;
diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp
index c1989bb23..f46363c69 100644
--- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp
+++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp
@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "history/view/history_view_top_bar_widget.h"
 #include "history/view/history_view_list_widget.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "lang/lang_keys.h"
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/shadow.h"
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index c6568788a..e58327acf 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #include "history/history.h"
 
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "history/history_message.h"
 #include "history/history_media_types.h"
 #include "history/history_service.h"
@@ -1388,8 +1388,8 @@ void History::addItemToBlock(not_null<HistoryItem*> item) {
 
 	auto block = prepareBlockForAddingItem();
 
-	block->messages.push_back(std::make_unique<HistoryView::Message>(
-		item,
+	block->messages.push_back(item->createView(
+		App::wnd()->controller(),
 		HistoryView::Context::History));
 	block->messages.back()->attachToBlock(block, block->messages.size() - 1);
 	item->previousItemChanged();
@@ -1965,8 +1965,8 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
 
 	const auto it = block->messages.insert(
 		block->messages.begin() + itemIndex,
-		std::make_unique<HistoryView::Message>(
-			newItem,
+		newItem->createView(
+			App::wnd()->controller(),
 			HistoryView::Context::History));
 	(*it)->attachToBlock(block.get(), itemIndex);
 	newItem->previousItemChanged();
@@ -2566,7 +2566,7 @@ void HistoryBlock::clear(bool leaveItems) {
 	// #TODO feeds delete all items in history
 }
 
-void HistoryBlock::remove(not_null<Message*> view) {
+void HistoryBlock::remove(not_null<Element*> view) {
 	Expects(view->block() == this);
 
 	const auto item = view->data();
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index f28c5c3b6..f563fc430 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -28,7 +28,7 @@ enum NewMessageType {
 };
 
 namespace HistoryView {
-class Message;
+class Element;
 } // namespace HistoryView
 
 class Histories {
@@ -397,7 +397,7 @@ public:
 	// we save a pointer of the history item at the top of the displayed window
 	// together with an offset from the window top to the top of this message
 	// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
-	HistoryView::Message *scrollTopItem = nullptr;
+	HistoryView::Element *scrollTopItem = nullptr;
 	int scrollTopOffset = 0;
 	void forgetScrollState() {
 		scrollTopItem = nullptr;
@@ -579,17 +579,17 @@ private:
 
 class HistoryBlock {
 public:
-	using Message = HistoryView::Message;
+	using Element = HistoryView::Element;
 
 	HistoryBlock(not_null<History*> history);
 	HistoryBlock(const HistoryBlock &) = delete;
 	HistoryBlock &operator=(const HistoryBlock &) = delete;
 	~HistoryBlock();
 
-	std::vector<std::unique_ptr<Message>> messages;
+	std::vector<std::unique_ptr<Element>> messages;
 
 	void clear(bool leaveItems = false);
-	void remove(not_null<Message*> view);
+	void remove(not_null<Element*> view);
 
 	int resizeGetHeight(int newWidth, bool resizeAllItems);
 	int y() const {
diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index 4d3e0213c..4d85dfeec 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_media_types.h"
 #include "history/history_item_components.h"
 #include "history/view/history_view_service_message.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "ui/text_options.h"
 #include "ui/widgets/popup_menu.h"
 #include "window/window_controller.h"
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_widget.h"
 #include "mainwindow.h"
 #include "mainwidget.h"
+#include "layout.h"
 #include "auth_session.h"
 #include "messenger.h"
 #include "apiwrap.h"
@@ -193,7 +194,7 @@ void HistoryInner::repaintItem(const HistoryItem *item) {
 	}
 }
 
-void HistoryInner::repaintItem(const Message *view) {
+void HistoryInner::repaintItem(const Element *view) {
 	if (view) {
 		const auto top = itemTop(view);
 		if (top >= 0) {
@@ -303,7 +304,7 @@ void HistoryInner::enumerateUserpics(Method method) {
 	// -1 means we didn't find an attached to next message yet.
 	int lowestAttachedItemTop = -1;
 
-	auto userpicCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto userpicCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		// Skip all service messages.
 		const auto item = view->data();
 		const auto message = item->toHistoryMessage();
@@ -352,7 +353,7 @@ void HistoryInner::enumerateDates(Method method) {
 	// -1 means we didn't find a same-day with previous message yet.
 	auto lowestInOneDayItemBottom = -1;
 
-	auto dateCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto dateCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		const auto item = view->data();
 		if (lowestInOneDayItemBottom < 0 && item->isInOneDayWithPrevious()) {
 			lowestInOneDayItemBottom = itembottom - item->marginBottom();
@@ -440,7 +441,7 @@ TextSelection HistoryInner::computeRenderSelection(
 }
 
 TextSelection HistoryInner::itemRenderSelection(
-		not_null<Message*> view,
+		not_null<Element*> view,
 		int selfromy,
 		int seltoy) const {
 	const auto item = view->data();
@@ -598,7 +599,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 		}
 
 		if (mtop >= 0 || htop >= 0) {
-			enumerateUserpics([&](not_null<Message*> view, int userpicTop) {
+			enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
 				// stop the enumeration if the userpic is below the painted rect
 				if (userpicTop >= clip.top() + clip.height()) {
 					return false;
@@ -627,7 +628,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 			//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
 
 			auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
-			enumerateDates([&](not_null<Message*> view, int itemtop, int dateTop) {
+			enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
 				// stop the enumeration if the date is above the painted rect
 				if (dateTop + dateHeight <= clip.top()) {
 					return false;
@@ -883,7 +884,7 @@ void HistoryInner::touchScrollUpdated(const QPoint &screenPos) {
 	touchUpdateSpeed();
 }
 
-QPoint HistoryInner::mapPointToItem(QPoint p, const Message *view) {
+QPoint HistoryInner::mapPointToItem(QPoint p, const Element *view) {
 	if (view) {
 		const auto top = itemTop(view);
 		p.setY(p.y() - top);
@@ -2109,7 +2110,7 @@ void HistoryInner::adjustCurrent(int32 y, History *history) const {
 	}
 }
 
-HistoryView::Message *HistoryInner::prevItem(Message *view) {
+auto HistoryInner::prevItem(Element *view) -> Element* {
 	if (!view) {
 		return nullptr;
 	} else if (const auto result = view->previousInBlocks()) {
@@ -2124,7 +2125,7 @@ HistoryView::Message *HistoryInner::prevItem(Message *view) {
 	return nullptr;
 }
 
-HistoryView::Message *HistoryInner::nextItem(Message *view) {
+auto HistoryInner::nextItem(Element *view) -> Element* {
 	if (!view) {
 		return nullptr;
 	} else if (const auto result = view->nextInBlocks()) {
@@ -2225,7 +2226,7 @@ void HistoryInner::onUpdateSelected() {
 
 	auto block = (HistoryBlock*)nullptr;
 	auto item = (HistoryItem*)nullptr;
-	auto view = (Message*)nullptr;
+	auto view = (Element*)nullptr;
 	QPoint m;
 
 	adjustCurrent(point.y());
@@ -2277,7 +2278,7 @@ void HistoryInner::onUpdateSelected() {
 
 		auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
 		auto scrollDateOpacity = _scrollDateOpacity.current(_scrollDateShown ? 1. : 0.);
-		enumerateDates([&](not_null<Message*> view, int itemtop, int dateTop) {
+		enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
 			// stop enumeration if the date is above our point
 			if (dateTop + dateHeight <= point.y()) {
 				return false;
@@ -2341,7 +2342,7 @@ void HistoryInner::onUpdateSelected() {
 			if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) {
 				if (auto msg = item->toHistoryMessage()) {
 					if (msg->hasFromPhoto()) {
-						enumerateUserpics([&](not_null<Message*> view, int userpicTop) -> bool {
+						enumerateUserpics([&](not_null<Element*> view, int userpicTop) -> bool {
 							// stop enumeration if the userpic is below our point
 							if (userpicTop > point.y()) {
 								return false;
@@ -2490,7 +2491,7 @@ void HistoryInner::onUpdateSelected() {
 	}
 }
 
-void HistoryInner::updateDragSelection(Message *dragSelFrom, Message *dragSelTo, bool dragSelecting) {
+void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo, bool dragSelecting) {
 	if (_dragSelFrom == dragSelFrom && _dragSelTo == dragSelTo && _dragSelecting == dragSelecting) {
 		return;
 	}
@@ -2552,7 +2553,7 @@ int HistoryInner::itemTop(const HistoryItem *item) const {
 	return itemTop(item->mainView());
 }
 
-int HistoryInner::itemTop(const Message *view) const {
+int HistoryInner::itemTop(const Element *view) const {
 	if (!view) {
 		return -1;
 	}
diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h
index f79c999fe..e9d2ec435 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.h
+++ b/Telegram/SourceFiles/history/history_inner_widget.h
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/rp_widget.h"
 #include "ui/widgets/tooltip.h"
 #include "ui/widgets/scroll_area.h"
+#include "history/view/history_view_cursor_state.h"
 #include "history/view/history_view_top_bar_widget.h"
 
 namespace Window {
@@ -28,7 +29,7 @@ class HistoryInner
 	Q_OBJECT
 
 public:
-	using Message = HistoryView::Message;
+	using Element = HistoryView::Element;
 
 	HistoryInner(
 		not_null<HistoryWidget*> historyWidget,
@@ -47,7 +48,7 @@ public:
 	void updateSize();
 
 	void repaintItem(const HistoryItem *item);
-	void repaintItem(const Message *view);
+	void repaintItem(const Element *view);
 
 	bool canCopySelected() const;
 	bool canDeleteSelected() const;
@@ -73,7 +74,7 @@ public:
 
 	// -1 if should not be visible, -2 if bad history()
 	int itemTop(const HistoryItem *item) const;
-	int itemTop(const Message *view) const;
+	int itemTop(const Element *view) const;
 
 	void notifyIsBotChanged();
 	void notifyMigrateUpdated();
@@ -140,7 +141,7 @@ private:
 	// This function finds all history items that are displayed and calls template method
 	// for each found message (in given direction) in the passed history with passed top offset.
 	//
-	// Method has "bool (*Method)(not_null<Message*> view, int itemtop, int itembottom)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
 	// if it returns false the enumeration stops immidiately.
 	template <bool TopToBottom, typename Method>
 	void enumerateItemsInHistory(History *history, int historytop, Method method);
@@ -160,7 +161,7 @@ private:
 	// This function finds all userpics on the left that are displayed and calls template method
 	// for each found userpic (from the top to the bottom) using enumerateItems() method.
 	//
-	// Method has "bool (*Method)(not_null<Message*> view, int userpicTop)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
 	// if it returns false the enumeration stops immidiately.
 	template <typename Method>
 	void enumerateUserpics(Method method);
@@ -168,7 +169,7 @@ private:
 	// This function finds all date elements that are displayed and calls template method
 	// for each found date element (from the bottom to the top) using enumerateItems() method.
 	//
-	// Method has "bool (*Method)(not_null<Message*> view, int itemtop, int dateTop)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int dateTop)" signature
 	// if it returns false the enumeration stops immidiately.
 	template <typename Method>
 	void enumerateDates(Method method);
@@ -179,7 +180,7 @@ private:
 	void mouseActionCancel();
 	void performDrag();
 
-	QPoint mapPointToItem(QPoint p, const Message *view);
+	QPoint mapPointToItem(QPoint p, const Element *view);
 	QPoint mapPointToItem(QPoint p, const HistoryItem *item);
 
 	void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
@@ -202,11 +203,11 @@ private:
 
 	void adjustCurrent(int32 y) const;
 	void adjustCurrent(int32 y, History *history) const;
-	Message *prevItem(Message *item);
-	Message *nextItem(Message *item);
-	void updateDragSelection(Message *dragSelFrom, Message *dragSelTo, bool dragSelecting);
+	Element *prevItem(Element *item);
+	Element *nextItem(Element *item);
+	void updateDragSelection(Element *dragSelFrom, Element *dragSelTo, bool dragSelecting);
 	TextSelection itemRenderSelection(
-		not_null<Message*> view,
+		not_null<Element*> view,
 		int selfromy,
 		int seltoy) const;
 	TextSelection computeRenderSelection(
@@ -305,8 +306,8 @@ private:
 
 	ClickHandlerPtr _contextMenuLink;
 
-	Message *_dragSelFrom = nullptr;
-	Message *_dragSelTo = nullptr;
+	Element *_dragSelFrom = nullptr;
+	Element *_dragSelTo = nullptr;
 	bool _dragSelecting = false;
 	bool _wasSelectedText = false; // was some text selected in current drag action
 
@@ -336,7 +337,7 @@ private:
 	Animation _scrollDateOpacity;
 	SingleQueuedInvokation _scrollDateCheck;
 	SingleTimer _scrollDateHideTimer;
-	Message *_scrollDateLastItem = nullptr;
+	Element *_scrollDateLastItem = nullptr;
 	int _scrollDateLastItemTop = 0;
 	ClickHandlerPtr _scrollDateLink;
 
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index cb6f1cda8..4479ccd0b 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "lang/lang_keys.h"
 #include "mainwidget.h"
-#include "history/view/history_view_message.h"
+#include "layout.h"
+#include "history/view/history_view_element.h"
 #include "history/view/history_view_service_message.h"
 #include "history/history_item_components.h"
 #include "history/history_media_types.h"
@@ -41,57 +42,6 @@ constexpr int kAttachMessageToPreviousSecondsDelta = 900;
 
 } // namespace
 
-HistoryTextState::HistoryTextState(not_null<const HistoryItem*> item)
-: itemId(item->fullId()) {
-}
-
-HistoryTextState::HistoryTextState(
-	not_null<const HistoryItem*> item,
-	const Text::StateResult &state)
-: itemId(item->fullId())
-, cursor(state.uponSymbol
-	? HistoryInTextCursorState
-	: HistoryDefaultCursorState)
-, link(state.link)
-, afterSymbol(state.afterSymbol)
-, symbol(state.symbol) {
-}
-
-HistoryTextState::HistoryTextState(
-	not_null<const HistoryItem*> item,
-	ClickHandlerPtr link)
-: itemId(item->fullId())
-, link(link) {
-}
-
-HistoryMediaPtr::HistoryMediaPtr() = default;
-
-HistoryMediaPtr::HistoryMediaPtr(std::unique_ptr<HistoryMedia> pointer)
-: _pointer(std::move(pointer)) {
-	if (_pointer) {
-		_pointer->attachToParent();
-	}
-}
-
-void HistoryMediaPtr::reset(std::unique_ptr<HistoryMedia> pointer) {
-	*this = std::move(pointer);
-}
-
-HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr<HistoryMedia> pointer) {
-	if (_pointer) {
-		_pointer->detachFromParent();
-	}
-	_pointer = std::move(pointer);
-	if (_pointer) {
-		_pointer->attachToParent();
-	}
-	return *this;
-}
-
-HistoryMediaPtr::~HistoryMediaPtr() {
-	reset();
-}
-
 namespace internal {
 
 TextSelection unshiftSelection(TextSelection selection, uint16 byLength) {
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index 02b8e4fd5..43adf25dd 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "base/runtime_composer.h"
 #include "base/flags.h"
 #include "base/value_ordering.h"
+#include "history/history_media_pointer.h"
+#include "history/view/history_view_cursor_state.h"
 
 struct MessageGroupId;
 struct HistoryMessageGroup;
@@ -41,6 +43,14 @@ namespace Data {
 struct MessagePosition;
 } // namespace Data
 
+namespace Window {
+class Controller;
+} // namespace Window
+
+namespace HistoryView {
+enum class Context : char;
+} // namespace HistoryView
+
 class HistoryElement {
 public:
 	HistoryElement() = default;
@@ -70,94 +80,6 @@ protected:
 
 };
 
-enum HistoryCursorState {
-	HistoryDefaultCursorState,
-	HistoryInTextCursorState,
-	HistoryInDateCursorState,
-	HistoryInForwardedCursorState,
-};
-
-struct HistoryTextState {
-	HistoryTextState() = default;
-	HistoryTextState(not_null<const HistoryItem*> item);
-	HistoryTextState(
-		not_null<const HistoryItem*> item,
-		const Text::StateResult &state);
-	HistoryTextState(
-		not_null<const HistoryItem*> item,
-		ClickHandlerPtr link);
-	HistoryTextState(
-		std::nullptr_t,
-		const Text::StateResult &state)
-	: cursor(state.uponSymbol
-		? HistoryInTextCursorState
-		: HistoryDefaultCursorState)
-	, link(state.link)
-	, afterSymbol(state.afterSymbol)
-	, symbol(state.symbol) {
-	}
-	HistoryTextState(std::nullptr_t, ClickHandlerPtr link)
-	: link(link) {
-	}
-
-	FullMsgId itemId;
-	HistoryCursorState cursor = HistoryDefaultCursorState;
-	ClickHandlerPtr link;
-	bool afterSymbol = false;
-	uint16 symbol = 0;
-
-};
-
-struct HistoryStateRequest {
-	Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink;
-	Text::StateRequest forText() const {
-		Text::StateRequest result;
-		result.flags = flags;
-		return result;
-	}
-};
-
-enum InfoDisplayType {
-	InfoDisplayDefault,
-	InfoDisplayOverImage,
-	InfoDisplayOverBackground,
-};
-
-// HistoryMedia has a special owning smart pointer
-// which regs/unregs this media to the holding HistoryItem
-class HistoryMediaPtr {
-public:
-	HistoryMediaPtr();
-	HistoryMediaPtr(const HistoryMediaPtr &other) = delete;
-	HistoryMediaPtr &operator=(const HistoryMediaPtr &other) = delete;
-	HistoryMediaPtr(std::unique_ptr<HistoryMedia> other);
-	HistoryMediaPtr &operator=(std::unique_ptr<HistoryMedia> other);
-
-	HistoryMedia *get() const {
-		return _pointer.get();
-	}
-	void reset(std::unique_ptr<HistoryMedia> pointer = nullptr);
-	bool isNull() const {
-		return !_pointer;
-	}
-
-	HistoryMedia *operator->() const {
-		return get();
-	}
-	HistoryMedia &operator*() const {
-		Expects(!isNull());
-		return *get();
-	}
-	explicit operator bool() const {
-		return !isNull();
-	}
-	~HistoryMediaPtr();
-
-private:
-	std::unique_ptr<HistoryMedia> _pointer;
-
-};
-
 namespace internal {
 
 TextSelection unshiftSelection(TextSelection selection, uint16 byLength);
@@ -229,10 +151,10 @@ public:
 	PeerData *from() const {
 		return _from;
 	}
-	HistoryView::Message *mainView() const {
+	HistoryView::Element *mainView() const {
 		return _mainView;
 	}
-	void setMainView(HistoryView::Message *view) {
+	void setMainView(HistoryView::Element *view) {
 		_mainView = view;
 	}
 	void clearMainView();
@@ -536,6 +458,10 @@ public:
 	HistoryItem *previousItem() const;
 	HistoryItem *nextItem() const;
 
+	virtual std::unique_ptr<HistoryView::Element> createView(
+		not_null<Window::Controller*> controller,
+		HistoryView::Context context) = 0;
+
 	~HistoryItem();
 
 protected:
@@ -616,7 +542,7 @@ protected:
 private:
 	void resetGroupMedia(const std::vector<not_null<HistoryItem*>> &others);
 
-	HistoryView::Message *_mainView = nullptr;
+	HistoryView::Element *_mainView = nullptr;
 
 };
 
diff --git a/Telegram/SourceFiles/history/history_media.h b/Telegram/SourceFiles/history/history_media.h
index 1ed783e4e..870dd3ad4 100644
--- a/Telegram/SourceFiles/history/history_media.h
+++ b/Telegram/SourceFiles/history/history_media.h
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "history/history_item.h"
+
 struct HistoryMessageEdited;
 
 namespace base {
diff --git a/Telegram/SourceFiles/history/history_media_grouped.cpp b/Telegram/SourceFiles/history/history_media_grouped.cpp
index 709495c8c..1bc53880b 100644
--- a/Telegram/SourceFiles/history/history_media_grouped.cpp
+++ b/Telegram/SourceFiles/history/history_media_grouped.cpp
@@ -10,12 +10,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_item_components.h"
 #include "history/history_media_types.h"
 #include "history/history_message.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "storage/storage_shared_media.h"
 #include "lang/lang_keys.h"
 #include "ui/grouped_layout.h"
 #include "ui/text_options.h"
 #include "styles/style_history.h"
+#include "layout.h"
 
 HistoryGroupedMedia::Element::Element(not_null<HistoryItem*> item)
 : item(item) {
diff --git a/Telegram/SourceFiles/history/history_media_pointer.cpp b/Telegram/SourceFiles/history/history_media_pointer.cpp
new file mode 100644
index 000000000..4f8167c54
--- /dev/null
+++ b/Telegram/SourceFiles/history/history_media_pointer.cpp
@@ -0,0 +1,38 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/history_media_pointer.h"
+
+#include "history/history_media.h"
+
+HistoryMediaPtr::HistoryMediaPtr() = default;
+
+HistoryMediaPtr::HistoryMediaPtr(std::unique_ptr<HistoryMedia> pointer)
+: _pointer(std::move(pointer)) {
+	if (_pointer) {
+		_pointer->attachToParent();
+	}
+}
+
+void HistoryMediaPtr::reset(std::unique_ptr<HistoryMedia> pointer) {
+	*this = std::move(pointer);
+}
+
+HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr<HistoryMedia> pointer) {
+	if (_pointer) {
+		_pointer->detachFromParent();
+	}
+	_pointer = std::move(pointer);
+	if (_pointer) {
+		_pointer->attachToParent();
+	}
+	return *this;
+}
+
+HistoryMediaPtr::~HistoryMediaPtr() {
+	reset();
+}
diff --git a/Telegram/SourceFiles/history/history_media_pointer.h b/Telegram/SourceFiles/history/history_media_pointer.h
new file mode 100644
index 000000000..01e4e4b69
--- /dev/null
+++ b/Telegram/SourceFiles/history/history_media_pointer.h
@@ -0,0 +1,45 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+class HistoryMedia;
+
+// HistoryMedia has a special owning smart pointer
+// which regs/unregs this media to the holding HistoryItem
+class HistoryMediaPtr {
+public:
+	HistoryMediaPtr();
+	HistoryMediaPtr(const HistoryMediaPtr &other) = delete;
+	HistoryMediaPtr &operator=(const HistoryMediaPtr &other) = delete;
+	HistoryMediaPtr(std::unique_ptr<HistoryMedia> other);
+	HistoryMediaPtr &operator=(std::unique_ptr<HistoryMedia> other);
+
+	HistoryMedia *get() const {
+		return _pointer.get();
+	}
+	void reset(std::unique_ptr<HistoryMedia> pointer = nullptr);
+	bool isNull() const {
+		return !_pointer;
+	}
+
+	HistoryMedia *operator->() const {
+		return get();
+	}
+	HistoryMedia &operator*() const {
+		Expects(!isNull());
+		return *get();
+	}
+	explicit operator bool() const {
+		return !isNull();
+	}
+	~HistoryMediaPtr();
+
+private:
+	std::unique_ptr<HistoryMedia> _pointer;
+
+};
diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp
index 77db04b08..9f0d03027 100644
--- a/Telegram/SourceFiles/history/history_media_types.cpp
+++ b/Telegram/SourceFiles/history/history_media_types.cpp
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "lang/lang_keys.h"
 #include "mainwidget.h"
+#include "layout.h"
 #include "mainwindow.h"
 #include "storage/localstorage.h"
 #include "storage/storage_shared_media.h"
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index 7a10ad738..223d786c0 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/toast/toast.h"
 #include "ui/text_options.h"
 #include "messenger.h"
+#include "layout.h"
 #include "styles/style_dialogs.h"
 #include "styles/style_widgets.h"
 #include "styles/style_history.h"
@@ -2407,7 +2408,7 @@ bool HistoryMessage::getStateForwardedInfo(
 		QPoint point,
 		QRect &trect,
 		not_null<HistoryTextState*> outResult,
-		const HistoryStateRequest &request) const {
+		HistoryStateRequest request) const {
 	if (displayForwardedFrom()) {
 		auto forwarded = Get<HistoryMessageForwarded>();
 		auto fwdheight = ((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
@@ -2472,7 +2473,7 @@ bool HistoryMessage::getStateText(
 		QPoint point,
 		QRect &trect,
 		not_null<HistoryTextState*> outResult,
-		const HistoryStateRequest &request) const {
+		HistoryStateRequest request) const {
 	if (trect.contains(point)) {
 		*outResult = HistoryTextState(this, _text.getState(
 			point - trect.topLeft(),
@@ -2537,6 +2538,12 @@ bool HistoryMessage::hasFromPhoto() const {
 	return !out() && !history()->peer->isUser();
 }
 
+std::unique_ptr<HistoryView::Element> HistoryMessage::createView(
+		not_null<Window::Controller*> controller,
+		HistoryView::Context context) {
+	return controller->createMessageView(this, context);
+}
+
 HistoryMessage::~HistoryMessage() {
 	_media.reset();
 	if (auto reply = Get<HistoryMessageReply>()) {
diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h
index 7dcae1064..3728cff7a 100644
--- a/Telegram/SourceFiles/history/history_message.h
+++ b/Telegram/SourceFiles/history/history_message.h
@@ -228,6 +228,10 @@ public:
 	bool displayFromPhoto() const;
 	bool hasFromPhoto() const;
 
+	std::unique_ptr<HistoryView::Element> createView(
+		not_null<Window::Controller*> controller,
+		HistoryView::Context context) override;
+
 	~HistoryMessage();
 
 protected:
@@ -324,7 +328,7 @@ private:
 		QPoint point,
 		QRect &trect,
 		not_null<HistoryTextState*> outResult,
-		const HistoryStateRequest &request) const;
+		HistoryStateRequest request) const;
 	bool getStateReplyInfo(
 		QPoint point,
 		QRect &trect,
@@ -337,7 +341,7 @@ private:
 		QPoint point,
 		QRect &trect,
 		not_null<HistoryTextState*> outResult,
-		const HistoryStateRequest &request) const;
+		HistoryStateRequest request) const;
 
 	void setMedia(const MTPMessageMedia *media);
 	void setReplyMarkup(const MTPReplyMarkup *markup);
diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp
index f787f6bf6..8907a6ba7 100644
--- a/Telegram/SourceFiles/history/history_service.cpp
+++ b/Telegram/SourceFiles/history/history_service.cpp
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "lang/lang_keys.h"
 #include "mainwidget.h"
 #include "apiwrap.h"
+#include "layout.h"
 #include "history/history_media_types.h"
 #include "history/history_message.h"
 #include "history/history_item_components.h"
@@ -17,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_feed.h"
 #include "auth_session.h"
 #include "window/notifications_manager.h"
+#include "window/window_controller.h"
 #include "storage/storage_shared_media.h"
 #include "ui/text_options.h"
 
@@ -476,6 +478,12 @@ QString HistoryService::inReplyText() const {
 	return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
 }
 
+std::unique_ptr<HistoryView::Element> HistoryService::createView(
+		not_null<Window::Controller*> controller,
+		HistoryView::Context context) {
+	return controller->createMessageView(this, context);
+}
+
 void HistoryService::setServiceText(const PreparedText &prepared) {
 	_text.setText(
 		st::serviceTextStyle,
diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h
index 0fb191b40..e20ea6faa 100644
--- a/Telegram/SourceFiles/history/history_service.h
+++ b/Telegram/SourceFiles/history/history_service.h
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "history/history_item.h"
+
 struct HistoryServiceDependentData {
 	MsgId msgId = 0;
 	HistoryItem *msg = nullptr;
@@ -103,6 +105,10 @@ public:
 	QString inDialogsText(DrawInDialog way) const override;
 	QString inReplyText() const override;
 
+	std::unique_ptr<HistoryView::Element> createView(
+		not_null<Window::Controller*> controller,
+		HistoryView::Context context) override;
+
 	~HistoryService();
 
 protected:
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index c03676083..6bbc4f48a 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -29,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_inner_widget.h"
 #include "history/history_item_components.h"
 #include "history/view/history_view_service_message.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "profile/profile_block_group_members.h"
 #include "info/info_memento.h"
 #include "core/click_handler_types.h"
diff --git a/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp b/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp
new file mode 100644
index 000000000..506edce2a
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp
@@ -0,0 +1,33 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/view/history_view_cursor_state.h"
+
+#include "history/history_item.h"
+
+HistoryTextState::HistoryTextState(not_null<const HistoryItem*> item)
+: itemId(item->fullId()) {
+}
+
+HistoryTextState::HistoryTextState(
+	not_null<const HistoryItem*> item,
+	const Text::StateResult &state)
+: itemId(item->fullId())
+, cursor(state.uponSymbol
+	? HistoryInTextCursorState
+	: HistoryDefaultCursorState)
+, link(state.link)
+, afterSymbol(state.afterSymbol)
+, symbol(state.symbol) {
+}
+
+HistoryTextState::HistoryTextState(
+	not_null<const HistoryItem*> item,
+	ClickHandlerPtr link)
+: itemId(item->fullId())
+, link(link) {
+}
diff --git a/Telegram/SourceFiles/history/view/history_view_cursor_state.h b/Telegram/SourceFiles/history/view/history_view_cursor_state.h
new file mode 100644
index 000000000..d220d113a
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/history_view_cursor_state.h
@@ -0,0 +1,63 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+class HistoryItem;
+
+enum HistoryCursorState {
+	HistoryDefaultCursorState,
+	HistoryInTextCursorState,
+	HistoryInDateCursorState,
+	HistoryInForwardedCursorState,
+};
+
+struct HistoryTextState {
+	HistoryTextState() = default;
+	HistoryTextState(not_null<const HistoryItem*> item);
+	HistoryTextState(
+		not_null<const HistoryItem*> item,
+		const Text::StateResult &state);
+	HistoryTextState(
+		not_null<const HistoryItem*> item,
+		ClickHandlerPtr link);
+	HistoryTextState(
+		std::nullptr_t,
+		const Text::StateResult &state)
+	: cursor(state.uponSymbol
+		? HistoryInTextCursorState
+		: HistoryDefaultCursorState)
+	, link(state.link)
+	, afterSymbol(state.afterSymbol)
+	, symbol(state.symbol) {
+	}
+	HistoryTextState(std::nullptr_t, ClickHandlerPtr link)
+	: link(link) {
+	}
+
+	FullMsgId itemId;
+	HistoryCursorState cursor = HistoryDefaultCursorState;
+	ClickHandlerPtr link;
+	bool afterSymbol = false;
+	uint16 symbol = 0;
+
+};
+
+struct HistoryStateRequest {
+	Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink;
+	Text::StateRequest forText() const {
+		Text::StateRequest result;
+		result.flags = flags;
+		return result;
+	}
+};
+
+enum InfoDisplayType {
+	InfoDisplayDefault,
+	InfoDisplayOverImage,
+	InfoDisplayOverBackground,
+};
diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp
new file mode 100644
index 000000000..36ae4f6a6
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/history_view_element.cpp
@@ -0,0 +1,104 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/view/history_view_element.h"
+
+#include "history/history_item_components.h"
+#include "history/history_media.h"
+#include "data/data_session.h"
+#include "auth_session.h"
+
+namespace HistoryView {
+
+Element::Element(not_null<HistoryItem*> data, Context context)
+: _data(data)
+, _context(context) {
+}
+
+not_null<HistoryItem*> Element::data() const {
+	return _data;
+}
+
+void Element::attachToBlock(not_null<HistoryBlock*> block, int index) {
+	Expects(!_data->isLogEntry());
+	Expects(_block == nullptr);
+	Expects(_indexInBlock < 0);
+	Expects(index >= 0);
+
+	_block = block;
+	_indexInBlock = index;
+	_data->setMainView(this);
+	_data->setPendingResize();
+}
+
+void Element::removeFromBlock() {
+	Expects(_block != nullptr);
+
+	_block->remove(this);
+}
+
+Element *Element::previousInBlocks() const {
+	if (_block && _indexInBlock >= 0) {
+		if (_indexInBlock > 0) {
+			return _block->messages[_indexInBlock - 1].get();
+		}
+		if (auto previous = _block->previousBlock()) {
+			Assert(!previous->messages.empty());
+			return previous->messages.back().get();
+		}
+	}
+	return nullptr;
+}
+
+Element *Element::nextInBlocks() const {
+	if (_block && _indexInBlock >= 0) {
+		if (_indexInBlock + 1 < _block->messages.size()) {
+			return _block->messages[_indexInBlock + 1].get();
+		}
+		if (auto next = _block->nextBlock()) {
+			Assert(!next->messages.empty());
+			return next->messages.front().get();
+		}
+	}
+	return nullptr;
+}
+
+void Element::clickHandlerActiveChanged(
+		const ClickHandlerPtr &handler,
+		bool active) {
+	if (const auto markup = _data->Get<HistoryMessageReplyMarkup>()) {
+		if (const auto keyboard = markup->inlineKeyboard.get()) {
+			keyboard->clickHandlerActiveChanged(handler, active);
+		}
+	}
+	App::hoveredLinkItem(active ? this : nullptr);
+	Auth().data().requestItemRepaint(_data);
+	if (const auto media = _data->getMedia()) {
+		media->clickHandlerActiveChanged(handler, active);
+	}
+}
+
+void Element::clickHandlerPressedChanged(
+		const ClickHandlerPtr &handler,
+		bool pressed) {
+	if (const auto markup = _data->Get<HistoryMessageReplyMarkup>()) {
+		if (const auto keyboard = markup->inlineKeyboard.get()) {
+			keyboard->clickHandlerPressedChanged(handler, pressed);
+		}
+	}
+	App::pressedLinkItem(pressed ? this : nullptr);
+	Auth().data().requestItemRepaint(_data);
+	if (const auto media = _data->getMedia()) {
+		media->clickHandlerPressedChanged(handler, pressed);
+	}
+}
+
+Element::~Element() {
+	App::messageViewDestroyed(this);
+}
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h
new file mode 100644
index 000000000..927818b9e
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/history_view_element.h
@@ -0,0 +1,80 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "base/runtime_composer.h"
+
+class HistoryItem;
+
+namespace HistoryView {
+
+enum class Context : char {
+	History,
+	Feed,
+	AdminLog
+};
+
+class Element
+	: public RuntimeComposer
+	, public ClickHandlerHost {
+public:
+	Element(not_null<HistoryItem*> data, Context context);
+
+	not_null<HistoryItem*> data() const;
+
+	int y() const {
+		return _y;
+	}
+	void setY(int y) {
+		_y = y;
+	}
+
+	HistoryBlock *block() {
+		return _block;
+	}
+	const HistoryBlock *block() const {
+		return _block;
+	}
+	void attachToBlock(not_null<HistoryBlock*> block, int index);
+	void removeFromBlock();
+	void setIndexInBlock(int index) {
+		Expects(_block != nullptr);
+		Expects(index >= 0);
+
+		_indexInBlock = index;
+	}
+	int indexInBlock() const {
+		Expects((_indexInBlock >= 0) == (_block != nullptr));
+		Expects((_block == nullptr) || (_block->messages[_indexInBlock].get() == this));
+
+		return _indexInBlock;
+	}
+	Element *previousInBlocks() const;
+	Element *nextInBlocks() const;
+
+	// ClickHandlerHost interface
+	void clickHandlerActiveChanged(
+		const ClickHandlerPtr &handler,
+		bool active) override;
+	void clickHandlerPressedChanged(
+		const ClickHandlerPtr &handler,
+		bool pressed) override;
+
+	virtual ~Element();
+
+private:
+	const not_null<HistoryItem*> _data;
+	int _y = 0;
+	Context _context;
+
+	HistoryBlock *_block = nullptr;
+	int _indexInBlock = -1;
+
+};
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
index da6b448ae..7c71d9910 100644
--- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
@@ -10,13 +10,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_media_types.h"
 #include "history/history_message.h"
 #include "history/history_item_components.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "history/view/history_view_service_message.h"
 #include "chat_helpers/message_field.h"
 #include "mainwindow.h"
 #include "mainwidget.h"
 #include "messenger.h"
 #include "apiwrap.h"
+#include "layout.h"
 #include "window/window_controller.h"
 #include "auth_session.h"
 #include "ui/widgets/popup_menu.h"
@@ -125,7 +126,7 @@ void ListWidget::enumerateUserpics(Method method) {
 	// -1 means we didn't find an attached to next message yet.
 	int lowestAttachedItemTop = -1;
 
-	auto userpicCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto userpicCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		// Skip all service messages.
 		auto message = view->data()->toHistoryMessage();
 		if (!message) return true;
@@ -171,7 +172,7 @@ void ListWidget::enumerateDates(Method method) {
 	// -1 means we didn't find a same-day with previous message yet.
 	auto lowestInOneDayItemBottom = -1;
 
-	auto dateCallback = [&](not_null<Message*> view, int itemtop, int itembottom) {
+	auto dateCallback = [&](not_null<Element*> view, int itemtop, int itembottom) {
 		const auto item = view->data();
 		if (lowestInOneDayItemBottom < 0 && item->isInOneDayWithPrevious()) {
 			lowestInOneDayItemBottom = itembottom - item->marginBottom();
@@ -288,7 +289,7 @@ void ListWidget::restoreScrollState() {
 	_scrollTopState = ScrollTopState();
 }
 
-Message *ListWidget::viewForItem(const HistoryItem *item) const {
+Element *ListWidget::viewForItem(const HistoryItem *item) const {
 	if (item) {
 		if (const auto i = _views.find(item); i != _views.end()) {
 			return i->second.get();
@@ -297,14 +298,14 @@ Message *ListWidget::viewForItem(const HistoryItem *item) const {
 	return nullptr;
 }
 
-not_null<Message*> ListWidget::enforceViewForItem(
+not_null<Element*> ListWidget::enforceViewForItem(
 		not_null<HistoryItem*> item) {
 	if (const auto view = viewForItem(item)) {
 		return view;
 	}
 	const auto [i, ok] = _views.emplace(
 		item,
-		std::make_unique<Message>(item, _context));
+		item->createView(_controller, _context));
 	return i->second.get();
 }
 
@@ -321,7 +322,7 @@ int ListWidget::findNearestItem(Data::MessagePosition position) const {
 	}
 	const auto after = ranges::find_if(
 		_items,
-		[&](not_null<Message*> view) {
+		[&](not_null<Element*> view) {
 			return (view->data()->position() >= position);
 		});
 	return (after == end(_items))
@@ -435,7 +436,7 @@ void ListWidget::checkMoveToOtherViewer() {
 		- kPreloadIfLessThanScreens;
 	auto minUniversalIdDelta = (minScreenDelta * visibleHeight)
 		/ minItemHeight;
-	auto preloadAroundMessage = [&](not_null<Message*> view) {
+	auto preloadAroundMessage = [&](not_null<Element*> view) {
 		auto preloadRequired = false;
 		auto itemPosition = view->data()->position();
 		auto itemIndex = ranges::find(_items, view) - begin(_items);
@@ -586,7 +587,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
 		}
 		p.translate(0, -top);
 
-		enumerateUserpics([&](not_null<Message*> view, int userpicTop) {
+		enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
 			// stop the enumeration if the userpic is below the painted rect
 			if (userpicTop >= clip.top() + clip.height()) {
 				return false;
@@ -609,7 +610,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
 
 		auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
 		auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
-		enumerateDates([&](not_null<Message*> view, int itemtop, int dateTop) {
+		enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
 			// stop the enumeration if the date is above the painted rect
 			if (dateTop + dateHeight <= clip.top()) {
 				return false;
@@ -655,7 +656,7 @@ TextWithEntities ListWidget::getSelectedText() const {
 		: TextWithEntities();
 }
 
-not_null<Message*> ListWidget::findItemByY(int y) const {
+not_null<Element*> ListWidget::findItemByY(int y) const {
 	Expects(!_items.empty());
 
 	if (y < _itemsTop) {
@@ -671,7 +672,7 @@ not_null<Message*> ListWidget::findItemByY(int y) const {
 	return (i != end(_items)) ? i->get() : _items.back().get();
 }
 
-Message *ListWidget::strictFindItemByY(int y) const {
+Element *ListWidget::strictFindItemByY(int y) const {
 	if (_items.empty()) {
 		return nullptr;
 	}
@@ -1191,7 +1192,7 @@ void ListWidget::updateSelected() {
 		if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) {
 			if (auto message = item->toHistoryMessage()) {
 				if (message->hasFromPhoto()) {
-					enumerateUserpics([&](not_null<Message*> view, int userpicTop) -> bool {
+					enumerateUserpics([&](not_null<Element*> view, int userpicTop) -> bool {
 						// stop enumeration if the userpic is below our point
 						if (userpicTop > point.y()) {
 							return false;
@@ -1371,11 +1372,11 @@ void ListWidget::performDrag() {
 	//} // #TODO drag
 }
 
-int ListWidget::itemTop(not_null<const Message*> view) const {
+int ListWidget::itemTop(not_null<const Element*> view) const {
 	return _itemsTop + view->y();
 }
 
-void ListWidget::repaintItem(const Message *view) {
+void ListWidget::repaintItem(const Element *view) {
 	if (!view) {
 		return;
 	}
@@ -1384,7 +1385,7 @@ void ListWidget::repaintItem(const Message *view) {
 
 QPoint ListWidget::mapPointToItem(
 		QPoint point,
-		const Message *view) const {
+		const Element *view) const {
 	if (!view) {
 		return QPoint();
 	}
diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h
index cab38c6be..101073bee 100644
--- a/Telegram/SourceFiles/history/view/history_view_list_widget.h
+++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "mtproto/sender.h"
 #include "base/timer.h"
 #include "data/data_messages.h"
+#include "history/view/history_view_cursor_state.h"
 
 namespace Ui {
 class PopupMenu;
@@ -24,7 +25,7 @@ class Controller;
 namespace HistoryView {
 
 enum class Context : char;
-class Message;
+class Element;
 
 class ListDelegate {
 public:
@@ -142,8 +143,8 @@ private:
 	void saveScrollState();
 	void restoreScrollState();
 
-	Message *viewForItem(const HistoryItem *item) const;
-	not_null<Message*> enforceViewForItem(not_null<HistoryItem*> item);
+	Element *viewForItem(const HistoryItem *item) const;
+	not_null<Element*> enforceViewForItem(not_null<HistoryItem*> item);
 
 	void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
 	void mouseActionUpdate(const QPoint &screenPos);
@@ -151,9 +152,9 @@ private:
 	void mouseActionCancel();
 	void updateSelected();
 	void performDrag();
-	int itemTop(not_null<const Message*> view) const;
-	void repaintItem(const Message *view);
-	QPoint mapPointToItem(QPoint point, const Message *view) const;
+	int itemTop(not_null<const Element*> view) const;
+	void repaintItem(const Element *view);
+	QPoint mapPointToItem(QPoint point, const Element *view) const;
 	void handlePendingHistoryResize();
 
 	void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
@@ -172,8 +173,8 @@ private:
 		const TextWithEntities &forClipboard,
 		QClipboard::Mode mode = QClipboard::Clipboard);
 
-	not_null<Message*> findItemByY(int y) const;
-	Message *strictFindItemByY(int y) const;
+	not_null<Element*> findItemByY(int y) const;
+	Element *strictFindItemByY(int y) const;
 	int findNearestItem(Data::MessagePosition position) const;
 
 	void checkMoveToOtherViewer();
@@ -191,7 +192,7 @@ private:
 	// This function finds all history items that are displayed and calls template method
 	// for each found message (in given direction) in the passed history with passed top offset.
 	//
-	// Method has "bool (*Method)(Message *view, int itemtop, int itembottom)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
 	// if it returns false the enumeration stops immediately.
 	template <EnumItemsDirection direction, typename Method>
 	void enumerateItems(Method method);
@@ -199,7 +200,7 @@ private:
 	// This function finds all userpics on the left that are displayed and calls template method
 	// for each found userpic (from the top to the bottom) using enumerateItems() method.
 	//
-	// Method has "bool (*Method)(not_null<HistoryMessage*> message, int userpicTop)" signature
+	// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
 	// if it returns false the enumeration stops immediately.
 	template <typename Method>
 	void enumerateUserpics(Method method);
@@ -221,15 +222,15 @@ private:
 	int _aroundIndex = -1;
 	int _idsLimit = kMinimalIdsLimit;
 	Data::MessagesSlice _slice;
-	std::vector<not_null<Message*>> _items;
-	std::map<not_null<HistoryItem*>, std::unique_ptr<Message>, std::less<>> _views;
+	std::vector<not_null<Element*>> _items;
+	std::map<not_null<HistoryItem*>, std::unique_ptr<Element>, std::less<>> _views;
 	int _itemsTop = 0;
 	int _itemsHeight = 0;
 
 	int _minHeight = 0;
 	int _visibleTop = 0;
 	int _visibleBottom = 0;
-	Message *_visibleTopItem = nullptr;
+	Element *_visibleTopItem = nullptr;
 	int _visibleTopFromItem = 0;
 	ScrollTopState _scrollTopState;
 
@@ -237,19 +238,19 @@ private:
 	Animation _scrollDateOpacity;
 	SingleQueuedInvokation _scrollDateCheck;
 	base::Timer _scrollDateHideTimer;
-	Message *_scrollDateLastItem = nullptr;
+	Element *_scrollDateLastItem = nullptr;
 	int _scrollDateLastItemTop = 0;
 
 	MouseAction _mouseAction = MouseAction::None;
 	TextSelectType _mouseSelectType = TextSelectType::Letters;
 	QPoint _dragStartPosition;
 	QPoint _mousePosition;
-	Message *_mouseActionItem = nullptr;
+	Element *_mouseActionItem = nullptr;
 	HistoryCursorState _mouseCursorState = HistoryDefaultCursorState;
 	uint16 _mouseTextSymbol = 0;
 	bool _pressWasInactive = false;
 
-	Message *_selectedItem = nullptr;
+	Element *_selectedItem = nullptr;
 	TextSelection _selectedText;
 	bool _wasSelectedText = false; // was some text selected in current drag action
 	Qt::CursorShape _cursor = style::cur_default;
diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp
index 997f78f86..f7297c43b 100644
--- a/Telegram/SourceFiles/history/view/history_view_message.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_message.cpp
@@ -7,98 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #include "history/view/history_view_message.h"
 
-#include "history/history_item_components.h"
-#include "history/history_media.h"
-#include "data/data_session.h"
-#include "auth_session.h"
+#include "history/history_message.h"
 
 namespace HistoryView {
 
-Message::Message(not_null<HistoryItem*> data, Context context)
-: _data(data)
-, _context(context) {
+Message::Message(not_null<HistoryMessage*> data, Context context)
+: Element(data, context) {
 }
 
-not_null<HistoryItem*> Message::data() const {
-	return _data;
-}
-
-void Message::attachToBlock(not_null<HistoryBlock*> block, int index) {
-	Expects(!_data->isLogEntry());
-	Expects(_block == nullptr);
-	Expects(_indexInBlock < 0);
-	Expects(index >= 0);
-
-	_block = block;
-	_indexInBlock = index;
-	_data->setMainView(this);
-	_data->setPendingResize();
-}
-
-void Message::removeFromBlock() {
-	Expects(_block != nullptr);
-
-	_block->remove(this);
-}
-
-Message *Message::previousInBlocks() const {
-	if (_block && _indexInBlock >= 0) {
-		if (_indexInBlock > 0) {
-			return _block->messages[_indexInBlock - 1].get();
-		}
-		if (auto previous = _block->previousBlock()) {
-			Assert(!previous->messages.empty());
-			return previous->messages.back().get();
-		}
-	}
-	return nullptr;
-}
-
-Message *Message::nextInBlocks() const {
-	if (_block && _indexInBlock >= 0) {
-		if (_indexInBlock + 1 < _block->messages.size()) {
-			return _block->messages[_indexInBlock + 1].get();
-		}
-		if (auto next = _block->nextBlock()) {
-			Assert(!next->messages.empty());
-			return next->messages.front().get();
-		}
-	}
-	return nullptr;
-}
-
-void Message::clickHandlerActiveChanged(
-		const ClickHandlerPtr &handler,
-		bool active) {
-	if (const auto markup = _data->Get<HistoryMessageReplyMarkup>()) {
-		if (const auto keyboard = markup->inlineKeyboard.get()) {
-			keyboard->clickHandlerActiveChanged(handler, active);
-		}
-	}
-	App::hoveredLinkItem(active ? this : nullptr);
-	Auth().data().requestItemRepaint(_data);
-	if (const auto media = _data->getMedia()) {
-		media->clickHandlerActiveChanged(handler, active);
-	}
-}
-
-void Message::clickHandlerPressedChanged(
-		const ClickHandlerPtr &handler,
-		bool pressed) {
-	if (const auto markup = _data->Get<HistoryMessageReplyMarkup>()) {
-		if (const auto keyboard = markup->inlineKeyboard.get()) {
-			keyboard->clickHandlerPressedChanged(handler, pressed);
-		}
-	}
-	App::pressedLinkItem(pressed ? this : nullptr);
-	Auth().data().requestItemRepaint(_data);
-	if (const auto media = _data->getMedia()) {
-		media->clickHandlerPressedChanged(handler, pressed);
-	}
-}
-
-Message::~Message() {
-	App::messageViewDestroyed(this);
+not_null<HistoryMessage*> Message::message() const {
+	return static_cast<HistoryMessage*>(data().get());
 }
 
 } // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h
index cd8578b22..74663e9ef 100644
--- a/Telegram/SourceFiles/history/view/history_view_message.h
+++ b/Telegram/SourceFiles/history/view/history_view_message.h
@@ -7,71 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
-class HistoryItem;
+#include "history/view/history_view_element.h"
+
+class HistoryMessage;
 
 namespace HistoryView {
 
-enum class Context : char {
-	History,
-	Feed,
-	AdminLog
-};
-
-class Message
-	: public RuntimeComposer
-	, public ClickHandlerHost {
+class Message : public Element {
 public:
-	Message(not_null<HistoryItem*> data, Context context);
-
-	not_null<HistoryItem*> data() const;
-
-	int y() const {
-		return _y;
-	}
-	void setY(int y) {
-		_y = y;
-	}
-
-	HistoryBlock *block() {
-		return _block;
-	}
-	const HistoryBlock *block() const {
-		return _block;
-	}
-	void attachToBlock(not_null<HistoryBlock*> block, int index);
-	void removeFromBlock();
-	void setIndexInBlock(int index) {
-		Expects(_block != nullptr);
-		Expects(index >= 0);
-
-		_indexInBlock = index;
-	}
-	int indexInBlock() const {
-		Expects((_indexInBlock >= 0) == (_block != nullptr));
-		Expects((_block == nullptr) || (_block->messages[_indexInBlock].get() == this));
-
-		return _indexInBlock;
-	}
-	Message *previousInBlocks() const;
-	Message *nextInBlocks() const;
-
-	// ClickHandlerHost interface
-	void clickHandlerActiveChanged(
-		const ClickHandlerPtr &handler,
-		bool active) override;
-	void clickHandlerPressedChanged(
-		const ClickHandlerPtr &handler,
-		bool pressed) override;
-
-	~Message();
+	Message(not_null<HistoryMessage*> data, Context context);
 
 private:
-	const not_null<HistoryItem*> _data;
-	int _y = 0;
-	Context _context;
-
-	HistoryBlock *_block = nullptr;
-	int _indexInBlock = -1;
+	not_null<HistoryMessage*> message() const;
 
 };
 
diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp
index a5b96638b..014e6aee5 100644
--- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp
@@ -171,6 +171,14 @@ void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, i
 
 } // namepsace
 
+Service::Service(not_null<HistoryService*> data, Context context)
+: Element(data, context) {
+}
+
+not_null<HistoryService*> Service::message() const {
+	return static_cast<HistoryService*>(data().get());
+}
+
 int WideChatWidth() {
 	return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left();
 }
diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h
index 90cc670a1..c2bff03d3 100644
--- a/Telegram/SourceFiles/history/view/history_view_service_message.h
+++ b/Telegram/SourceFiles/history/view/history_view_service_message.h
@@ -7,10 +7,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "history/view/history_view_element.h"
+
 class HistoryService;
 
 namespace HistoryView {
 
+class Service : public Element {
+public:
+	Service(not_null<HistoryService*> data, Context context);
+
+private:
+	not_null<HistoryService*> message() const;
+
+};
+
 int WideChatWidth();
 
 struct PaintContext {
diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h
index 3662cf330..19aa7e66c 100644
--- a/Telegram/SourceFiles/info/info_wrap_widget.h
+++ b/Telegram/SourceFiles/info/info_wrap_widget.h
@@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include <rpl/event_stream.h>
 #include "window/section_widget.h"
 
+namespace Storage {
+enum class SharedMediaType : char;
+} // namespace Storage
+
 namespace Ui {
 class SettingsSlider;
 class FadeShadow;
diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h
index 7e4e3afb1..ba98e577f 100644
--- a/Telegram/SourceFiles/info/media/info_media_list_widget.h
+++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/rp_widget.h"
 #include "info/media/info_media_widget.h"
 #include "data/data_shared_media.h"
+#include "history/view/history_view_cursor_state.h"
 
 namespace Ui {
 class PopupMenu;
diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h
index 25390b0d3..a7c958a92 100644
--- a/Telegram/SourceFiles/info/profile/info_profile_values.h
+++ b/Telegram/SourceFiles/info/profile/info_profile_values.h
@@ -17,6 +17,10 @@ template <typename Widget>
 class SlideWrap;
 } // namespace Ui
 
+namespace Storage {
+enum class SharedMediaType : char;
+} // namespace Storage
+
 namespace Info {
 namespace Profile {
 
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
index 05d382baa..d78e70f0b 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/media_clip_reader.h"
 #include "media/player/media_player_instance.h"
 #include "history/history_location_manager.h"
+#include "history/view/history_view_cursor_state.h"
 #include "storage/localstorage.h"
 #include "auth_session.h"
 #include "lang/lang_keys.h"
diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
index 41eeebe00..c0cabf0f0 100644
--- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
@@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/widgets/scroll_area.h"
 #include "ui/widgets/labels.h"
 #include "observer_peer.h"
+#include "history/view/history_view_cursor_state.h"
 
 namespace InlineBots {
 namespace Layout {
diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp
index 4ec5fb66c..f69e952f2 100644
--- a/Telegram/SourceFiles/layout.cpp
+++ b/Telegram/SourceFiles/layout.cpp
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "boxes/confirm_box.h"
 #include "media/media_audio.h"
 #include "storage/localstorage.h"
+#include "history/view/history_view_cursor_state.h"
 
 QString formatSizeText(qint64 size) {
 	if (size >= 1024 * 1024) { // more than 1 mb
@@ -221,3 +222,15 @@ msp mst paf pif ps1 reg rgs sct shb shs u3p vb vbe vbs vbscript ws wsf\
 	auto lastDotIndex = filename.lastIndexOf('.');
 	return (lastDotIndex >= 0) && (executableTypes->indexOf(filename.mid(lastDotIndex + 1).toLower()) >= 0);
 }
+
+[[nodiscard]] HistoryTextState LayoutItemBase::getState(
+		QPoint point,
+		HistoryStateRequest request) const {
+	return {};
+}
+
+[[nodiscard]] TextSelection LayoutItemBase::adjustSelection(
+		TextSelection selection,
+		TextSelectType type) const {
+	return selection;
+}
diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h
index 4ddf9e3b4..95161be29 100644
--- a/Telegram/SourceFiles/layout.h
+++ b/Telegram/SourceFiles/layout.h
@@ -9,6 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "base/runtime_composer.h"
 
+struct HistoryTextState;
+struct HistoryStateRequest;
+
 constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF };
 
 inline bool IsSubGroupSelection(TextSelection selection) {
@@ -45,42 +48,6 @@ inline bool IsGroupItemSelection(
 		: selection;
 }
 
-enum RoundCorners {
-	SmallMaskCorners = 0x00, // for images
-	LargeMaskCorners,
-
-	BoxCorners,
-	MenuCorners,
-	BotKbOverCorners,
-	StickerCorners,
-	StickerSelectedCorners,
-	SelectedOverlaySmallCorners,
-	SelectedOverlayLargeCorners,
-	DateCorners,
-	DateSelectedCorners,
-	ForwardCorners,
-	MediaviewSaveCorners,
-	EmojiHoverCorners,
-	StickerHoverCorners,
-	BotKeyboardCorners,
-	PhotoSelectOverlayCorners,
-
-	Doc1Corners,
-	Doc2Corners,
-	Doc3Corners,
-	Doc4Corners,
-
-	InShadowCorners, // for photos without bg
-	InSelectedShadowCorners,
-
-	MessageInCorners, // with shadow
-	MessageInSelectedCorners,
-	MessageOutCorners,
-	MessageOutSelectedCorners,
-
-	RoundCornersCount
-};
-
 static const int32 FileStatusSizeReady = 0x7FFFFFF0;
 static const int32 FileStatusSizeLoaded = 0x7FFFFFF1;
 static const int32 FileStatusSizeFailed = 0x7FFFFFF2;
@@ -133,15 +100,11 @@ public:
 	}
 
 	[[nodiscard]] virtual HistoryTextState getState(
-			QPoint point,
-			HistoryStateRequest request) const {
-		return {};
-	}
+		QPoint point,
+		HistoryStateRequest request) const;
 	[[nodiscard]] virtual TextSelection adjustSelection(
-			TextSelection selection,
-			TextSelectType type) const {
-		return selection;
-	}
+		TextSelection selection,
+		TextSelectType type) const;
 
 	int width() const {
 		return _width;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 1c2a63d67..55aab289f 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -39,7 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_message.h"
 #include "history/history_media.h"
 #include "history/view/history_view_service_message.h"
-#include "history/view/history_view_message.h"
+#include "history/view/history_view_element.h"
 #include "lang/lang_keys.h"
 #include "lang/lang_cloud_manager.h"
 #include "boxes/add_contact_box.h"
diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp
index 6da36d5da..27039b0b2 100644
--- a/Telegram/SourceFiles/mainwindow.cpp
+++ b/Telegram/SourceFiles/mainwindow.cpp
@@ -894,10 +894,6 @@ void MainWindow::onClearFailed(int task, void *manager) {
 	emit tempDirClearFailed(task);
 }
 
-void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
-	handler->onClick(button);
-}
-
 void MainWindow::placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) {
 	QPainter p(&img);
 
diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h
index cdcf7334a..2b3f5734e 100644
--- a/Telegram/SourceFiles/mainwindow.h
+++ b/Telegram/SourceFiles/mainwindow.h
@@ -168,8 +168,6 @@ public slots:
 	void onShowNewChannel();
 	void onLogout();
 
-	void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
-
 signals:
 	void tempDirCleared(int task);
 	void tempDirClearFailed(int task);
diff --git a/Telegram/SourceFiles/media/player/media_player_cover.cpp b/Telegram/SourceFiles/media/player/media_player_cover.cpp
index 8db1c254e..7c40f5380 100644
--- a/Telegram/SourceFiles/media/player/media_player_cover.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_cover.cpp
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/player/media_player_volume_controller.h"
 #include "styles/style_media_player.h"
 #include "styles/style_mediaview.h"
+#include "layout.h"
 
 namespace Media {
 namespace Player {
diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp
index 8fa6859bd..1cc63129c 100644
--- a/Telegram/SourceFiles/media/player/media_player_widget.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp
@@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/player/media_player_volume_controller.h"
 #include "styles/style_media_player.h"
 #include "styles/style_mediaview.h"
+#include "history/history_item.h"
+#include "layout.h"
 
 namespace Media {
 namespace Player {
diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_controller.cpp
index 7fdc8d0af..a1c1a02aa 100644
--- a/Telegram/SourceFiles/media/view/media_clip_controller.cpp
+++ b/Telegram/SourceFiles/media/view/media_clip_controller.cpp
@@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/effects/fade_animation.h"
 #include "ui/widgets/buttons.h"
 #include "media/media_audio.h"
+#include "layout.h"
 
 namespace Media {
 namespace Clip {
diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp
index c38ffc8a7..70b06db17 100644
--- a/Telegram/SourceFiles/mediaview.cpp
+++ b/Telegram/SourceFiles/mediaview.cpp
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "observer_peer.h"
 #include "auth_session.h"
 #include "messenger.h"
+#include "layout.h"
 #include "storage/file_download.h"
 #include "calls/calls_instance.h"
 #include "styles/style_mediaview.h"
diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp
index c9bf134c4..cf1180cd6 100644
--- a/Telegram/SourceFiles/overview/overview_layout.cpp
+++ b/Telegram/SourceFiles/overview/overview_layout.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "media/media_audio.h"
 #include "media/player/media_player_instance.h"
 #include "storage/localstorage.h"
+#include "history/history_item.h"
 #include "history/history_media_types.h"
 #include "history/history_item_components.h"
 #include "ui/effects/round_checkbox.h"
@@ -114,6 +115,11 @@ void Checkbox::startAnimation() {
 	_pression.start(_updateCallback, showPressed ? 0. : 1., showPressed ? 1. : 0., st::overviewCheck.duration);
 }
 
+MsgId AbstractItem::msgId() const {
+	auto item = getItem();
+	return item ? item->id : 0;
+}
+
 ItemBase::ItemBase(not_null<HistoryItem*> parent) : _parent(parent) {
 }
 
diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h
index 7fe8cb5fd..cb9e22245 100644
--- a/Telegram/SourceFiles/overview/overview_layout.h
+++ b/Telegram/SourceFiles/overview/overview_layout.h
@@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/effects/radial_animation.h"
 #include "styles/style_overview.h"
 
+struct HistoryTextState;
+struct HistoryStateRequest;
+
 namespace style {
 struct RoundCheckbox;
 } // namespace style
@@ -47,10 +50,7 @@ public:
 	virtual DocumentData *getDocument() const {
 		return nullptr;
 	}
-	MsgId msgId() const {
-		auto item = getItem();
-		return item ? item->id : 0;
-	}
+	MsgId msgId() const;
 
 	virtual void invalidateCache() {
 	}
diff --git a/Telegram/SourceFiles/ui/countryinput.h b/Telegram/SourceFiles/ui/countryinput.h
index 22e6cf15f..acdc7601b 100644
--- a/Telegram/SourceFiles/ui/countryinput.h
+++ b/Telegram/SourceFiles/ui/countryinput.h
@@ -14,6 +14,7 @@ QString findValidCode(QString fullCode);
 
 namespace Ui {
 class MultiSelect;
+class RippleAnimation;
 } // namespace Ui
 
 class CountryInput : public TWidget {
diff --git a/Telegram/SourceFiles/ui/images.cpp b/Telegram/SourceFiles/ui/images.cpp
index 32d0ac829..de9af7a94 100644
--- a/Telegram/SourceFiles/ui/images.cpp
+++ b/Telegram/SourceFiles/ui/images.cpp
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "storage/localstorage.h"
 #include "platform/platform_specific.h"
 #include "auth_session.h"
+#include "history/history_item.h"
 
 namespace Images {
 namespace {
diff --git a/Telegram/SourceFiles/ui/text_options.cpp b/Telegram/SourceFiles/ui/text_options.cpp
index 570b0f66c..fc5a817bd 100644
--- a/Telegram/SourceFiles/ui/text_options.cpp
+++ b/Telegram/SourceFiles/ui/text_options.cpp
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/text_options.h"
 
 #include "styles/style_window.h"
+#include "history/history_item.h"
 
 namespace Ui {
 namespace {
diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp
index 88c9567fc..09f4027b3 100644
--- a/Telegram/SourceFiles/window/notifications_manager_default.cpp
+++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "styles/style_window.h"
 #include "storage/file_download.h"
 #include "auth_session.h"
+#include "history/history_item.h"
 #include "platform/platform_specific.h"
 
 namespace Window {
@@ -63,6 +64,16 @@ Manager::Manager(System *system) : Notifications::Manager(system) {
 	_inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); });
 }
 
+Manager::QueuedNotification::QueuedNotification(
+	not_null<HistoryItem*> item
+	, int forwardedCount)
+: history(item->history())
+, peer(history->peer)
+, author((!peer->isUser() && !item->isPost()) ? item->author() : nullptr)
+, item((forwardedCount < 2) ? item.get() : nullptr)
+, forwardedCount(forwardedCount) {
+}
+
 QPixmap Manager::hiddenUserpicPlaceholder() const {
 	if (_hiddenUserpicPlaceholder.isNull()) {
 		_hiddenUserpicPlaceholder = App::pixmapFromImageInPlace(Messenger::Instance().logoNoMargin().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
diff --git a/Telegram/SourceFiles/window/notifications_manager_default.h b/Telegram/SourceFiles/window/notifications_manager_default.h
index 46abce7f3..7d847c4fc 100644
--- a/Telegram/SourceFiles/window/notifications_manager_default.h
+++ b/Telegram/SourceFiles/window/notifications_manager_default.h
@@ -82,16 +82,10 @@ private:
 	SingleTimer _inputCheckTimer;
 
 	struct QueuedNotification {
-		QueuedNotification(HistoryItem *item, int forwardedCount)
-		: history(item->history())
-		, peer(history->peer)
-		, author((!peer->isUser() && !item->isPost()) ? item->author() : nullptr)
-		, item((forwardedCount > 1) ? nullptr : item)
-		, forwardedCount(forwardedCount) {
-		}
+		QueuedNotification(not_null<HistoryItem*> item, int forwardedCount);
 
-		History *history;
-		PeerData *peer;
+		not_null<History*> history;
+		not_null<PeerData*> peer;
 		PeerData *author;
 		HistoryItem *item;
 		int forwardedCount;
diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor.cpp
index 2a41275ce..a1feff147 100644
--- a/Telegram/SourceFiles/window/themes/window_theme_editor.cpp
+++ b/Telegram/SourceFiles/window/themes/window_theme_editor.cpp
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "window/themes/window_theme.h"
 #include "window/themes/window_theme_editor_block.h"
 #include "mainwindow.h"
+#include "layout.h"
 #include "storage/localstorage.h"
 #include "boxes/confirm_box.h"
 #include "styles/style_window.h"
diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp
index c524575a9..aea7fe54d 100644
--- a/Telegram/SourceFiles/window/window_controller.cpp
+++ b/Telegram/SourceFiles/window/window_controller.cpp
@@ -9,7 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "window/main_window.h"
 #include "info/info_memento.h"
+#include "history/view/history_view_element.h"
 #include "history/view/history_view_message.h"
+#include "history/view/history_view_service_message.h"
+#include "history/history_item.h"
 #include "mainwidget.h"
 #include "mainwindow.h"
 #include "styles/style_window.h"
@@ -403,4 +406,16 @@ not_null<MainWidget*> Controller::chats() const {
 	return App::wnd()->chatsWidget();
 }
 
+std::unique_ptr<HistoryView::Element> Controller::createMessageView(
+		not_null<HistoryMessage*> message,
+		HistoryView::Context context) {
+	return std::make_unique<HistoryView::Message>(message, context);
+}
+
+std::unique_ptr<HistoryView::Element> Controller::createMessageView(
+		not_null<HistoryService*> message,
+		HistoryView::Context context) {
+	return std::make_unique<HistoryView::Service>(message, context);
+}
+
 } // namespace Window
diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h
index 95ce9085c..0a5cfebde 100644
--- a/Telegram/SourceFiles/window/window_controller.h
+++ b/Telegram/SourceFiles/window/window_controller.h
@@ -11,6 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "base/flags.h"
 
 class MainWidget;
+class HistoryMessage;
+class HistoryService;
+
+namespace HistoryView {
+enum class Context : char;
+} // namespace HistoryView
 
 namespace Window {
 
@@ -195,6 +201,13 @@ public:
 		return this;
 	}
 
+	std::unique_ptr<HistoryView::Element> createMessageView(
+		not_null<HistoryMessage*> message,
+		HistoryView::Context context);
+	std::unique_ptr<HistoryView::Element> createMessageView(
+		not_null<HistoryService*> message,
+		HistoryView::Context context);
+
 private:
 	int minimalThreeColumnWidth() const;
 	not_null<MainWidget*> chats() const;
diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt
index 9597e0635..4dfcc1019 100644
--- a/Telegram/gyp/telegram_sources.txt
+++ b/Telegram/gyp/telegram_sources.txt
@@ -225,6 +225,10 @@
 <(src_loc)/history/admin_log/history_admin_log_section.h
 <(src_loc)/history/feed/history_feed_section.cpp
 <(src_loc)/history/feed/history_feed_section.h
+<(src_loc)/history/view/history_view_cursor_state.cpp
+<(src_loc)/history/view/history_view_cursor_state.h
+<(src_loc)/history/view/history_view_element.cpp
+<(src_loc)/history/view/history_view_element.h
 <(src_loc)/history/view/history_view_list_widget.cpp
 <(src_loc)/history/view/history_view_list_widget.h
 <(src_loc)/history/view/history_view_message.cpp
@@ -249,6 +253,8 @@
 <(src_loc)/history/history_media.cpp
 <(src_loc)/history/history_media_grouped.h
 <(src_loc)/history/history_media_grouped.cpp
+<(src_loc)/history/history_media_pointer.h
+<(src_loc)/history/history_media_pointer.cpp
 <(src_loc)/history/history_media_types.cpp
 <(src_loc)/history/history_media_types.h
 <(src_loc)/history/history_message.cpp