From f0a8356ff08116ab301f7869ee462a184e43e6f5 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Fri, 17 Jun 2016 21:18:01 +0300
Subject: [PATCH 1/2] Profile members block displayed when mouse is over group
 members count.

---
 Telegram/SourceFiles/dropdown.cpp             |  10 +-
 Telegram/SourceFiles/dropdown.h               |  30 +--
 Telegram/SourceFiles/historywidget.cpp        |  39 +++-
 Telegram/SourceFiles/historywidget.h          |   8 +-
 Telegram/SourceFiles/mainwidget.cpp           |  13 ++
 Telegram/SourceFiles/mainwidget.h             |   3 +
 Telegram/SourceFiles/mediaview.h              |   4 +-
 .../profile/profile_block_widget.cpp          |  17 +-
 .../profile/profile_block_widget.h            |  20 +-
 .../profile/profile_members_widget.cpp        |   5 +-
 .../profile/profile_members_widget.h          |  10 +-
 Telegram/SourceFiles/ui/animation.h           |  11 +-
 Telegram/SourceFiles/ui/inner_dropdown.cpp    | 185 ++++++++++++++++++
 Telegram/SourceFiles/ui/inner_dropdown.h      |  82 ++++++++
 Telegram/SourceFiles/ui/scrollarea.h          |  22 +++
 Telegram/SourceFiles/ui/twidget.h             |  11 +-
 .../SourceFiles/window/top_bar_widget.cpp     |  78 +++++++-
 Telegram/SourceFiles/window/top_bar_widget.h  |  10 +-
 Telegram/Telegram.vcxproj                     |  27 +++
 Telegram/Telegram.vcxproj.filters             |  15 ++
 20 files changed, 532 insertions(+), 68 deletions(-)
 create mode 100644 Telegram/SourceFiles/ui/inner_dropdown.cpp
 create mode 100644 Telegram/SourceFiles/ui/inner_dropdown.h

diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp
index 6d4ae62fc..d862a660d 100644
--- a/Telegram/SourceFiles/dropdown.cpp
+++ b/Telegram/SourceFiles/dropdown.cpp
@@ -1019,11 +1019,11 @@ void EmojiPanInner::leaveEvent(QEvent *e) {
 	clearSelection();
 }
 
-void EmojiPanInner::leaveToChildEvent(QEvent *e) {
+void EmojiPanInner::leaveToChildEvent(QEvent *e, QWidget *child) {
 	clearSelection();
 }
 
-void EmojiPanInner::enterFromChildEvent(QEvent *e) {
+void EmojiPanInner::enterFromChildEvent(QEvent *e, QWidget *child) {
 	_lastMousePos = QCursor::pos();
 	updateSelected();
 }
@@ -1544,11 +1544,11 @@ void StickerPanInner::leaveEvent(QEvent *e) {
 	clearSelection();
 }
 
-void StickerPanInner::leaveToChildEvent(QEvent *e) {
+void StickerPanInner::leaveToChildEvent(QEvent *e, QWidget *child) {
 	clearSelection();
 }
 
-void StickerPanInner::enterFromChildEvent(QEvent *e) {
+void StickerPanInner::enterFromChildEvent(QEvent *e, QWidget *child) {
 	_lastMousePos = QCursor::pos();
 	updateSelected();
 }
@@ -3139,7 +3139,7 @@ void EmojiPan::onRefreshPanels() {
 	}
 }
 
-void EmojiPan::leaveToChildEvent(QEvent *e) {
+void EmojiPan::leaveToChildEvent(QEvent *e, QWidget *child) {
 	if (!_stickersShown) return;
 	_iconsMousePos = QCursor::pos();
 	updateSelected();
diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h
index ae7a33159..32faf3568 100644
--- a/Telegram/SourceFiles/dropdown.h
+++ b/Telegram/SourceFiles/dropdown.h
@@ -254,14 +254,14 @@ public:
 	EmojiPanInner();
 
 	void setMaxHeight(int32 h);
-	void paintEvent(QPaintEvent *e);
+	void paintEvent(QPaintEvent *e) override;
 
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void leaveEvent(QEvent *e);
-	void leaveToChildEvent(QEvent *e);
-	void enterFromChildEvent(QEvent *e);
+	void mousePressEvent(QMouseEvent *e) override;
+	void mouseReleaseEvent(QMouseEvent *e) override;
+	void mouseMoveEvent(QMouseEvent *e) override;
+	void leaveEvent(QEvent *e) override;
+	void leaveToChildEvent(QEvent *e, QWidget *child) override;
+	void enterFromChildEvent(QEvent *e, QWidget *child) override;
 
 	void step_selected(uint64 ms, bool timer);
 	void hideFinish();
@@ -346,14 +346,14 @@ public:
 	StickerPanInner();
 
 	void setMaxHeight(int32 h);
-	void paintEvent(QPaintEvent *e);
+	void paintEvent(QPaintEvent *e) override;
 
-	void mousePressEvent(QMouseEvent *e);
-	void mouseReleaseEvent(QMouseEvent *e);
-	void mouseMoveEvent(QMouseEvent *e);
-	void leaveEvent(QEvent *e);
-	void leaveToChildEvent(QEvent *e);
-	void enterFromChildEvent(QEvent *e);
+	void mousePressEvent(QMouseEvent *e) override;
+	void mouseReleaseEvent(QMouseEvent *e) override;
+	void mouseMoveEvent(QMouseEvent *e) override;
+	void leaveEvent(QEvent *e) override;
+	void leaveToChildEvent(QEvent *e, QWidget *child) override;
+	void enterFromChildEvent(QEvent *e, QWidget *child) override;
 
 	void step_selected(uint64 ms, bool timer);
 
@@ -663,7 +663,7 @@ private:
 	bool _horizontal;
 	void updateContentHeight();
 
-	void leaveToChildEvent(QEvent *e);
+	void leaveToChildEvent(QEvent *e, QWidget *child);
 	void hideAnimated();
 	void prepareShowHideCache();
 
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 9c8b6c3f9..e2018e752 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -28,9 +28,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "ui/filedialog.h"
 #include "ui/toast/toast.h"
 #include "ui/buttons/history_down_button.h"
+#include "ui/inner_dropdown.h"
 #include "inline_bots/inline_bot_result.h"
 #include "data/data_drafts.h"
 #include "history/history_service_layout.h"
+#include "profile/profile_members_widget.h"
 #include "lang.h"
 #include "application.h"
 #include "mainwidget.h"
@@ -5442,7 +5444,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
 	if (startAnim) _a_record.start();
 }
 
-void HistoryWidget::leaveToChildEvent(QEvent *e) { // e -- from enterEvent() of child TWidget
+void HistoryWidget::leaveToChildEvent(QEvent *e, QWidget *child) { // e -- from enterEvent() of child TWidget
 	if (hasMouseTracking()) mouseMoveEvent(0);
 }
 
@@ -6009,6 +6011,37 @@ void HistoryWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) {
 	}
 }
 
+QRect HistoryWidget::getMembersShowAreaGeometry() const {
+	int increaseLeft = Adaptive::OneColumn() ? (st::topBarForwardPadding.right() - st::topBarForwardPadding.left()) : 0;
+	int membersTextLeft = st::topBarForwardPadding.left() + increaseLeft;
+	int membersTextTop = st::topBarHeight - st::topBarForwardPadding.bottom() - st::dialogsTextFont->height - st::topBarForwardPadding.bottom();
+	int membersTextWidth = _titlePeerTextWidth;
+	int membersTextHeight = st::topBarHeight - membersTextTop;
+
+	membersTextLeft -= st::topBarForwardPadding.left();
+	membersTextWidth += 2 * st::topBarForwardPadding.left();
+
+	return rtlrect(membersTextLeft, membersTextTop, membersTextWidth, membersTextHeight, width());
+}
+
+void HistoryWidget::setMembersShowAreaActive(bool active) {
+	if (active && _peer && (_peer->isChat() || _peer->isMegagroup())) {
+		if (!_membersDropdown) {
+			_membersDropdown = new Ui::InnerDropdown(this, st::dropdownDef, st::solidScroll);
+			_membersDropdown->setOwnedWidget(new Profile::MembersWidget(_membersDropdown, _peer, Profile::MembersWidget::TitleVisibility::Hidden));
+			_membersDropdown->setGeometry(0, 0, st::emojiPanWidth, st::emojiPanMaxHeight);
+			connect(_membersDropdown, SIGNAL(hidden()), this, SLOT(onMembersDropdownHidden()));
+		}
+		_membersDropdown->otherEnter();
+	} else if (_membersDropdown) {
+		_membersDropdown->otherLeave();
+	}
+}
+
+void HistoryWidget::onMembersDropdownHidden() {
+	_membersDropdown.destroyDelayed();
+}
+
 void HistoryWidget::topBarClick() {
 	if (Adaptive::OneColumn()) {
 		Ui::showChatsList();
@@ -6074,6 +6107,7 @@ void HistoryWidget::updateOnlineDisplay(int32 x, int32 w) {
 		_titlePeerTextOnline = titlePeerTextOnline;
 		_titlePeerTextWidth = st::dialogsTextFont->width(_titlePeerText);
 		if (App::main()) {
+			App::main()->topBar()->updateMembersShowArea();
 			App::main()->topBar()->update();
 		}
 	}
@@ -7263,6 +7297,9 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
 			connect(&_pinnedBar->cancel, SIGNAL(clicked()), this, SLOT(onPinnedHide()));
 			_reportSpamPanel.raise();
 			_topShadow.raise();
+			if (_membersDropdown) {
+				_membersDropdown->raise();
+			}
 			updatePinnedBar();
 			result = true;
 
diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h
index c1481437b..e274de9d3 100644
--- a/Telegram/SourceFiles/historywidget.h
+++ b/Telegram/SourceFiles/historywidget.h
@@ -36,6 +36,7 @@ class Result;
 
 namespace Ui {
 class HistoryDownButton;
+class InnerDropdown;
 } // namespace Ui
 
 class HistoryWidget;
@@ -540,12 +541,14 @@ public:
     void dropEvent(QDropEvent *e) override;
 	void mouseReleaseEvent(QMouseEvent *e) override;
 	void mouseMoveEvent(QMouseEvent *e) override;
-	void leaveToChildEvent(QEvent *e) override;
+	void leaveToChildEvent(QEvent *e, QWidget *child) override;
 	void contextMenuEvent(QContextMenuEvent *e) override;
 
 	void updateTopBarSelection();
 
 	void paintTopBar(Painter &p, float64 over, int32 decreaseWidth);
+	QRect getMembersShowAreaGeometry() const;
+	void setMembersShowAreaActive(bool active);
 	void topBarClick();
 
 	void loadMessages();
@@ -839,6 +842,7 @@ private slots:
 	void onHashtagOrBotCommandInsert(QString str, FieldAutocomplete::ChooseMethod method);
 	void onMentionInsert(UserData *user);
 	void onInlineBotCancel();
+	void onMembersDropdownHidden();
 
 	void updateField();
 
@@ -1099,6 +1103,8 @@ private:
 	ScrollArea _kbScroll;
 	BotKeyboard _keyboard;
 
+	ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
+
 	Dropdown _attachType;
 	EmojiPan _emojiPan;
 	DragState _attachDrag = DragStateNone;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 8b48d365a..9439a61df 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -2696,6 +2696,19 @@ void MainWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) {
 	}
 }
 
+QRect MainWidget::getMembersShowAreaGeometry() const {
+	if (!_overview && !_wideSection) {
+		return _history->getMembersShowAreaGeometry();
+	}
+	return QRect();
+}
+
+void MainWidget::setMembersShowAreaActive(bool active) {
+	if (!active || (!_overview && !_wideSection)) {
+		_history->setMembersShowAreaActive(active);
+	}
+}
+
 void MainWidget::onPhotosSelect() {
 	if (_overview) _overview->switchType(OverviewPhotos);
 	_mediaType->hideStart();
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 62a85bab9..7b57d4742 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -162,7 +162,10 @@ public:
 	void updateAdaptiveLayout();
 	bool needBackButton();
 
+	// Temporary methods, while top bar was not done inside HistoryWidget / OverviewWidget.
 	void paintTopBar(Painter &p, float64 over, int32 decreaseWidth);
+	QRect getMembersShowAreaGeometry() const;
+	void setMembersShowAreaActive(bool active);
 	Window::TopBarWidget *topBar();
 
 	PlayerWidget *player();
diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h
index 8045e7a22..ec34e421c 100644
--- a/Telegram/SourceFiles/mediaview.h
+++ b/Telegram/SourceFiles/mediaview.h
@@ -51,10 +51,10 @@ public:
 	bool moveToNext(int32 delta);
 	void preloadData(int32 delta);
 
-	void leaveToChildEvent(QEvent *e) override { // e -- from enterEvent() of child TWidget
+	void leaveToChildEvent(QEvent *e, QWidget *child) override { // e -- from enterEvent() of child TWidget
 		updateOverState(OverNone);
 	}
-	void enterFromChildEvent(QEvent *e) override { // e -- from leaveEvent() of child TWidget
+	void enterFromChildEvent(QEvent *e, QWidget *child) override { // e -- from leaveEvent() of child TWidget
 		updateOver(mapFromGlobal(QCursor::pos()));
 	}
 
diff --git a/Telegram/SourceFiles/profile/profile_block_widget.cpp b/Telegram/SourceFiles/profile/profile_block_widget.cpp
index ba2c8ac5f..f6d108fa7 100644
--- a/Telegram/SourceFiles/profile/profile_block_widget.cpp
+++ b/Telegram/SourceFiles/profile/profile_block_widget.cpp
@@ -25,29 +25,30 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 
 namespace Profile {
 
-BlockWidget::BlockWidget(QWidget *parent, PeerData *peer, const QString &title) : TWidget(parent)
+BlockWidget::BlockWidget(QWidget *parent, PeerData *peer, const QString &title) : ScrolledWidget(parent)
 , _peer(peer)
 , _title(title) {
 }
 
-void BlockWidget::resizeToWidth(int newWidth) {
-	resize(newWidth, resizeGetHeight(newWidth));
-}
-
 int BlockWidget::contentTop() const {
-	return st::profileBlockMarginTop + st::profileBlockTitleHeight;
+	return st::profileBlockMarginTop + (emptyTitle() ? 0 : st::profileBlockTitleHeight);
 }
 
 void BlockWidget::paintEvent(QPaintEvent *e) {
 	Painter p(this);
 
+	paintTitle(p);
+	paintContents(p);
+}
+
+void BlockWidget::paintTitle(Painter &p) {
+	if (emptyTitle()) return;
+
 	p.setFont(st::profileBlockTitleFont);
 	p.setPen(st::profileBlockTitleFg);
 	int titleLeft = st::profileBlockTitlePosition.x();
 	int titleTop = st::profileBlockMarginTop + st::profileBlockTitlePosition.y();
 	p.drawTextLeft(titleLeft, titleTop, width(), _title);
-
-	paintContents(p);
 }
 
 int defaultOutlineButtonLeft() {
diff --git a/Telegram/SourceFiles/profile/profile_block_widget.h b/Telegram/SourceFiles/profile/profile_block_widget.h
index da93aad75..8f57e04e7 100644
--- a/Telegram/SourceFiles/profile/profile_block_widget.h
+++ b/Telegram/SourceFiles/profile/profile_block_widget.h
@@ -24,22 +24,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 
 namespace Profile {
 
-class BlockWidget : public TWidget, public Notify::Observer {
+class BlockWidget : public ScrolledWidget, public Notify::Observer {
 	Q_OBJECT
 
 public:
 	BlockWidget(QWidget *parent, PeerData *peer, const QString &title);
 
-	// Count new height for width=newWidth and resize to it.
-	void resizeToWidth(int newWidth);
-
-	// Updates the area that is visible inside the scroll container.
-	virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
-	}
-
-	virtual ~BlockWidget() {
-	}
-
 signals:
 	void heightUpdated();
 
@@ -52,7 +42,7 @@ protected:
 	int contentTop() const;
 
 	// Resizes content and counts natural widget height for the desired width.
-	virtual int resizeGetHeight(int newWidth) = 0;
+	int resizeGetHeight(int newWidth) override = 0;
 
 	void contentSizeUpdated() {
 		resizeToWidth(width());
@@ -63,7 +53,13 @@ protected:
 		return _peer;
 	}
 
+	bool emptyTitle() const {
+		return _title.isEmpty();
+	}
+
 private:
+	void paintTitle(Painter &p);
+
 	PeerData *_peer;
 	QString _title;
 
diff --git a/Telegram/SourceFiles/profile/profile_members_widget.cpp b/Telegram/SourceFiles/profile/profile_members_widget.cpp
index af1c9cfc0..d9b59f13f 100644
--- a/Telegram/SourceFiles/profile/profile_members_widget.cpp
+++ b/Telegram/SourceFiles/profile/profile_members_widget.cpp
@@ -37,7 +37,8 @@ namespace Profile {
 
 using UpdateFlag = Notify::PeerUpdate::Flag;
 
-MembersWidget::MembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section)) {
+MembersWidget::MembersWidget(QWidget *parent, PeerData *peer, TitleVisibility titleVisibility)
+: BlockWidget(parent, peer, (titleVisibility == TitleVisibility::Visible) ? lang(lng_profile_participants_section) : QString()) {
 	setMouseTracking(true);
 
 	_removeWidth = st::normalFont->width(lang(lng_profile_kick));
@@ -309,7 +310,7 @@ void MembersWidget::refreshLimitReached() {
 	auto chat = peer()->asChat();
 	if (!chat) return;
 
-	bool limitReachedShown = (_list.size() >= Global::ChatSizeMax()) && chat->amCreator();
+	bool limitReachedShown = (_list.size() >= Global::ChatSizeMax()) && chat->amCreator() && !emptyTitle();
 	if (limitReachedShown && !_limitReachedInfo) {
 		_limitReachedInfo = new FlatLabel(this, st::profileLimitReachedLabel, st::profileLimitReachedStyle);
 		QString title = textRichPrepare(lng_profile_migrate_reached(lt_count, Global::ChatSizeMax()));
diff --git a/Telegram/SourceFiles/profile/profile_members_widget.h b/Telegram/SourceFiles/profile/profile_members_widget.h
index 45f717894..f71e7f21d 100644
--- a/Telegram/SourceFiles/profile/profile_members_widget.h
+++ b/Telegram/SourceFiles/profile/profile_members_widget.h
@@ -38,7 +38,11 @@ class MembersWidget : public BlockWidget {
 	Q_OBJECT
 
 public:
-	MembersWidget(QWidget *parent, PeerData *peer);
+	enum class TitleVisibility {
+		Visible,
+		Hidden,
+	};
+	MembersWidget(QWidget *parent, PeerData *peer, TitleVisibility titleVisibility = TitleVisibility::Visible);
 
 	void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
 	int onlineCount() const {
@@ -57,11 +61,11 @@ protected:
 	void mousePressEvent(QMouseEvent *e) override;
 	void mouseReleaseEvent(QMouseEvent *e) override;
 	void enterEvent(QEvent *e) override;
-	void enterFromChildEvent(QEvent *e) override {
+	void enterFromChildEvent(QEvent *e, QWidget *child) override {
 		enterEvent(e);
 	}
 	void leaveEvent(QEvent *e) override;
-	void leaveToChildEvent(QEvent *e) override {
+	void leaveToChildEvent(QEvent *e, QWidget *child) override {
 		leaveEvent(e);
 	}
 
diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h
index 90422651a..ff1a944ed 100644
--- a/Telegram/SourceFiles/ui/animation.h
+++ b/Telegram/SourceFiles/ui/animation.h
@@ -449,13 +449,18 @@ private:
 		} else {
 			_data->a.update(dt, _data->transition);
 		}
-		if (timer) {
-			_data->update.call();
-		}
+
+		Callback callbackCache, *toCall = &_data->update;
 		if (!_data->_a.animating()) {
+			callbackCache = std_::move(_data->update);
+			toCall = &callbackCache;
+
 			delete _data;
 			_data = nullptr;
 		}
+		if (timer) {
+			toCall->call();
+		}
 	}
 
 };
diff --git a/Telegram/SourceFiles/ui/inner_dropdown.cpp b/Telegram/SourceFiles/ui/inner_dropdown.cpp
new file mode 100644
index 000000000..dd1b49283
--- /dev/null
+++ b/Telegram/SourceFiles/ui/inner_dropdown.cpp
@@ -0,0 +1,185 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+It is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
+*/
+#include "stdafx.h"
+#include "ui/inner_dropdown.h"
+
+#include "mainwindow.h"
+#include "ui/scrollarea.h"
+#include "profile/profile_members_widget.h"
+
+namespace Ui {
+
+InnerDropdown::InnerDropdown(QWidget *parent, const style::dropdown &st, const style::flatScroll &scrollSt) : TWidget(parent)
+, _st(st)
+, _shadow(_st.shadow)
+, _scroll(this, scrollSt) {
+	_hideTimer.setSingleShot(true);
+	connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
+
+	connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
+
+	if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
+		connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged()));
+	}
+
+	hide();
+}
+
+void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
+	_scroll->setOwnedWidget(widget);
+	widget->show();
+	widget->move(0, 0);
+	widget->resizeToWidth(_scroll->width() - st::scrollDef.width);
+}
+
+void InnerDropdown::onWindowActiveChanged() {
+	if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
+		leaveEvent(nullptr);
+	}
+}
+
+void InnerDropdown::resizeEvent(QResizeEvent *e) {
+	_scroll->setGeometry(rect().marginsRemoved(_st.padding));
+	if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
+		widget->resizeToWidth(_scroll->width() - st::scrollDef.width);
+		onScroll();
+	}
+}
+
+void InnerDropdown::onScroll() {
+	if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
+		int visibleTop = _scroll->scrollTop();
+		int visibleBottom = visibleTop + _scroll->height();
+		widget->setVisibleTopBottom(visibleTop, visibleBottom);
+	}
+}
+
+void InnerDropdown::paintEvent(QPaintEvent *e) {
+	QPainter p(this);
+
+	if (!_cache.isNull()) {
+		bool animating = _a_appearance.animating(getms());
+		if (animating) {
+			p.setOpacity(_a_appearance.current(_hiding));
+		} else if (_hiding) {
+			hidingFinished();
+			return;
+		}
+		p.drawPixmap(0, 0, _cache);
+		if (!animating) {
+			showChildren();
+			_cache = QPixmap();
+		}
+		return;
+	}
+
+	// draw shadow
+	QRect shadowedRect = rect().marginsRemoved(_st.padding);
+	_shadow.paint(p, shadowedRect, _st.shadowShift);
+	p.fillRect(shadowedRect, st::windowBg);
+}
+
+void InnerDropdown::enterEvent(QEvent *e) {
+	_hideTimer.stop();
+	if (_hiding) showingStarted();
+	return TWidget::enterEvent(e);
+}
+
+void InnerDropdown::leaveEvent(QEvent *e) {
+	if (_a_appearance.animating(getms())) {
+		onHideStart();
+	} else {
+		_hideTimer.start(300);
+	}
+	return TWidget::leaveEvent(e);
+}
+
+void InnerDropdown::otherEnter() {
+	_hideTimer.stop();
+	showingStarted();
+}
+
+void InnerDropdown::otherLeave() {
+	if (_a_appearance.animating(getms())) {
+		onHideStart();
+	} else {
+		_hideTimer.start(0);
+	}
+}
+
+void InnerDropdown::onHideStart() {
+	if (_hiding) return;
+
+	_hiding = true;
+	startAnimation();
+}
+
+void InnerDropdown::startAnimation() {
+	auto from = _hiding ? 1. : 0.;
+	auto to = _hiding ? 0. : 1.;
+	if (_a_appearance.isNull()) {
+		showChildren();
+		_cache = myGrab(this);
+	}
+	hideChildren();
+	START_ANIMATION(_a_appearance, func(this, &InnerDropdown::repaintCallback), from, to, _st.duration, anim::linear);
+}
+
+void InnerDropdown::hidingFinished() {
+	hide();
+//	showChildren();
+	emit hidden();
+}
+
+void InnerDropdown::showingStarted() {
+	if (isHidden()) {
+		show();
+	} else if (!_hiding) {
+		return;
+	}
+	_hiding = false;
+	startAnimation();
+}
+
+void InnerDropdown::repaintCallback() {
+	update();
+	if (!_a_appearance.animating(getms()) && _hiding) {
+		_hiding = false;
+		hidingFinished();
+	}
+}
+
+bool InnerDropdown::eventFilter(QObject *obj, QEvent *e) {
+	if (e->type() == QEvent::Enter) {
+		otherEnter();
+	} else if (e->type() == QEvent::Leave) {
+		otherLeave();
+	} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) {
+		if (isHidden() || _hiding) {
+			otherEnter();
+		} else {
+			otherLeave();
+		}
+	}
+	return false;
+}
+
+} // namespace Ui
diff --git a/Telegram/SourceFiles/ui/inner_dropdown.h b/Telegram/SourceFiles/ui/inner_dropdown.h
new file mode 100644
index 000000000..827016002
--- /dev/null
+++ b/Telegram/SourceFiles/ui/inner_dropdown.h
@@ -0,0 +1,82 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+It is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
+*/
+#pragma once
+
+class ScrollArea;
+
+namespace Ui {
+
+class InnerDropdown : public TWidget {
+	Q_OBJECT
+
+public:
+	InnerDropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef, const style::flatScroll &scrollSt = st::scrollDef);
+
+	void setOwnedWidget(ScrolledWidget *widget);
+
+	bool overlaps(const QRect &globalRect) {
+		if (isHidden() || !_a_appearance.isNull()) return false;
+
+		return rect().marginsRemoved(_st.padding).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
+	}
+
+	void otherEnter();
+	void otherLeave();
+
+protected:
+	void resizeEvent(QResizeEvent *e) override;
+	void paintEvent(QPaintEvent *e) override;
+	void enterEvent(QEvent *e) override;
+	void leaveEvent(QEvent *e) override;
+
+	bool eventFilter(QObject *obj, QEvent *e) override;
+
+signals:
+	void hidden();
+
+private slots:
+	void onHideStart();
+	void onWindowActiveChanged();
+	void onScroll();
+
+private:
+	void repaintCallback();
+
+	void hidingFinished();
+	void showingStarted();
+
+	void startAnimation();
+
+	const style::dropdown &_st;
+
+	bool _hiding = false;
+
+	QPixmap _cache;
+	FloatAnimation _a_appearance;
+
+	QTimer _hideTimer;
+
+	BoxShadow _shadow;
+	ChildWidget<ScrollArea> _scroll;
+
+};
+
+} // namespace Ui
diff --git a/Telegram/SourceFiles/ui/scrollarea.h b/Telegram/SourceFiles/ui/scrollarea.h
index 1552cf5ad..43a0d4817 100644
--- a/Telegram/SourceFiles/ui/scrollarea.h
+++ b/Telegram/SourceFiles/ui/scrollarea.h
@@ -268,3 +268,25 @@ public:
 	}
 	void paintEvent(QPaintEvent *e);
 };
+
+class ScrolledWidget : public TWidget {
+public:
+	ScrolledWidget(QWidget *parent = nullptr) : TWidget(parent) {
+	}
+
+	// Count new height for width=newWidth and resize to it.
+	void resizeToWidth(int newWidth) {
+		resize(newWidth, resizeGetHeight(newWidth));
+	}
+
+	// Updates the area that is visible inside the scroll container.
+	virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
+	}
+
+protected:
+	// Resizes content and counts natural widget height for the desired width.
+	virtual int resizeGetHeight(int newWidth) {
+		return height();
+	}
+
+};
diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h
index 089b9379c..2fe3a169e 100644
--- a/Telegram/SourceFiles/ui/twidget.h
+++ b/Telegram/SourceFiles/ui/twidget.h
@@ -127,9 +127,9 @@ return qobject_cast<TWidget*>(parentWidget()); \
 const TWidget *tparent() const { \
 	return qobject_cast<const TWidget*>(parentWidget()); \
 } \
-virtual void leaveToChildEvent(QEvent *e) { /* e -- from enterEvent() of child TWidget */ \
+virtual void leaveToChildEvent(QEvent *e, QWidget *child) { /* e -- from enterEvent() of child TWidget */ \
 } \
-virtual void enterFromChildEvent(QEvent *e) { /* e -- from leaveEvent() of child TWidget */ \
+virtual void enterFromChildEvent(QEvent *e, QWidget *child) { /* e -- from leaveEvent() of child TWidget */ \
 } \
 void moveToLeft(int x, int y, int outerw = 0) { \
 	move(rtl() ? ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()) : x, y); \
@@ -158,12 +158,12 @@ void rtlupdate(int x, int y, int w, int h) { \
 protected: \
 void enterEvent(QEvent *e) override { \
 	TWidget *p(tparent()); \
-	if (p) p->leaveToChildEvent(e); \
+	if (p) p->leaveToChildEvent(e, this); \
 	return enterEventHook(e); \
 } \
 void leaveEvent(QEvent *e) override { \
 	TWidget *p(tparent()); \
-	if (p) p->enterFromChildEvent(e); \
+	if (p) p->enterFromChildEvent(e, this); \
 	return leaveEventHook(e); \
 }
 
@@ -199,6 +199,9 @@ public:
 		}
 	}
 
+	virtual ~TWidget() {
+	}
+
 protected:
 	void enterEventHook(QEvent *e) {
 		return QWidget::enterEvent(e);
diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp
index 6c1772c79..2cb04a169 100644
--- a/Telegram/SourceFiles/window/top_bar_widget.cpp
+++ b/Telegram/SourceFiles/window/top_bar_widget.cpp
@@ -86,9 +86,11 @@ void TopBarWidget::enterEvent(QEvent *e) {
 	_a_appearance.start();
 }
 
-void TopBarWidget::enterFromChildEvent(QEvent *e) {
-	a_over.start(1);
-	_a_appearance.start();
+void TopBarWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
+	if (child != _membersShowArea) {
+		a_over.start(1);
+		_a_appearance.start();
+	}
 }
 
 void TopBarWidget::leaveEvent(QEvent *e) {
@@ -96,9 +98,11 @@ void TopBarWidget::leaveEvent(QEvent *e) {
 	_a_appearance.start();
 }
 
-void TopBarWidget::leaveToChildEvent(QEvent *e) {
-	a_over.start(0);
-	_a_appearance.start();
+void TopBarWidget::leaveToChildEvent(QEvent *e, QWidget *child) {
+	if (child != _membersShowArea) {
+		a_over.start(0);
+		_a_appearance.start();
+	}
 }
 
 void TopBarWidget::step_appearance(float64 ms, bool timer) {
@@ -112,6 +116,25 @@ void TopBarWidget::step_appearance(float64 ms, bool timer) {
 	if (timer) update();
 }
 
+bool TopBarWidget::eventFilter(QObject *obj, QEvent *e) {
+	if (obj == _membersShowArea) {
+		switch (e->type()) {
+		case QEvent::MouseButtonPress:
+			mousePressEvent(static_cast<QMouseEvent*>(e));
+			return true;
+
+		case QEvent::Enter:
+			main()->setMembersShowAreaActive(true);
+			break;
+
+		case QEvent::Leave:
+			main()->setMembersShowAreaActive(false);
+			break;
+		}
+	}
+	return TWidget::eventFilter(obj, e);
+}
+
 void TopBarWidget::paintEvent(QPaintEvent *e) {
 	Painter p(this);
 
@@ -136,8 +159,7 @@ void TopBarWidget::paintEvent(QPaintEvent *e) {
 }
 
 void TopBarWidget::mousePressEvent(QMouseEvent *e) {
-	PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
-	if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && (p || !_selCount)) {
+	if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && !_selCount) {
 		emit clicked();
 	}
 }
@@ -209,12 +231,16 @@ void TopBarWidget::startAnim() {
 	_forward->hide();
 	_mediaType->hide();
 	_search->hide();
+	if (_membersShowArea) {
+		_membersShowArea->hide();
+	}
 
 	_animating = true;
 }
 
 void TopBarWidget::stopAnim() {
 	_animating = false;
+	updateMembersShowArea();
 	showAll();
 }
 
@@ -255,21 +281,53 @@ void TopBarWidget::showAll() {
 		_search->hide();
 		_info->hide();
 	}
+	if (_membersShowArea) {
+		_membersShowArea->show();
+	}
 	resizeEvent(nullptr);
 }
 
+void TopBarWidget::updateMembersShowArea() {
+	auto membersShowAreaNeeded = [this]() {
+		if (_selCount || App::main()->overviewPeer() || !_selPeer) {
+			return false;
+		}
+		if (_selPeer->isChat()) {
+			return true;
+		}
+		if (_selPeer->isMegagroup()) {
+			return (_selPeer->asMegagroup()->membersCount() < Global::ChatSizeMax());
+		}
+		return false;
+	};
+	if (!membersShowAreaNeeded()) {
+		if (_membersShowArea) {
+			main()->setMembersShowAreaActive(false);
+			_membersShowArea.destroy();
+		}
+		return;
+	} else if (!_membersShowArea) {
+		_membersShowArea = new TWidget(this);
+		_membersShowArea->show();
+		_membersShowArea->installEventFilter(this);
+	}
+	_membersShowArea->setGeometry(App::main()->getMembersShowAreaGeometry());
+}
+
 void TopBarWidget::showSelected(uint32 selCount, bool canDelete) {
-	PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
 	_selPeer = App::main()->overviewPeer() ? App::main()->overviewPeer() : App::main()->peer();
 	_selCount = selCount;
 	_canDelete = canDelete;
 	_selStr = (_selCount > 0) ? lng_selected_count(lt_count, _selCount) : QString();
 	_selStrWidth = st::btnDefLink.font->width(_selStr);
-	setCursor((!p && _selCount) ? style::cur_default : style::cur_pointer);
+	setCursor(_selCount ? style::cur_default : style::cur_pointer);
+
+	updateMembersShowArea();
 	showAll();
 }
 
 void TopBarWidget::updateAdaptiveLayout() {
+	updateMembersShowArea();
 	showAll();
 }
 
diff --git a/Telegram/SourceFiles/window/top_bar_widget.h b/Telegram/SourceFiles/window/top_bar_widget.h
index 0f0d140bf..696d1afd2 100644
--- a/Telegram/SourceFiles/window/top_bar_widget.h
+++ b/Telegram/SourceFiles/window/top_bar_widget.h
@@ -38,9 +38,9 @@ public:
 	TopBarWidget(MainWidget *w);
 
 	void enterEvent(QEvent *e) override;
-	void enterFromChildEvent(QEvent *e) override;
+	void enterFromChildEvent(QEvent *e, QWidget *child) override;
 	void leaveEvent(QEvent *e) override;
-	void leaveToChildEvent(QEvent *e) override;
+	void leaveToChildEvent(QEvent *e, QWidget *child) override;
 	void paintEvent(QPaintEvent *e) override;
 	void mousePressEvent(QMouseEvent *e) override;
 	void resizeEvent(QResizeEvent *e) override;
@@ -54,8 +54,13 @@ public:
 
 	void updateAdaptiveLayout();
 
+	void updateMembersShowArea();
+
 	Ui::RoundButton *mediaTypeButton();
 
+protected:
+	bool eventFilter(QObject *obj, QEvent *e) override;
+
 public slots:
 	void onForwardSelection();
 	void onDeleteSelection();
@@ -87,6 +92,7 @@ private:
 	ChildWidget<Ui::RoundButton> _mediaType;
 
 	ChildWidget<IconedButton> _search;
+	ChildWidget<TWidget> _membersShowArea = { nullptr };
 
 };
 
diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj
index 764a5d330..9e96d8911 100644
--- a/Telegram/Telegram.vcxproj
+++ b/Telegram/Telegram.vcxproj
@@ -310,6 +310,10 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Debug\moc_inner_dropdown.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="GeneratedFiles\Debug\moc_introcode.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -631,6 +635,10 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Deploy\moc_inner_dropdown.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="GeneratedFiles\Deploy\moc_introcode.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -988,6 +996,10 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_inner_dropdown.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="GeneratedFiles\Release\moc_introcode.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -1351,6 +1363,7 @@
     <ClCompile Include="SourceFiles\ui\flatlabel.cpp" />
     <ClCompile Include="SourceFiles\ui\flattextarea.cpp" />
     <ClCompile Include="SourceFiles\ui\images.cpp" />
+    <ClCompile Include="SourceFiles\ui\inner_dropdown.cpp" />
     <ClCompile Include="SourceFiles\ui\popupmenu.cpp" />
     <ClCompile Include="SourceFiles\ui\scrollarea.cpp" />
     <ClCompile Include="SourceFiles\ui\style\style_core.cpp" />
@@ -1949,6 +1962,20 @@
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
       <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS  "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" "-fstdafx.h" "-f../../SourceFiles/ui/twidget.h"</Command>
     </CustomBuild>
+    <CustomBuild Include="SourceFiles\ui\inner_dropdown.h">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing inner_dropdown.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/ui/inner_dropdown.h"  -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing inner_dropdown.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/ui/inner_dropdown.h"  -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing inner_dropdown.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/ui/inner_dropdown.h"  -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
+    </CustomBuild>
     <ClInclude Include="SourceFiles\ui\style\style_core.h" />
     <ClInclude Include="SourceFiles\ui\style\style_core_color.h" />
     <ClInclude Include="SourceFiles\ui\style\style_core_font.h" />
diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters
index ec92871bb..131db6907 100644
--- a/Telegram/Telegram.vcxproj.filters
+++ b/Telegram/Telegram.vcxproj.filters
@@ -1329,6 +1329,18 @@
     <ClCompile Include="GeneratedFiles\Release\moc_main_window_linux.cpp">
       <Filter>GeneratedFiles\Release</Filter>
     </ClCompile>
+    <ClCompile Include="SourceFiles\ui\inner_dropdown.cpp">
+      <Filter>SourceFiles\ui</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Deploy\moc_inner_dropdown.cpp">
+      <Filter>GeneratedFiles\Deploy</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Debug\moc_inner_dropdown.cpp">
+      <Filter>GeneratedFiles\Debug</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_inner_dropdown.cpp">
+      <Filter>GeneratedFiles\Release</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="SourceFiles\stdafx.h">
@@ -1864,6 +1876,9 @@
     <CustomBuild Include="SourceFiles\platform\linux\main_window_linux.h">
       <Filter>SourceFiles\platform\linux</Filter>
     </CustomBuild>
+    <CustomBuild Include="SourceFiles\ui\inner_dropdown.h">
+      <Filter>SourceFiles\ui</Filter>
+    </CustomBuild>
   </ItemGroup>
   <ItemGroup>
     <None Include="Resources\langs\lang_it.strings">

From 7db7b177c03109ac8e4c973eaf99e677f3d45c6e Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 20 Jun 2016 14:31:12 +0300
Subject: [PATCH 2/2] Members block in group conversation view finished (except
 Xcode project).

---
 Telegram/Resources/basic.style                |  11 +++
 Telegram/Resources/basic_types.style          |  12 +++
 Telegram/Resources/icons/dropdown_shadow.png  | Bin 0 -> 128 bytes
 .../Resources/icons/dropdown_shadow@2x.png    | Bin 0 -> 146 bytes
 .../SourceFiles/codegen/style/generator.cpp   |   4 +
 Telegram/SourceFiles/codegen/style/module.cpp |   8 +-
 Telegram/SourceFiles/codegen/style/module.h   |   2 +-
 .../SourceFiles/codegen/style/parsed_file.cpp |  20 ++++-
 Telegram/SourceFiles/history/history.style    |  13 +++
 Telegram/SourceFiles/historywidget.cpp        |  17 +++-
 Telegram/SourceFiles/historywidget.h          |   2 +
 .../profile/profile_block_widget.cpp          |   2 +-
 Telegram/SourceFiles/ui/boxshadow.cpp         |  78 +++++++++++++++++-
 Telegram/SourceFiles/ui/boxshadow.h           |  29 +++++++
 Telegram/SourceFiles/ui/inner_dropdown.cpp    |  76 +++++++++++++++--
 Telegram/SourceFiles/ui/inner_dropdown.h      |  36 +++++++-
 Telegram/SourceFiles/ui/scrollarea.h          |   5 ++
 Telegram/Telegram.pro                         |   2 +
 Telegram/Telegram.xcodeproj/qt_preprocess.mak |   6 ++
 19 files changed, 304 insertions(+), 19 deletions(-)
 create mode 100644 Telegram/Resources/icons/dropdown_shadow.png
 create mode 100644 Telegram/Resources/icons/dropdown_shadow@2x.png

diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style
index ab50abf44..77912a38d 100644
--- a/Telegram/Resources/basic.style
+++ b/Telegram/Resources/basic.style
@@ -1734,6 +1734,17 @@ dropdownDef: dropdown {
 	width: 0px;
 }
 
+defaultInnerDropdownShadow: icon {
+	{ "dropdown_shadow", windowShadowFg },
+};
+defaultInnerDropdown: InnerDropdown {
+	padding: margins(10px, 10px, 10px, 10px);
+	shadow: defaultInnerDropdownShadow;
+	shadowShift: 1px;
+
+	duration: 150;
+}
+
 dropdownAttachDocument: iconedButton(btnAttachDocument) {
 	iconPos: point(14px, 13px);
 	downIconPos: point(14px, 14px);
diff --git a/Telegram/Resources/basic_types.style b/Telegram/Resources/basic_types.style
index 30d53110a..c8e1fa0f4 100644
--- a/Telegram/Resources/basic_types.style
+++ b/Telegram/Resources/basic_types.style
@@ -246,6 +246,18 @@ dropdown {
 	width: pixels;
 }
 
+InnerDropdown {
+	padding: margins;
+	shadow: icon;
+	shadowShift: pixels;
+
+	duration: int;
+	width: pixels;
+
+	scrollMargin: margins;
+	scrollPadding: margins;
+}
+
 PopupMenu {
 	skip: pixels;
 
diff --git a/Telegram/Resources/icons/dropdown_shadow.png b/Telegram/Resources/icons/dropdown_shadow.png
new file mode 100644
index 0000000000000000000000000000000000000000..7055a8b49d1e330ddb55af26f5885daee676b4bc
GIT binary patch
literal 128
zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XLTJzX3_IA-Rab>un_z~gjqxx}WQ
z-|Z9hF6ntOx9$>R3p{YtpGkq!^Txe>6Ixa&ac+~};2T<aZsBgvPq8KD#>@@z8+<3(
a?q^hJV(FWHr7;I+B!j1`pUXO@geCw`L@IRv

literal 0
HcmV?d00001

diff --git a/Telegram/Resources/icons/dropdown_shadow@2x.png b/Telegram/Resources/icons/dropdown_shadow@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..1931c7b11f2dd9ca5696bf63775026d9f503f2e8
GIT binary patch
literal 146
zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a)4NKY5X5RHjjCwg-oaNuwjUVQk@
z|0cPmcSWB$M|1P0Bz|agWU>gD5IW7C(T-h({XUb5;>%Cj3%>VtG~BHEDAvKT<(k4v
uNd->hW|bZKqSr5NHY%R+|G%@O1>-L+mf8u^9oGOYVeoYIb6Mw<&;$TcP%&fx

literal 0
HcmV?d00001

diff --git a/Telegram/SourceFiles/codegen/style/generator.cpp b/Telegram/SourceFiles/codegen/style/generator.cpp
index 801d5220f..84aa5e57e 100644
--- a/Telegram/SourceFiles/codegen/style/generator.cpp
+++ b/Telegram/SourceFiles/codegen/style/generator.cpp
@@ -646,6 +646,10 @@ bool Generator::collectUniqueValues() {
 	int iconMaskIndex = 0;
 	std::function<bool(const Variable&)> collector = [this, &collector, &fontFamilyIndex, &iconMaskIndex](const Variable &variable) {
 		auto value = variable.value;
+		if (!value.copyOf().isEmpty()) {
+			return true;
+		}
+
 		switch (value.type().tag) {
 		case Tag::Invalid:
 		case Tag::Int:
diff --git a/Telegram/SourceFiles/codegen/style/module.cpp b/Telegram/SourceFiles/codegen/style/module.cpp
index d11d4cdd0..ca49d8a23 100644
--- a/Telegram/SourceFiles/codegen/style/module.cpp
+++ b/Telegram/SourceFiles/codegen/style/module.cpp
@@ -52,7 +52,7 @@ const Struct *Module::findStruct(const FullName &name) const {
 		return result;
 	}
 	for (const auto &module : included_) {
-		if (auto result = findStructInModule(name, *module)) {
+		if (auto result = module->findStruct(name)) {
 			return result;
 		}
 	}
@@ -68,12 +68,14 @@ bool Module::addVariable(const Variable &value) {
 	return true;
 }
 
-const Variable *Module::findVariable(const FullName &name) const {
+const Variable *Module::findVariable(const FullName &name, bool *outFromThisModule) const {
 	if (auto result = findVariableInModule(name, *this)) {
+		if (outFromThisModule) *outFromThisModule = true;
 		return result;
 	}
 	for (const auto &module : included_) {
-		if (auto result = findVariableInModule(name, *module)) {
+		if (auto result = module->findVariable(name)) {
+			if (outFromThisModule) *outFromThisModule = false;
 			return result;
 		}
 	}
diff --git a/Telegram/SourceFiles/codegen/style/module.h b/Telegram/SourceFiles/codegen/style/module.h
index a890fd7dd..f8a043286 100644
--- a/Telegram/SourceFiles/codegen/style/module.h
+++ b/Telegram/SourceFiles/codegen/style/module.h
@@ -75,7 +75,7 @@ public:
 	// Returns false if there is a variable with such name already.
 	bool addVariable(const Variable &value);
 	// Returns nullptr if there is no such variable in result_ or any of included modules.
-	const Variable *findVariable(const FullName &name) const;
+	const Variable *findVariable(const FullName &name, bool *outFromThisModule = nullptr) const;
 	bool hasVariables() const {
 		return !variables_.isEmpty();
 	}
diff --git a/Telegram/SourceFiles/codegen/style/parsed_file.cpp b/Telegram/SourceFiles/codegen/style/parsed_file.cpp
index 859a7a428..a7acde231 100644
--- a/Telegram/SourceFiles/codegen/style/parsed_file.cpp
+++ b/Telegram/SourceFiles/codegen/style/parsed_file.cpp
@@ -43,6 +43,7 @@ constexpr int kErrorUnknownField       = 803;
 constexpr int kErrorIdentifierNotFound = 804;
 constexpr int kErrorAlreadyDefined     = 805;
 constexpr int kErrorBadString          = 806;
+constexpr int kErrorIconDuplicate      = 807;
 
 QString findInputFile(const Options &options) {
 	for (const auto &dir : options.includePaths) {
@@ -351,7 +352,8 @@ structure::Value ParsedFile::defaultConstructedStruct(const structure::FullName
 }
 
 void ParsedFile::applyStructParent(structure::Value &result, const structure::FullName &parentName) {
-	if (auto parent = module_->findVariable(parentName)) {
+	bool fromTheSameModule = false;
+	if (auto parent = module_->findVariable(parentName, &fromTheSameModule)) {
 		if (parent->value.type() != result.type()) {
 			logErrorTypeMismatch() << "parent '" << logFullName(parentName) << "' has type '" << logType(parent->value.type()) << "' while child value has type " << logType(result.type());
 			return;
@@ -374,6 +376,22 @@ void ParsedFile::applyStructParent(structure::Value &result, const structure::Fu
 				const auto &srcValue(srcField.variable.value);
 				auto &dstValue(dstField.variable.value);
 				logAssert(srcValue.type() == dstValue.type()) << "struct field type check failed";
+
+				// Optimization: don't let the style files to contain unnamed inherited
+				// icons from the other (included) style files, because they will
+				// duplicate the binary data across different style c++ source files.
+				//
+				// Example:
+				// a.style has "A: Struct { icon: icon { ..file.. } };" and
+				// b.style has "B: Struct(A) { .. };" with non-overriden icon field.
+				// Then both style_a.cpp and style_b.cpp will contain binary data of "file".
+				if (!fromTheSameModule
+					&& srcValue.type().tag == structure::TypeTag::Icon
+					&& !srcValue.Icon().parts.empty()
+					&& srcValue.copyOf().isEmpty()) {
+					logError(kErrorIconDuplicate) << "an unnamed icon field '" << logFullName(srcField.variable.name) << "' is inherited from parent '" << logFullName(parentName) << "'";
+					return;
+				}
 				dstValue = srcValue;
 				dstField.status = Status::Implicit;
 			}
diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style
index 1a5d33f1d..9ab0bd79f 100644
--- a/Telegram/SourceFiles/history/history.style
+++ b/Telegram/SourceFiles/history/history.style
@@ -29,3 +29,16 @@ historyToDownArrow: icon {
 	{ "history_down_arrow", #b9b9b9, point(14px, 19px) },
 };
 historyToDownPaddingTop: 10px;
+
+membersInnerScroll: flatScroll(solidScroll) {
+	deltat: 3px;
+	deltab: 3px;
+	width: 8px;
+	deltax: 3px;
+}
+membersInnerWidth: 310px;
+membersInnerHeightMax: 360px;
+membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
+	scrollMargin: margins(0px, 5px, 0px, 5px);
+	scrollPadding: margins(0px, 3px, 8px, 3px);
+}
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index e2018e752..cefc5bc07 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -6027,9 +6027,12 @@ QRect HistoryWidget::getMembersShowAreaGeometry() const {
 void HistoryWidget::setMembersShowAreaActive(bool active) {
 	if (active && _peer && (_peer->isChat() || _peer->isMegagroup())) {
 		if (!_membersDropdown) {
-			_membersDropdown = new Ui::InnerDropdown(this, st::dropdownDef, st::solidScroll);
+			_membersDropdown = new Ui::InnerDropdown(this, st::membersInnerDropdown, st::membersInnerScroll);
 			_membersDropdown->setOwnedWidget(new Profile::MembersWidget(_membersDropdown, _peer, Profile::MembersWidget::TitleVisibility::Hidden));
-			_membersDropdown->setGeometry(0, 0, st::emojiPanWidth, st::emojiPanMaxHeight);
+			_membersDropdown->resize(st::membersInnerWidth, _membersDropdown->height());
+
+			_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
+			_membersDropdown->moveToLeft(0, 0);
 			connect(_membersDropdown, SIGNAL(hidden()), this, SLOT(onMembersDropdownHidden()));
 		}
 		_membersDropdown->otherEnter();
@@ -6721,6 +6724,9 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
 	_historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll.y() + _scroll.height() - _historyToEnd->height() - st::historyToDownPosition.y());
 
 	_emojiPan.setMaxHeight(height() - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom() - _attachEmoji.height());
+	if (_membersDropdown) {
+		_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
+	}
 
 	switch (_attachDrag) {
 	case DragStateFiles:
@@ -7682,6 +7688,13 @@ void HistoryWidget::cancelReplyAfterMediaSend(bool lastKeyboardUsed) {
 	}
 }
 
+int HistoryWidget::countMembersDropdownHeightMax() const {
+	int result = height() - st::membersInnerDropdown.padding.top() - st::membersInnerDropdown.padding.bottom();
+	result -= _attachEmoji.height();
+	accumulate_min(result, st::membersInnerHeightMax);
+	return result;
+}
+
 void HistoryWidget::cancelEdit() {
 	if (!_editMsgId) return;
 
diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h
index e274de9d3..f506787c4 100644
--- a/Telegram/SourceFiles/historywidget.h
+++ b/Telegram/SourceFiles/historywidget.h
@@ -867,6 +867,8 @@ private:
 
 	void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
 
+	int countMembersDropdownHeightMax() const;
+
 	MsgId _replyToId = 0;
 	Text _replyToName;
 	int _replyToNameVersion = 0;
diff --git a/Telegram/SourceFiles/profile/profile_block_widget.cpp b/Telegram/SourceFiles/profile/profile_block_widget.cpp
index f6d108fa7..93007eefc 100644
--- a/Telegram/SourceFiles/profile/profile_block_widget.cpp
+++ b/Telegram/SourceFiles/profile/profile_block_widget.cpp
@@ -31,7 +31,7 @@ BlockWidget::BlockWidget(QWidget *parent, PeerData *peer, const QString &title)
 }
 
 int BlockWidget::contentTop() const {
-	return st::profileBlockMarginTop + (emptyTitle() ? 0 : st::profileBlockTitleHeight);
+	return emptyTitle() ? 0 : (st::profileBlockMarginTop + st::profileBlockTitleHeight);
 }
 
 void BlockWidget::paintEvent(QPaintEvent *e) {
diff --git a/Telegram/SourceFiles/ui/boxshadow.cpp b/Telegram/SourceFiles/ui/boxshadow.cpp
index 0ca3d787d..9e52f6229 100644
--- a/Telegram/SourceFiles/ui/boxshadow.cpp
+++ b/Telegram/SourceFiles/ui/boxshadow.cpp
@@ -60,7 +60,7 @@ BoxShadow::BoxShadow(const style::sprite &topLeft) : _size(topLeft.pxWidth()), _
 	_corners.setDevicePixelRatio(cRetinaFactor());
 	_colors.reserve(_pixsize);
 	uchar prev = 0;
-	for (int32 i = 0; i < _pixsize; ++i) {
+	for (int i = 0; i < _pixsize; ++i) {
 		uchar a = (cornersImage.pixel(QPoint(i, _pixsize - 1)) >> 24);
 		if (a < prev) break;
 
@@ -112,3 +112,79 @@ style::margins BoxShadow::getDimensions(int32 shifty) const {
 	int32 d = _colors.size() / cIntRetinaFactor();
 	return style::margins(d - shifty, d - 2 * shifty, d - shifty, d);
 }
+
+namespace Ui {
+
+RectShadow::RectShadow(const style::icon &topLeft) : _size(topLeft.width()), _pixsize(_size * cIntRetinaFactor()) {
+	if (!_size) return;
+
+	QImage cornersImage(_pixsize * 2, _pixsize * 2, QImage::Format_ARGB32_Premultiplied);
+	cornersImage.setDevicePixelRatio(cRetinaFactor());
+	{
+		Painter p(&cornersImage);
+		p.setCompositionMode(QPainter::CompositionMode_Source);
+		topLeft.paint(p, QPoint(0, 0), _size);
+	}
+	if (rtl()) cornersImage = cornersImage.mirrored(true, false);
+	{
+		QPainter p(&cornersImage);
+		p.setCompositionMode(QPainter::CompositionMode_Source);
+		QImage m = cornersImage.mirrored();
+		m.setDevicePixelRatio(cRetinaFactor());
+		p.drawImage(0, _size, m, 0, _pixsize, _pixsize, _pixsize);
+	}
+	{
+		QPainter p(&cornersImage);
+		p.setCompositionMode(QPainter::CompositionMode_Source);
+		QImage m = cornersImage.mirrored(true, false);
+		m.setDevicePixelRatio(cRetinaFactor());
+		p.drawImage(_size, 0, m, _pixsize, 0, _pixsize, _pixsize * 2);
+	}
+	_corners = QPixmap::fromImage(cornersImage, Qt::ColorOnly);
+	_corners.setDevicePixelRatio(cRetinaFactor());
+
+	uchar prev = 0;
+	for (int i = 0; i < _pixsize; ++i) {
+		uchar a = (cornersImage.pixel(QPoint(i, _pixsize - 1)) >> 24);
+		if (a < prev) break;
+
+		++_thickness;
+		prev = a;
+	}
+
+	_left = QPixmap::fromImage(cornersImage.copy(0, _pixsize - 1, _thickness, 1), Qt::ColorOnly);
+	_left.setDevicePixelRatio(cRetinaFactor());
+	_top = QPixmap::fromImage(cornersImage.copy(_pixsize - 1, 0, 1, _thickness), Qt::ColorOnly);
+	_top.setDevicePixelRatio(cRetinaFactor());
+	_right = QPixmap::fromImage(cornersImage.copy(_pixsize * 2 - _thickness, _pixsize, _thickness, 1), Qt::ColorOnly);
+	_right.setDevicePixelRatio(cRetinaFactor());
+	_bottom = QPixmap::fromImage(cornersImage.copy(_pixsize, _pixsize * 2 - _thickness, 1, _thickness), Qt::ColorOnly);
+	_bottom.setDevicePixelRatio(cRetinaFactor());
+}
+
+void RectShadow::paint(Painter &p, const QRect &box, int shifty, Sides sides) {
+	if (!_size) return;
+
+	int32 rshifty = shifty * cIntRetinaFactor();
+	int32 count = _thickness, countsize = count / cIntRetinaFactor(), minus = _size - countsize + shifty;
+	bool left = (sides & Side::Left), top = (sides & Side::Top), right = (sides & Side::Right), bottom = (sides & Side::Bottom);
+	if (left && top) p.drawPixmap(box.left() - _size + minus, box.top() - _size + minus + shifty, _corners, 0, 0, _pixsize, _pixsize);
+	if (right && top) p.drawPixmap(box.left() + box.width() - minus, box.top() - _size + minus + shifty, _corners, _pixsize, 0, _pixsize, _pixsize);
+	if (right && bottom) p.drawPixmap(box.left() + box.width() - minus, box.top() + box.height() - minus + shifty, _corners, _pixsize, _pixsize, _pixsize, _pixsize);
+	if (left && bottom) p.drawPixmap(box.left() - _size + minus, box.top() + box.height() - minus + shifty, _corners, 0, _pixsize, _pixsize, _pixsize);
+
+	bool wasSmooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
+	if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
+	if (left) p.drawPixmap(box.left() - countsize + shifty, box.top() + (top ? minus : 0) + shifty, countsize - shifty, box.height() - (bottom ? minus : 0) - (top ? minus : 0), _left, 0, 0, count - rshifty, 1);
+	if (top) p.drawPixmap(box.left() + (left ? minus : 0), box.top() - countsize + 2 * shifty, box.width() - (right ? minus : 0) - (left ? minus : 0), countsize - 2 * shifty, _top, 0, 0, 1, count - 2 * rshifty);
+	if (right) p.drawPixmap(box.left() + box.width(), box.top() + (top ? minus : 0) + shifty, countsize - shifty, box.height() - (bottom ? minus : 0) - (top ? minus : 0), _right, rshifty, 0, count - rshifty, 1);
+	if (bottom) p.drawPixmap(box.left() + (left ? minus : 0), box.top() + box.height(), box.width() - (right ? minus : 0) - (left ? minus : 0), countsize, _bottom, 0, 0, 1, count);
+	if (wasSmooth) p.setRenderHint(QPainter::SmoothPixmapTransform);
+}
+
+style::margins RectShadow::getDimensions(int32 shifty) const {
+	int d = _thickness / cIntRetinaFactor();
+	return style::margins(d - shifty, d - 2 * shifty, d - shifty, d);
+}
+
+} // namespace Ui
diff --git a/Telegram/SourceFiles/ui/boxshadow.h b/Telegram/SourceFiles/ui/boxshadow.h
index bd4bb7765..3eeb30292 100644
--- a/Telegram/SourceFiles/ui/boxshadow.h
+++ b/Telegram/SourceFiles/ui/boxshadow.h
@@ -42,3 +42,32 @@ private:
 	QVector<style::color> _colors;
 
 };
+
+namespace Ui {
+
+class RectShadow {
+public:
+	enum class Side {
+		Left   = 0x01,
+		Top    = 0x02,
+		Right  = 0x04,
+		Bottom = 0x08,
+	};
+	Q_DECLARE_FLAGS(Sides, Side);
+	Q_DECLARE_FRIEND_OPERATORS_FOR_FLAGS(Sides);
+
+	RectShadow(const style::icon &topLeft);
+
+	void paint(Painter &p, const QRect &box, int shifty, Sides sides = Side::Left | Side::Top | Side::Right | Side::Bottom);
+	style::margins getDimensions(int shifty) const;
+
+private:
+
+	int _size, _pixsize;
+	int _thickness = 0;
+	QPixmap _corners, _left, _top, _right, _bottom;
+
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(RectShadow::Sides);
+
+} // namespace Ui
\ No newline at end of file
diff --git a/Telegram/SourceFiles/ui/inner_dropdown.cpp b/Telegram/SourceFiles/ui/inner_dropdown.cpp
index dd1b49283..ad6ccf238 100644
--- a/Telegram/SourceFiles/ui/inner_dropdown.cpp
+++ b/Telegram/SourceFiles/ui/inner_dropdown.cpp
@@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 
 namespace Ui {
 
-InnerDropdown::InnerDropdown(QWidget *parent, const style::dropdown &st, const style::flatScroll &scrollSt) : TWidget(parent)
+InnerDropdown::InnerDropdown(QWidget *parent, const style::InnerDropdown &st, const style::flatScroll &scrollSt) : TWidget(parent)
 , _st(st)
 , _shadow(_st.shadow)
 , _scroll(this, scrollSt) {
@@ -44,10 +44,35 @@ InnerDropdown::InnerDropdown(QWidget *parent, const style::dropdown &st, const s
 }
 
 void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
-	_scroll->setOwnedWidget(widget);
+	auto container = new internal::Container(_scroll, widget, _st);
+	connect(container, SIGNAL(heightUpdated()), this, SLOT(onWidgetHeightUpdated()));
+	_scroll->setOwnedWidget(container);
+	container->resizeToWidth(_scroll->width());
+	container->moveToLeft(0, 0);
+	container->show();
 	widget->show();
-	widget->move(0, 0);
-	widget->resizeToWidth(_scroll->width() - st::scrollDef.width);
+}
+
+void InnerDropdown::setMaxHeight(int newMaxHeight) {
+	_maxHeight = newMaxHeight;
+	updateHeight();
+}
+
+void InnerDropdown::onWidgetHeightUpdated() {
+	updateHeight();
+}
+
+void InnerDropdown::updateHeight() {
+	int newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
+	if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
+		newHeight += widget->height();
+	}
+	if (_maxHeight > 0) {
+		accumulate_min(newHeight, _maxHeight);
+	}
+	if (newHeight != height()) {
+		resize(width(), newHeight);
+	}
 }
 
 void InnerDropdown::onWindowActiveChanged() {
@@ -57,9 +82,9 @@ void InnerDropdown::onWindowActiveChanged() {
 }
 
 void InnerDropdown::resizeEvent(QResizeEvent *e) {
-	_scroll->setGeometry(rect().marginsRemoved(_st.padding));
+	_scroll->setGeometry(rect().marginsRemoved(_st.padding).marginsRemoved(_st.scrollMargin));
 	if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
-		widget->resizeToWidth(_scroll->width() - st::scrollDef.width);
+		widget->resizeToWidth(_scroll->width());
 		onScroll();
 	}
 }
@@ -73,7 +98,7 @@ void InnerDropdown::onScroll() {
 }
 
 void InnerDropdown::paintEvent(QPaintEvent *e) {
-	QPainter p(this);
+	Painter p(this);
 
 	if (!_cache.isNull()) {
 		bool animating = _a_appearance.animating(getms());
@@ -182,4 +207,41 @@ bool InnerDropdown::eventFilter(QObject *obj, QEvent *e) {
 	return false;
 }
 
+namespace internal {
+
+Container::Container(QWidget *parent, ScrolledWidget *child, const style::InnerDropdown &st) : ScrolledWidget(parent), _st(st) {
+	child->setParent(this);
+	child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
+	connect(child, SIGNAL(heightUpdated()), this, SLOT(onHeightUpdate()));
+}
+
+void Container::setVisibleTopBottom(int visibleTop, int visibleBottom) {
+	if (auto child = static_cast<ScrolledWidget*>(children().front())) {
+		child->setVisibleTopBottom(visibleTop - _st.scrollPadding.top(), visibleBottom - _st.scrollPadding.top());
+	}
+}
+
+void Container::onHeightUpdate() {
+	int newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom();
+	if (auto child = static_cast<ScrolledWidget*>(children().front())) {
+		newHeight += child->height();
+	}
+	if (newHeight != height()) {
+		resize(width(), newHeight);
+		emit heightUpdated();
+	}
+}
+
+int Container::resizeGetHeight(int newWidth) {
+	int innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right();
+	int result = _st.scrollPadding.top() + _st.scrollPadding.bottom();
+	if (auto child = static_cast<ScrolledWidget*>(children().front())) {
+		child->resizeToWidth(innerWidth);
+		child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
+		result += child->height();
+	}
+	return result;
+}
+
+} // namespace internal
 } // namespace Ui
diff --git a/Telegram/SourceFiles/ui/inner_dropdown.h b/Telegram/SourceFiles/ui/inner_dropdown.h
index 827016002..55974f78e 100644
--- a/Telegram/SourceFiles/ui/inner_dropdown.h
+++ b/Telegram/SourceFiles/ui/inner_dropdown.h
@@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 */
 #pragma once
 
+#include "ui/boxshadow.h"
+
 class ScrollArea;
 
 namespace Ui {
@@ -28,7 +30,7 @@ class InnerDropdown : public TWidget {
 	Q_OBJECT
 
 public:
-	InnerDropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef, const style::flatScroll &scrollSt = st::scrollDef);
+	InnerDropdown(QWidget *parent, const style::InnerDropdown &st = st::defaultInnerDropdown, const style::flatScroll &scrollSt = st::scrollDef);
 
 	void setOwnedWidget(ScrolledWidget *widget);
 
@@ -38,6 +40,8 @@ public:
 		return rect().marginsRemoved(_st.padding).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
 	}
 
+	void setMaxHeight(int newMaxHeight);
+
 	void otherEnter();
 	void otherLeave();
 
@@ -56,6 +60,7 @@ private slots:
 	void onHideStart();
 	void onWindowActiveChanged();
 	void onScroll();
+	void onWidgetHeightUpdated();
 
 private:
 	void repaintCallback();
@@ -65,7 +70,9 @@ private:
 
 	void startAnimation();
 
-	const style::dropdown &_st;
+	void updateHeight();
+
+	const style::InnerDropdown &_st;
 
 	bool _hiding = false;
 
@@ -74,9 +81,32 @@ private:
 
 	QTimer _hideTimer;
 
-	BoxShadow _shadow;
+	RectShadow _shadow;
 	ChildWidget<ScrollArea> _scroll;
 
+	int _maxHeight = 0;
+
 };
 
+namespace internal {
+
+class Container : public ScrolledWidget {
+	Q_OBJECT
+
+public:
+	Container(QWidget *parent, ScrolledWidget *child, const style::InnerDropdown &st);
+	void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
+
+private slots:
+	void onHeightUpdate();
+
+protected:
+	int resizeGetHeight(int newWidth) override;
+
+private:
+	const style::InnerDropdown &_st;
+
+};
+
+} // namespace internal
 } // namespace Ui
diff --git a/Telegram/SourceFiles/ui/scrollarea.h b/Telegram/SourceFiles/ui/scrollarea.h
index 43a0d4817..524811308 100644
--- a/Telegram/SourceFiles/ui/scrollarea.h
+++ b/Telegram/SourceFiles/ui/scrollarea.h
@@ -270,6 +270,8 @@ public:
 };
 
 class ScrolledWidget : public TWidget {
+	Q_OBJECT
+
 public:
 	ScrolledWidget(QWidget *parent = nullptr) : TWidget(parent) {
 	}
@@ -289,4 +291,7 @@ protected:
 		return height();
 	}
 
+signals:
+	void heightUpdated();
+
 };
diff --git a/Telegram/Telegram.pro b/Telegram/Telegram.pro
index 321ae0d44..ad3dacc98 100644
--- a/Telegram/Telegram.pro
+++ b/Telegram/Telegram.pro
@@ -204,6 +204,7 @@ SOURCES += \
     ./SourceFiles/ui/flatlabel.cpp \
     ./SourceFiles/ui/flattextarea.cpp \
     ./SourceFiles/ui/images.cpp \
+    ./SourceFiles/ui/inner_dropdown.cpp \
     ./SourceFiles/ui/scrollarea.cpp \
     ./SourceFiles/ui/twidget.cpp \
     ./SourceFiles/window/main_window.cpp \
@@ -361,6 +362,7 @@ HEADERS += \
     ./SourceFiles/ui/flatlabel.h \
     ./SourceFiles/ui/flattextarea.h \
     ./SourceFiles/ui/images.h \
+    ./SourceFiles/ui/inner_dropdown.h \
     ./SourceFiles/ui/scrollarea.h \
     ./SourceFiles/ui/twidget.h \
     ./SourceFiles/window/main_window.h \
diff --git a/Telegram/Telegram.xcodeproj/qt_preprocess.mak b/Telegram/Telegram.xcodeproj/qt_preprocess.mak
index 5d7ef7490..0707e159e 100644
--- a/Telegram/Telegram.xcodeproj/qt_preprocess.mak
+++ b/Telegram/Telegram.xcodeproj/qt_preprocess.mak
@@ -86,6 +86,7 @@ compilers: GeneratedFiles/qrc_telegram.cpp\
 	 GeneratedFiles/Debug/moc_flattextarea.cpp\
 	 GeneratedFiles/Debug/moc_history.cpp\
 	 GeneratedFiles/Debug/moc_historywidget.cpp\
+	 GeneratedFiles/Debug/moc_inner_dropdown.cpp\
 	 GeneratedFiles/Debug/moc_introcode.cpp\
 	 GeneratedFiles/Debug/moc_introphone.cpp\
 	 GeneratedFiles/Debug/moc_intropwdcheck.cpp\
@@ -223,6 +224,7 @@ compiler_moc_header_make_all: GeneratedFiles/Debug/moc_aboutbox.cpp\
 	 GeneratedFiles/Debug/moc_flattextarea.cpp\
 	 GeneratedFiles/Debug/moc_history.cpp\
 	 GeneratedFiles/Debug/moc_historywidget.cpp\
+	 GeneratedFiles/Debug/moc_inner_dropdown.cpp\
 	 GeneratedFiles/Debug/moc_introcode.cpp\
 	 GeneratedFiles/Debug/moc_introphone.cpp\
 	 GeneratedFiles/Debug/moc_intropwdcheck.cpp\
@@ -303,6 +305,7 @@ compiler_moc_header_clean:
 	 GeneratedFiles/Debug/moc_flattextarea.cpp\
 	 GeneratedFiles/Debug/moc_history.cpp\
 	 GeneratedFiles/Debug/moc_historywidget.cpp\
+	 GeneratedFiles/Debug/moc_inner_dropdown.cpp\
 	 GeneratedFiles/Debug/moc_introcode.cpp\
 	 GeneratedFiles/Debug/moc_introphone.cpp\
 	 GeneratedFiles/Debug/moc_intropwdcheck.cpp\
@@ -456,6 +459,9 @@ GeneratedFiles/Debug/moc_history.cpp: SourceFiles/history.h
 GeneratedFiles/Debug/moc_historywidget.cpp: SourceFiles/historywidget.h
 	$(MOC_FILE) SourceFiles/historywidget.h -o GeneratedFiles/Debug/moc_historywidget.cpp
 
+GeneratedFiles/Debug/moc_inner_dropdown.cpp: SourceFiles/ui/inner_dropdown.h
+	$(MOC_FILE) SourceFiles/ui/inner_dropdown.h -o GeneratedFiles/Debug/moc_inner_dropdown.cpp
+
 GeneratedFiles/Debug/moc_introcode.cpp: SourceFiles/intro/introcode.h
 	$(MOC_FILE) SourceFiles/intro/introcode.h -o GeneratedFiles/Debug/moc_introcode.cpp