Mercurial > vim
comparison src/testdir/samples/box.txt @ 33844:58c9f11eae5b v9.0.2134
patch 9.0.2134: ml_get error when scrolling
Commit: https://github.com/vim/vim/commit/c4ffeddfe5bd1824650e9b911ed9245bf56c69e3
Author: Christian Brabandt <cb@256bit.org>
Date: Mon Nov 27 23:25:03 2023 +0100
patch 9.0.2134: ml_get error when scrolling
Problem: ml_get error when scrolling after delete
Solution: mark topline to be validated in main_loop
if it is larger than current buffers line
count
reset_lnums() is called after e.g. TextChanged autocommands and it may
accidentally cause curwin->w_topline to become invalid, e.g. if the
autocommand has deleted some lines.
So verify that curwin->w_topline points to a valid line and if not, mark
the window to have w_topline recalculated in main_loop() in
update_topline() after reset_lnums() returns.
fixes: #13568
fixes: #13578
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 27 Nov 2023 23:30:04 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
33843:dc37b35ded98 | 33844:58c9f11eae5b |
---|---|
1 void BackgroundBox::prepare() { | |
2 setTitle(tr::lng_backgrounds_header()); | |
3 | |
4 addButton(tr::lng_close(), [=] { closeBox(); }); | |
5 | |
6 setDimensions(st::boxWideWidth, st::boxMaxListHeight); | |
7 | |
8 auto wrap = object_ptr<Ui::VerticalLayout>(this); | |
9 const auto container = wrap.data(); | |
10 | |
11 Settings::AddSkip(container); | |
12 | |
13 const auto button = container->add(Settings::CreateButton( | |
14 container, | |
15 tr::lng_settings_bg_from_file(), | |
16 st::infoProfileButton)); | |
17 object_ptr<Info::Profile::FloatingIcon>( | |
18 button, | |
19 st::infoIconMediaPhoto, | |
20 st::infoSharedMediaButtonIconPosition); | |
21 | |
22 button->setClickedCallback([=] { | |
23 chooseFromFile(); | |
24 }); | |
25 | |
26 Settings::AddSkip(container); | |
27 Settings::AddDivider(container); | |
28 | |
29 _inner = container->add( | |
30 object_ptr<Inner>(this, &_controller->session(), _forPeer)); | |
31 | |
32 container->resizeToWidth(st::boxWideWidth); | |
33 | |
34 setInnerWidget(std::move(wrap), st::backgroundScroll); | |
35 setInnerTopSkip(st::lineWidth); | |
36 | |
37 _inner->chooseEvents( | |
38 ) | rpl::start_with_next([=](const Data::WallPaper &paper) { | |
39 chosen(paper); | |
40 }, _inner->lifetime()); | |
41 | |
42 _inner->removeRequests( | |
43 ) | rpl::start_with_next([=](const Data::WallPaper &paper) { | |
44 removePaper(paper); | |
45 }, _inner->lifetime()); | |
46 } | |
47 | |
48 void BackgroundBox::chooseFromFile() { | |
49 const auto filterStart = _forPeer | |
50 ? u"Image files (*"_q | |
51 : u"Theme files (*.tdesktop-theme *.tdesktop-palette *"_q; | |
52 auto filters = QStringList( | |
53 filterStart | |
54 + Ui::ImageExtensions().join(u" *"_q) | |
55 + u")"_q); | |
56 filters.push_back(FileDialog::AllFilesFilter()); | |
57 const auto callback = [=](const FileDialog::OpenResult &result) { | |
58 if (result.paths.isEmpty() && result.remoteContent.isEmpty()) { | |
59 return; | |
60 } | |
61 | |
62 if (!_forPeer && !result.paths.isEmpty()) { | |
63 const auto filePath = result.paths.front(); | |
64 const auto hasExtension = [&](QLatin1String extension) { | |
65 return filePath.endsWith(extension, Qt::CaseInsensitive); | |
66 }; | |
67 if (hasExtension(qstr(".tdesktop-theme")) | |
68 || hasExtension(qstr(".tdesktop-palette"))) { | |
69 Window::Theme::Apply(filePath); | |
70 return; | |
71 } | |
72 } | |
73 | |
74 auto image = Images::Read({ | |
75 .path = result.paths.isEmpty() ? QString() : result.paths.front(), | |
76 .content = result.remoteContent, | |
77 .forceOpaque = true, | |
78 }).image; | |
79 if (image.isNull() || image.width() <= 0 || image.height() <= 0) { | |
80 return; | |
81 } | |
82 auto local = Data::CustomWallPaper(); | |
83 local.setLocalImageAsThumbnail(std::make_shared<Image>( | |
84 std::move(image))); | |
85 _controller->show(Box<BackgroundPreviewBox>( | |
86 _controller, | |
87 local, | |
88 BackgroundPreviewArgs{ _forPeer })); | |
89 }; | |
90 FileDialog::GetOpenPath( | |
91 this, | |
92 tr::lng_choose_image(tr::now), | |
93 filters.join(u";;"_q), | |
94 crl::guard(this, callback)); | |
95 } | |
96 | |
97 bool BackgroundBox::hasDefaultForPeer() const { | |
98 Expects(_forPeer != nullptr); | |
99 | |
100 const auto paper = _forPeer->wallPaper(); | |
101 if (!paper) { | |
102 return true; | |
103 } | |
104 const auto reset = _inner->resolveResetCustomPaper(); | |
105 Assert(reset.has_value()); | |
106 return (paper->id() == reset->id()); | |
107 } | |
108 | |
109 bool BackgroundBox::chosenDefaultForPeer( | |
110 const Data::WallPaper &paper) const { | |
111 if (!_forPeer) { | |
112 return false; | |
113 } | |
114 | |
115 const auto reset = _inner->resolveResetCustomPaper(); | |
116 Assert(reset.has_value()); | |
117 return (paper.id() == reset->id()); | |
118 } | |
119 | |
120 void BackgroundBox::chosen(const Data::WallPaper &paper) { | |
121 if (chosenDefaultForPeer(paper)) { | |
122 if (!hasDefaultForPeer()) { | |
123 const auto reset = crl::guard(this, [=](Fn<void()> close) { | |
124 resetForPeer(); | |
125 close(); | |
126 }); | |
127 _controller->show(Ui::MakeConfirmBox({ | |
128 .text = tr::lng_background_sure_reset_default(), | |
129 .confirmed = reset, | |
130 .confirmText = tr::lng_background_reset_default(), | |
131 })); | |
132 } else { | |
133 closeBox(); | |
134 } | |
135 return; | |
136 } | |
137 _controller->show(Box<BackgroundPreviewBox>( | |
138 _controller, | |
139 paper, | |
140 BackgroundPreviewArgs{ _forPeer })); | |
141 } | |
142 | |
143 void BackgroundBox::resetForPeer() { | |
144 const auto api = &_controller->session().api(); | |
145 api->request(MTPmessages_SetChatWallPaper( | |
146 MTP_flags(0), | |
147 _forPeer->input, | |
148 MTPInputWallPaper(), | |
149 MTPWallPaperSettings(), | |
150 MTPint() | |
151 )).done([=](const MTPUpdates &result) { | |
152 api->applyUpdates(result); | |
153 }).send(); | |
154 | |
155 const auto weak = Ui::MakeWeak(this); | |
156 _forPeer->setWallPaper(std::nullopt); | |
157 if (weak) { | |
158 _controller->finishChatThemeEdit(_forPeer); | |
159 } | |
160 } | |
161 | |
162 void BackgroundBox::removePaper(const Data::WallPaper &paper) { | |
163 const auto session = &_controller->session(); | |
164 const auto remove = [=, weak = Ui::MakeWeak(this)](Fn<void()> &&close) { | |
165 close(); | |
166 if (weak) { | |
167 weak->_inner->removePaper(paper); | |
168 } | |
169 session->data().removeWallpaper(paper); | |
170 session->api().request(MTPaccount_SaveWallPaper( | |
171 paper.mtpInput(session), | |
172 MTP_bool(true), | |
173 paper.mtpSettings() | |
174 )).send(); | |
175 }; | |
176 _controller->show(Ui::MakeConfirmBox({ | |
177 .text = tr::lng_background_sure_delete(), | |
178 .confirmed = remove, | |
179 .confirmText = tr::lng_selected_delete(), | |
180 })); | |
181 } | |
182 | |
183 BackgroundBox::Inner::Inner( | |
184 QWidget *parent, | |
185 not_null<Main::Session*> session, | |
186 PeerData *forPeer) | |
187 : RpWidget(parent) | |
188 , _session(session) | |
189 , _forPeer(forPeer) | |
190 , _api(&_session->mtp()) | |
191 , _check(std::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [=] { update(); })) { | |
192 _check->setChecked(true, anim::type::instant); | |
193 resize(st::boxWideWidth, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); | |
194 Window::Theme::IsNightModeValue( | |
195 ) | rpl::start_with_next([=] { | |
196 updatePapers(); | |
197 }, lifetime()); | |
198 requestPapers(); | |
199 | |
200 _session->downloaderTaskFinished( | |
201 ) | rpl::start_with_next([=] { | |
202 update(); | |
203 }, lifetime()); | |
204 | |
205 style::PaletteChanged( | |
206 ) | rpl::start_with_next([=] { | |
207 _check->invalidateCache(); | |
208 }, lifetime()); | |
209 | |
210 using Update = Window::Theme::BackgroundUpdate; | |
211 Window::Theme::Background()->updates( | |
212 ) | rpl::start_with_next([=](const Update &update) { | |
213 if (update.type == Update::Type::New) { | |
214 sortPapers(); | |
215 requestPapers(); | |
216 this->update(); | |
217 } | |
218 }, lifetime()); | |
219 | |
220 | |
221 setMouseTracking(true); | |
222 } | |
223 | |
224 void BackgroundBox::Inner::requestPapers() { | |
225 _api.request(MTPaccount_GetWallPapers( | |
226 MTP_long(_session->data().wallpapersHash()) | |
227 )).done([=](const MTPaccount_WallPapers &result) { | |
228 if (_session->data().updateWallpapers(result)) { | |
229 updatePapers(); | |
230 } | |
231 }).send(); | |
232 } | |
233 | |
234 auto BackgroundBox::Inner::resolveResetCustomPaper() const | |
235 -> std::optional<Data::WallPaper> { | |
236 if (!_forPeer) { | |
237 return {}; | |
238 } | |
239 const auto nonCustom = Window::Theme::Background()->paper(); | |
240 const auto themeEmoji = _forPeer->themeEmoji(); | |
241 if (themeEmoji.isEmpty()) { | |
242 return nonCustom; | |
243 } | |
244 const auto &themes = _forPeer->owner().cloudThemes(); | |
245 const auto theme = themes.themeForEmoji(themeEmoji); | |
246 if (!theme) { | |
247 return nonCustom; | |
248 } | |
249 using Type = Data::CloudTheme::Type; XXXXX | |
250 const auto dark = Window::Theme::IsNightMode(); | |
251 const auto i = theme->settings.find(dark ? Type::Dark : Type::Light); | |
252 if (i != end(theme->settings) && i->second.paper) { | |
253 return *i->second.paper; | |
254 } | |
255 return nonCustom; | |
256 } | |
257 | |
258 void BackgroundBox::Inner::pushCustomPapers() { | |
259 auto customId = uint64(); | |
260 if (const auto custom = _forPeer ? _forPeer->wallPaper() : nullptr) { | |
261 customId = custom->id(); | |
262 const auto j = ranges::find( | |
263 _papers, | |
264 custom->id(), | |
265 [](const Paper &paper) { return paper.data.id(); }); | |
266 if (j != end(_papers)) { | |
267 j->data = j->data.withParamsFrom(*custom); | |
268 } else { | |
269 _papers.insert(begin(_papers), Paper{ *custom }); | |
270 } | |
271 } | |
272 if (const auto reset = resolveResetCustomPaper()) { | |
273 _insertedResetId = reset->id(); | |
274 const auto j = ranges::find( | |
275 _papers, | |
276 _insertedResetId, | |
277 [](const Paper &paper) { return paper.data.id(); }); | |
278 if (j != end(_papers)) { | |
279 if (_insertedResetId != customId) { | |
280 j->data = j->data.withParamsFrom(*reset); | |
281 } | |
282 } else { | |
283 _papers.insert(begin(_papers), Paper{ *reset }); | |
284 } | |
285 } | |
286 } | |
287 | |
288 void BackgroundBox::Inner::sortPapers() { | |
289 const auto currentCustom = _forPeer ? _forPeer->wallPaper() : nullptr; | |
290 _currentId = currentCustom | |
291 ? currentCustom->id() | |
292 : _insertedResetId | |
293 ? _insertedResetId | |
294 : Window::Theme::Background()->id(); | |
295 const auto dark = Window::Theme::IsNightMode(); | |
296 ranges::stable_sort(_papers, std::greater<>(), [&](const Paper &paper) { | |
297 const auto &data = paper.data; | |
298 return std::make_tuple( | |
299 _insertedResetId && (_insertedResetId == data.id()), | |
300 data.id() == _currentId, | |
301 dark ? data.isDark() : !data.isDark(), | |
302 Data::IsDefaultWallPaper(data), | |
303 !data.isDefault() && !Data::IsLegacy1DefaultWallPaper(data), | |
304 Data::IsLegacy3DefaultWallPaper(data), | |
305 Data::IsLegacy2DefaultWallPaper(data), | |
306 Data::IsLegacy1DefaultWallPaper(data)); | |
307 }); | |
308 if (!_papers.empty() | |
309 && _papers.front().data.id() == _currentId | |
310 && !currentCustom | |
311 && !_insertedResetId) { | |
312 _papers.front().data = _papers.front().data.withParamsFrom( | |
313 Window::Theme::Background()->paper()); | |
314 } | |
315 } | |
316 | |
317 void BackgroundBox::Inner::updatePapers() { | |
318 if (_session->data().wallpapers().empty()) { | |
319 return; | |
320 } | |
321 _over = _overDown = Selection(); | |
322 | |
323 _papers = _session->data().wallpapers( | |
324 ) | ranges::views::filter([&](const Data::WallPaper &paper) { | |
325 return (!paper.isPattern() || !paper.backgroundColors().empty()) | |
326 && (!_forPeer | |
327 || (!Data::IsDefaultWallPaper(paper) | |
328 && (Data::IsCloudWallPaper(paper) | |
329 || Data::IsCustomWallPaper(paper)))); | |
330 }) | ranges::views::transform([](const Data::WallPaper &paper) { | |
331 return Paper{ paper }; | |
332 }) | ranges::to_vector; | |
333 pushCustomPapers(); | |
334 sortPapers(); | |
335 resizeToContentAndPreload(); | |
336 } | |
337 | |
338 void BackgroundBox::Inner::resizeToContentAndPreload() { | |
339 const auto count = _papers.size(); | |
340 const auto rows = (count / kBackgroundsInRow) | |
341 + (count % kBackgroundsInRow ? 1 : 0); | |
342 | |
343 resize( | |
344 st::boxWideWidth, | |
345 (rows * (st::backgroundSize.height() + st::backgroundPadding) | |
346 + st::backgroundPadding)); | |
347 | |
348 const auto preload = kBackgroundsInRow * 3; | |
349 for (const auto &paper : _papers | ranges::views::take(preload)) { | |
350 if (!paper.data.localThumbnail() && !paper.dataMedia) { | |
351 if (const auto document = paper.data.document()) { | |
352 paper.dataMedia = document->createMediaView(); | |
353 paper.dataMedia->thumbnailWanted(paper.data.fileOrigin()); | |
354 } | |
355 } | |
356 } | |
357 update(); | |
358 } | |
359 | |
360 void BackgroundBox::Inner::paintEvent(QPaintEvent *e) { | |
361 QRect r(e->rect()); | |
362 auto p = QPainter(this); | |
363 | |
364 if (_papers.empty()) { | |
365 p.setFont(st::noContactsFont); | |
366 p.setPen(st::noContactsColor); | |
367 p.drawText(QRect(0, 0, width(), st::noContactsHeight), tr::lng_contacts_loading(tr::now), style::al_center); | |
368 return; | |
369 } | |
370 auto row = 0; | |
371 auto column = 0; | |
372 for (const auto &paper : _papers) { | |
373 const auto increment = gsl::finally([&] { | |
374 ++column; | |
375 if (column == kBackgroundsInRow) { | |
376 column = 0; | |
377 ++row; | |
378 } | |
379 }); | |
380 if ((st::backgroundSize.height() + st::backgroundPadding) * (row + 1) <= r.top()) { | |
381 continue; | |
382 } else if ((st::backgroundSize.height() + st::backgroundPadding) * row >= r.top() + r.height()) { | |
383 break; | |
384 } | |
385 paintPaper(p, paper, column, row); | |
386 } | |
387 } | |
388 | |
389 void BackgroundBox::Inner::validatePaperThumbnail( | |
390 const Paper &paper) const { | |
391 if (!paper.thumbnail.isNull()) { | |
392 return; | |
393 } | |
394 const auto localThumbnail = paper.data.localThumbnail(); | |
395 if (!localThumbnail) { | |
396 if (const auto document = paper.data.document()) { | |
397 if (!paper.dataMedia) { | |
398 paper.dataMedia = document->createMediaView(); | |
399 paper.dataMedia->thumbnailWanted(paper.data.fileOrigin()); | |
400 } | |
401 if (!paper.dataMedia->thumbnail()) { | |
402 return; | |
403 } | |
404 } else if (!paper.data.backgroundColors().empty()) { | |
405 paper.thumbnail = Ui::PixmapFromImage( | |
406 Ui::GenerateBackgroundImage( | |
407 st::backgroundSize * cIntRetinaFactor(), | |
408 paper.data.backgroundColors(), | |
409 paper.data.gradientRotation())); | |
410 paper.thumbnail.setDevicePixelRatio(cRetinaFactor()); | |
411 return; | |
412 } else { | |
413 return; | |
414 } | |
415 } | |
416 const auto thumbnail = localThumbnail | |
417 ? localThumbnail | |
418 : paper.dataMedia->thumbnail(); | |
419 auto original = thumbnail->original(); | |
420 if (paper.data.isPattern()) { | |
421 original = Ui::PreparePatternImage( | |
422 std::move(original), | |
423 paper.data.backgroundColors(), | |
424 paper.data.gradientRotation(), | |
425 paper.data.patternOpacity()); | |
426 } | |
427 paper.thumbnail = Ui::PixmapFromImage(TakeMiddleSample( | |
428 original, | |
429 st::backgroundSize)); | |
430 paper.thumbnail.setDevicePixelRatio(cRetinaFactor()); | |
431 } | |
432 | |
433 void BackgroundBox::Inner::paintPaper( | |
434 QPainter &p, | |
435 const Paper &paper, | |
436 int column, | |
437 int row) const { | |
438 const auto x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding); | |
439 const auto y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding); | |
440 validatePaperThumbnail(paper); | |
441 if (!paper.thumbnail.isNull()) { | |
442 p.drawPixmap(x, y, paper.thumbnail); | |
443 } | |
444 | |
445 const auto over = !v::is_null(_overDown) ? _overDown : _over; | |
446 if (paper.data.id() == _currentId) { | |
447 const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size; | |
448 const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size; | |
449 _check->paint(p, checkLeft, checkTop, width()); | |
450 } else if (Data::IsCloudWallPaper(paper.data) | |
451 && !Data::IsDefaultWallPaper(paper.data) | |
452 && !Data::IsLegacy2DefaultWallPaper(paper.data) | |
453 && !Data::IsLegacy3DefaultWallPaper(paper.data) | |
454 && !v::is_null(over) | |
455 && (&paper == &_papers[getSelectionIndex(over)])) { | |
456 const auto deleteSelected = v::is<DeleteSelected>(over); | |
457 const auto deletePos = QPoint(x + st::backgroundSize.width() - st::stickerPanDeleteIconBg.width(), y); | |
458 p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg); | |
459 st::stickerPanDeleteIconBg.paint(p, deletePos, width()); | |
460 p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityFgOver : st::stickerPanDeleteOpacityFg); | |
461 st::stickerPanDeleteIconFg.paint(p, deletePos, width()); | |
462 p.setOpacity(1.); | |
463 } | |
464 } | |
465 | |
466 void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) { | |
467 const auto newOver = [&] { | |
468 const auto x = e->pos().x(); | |
469 const auto y = e->pos().y(); | |
470 const auto width = st::backgroundSize.width(); | |
471 const auto height = st::backgroundSize.height(); | |
472 const auto skip = st::backgroundPadding; | |
473 const auto row = int((y - skip) / (height + skip)); | |
474 const auto column = int((x - skip) / (width + skip)); | |
475 const auto result = row * kBackgroundsInRow + column; | |
476 if (y - row * (height + skip) > skip + height) { | |
477 return Selection(); | |
478 } else if (x - column * (width + skip) > skip + width) { | |
479 return Selection(); | |
480 } else if (result >= _papers.size()) { | |
481 return Selection(); | |
482 } | |
483 auto &data = _papers[result].data; | |
484 const auto deleteLeft = (column + 1) * (width + skip) | |
485 - st::stickerPanDeleteIconBg.width(); | |
486 const auto deleteBottom = row * (height + skip) + skip | |
487 + st::stickerPanDeleteIconBg.height(); | |
488 const auto inDelete = (x >= deleteLeft) | |
489 && (y < deleteBottom) | |
490 && Data::IsCloudWallPaper(data) | |
491 && !Data::IsDefaultWallPaper(data) | |
492 && !Data::IsLegacy2DefaultWallPaper(data) | |
493 && !Data::IsLegacy3DefaultWallPaper(data) | |
494 && (_currentId != data.id()); | |
495 return (result >= _papers.size()) | |
496 ? Selection() | |
497 : inDelete | |
498 ? Selection(DeleteSelected{ result }) | |
499 : Selection(Selected{ result }); | |
500 }(); | |
501 if (_over != newOver) { | |
502 repaintPaper(getSelectionIndex(_over)); | |
503 _over = newOver; | |
504 repaintPaper(getSelectionIndex(_over)); | |
505 setCursor((!v::is_null(_over) || !v::is_null(_overDown)) | |
506 ? style::cur_pointer | |
507 : style::cur_default); | |
508 } | |
509 } | |
510 | |
511 void BackgroundBox::Inner::repaintPaper(int index) { | |
512 if (index < 0 || index >= _papers.size()) { | |
513 return; | |
514 } | |
515 const auto row = (index / kBackgroundsInRow); | |
516 const auto column = (index % kBackgroundsInRow); | |
517 const auto width = st::backgroundSize.width(); | |
518 const auto height = st::backgroundSize.height(); | |
519 const auto skip = st::backgroundPadding; | |
520 update( | |
521 (width + skip) * column + skip, | |
522 (height + skip) * row + skip, | |
523 width, | |
524 height); | |
525 } | |
526 | |
527 void BackgroundBox::Inner::mousePressEvent(QMouseEvent *e) { | |
528 _overDown = _over; | |
529 } | |
530 | |
531 int BackgroundBox::Inner::getSelectionIndex( | |
532 const Selection &selection) const { | |
533 return v::match(selection, [](const Selected &data) { | |
534 return data.index; | |
535 }, [](const DeleteSelected &data) { | |
536 return data.index; | |
537 }, [](v::null_t) { | |
538 return -1; | |
539 }); | |
540 } | |
541 | |
542 void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) { | |
543 if (base::take(_overDown) == _over && !v::is_null(_over)) { | |
544 const auto index = getSelectionIndex(_over); | |
545 if (index >= 0 && index < _papers.size()) { | |
546 if (std::get_if<DeleteSelected>(&_over)) { | |
547 _backgroundRemove.fire_copy(_papers[index].data); | |
548 } else if (std::get_if<Selected>(&_over)) { | |
549 auto &paper = _papers[index]; | |
550 if (!paper.dataMedia) { | |
551 if (const auto document = paper.data.document()) { | |
552 // Keep it alive while it is on the screen. | |
553 paper.dataMedia = document->createMediaView(); | |
554 } | |
555 } | |
556 _backgroundChosen.fire_copy(paper.data); | |
557 } | |
558 } | |
559 } else if (v::is_null(_over)) { | |
560 setCursor(style::cur_default); | |
561 } | |
562 } | |
563 | |
564 void BackgroundBox::Inner::visibleTopBottomUpdated( | |
565 int visibleTop, | |
566 int visibleBottom) { | |
567 for (auto i = 0, count = int(_papers.size()); i != count; ++i) { | |
568 const auto row = (i / kBackgroundsInRow); | |
569 const auto height = st::backgroundSize.height(); | |
570 const auto skip = st::backgroundPadding; | |
571 const auto top = skip + row * (height + skip); | |
572 const auto bottom = top + height; | |
573 if ((bottom <= visibleTop || top >= visibleBottom) | |
574 && !_papers[i].thumbnail.isNull()) { | |
575 _papers[i].dataMedia = nullptr; | |
576 } | |
577 } | |
578 } | |
579 | |
580 rpl::producer<Data::WallPaper> BackgroundBox::Inner::chooseEvents() const { | |
581 return _backgroundChosen.events(); | |
582 } | |
583 | |
584 auto BackgroundBox::Inner::removeRequests() const | |
585 -> rpl::producer<Data::WallPaper> { | |
586 return _backgroundRemove.events(); | |
587 } | |
588 | |
589 void BackgroundBox::Inner::removePaper(const Data::WallPaper &data) { | |
590 const auto i = ranges::find( | |
591 _papers, | |
592 data.id(), | |
593 [](const Paper &paper) { return paper.data.id(); }); | |
594 if (i != end(_papers)) { | |
595 _papers.erase(i); | |
596 _over = _overDown = Selection(); | |
597 resizeToContentAndPreload(); | |
598 } | |
599 } | |
600 | |
601 BackgroundBox::Inner::~Inner() = default; |