Serenity Operating System
at hosted 160 lines 5.0 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 <LibGUI/MessageBox.h> 29#include <LibGUI/Painter.h> 30#include <LibGUI/Window.h> 31#include <LibGfx/Bitmap.h> 32#include <LibGfx/Palette.h> 33 34QSWidget::QSWidget() 35{ 36 set_fill_with_background_color(false); 37} 38 39QSWidget::~QSWidget() 40{ 41} 42 43void QSWidget::relayout() 44{ 45 if (m_bitmap.is_null()) 46 return; 47 48 float scale_factor = (float)m_scale / 100.0f; 49 50 Gfx::Size new_size; 51 new_size.set_width(m_bitmap->width() * scale_factor); 52 new_size.set_height(m_bitmap->height() * scale_factor); 53 m_bitmap_rect.set_size(new_size); 54 55 Gfx::Point new_location; 56 new_location.set_x((width() / 2) - (new_size.width() / 2) - (m_pan_origin.x() * scale_factor)); 57 new_location.set_y((height() / 2) - (new_size.height() / 2) - (m_pan_origin.y() * scale_factor)); 58 m_bitmap_rect.set_location(new_location); 59 60 update(); 61} 62 63void QSWidget::resize_event(GUI::ResizeEvent& event) 64{ 65 relayout(); 66 GUI::Widget::resize_event(event); 67} 68 69void QSWidget::paint_event(GUI::PaintEvent& event) 70{ 71 GUI::Painter painter(*this); 72 painter.add_clip_rect(event.rect()); 73 74 painter.fill_rect_with_checkerboard(rect(), { 8, 8 }, palette().base().darkened(0.9), palette().base()); 75 76 if (!m_bitmap.is_null()) 77 painter.draw_scaled_bitmap(m_bitmap_rect, *m_bitmap, m_bitmap->rect()); 78} 79 80void QSWidget::mousedown_event(GUI::MouseEvent& event) 81{ 82 if (event.button() != GUI::MouseButton::Left) 83 return; 84 m_click_position = event.position(); 85 m_saved_pan_origin = m_pan_origin; 86} 87 88void QSWidget::mouseup_event(GUI::MouseEvent& event) 89{ 90 UNUSED_PARAM(event); 91} 92 93void QSWidget::mousemove_event(GUI::MouseEvent& event) 94{ 95 if (!(event.buttons() & GUI::MouseButton::Left)) 96 return; 97 98 auto delta = event.position() - m_click_position; 99 float scale_factor = (float)m_scale / 100.0f; 100 m_pan_origin = m_saved_pan_origin.translated( 101 -delta.x() / scale_factor, 102 -delta.y() / scale_factor); 103 104 relayout(); 105} 106 107void QSWidget::mousewheel_event(GUI::MouseEvent& event) 108{ 109 auto old_scale = m_scale; 110 auto old_scale_factor = (float)m_scale / 100.0f; 111 112 m_scale += -event.wheel_delta() * 10; 113 if (m_scale < 10) 114 m_scale = 10; 115 if (m_scale > 1000) 116 m_scale = 1000; 117 118 auto new_scale_factor = (float)m_scale / 100.0f; 119 120 auto focus_point = Gfx::FloatPoint( 121 m_pan_origin.x() - ((float)event.x() - (float)width() / 2.0) / old_scale_factor, 122 m_pan_origin.y() - ((float)event.y() - (float)height() / 2.0) / old_scale_factor); 123 124 m_pan_origin = Gfx::FloatPoint( 125 focus_point.x() - new_scale_factor / old_scale_factor * (focus_point.x() - m_pan_origin.x()), 126 focus_point.y() - new_scale_factor / old_scale_factor * (focus_point.y() - m_pan_origin.y())); 127 128 relayout(); 129 130 if (old_scale != m_scale) { 131 if (on_scale_change) 132 on_scale_change(m_scale); 133 } 134} 135 136void QSWidget::load_from_file(const String& path) 137{ 138 auto bitmap = Gfx::Bitmap::load_from_file(path); 139 if (!bitmap) { 140 GUI::MessageBox::show(String::format("Failed to open %s", path.characters()), "Cannot open image", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window()); 141 return; 142 } 143 144 window()->resize(bitmap->size()); 145 146 m_path = path; 147 m_bitmap = bitmap; 148 m_scale = 100; 149 m_pan_origin = { 0, 0 }; 150 if (on_scale_change) 151 on_scale_change(m_scale); 152 relayout(); 153} 154 155void QSWidget::drop_event(GUI::DropEvent& event) 156{ 157 event.accept(); 158 if (on_drop) 159 on_drop(event); 160}