Members block in group conversation view finished (except Xcode project).

This commit is contained in:
John Preston 2016-06-20 14:31:12 +03:00
parent f0a8356ff0
commit 7db7b177c0
19 changed files with 304 additions and 19 deletions

View File

@ -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);

View File

@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -867,6 +867,8 @@ private:
void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
int countMembersDropdownHeightMax() const;
MsgId _replyToId = 0;
Text _replyToName;
int _replyToNameVersion = 0;

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
};

View File

@ -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 \

View File

@ -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