ImageWidget.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibCore/MappedFile.h>
  8. #include <LibCore/MimeData.h>
  9. #include <LibGUI/ImageWidget.h>
  10. #include <LibGUI/Painter.h>
  11. #include <LibGfx/Bitmap.h>
  12. #include <LibGfx/ImageFormats/ImageDecoder.h>
  13. REGISTER_WIDGET(GUI, ImageWidget)
  14. namespace GUI {
  15. ImageWidget::ImageWidget(StringView)
  16. : m_timer(Core::Timer::try_create().release_value_but_fixme_should_propagate_errors())
  17. {
  18. set_frame_style(Gfx::FrameStyle::NoFrame);
  19. set_auto_resize(true);
  20. REGISTER_BOOL_PROPERTY("auto_resize", auto_resize, set_auto_resize);
  21. REGISTER_BOOL_PROPERTY("should_stretch", should_stretch, set_should_stretch);
  22. REGISTER_WRITE_ONLY_STRING_PROPERTY("bitmap", load_from_file);
  23. }
  24. void ImageWidget::set_bitmap(Gfx::Bitmap const* bitmap)
  25. {
  26. if (m_bitmap == bitmap)
  27. return;
  28. m_bitmap = bitmap;
  29. if (m_bitmap && m_auto_resize)
  30. set_fixed_size(m_bitmap->size());
  31. update();
  32. }
  33. void ImageWidget::set_auto_resize(bool value)
  34. {
  35. if (m_auto_resize == value)
  36. return;
  37. m_auto_resize = value;
  38. if (m_bitmap && m_auto_resize)
  39. set_fixed_size(m_bitmap->size());
  40. }
  41. // Same as ImageViewer::ViewWidget::animate(), you probably want to keep any changes in sync
  42. void ImageWidget::animate()
  43. {
  44. auto first_animated_frame_index = m_image_decoder->first_animated_frame_index();
  45. auto total_animated_frames = m_image_decoder->frame_count() - first_animated_frame_index;
  46. m_current_frame_index = (m_current_frame_index + 1) % total_animated_frames;
  47. auto current_frame = m_image_decoder->frame(first_animated_frame_index + m_current_frame_index).release_value_but_fixme_should_propagate_errors();
  48. set_bitmap(current_frame.image);
  49. if (current_frame.duration != m_timer->interval()) {
  50. m_timer->restart(current_frame.duration);
  51. }
  52. if (m_current_frame_index == total_animated_frames - 1) {
  53. ++m_loops_completed;
  54. if (m_image_decoder->loop_count() > 0 && m_loops_completed == m_image_decoder->loop_count()) {
  55. m_timer->stop();
  56. }
  57. }
  58. }
  59. void ImageWidget::load_from_file(StringView path)
  60. {
  61. auto file_or_error = Core::MappedFile::map(path);
  62. if (file_or_error.is_error())
  63. return;
  64. auto& mapped_file = *file_or_error.value();
  65. auto mime_type = Core::guess_mime_type_based_on_filename(path);
  66. m_image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file.bytes(), mime_type);
  67. VERIFY(m_image_decoder);
  68. auto frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors();
  69. auto bitmap = frame.image;
  70. VERIFY(bitmap);
  71. set_bitmap(bitmap);
  72. if (m_image_decoder->is_animated() && m_image_decoder->frame_count() > 1) {
  73. auto first_frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors();
  74. m_timer->set_interval(first_frame.duration);
  75. m_timer->on_timeout = [this] { animate(); };
  76. m_timer->start();
  77. }
  78. }
  79. void ImageWidget::mousedown_event(GUI::MouseEvent&)
  80. {
  81. if (on_click)
  82. on_click();
  83. }
  84. void ImageWidget::paint_event(PaintEvent& event)
  85. {
  86. Frame::paint_event(event);
  87. if (!m_bitmap) {
  88. return;
  89. }
  90. Painter painter(*this);
  91. painter.add_clip_rect(event.rect());
  92. if (m_should_stretch) {
  93. painter.draw_scaled_bitmap(frame_inner_rect(), *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f);
  94. } else {
  95. auto location = frame_inner_rect().center().translated(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2));
  96. painter.blit(location, *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f);
  97. }
  98. }
  99. void ImageWidget::set_opacity_percent(int percent)
  100. {
  101. if (m_opacity_percent == percent)
  102. return;
  103. m_opacity_percent = percent;
  104. update();
  105. }
  106. }