Serenity Operating System
at portability 152 lines 4.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "QSWidget.h" 28#include <AK/URL.h> 29#include <LibCore/MimeData.h> 30#include <LibGUI/MessageBox.h> 31#include <LibGUI/Painter.h> 32#include <LibGUI/Window.h> 33#include <LibGfx/Bitmap.h> 34 35QSWidget::QSWidget() 36{ 37 set_fill_with_background_color(true); 38 set_background_color(Color::Black); 39} 40 41QSWidget::~QSWidget() 42{ 43} 44 45void QSWidget::set_bitmap(NonnullRefPtr<Gfx::Bitmap> bitmap) 46{ 47 m_bitmap = move(bitmap); 48} 49 50void QSWidget::relayout() 51{ 52 Gfx::Size new_size; 53 float scale_factor = (float)m_scale / 100.0f; 54 new_size.set_width(m_bitmap->width() * scale_factor); 55 new_size.set_height(m_bitmap->height() * scale_factor); 56 m_bitmap_rect.set_size(new_size); 57 update(); 58} 59 60void QSWidget::resize_event(GUI::ResizeEvent& event) 61{ 62 relayout(); 63 GUI::Widget::resize_event(event); 64} 65 66void QSWidget::paint_event(GUI::PaintEvent& event) 67{ 68 GUI::Painter painter(*this); 69 painter.add_clip_rect(event.rect()); 70 71 painter.draw_scaled_bitmap(m_bitmap_rect, *m_bitmap, m_bitmap->rect()); 72} 73 74void QSWidget::mousedown_event(GUI::MouseEvent& event) 75{ 76 if (event.button() != GUI::MouseButton::Left) 77 return; 78 m_pan_origin = event.position(); 79 m_pan_bitmap_origin = m_bitmap_rect.location(); 80} 81 82void QSWidget::mouseup_event(GUI::MouseEvent& event) 83{ 84 UNUSED_PARAM(event); 85} 86 87void QSWidget::mousemove_event(GUI::MouseEvent& event) 88{ 89 if (!(event.buttons() & GUI::MouseButton::Left)) 90 return; 91 92 auto delta = event.position() - m_pan_origin; 93 m_bitmap_rect.set_location(m_pan_bitmap_origin.translated(delta)); 94 update(); 95} 96 97void QSWidget::mousewheel_event(GUI::MouseEvent& event) 98{ 99 auto old_scale = m_scale; 100 auto old_scale_factor = (float)m_scale / 100.0f; 101 auto zoom_point = event.position().translated(-m_bitmap_rect.location()); 102 zoom_point.set_x((float)zoom_point.x() / old_scale_factor); 103 zoom_point.set_y((float)zoom_point.y() / old_scale_factor); 104 m_scale += -event.wheel_delta() * 10; 105 if (m_scale < 10) 106 m_scale = 10; 107 if (m_scale > 1000) 108 m_scale = 1000; 109 relayout(); 110 auto new_scale_factor = (float)m_scale / 100.0f; 111 auto scale_factor_change = new_scale_factor - old_scale_factor; 112 m_bitmap_rect.move_by(-Gfx::Point((float)zoom_point.x() * scale_factor_change, (float)zoom_point.y() * scale_factor_change)); 113 if (old_scale != m_scale) { 114 if (on_scale_change) 115 on_scale_change(m_scale); 116 } 117} 118 119void QSWidget::set_path(const String& path) 120{ 121 m_path = path; 122} 123 124void QSWidget::drop_event(GUI::DropEvent& event) 125{ 126 event.accept(); 127 window()->move_to_front(); 128 129 if (event.mime_data().has_urls()) { 130 auto urls = event.mime_data().urls(); 131 if (urls.is_empty()) 132 return; 133 if (urls.size() > 1) { 134 GUI::MessageBox::show("QuickShow can only open one file at a time!", "One at a time please!", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window()); 135 return; 136 } 137 auto url = urls.first(); 138 auto bitmap = Gfx::Bitmap::load_from_file(url.path()); 139 if (!bitmap) { 140 GUI::MessageBox::show(String::format("Failed to open %s", url.to_string().characters()), "Cannot open image", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window()); 141 return; 142 } 143 144 m_path = url.path(); 145 m_bitmap = bitmap; 146 m_scale = 100; 147 if (on_scale_change) 148 on_scale_change(m_scale); 149 relayout(); 150 m_bitmap_rect.center_within(rect()); 151 } 152}