frame.cc
来自「rtorrent」· CC 代码 · 共 484 行
CC
484 行
// rTorrent - BitTorrent client// Copyright (C) 2005-2006, Jari Sundell//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.// // This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// // You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//// In addition, as a special exception, the copyright holders give// permission to link the code of portions of this program with the// OpenSSL library under certain conditions as described in each// individual source file, and distribute linked combinations// including the two.//// You must obey the GNU General Public License in all respects for// all of the code used other than OpenSSL. If you modify file(s)// with this exception, you may extend this exception to your version// of the file(s), but you are not obligated to do so. If you do not// wish to do so, delete this exception statement from your version.// If you delete this exception statement from all source files in the// program, then also delete it here.//// Contact: Jari Sundell <jaris@ifi.uio.no>//// Skomakerveien 33// 3185 Skoppum, NORWAY#include "config.h"#include <algorithm>#include <functional>#include <rak/algorithm.h>#include <torrent/exceptions.h>#include "frame.h"#include "window.h"namespace display {Frame::Frame() : m_type(TYPE_NONE), m_positionX(0), m_positionY(0), m_width(0), m_height(0) {}boolFrame::is_width_dynamic() const { switch (m_type) { case TYPE_NONE: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_width_dynamic(); case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->is_width_dynamic()) return true; return false; } return false;}boolFrame::is_height_dynamic() const { switch (m_type) { case TYPE_NONE: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_height_dynamic(); case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->is_height_dynamic()) return true; return false; } return false;}boolFrame::has_left_frame() const { switch (m_type) { case TYPE_NONE: case TYPE_ROW: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_left(); case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->has_left_frame()) return true; return false; } return false;}boolFrame::has_bottom_frame() const { switch (m_type) { case TYPE_NONE: case TYPE_COLUMN: return false; case TYPE_WINDOW: return m_window->is_active() && m_window->is_bottom(); case TYPE_ROW: for (size_type i = 0; i < m_containerSize; ++i) if (m_container[i]->has_bottom_frame()) return true; return false; } return false;}Frame::bounds_typeFrame::preferred_size() const { switch (m_type) { case TYPE_NONE: return bounds_type(0, 0, 0, 0); case TYPE_WINDOW: if (m_window->is_active()) return bounds_type(m_window->min_width(), m_window->min_height(), m_window->max_width(), m_window->max_height()); else return bounds_type(0, 0, 0, 0); case TYPE_ROW: case TYPE_COLUMN: { bounds_type accum(0, 0, 0, 0); for (size_type i = 0; i < m_containerSize; ++i) { bounds_type p = m_container[i]->preferred_size(); accum.minWidth += p.minWidth; accum.minHeight += p.minHeight; if (p.maxWidth == Window::extent_full || accum.maxWidth == Window::extent_full) accum.maxWidth = Window::extent_full; else accum.maxWidth += p.maxWidth; if (p.maxHeight == Window::extent_full || accum.maxHeight == Window::extent_full) accum.maxHeight = Window::extent_full; else accum.maxHeight += p.maxHeight; } return accum; } } return bounds_type(0, 0, 0, 0);}voidFrame::set_container_size(size_type size) { if ((m_type != TYPE_ROW && m_type != TYPE_COLUMN) || size >= max_size) throw torrent::client_error("Frame::set_container_size(...) Bad state."); while (m_containerSize > size) { delete m_container[--m_containerSize]; m_container[m_containerSize] = NULL; } while (m_containerSize < size) { m_container[m_containerSize++] = new Frame(); }}voidFrame::initialize_window(Window* window) { if (m_type != TYPE_NONE) throw torrent::client_error("Frame::initialize_window(...) m_type != TYPE_NONE."); m_type = TYPE_WINDOW; m_window = window;}voidFrame::initialize_row(size_type size) { if (m_type != TYPE_NONE) throw torrent::client_error("Frame::initialize_container(...) Invalid state."); if (size > max_size) throw torrent::client_error("Frame::initialize_container(...) size >= max_size."); m_type = TYPE_ROW; m_containerSize = size; for (size_type i = 0; i < m_containerSize; ++i) m_container[i] = new Frame();}voidFrame::initialize_column(size_type size) { if (m_type != TYPE_NONE) throw torrent::client_error("Frame::initialize_container(...) Invalid state."); if (size > max_size) throw torrent::client_error("Frame::initialize_container(...) size >= max_size."); m_type = TYPE_COLUMN; m_containerSize = size; for (size_type i = 0; i < m_containerSize; ++i) m_container[i] = new Frame();}voidFrame::clear() { switch (m_type) { case TYPE_WINDOW: if (m_window != NULL) m_window->set_offscreen(true); break; case TYPE_ROW: case TYPE_COLUMN: for (size_type i = 0; i < m_containerSize; ++i) { m_container[i]->clear(); delete m_container[i]; } break; default: break; } m_type = TYPE_NONE;}voidFrame::refresh() { switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: if (m_window->is_active() && !m_window->is_offscreen()) m_window->refresh(); break; case TYPE_ROW: case TYPE_COLUMN: for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) (*itr)->refresh(); break; }}voidFrame::redraw() { switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: if (m_window->is_active() && !m_window->is_offscreen()) m_window->redraw(); break; case TYPE_ROW: case TYPE_COLUMN: for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) (*itr)->redraw(); break; }}voidFrame::balance(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { m_positionX = x; m_positionY = y; m_width = width; m_height = height; switch (m_type) { case TYPE_NONE: break; case TYPE_WINDOW: balance_window(x, y, width, height); break; case TYPE_ROW: balance_row(x, y, width, height); break; case TYPE_COLUMN: balance_column(x, y, width, height); break; }}inline voidFrame::balance_window(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Ensure that we don't draw windows that are offscreen or have // zero extent. if (width == 0 || height == 0 || !m_window->is_active()) { m_window->set_offscreen(true); return; } if (width > m_window->max_width()) { if (m_window->is_left()) x += width - m_window->max_width(); width = m_window->max_width(); } if (height > m_window->max_height()) { if (m_window->is_bottom()) y += height - m_window->max_height(); height = m_window->max_height(); } m_window->set_offscreen(false); m_window->resize(x, y, width, height); m_window->mark_dirty();}inline voidFrame::balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Find the size of the static frames. The dynamic frames are added // to a temporary list for the second pass. Each frame uses the // m_width and m_height as temporary storage for width and height in // this algorithm. size_type dynamicSize = 0; dynamic_type dynamicFrames[max_size]; int remaining = height; for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { bounds_type bounds = (*itr)->preferred_size(); if ((*itr)->is_height_dynamic()) { (*itr)->m_height = 0; dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds); } else { (*itr)->m_height = bounds.minHeight; remaining -= bounds.minHeight; } } // Sort the dynamic frames by the min size in the direction we are // interested in. Then try to satisfy the largest first, and if we // have any remaining space we can use that to extend it and any // following frames. // // Else if we're short, only give each what they require. std::sort(dynamicFrames, dynamicFrames + dynamicSize, rak::greater2(rak::on(rak::const_mem_ref(&dynamic_type::second), rak::const_mem_ref(&Frame::bounds_type::minHeight)), rak::on(rak::const_mem_ref(&dynamic_type::second), rak::const_mem_ref(&Frame::bounds_type::minHeight)))); bool retry; do { retry = false; for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) { uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last); adjust += itr->first->m_height; adjust = std::max(adjust, itr->second.minHeight); adjust = std::min(adjust, itr->second.maxHeight); remaining -= adjust - itr->first->m_height; retry = retry || itr->first->m_height != adjust; itr->first->m_height = adjust; } } while (retry && remaining > 0); // Use the pre-calculated frame sizes to balance the sub-frames. If // the frame is too small, it will set the remaining windows to zero // extent which will flag them as offscreen. for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { // If there is any remaining space, check if we want to shift // the subsequent frames to the other side of this frame. if (remaining > 0 && (*itr)->has_bottom_frame()) { (*itr)->m_height += remaining; remaining = 0; } (*itr)->balance(x, y, m_width, std::min((*itr)->m_height, height)); y += (*itr)->m_height; height -= (*itr)->m_height; }}inline voidFrame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // Find the size of the static frames. The dynamic frames are added // to a temporary list for the second pass. Each frame uses the // m_width and m_height as temporary storage for width and height in // this algorithm. size_type dynamicSize = 0; dynamic_type dynamicFrames[max_size]; int remaining = width; for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { bounds_type bounds = (*itr)->preferred_size(); if ((*itr)->is_width_dynamic()) { (*itr)->m_width = 0; dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds); } else { (*itr)->m_width = bounds.minWidth; remaining -= bounds.minWidth; } } // Sort the dynamic frames by the min size in the direction we are // interested in. Then try to satisfy the largest first, and if we // have any remaining space we can use that to extend it and any // following frames. // // Else if we're short, only give each what they require. std::sort(dynamicFrames, dynamicFrames + dynamicSize, rak::greater2(rak::on(rak::const_mem_ref(&dynamic_type::second), rak::const_mem_ref(&Frame::bounds_type::minWidth)), rak::on(rak::const_mem_ref(&dynamic_type::second), rak::const_mem_ref(&Frame::bounds_type::minWidth)))); bool retry; do { retry = false; for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) { uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last); adjust += itr->first->m_width; adjust = std::max(adjust, itr->second.minWidth); adjust = std::min(adjust, itr->second.maxWidth); remaining -= adjust - itr->first->m_width; retry = retry || itr->first->m_width != adjust; itr->first->m_width = adjust; } } while (retry && remaining > 0); // Use the pre-calculated frame sizes to balance the sub-frames. If // the frame is too small, it will set the remaining windows to zero // extent which will flag them as offscreen. for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) { // If there is any remaining space, check if we want to shift // the subsequent frames to the other side of this frame. if (remaining > 0 && (*itr)->has_left_frame()) { (*itr)->m_width += remaining; remaining = 0; } (*itr)->balance(x, y, std::min((*itr)->m_width, width), m_height); x += (*itr)->m_width; width -= (*itr)->m_width; }}}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?