library/forms/view.cpp (262 lines of code) (raw):

/* * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is designed to work with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, as * designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have either included with * the program or referenced in the documentation. * 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, version 2.0, 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., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * Implementation of the mforms view, which is the base for most of the visual controls in mforms. */ #include "mforms/mforms.h" #include "base/log.h" #include "base/notifications.h" using namespace mforms; //-------------------------------------------------------------------------------------------------- View::View() { _parent = NULL; _view_impl = &ControlFactory::get_instance()->_view_impl; _layout_dirty = true; } //-------------------------------------------------------------------------------------------------- View::~View() { set_destroying(); if (_parent && !_parent->is_destroying()) _parent->remove_from_cache(this); clear_subviews(); #ifdef __APPLE__ // Let the frontend delete all resources it allocated. // This is only needed for OSX as on Win + Linux we use the data free function (set in set_data()) to free // platform resources. if (_view_impl->destroy) _view_impl->destroy(this); #endif } //-------------------------------------------------------------------------------------------------- void View::clear_subviews() { while (_subviews.size() > 0) remove_from_cache( _subviews[0].first); // Let descendants adjust their child lists. This will also release the object if necessary. } //-------------------------------------------------------------------------------------------------- void View::set_managed() { Object::set_managed(); if (_parent) { for (std::vector<std::pair<View *, bool> >::iterator iter = _parent->_subviews.begin(); iter != _parent->_subviews.end(); ++iter) { if (iter->first == this) { iter->second = true; break; } } } } //-------------------------------------------------------------------------------------------------- void View::cache_view(View *sv) { if (!sv) throw std::logic_error("mforms: attempt to add NULL subview"); if (sv->get_parent() != NULL) throw std::logic_error("mforms: attempt to add a subview already contained somewhere"); if (sv == this) throw std::logic_error("mforms: Can't add a view inside itself"); sv->set_parent(this); if (!sv->_release_on_add) // Means: don't increase the ref count, the caller retained already, but won't release. sv->retain(); else sv->_release_on_add = false; _subviews.push_back(std::make_pair(sv, sv->_managed)); } //-------------------------------------------------------------------------------------------------- void View::reorder_cache(View *sv, int position) { int old = get_subview_index(sv); if (old < 0) throw std::invalid_argument("mforms: invalid subview"); std::pair<View *, bool> value = _subviews[old]; _subviews.erase(_subviews.begin() + old); _subviews.insert(_subviews.begin() + position, value); } //-------------------------------------------------------------------------------------------------- void View::remove_from_cache(View *sv) { sv->_parent = NULL; for (std::vector<std::pair<View *, bool> >::iterator iter = _subviews.begin(); iter != _subviews.end(); ++iter) { if (iter->first == sv) { _subviews.erase(iter); sv->release(); break; } } } //-------------------------------------------------------------------------------------------------- /** * Searches for a subview with the given name in this view or any of its subviews using a depth-first search. */ View *View::find_subview(const std::string &name) { for (std::vector<std::pair<View *, bool> >::const_iterator iter = _subviews.begin(); iter != _subviews.end(); ++iter) { if (iter->first->getInternalName() == name) return iter->first; View *sv = iter->first->find_subview(name); if (sv) return sv; } return 0; } //-------------------------------------------------------------------------------------------------- int View::get_subview_index(View *sv) { int i = 0; for (std::vector<std::pair<View *, bool> >::const_iterator iter = _subviews.begin(); iter != _subviews.end(); ++iter, ++i) { if (iter->first == sv) return i; } return -1; } //-------------------------------------------------------------------------------------------------- View *View::get_subview_at_index(int index) { if (index < 0 || index >= (int)_subviews.size()) return NULL; return _subviews[index].first; } //-------------------------------------------------------------------------------------------------- int View::get_subview_count() { return (int)_subviews.size(); } //-------------------------------------------------------------------------------------------------- /** * Returns true if the given subview is a direct child of this view. */ bool View::contains_subview(View *subview) { return subview->get_parent() == this; } //-------------------------------------------------------------------------------------------------- void View::set_name(const std::string &name) { // Optional implementation. if (_view_impl->set_name) _view_impl->set_name(this, name); } //-------------------------------------------------------------------------------------------------- void View::set_tooltip(const std::string &text) { _view_impl->set_tooltip(this, text); } //-------------------------------------------------------------------------------------------------- void View::set_font(const std::string &fontDescription) { _view_impl->set_font(this, fontDescription); } //-------------------------------------------------------------------------------------------------- void View::setInternalName(const std::string &name) { _internalName = name; } //-------------------------------------------------------------------------------------------------- std::string View::getInternalName() const { return _internalName; } //-------------------------------------------------------------------------------------------------- void View::set_parent(View *parent) { _parent = parent; if (_managed) set_managed(); } //-------------------------------------------------------------------------------------------------- View *View::get_parent() const { return _parent; } //-------------------------------------------------------------------------------------------------- Form *View::get_parent_form() const { View *parent = get_parent(); Form *form = 0; while (parent && (form = dynamic_cast<Form *>(parent)) == 0) parent = parent->get_parent(); return form; } //-------------------------------------------------------------------------------------------------- int View::get_width() const { return (*_view_impl->get_width)(this); } //-------------------------------------------------------------------------------------------------- int View::get_height() const { return (*_view_impl->get_height)(this); } //-------------------------------------------------------------------------------------------------- int View::get_preferred_width() { return (*_view_impl->get_preferred_width)(this); } //-------------------------------------------------------------------------------------------------- int View::get_preferred_height() { return (*_view_impl->get_preferred_height)(this); } //-------------------------------------------------------------------------------------------------- int View::get_x() const { return (*_view_impl->get_x)(this); } //-------------------------------------------------------------------------------------------------- int View::get_y() const { return (*_view_impl->get_y)(this); } //-------------------------------------------------------------------------------------------------- void View::set_position(int x, int y) { (*_view_impl->set_position)(this, x, y); } //-------------------------------------------------------------------------------------------------- void View::set_size(int width, int height) { set_layout_dirty(true); (*_view_impl->set_size)(this, width, height); } //-------------------------------------------------------------------------------------------------- void View::set_min_size(int width, int height) { set_layout_dirty(true); (*_view_impl->set_min_size)(this, width, height); } //-------------------------------------------------------------------------------------------------- std::pair<int, int> View::client_to_screen(int x, int y) { return (*_view_impl->client_to_screen)(this, x, y); } //-------------------------------------------------------------------------------------------------- std::pair<int, int> View::screen_to_client(int x, int y) { return (*_view_impl->screen_to_client)(this, x, y); } //-------------------------------------------------------------------------------------------------- void View::show(bool flag) { (*_view_impl->show)(this, flag); } //-------------------------------------------------------------------------------------------------- bool View::is_shown() { return (*_view_impl->is_shown)(this); } //-------------------------------------------------------------------------------------------------- bool View::is_fully_visible() { return (*_view_impl->is_fully_visible)(this); } //-------------------------------------------------------------------------------------------------- void View::set_enabled(bool flag) { (*_view_impl->set_enabled)(this, flag); } //-------------------------------------------------------------------------------------------------- bool View::is_enabled() { return (*_view_impl->is_enabled)(this); } //-------------------------------------------------------------------------------------------------- void View::set_needs_repaint() { _view_impl->set_needs_repaint(this); } //-------------------------------------------------------------------------------------------------- void View::set_layout_dirty(bool value) { _layout_dirty = value; if (_parent != NULL && value) _parent->set_layout_dirty(true); } //-------------------------------------------------------------------------------------------------- bool View::is_layout_dirty() { return _layout_dirty; } //-------------------------------------------------------------------------------------------------- void View::relayout() { _view_impl->relayout(this); if (_parent != nullptr) // Propagate relayout up the parent chain. _parent->relayout(); } //-------------------------------------------------------------------------------------------------- void View::suspend_layout() { if (_view_impl->suspend_layout) _view_impl->suspend_layout(this, true); } //-------------------------------------------------------------------------------------------------- void View::resume_layout() { if (_view_impl->suspend_layout) _view_impl->suspend_layout(this, false); } //-------------------------------------------------------------------------------------------------- void View::set_front_color(const std::string &color) { _view_impl->set_front_color(this, color); } //-------------------------------------------------------------------------------------------------- std::string View::get_front_color() { return _view_impl->get_front_color(this); } //-------------------------------------------------------------------------------------------------- void View::set_back_color(const std::string &color) { _view_impl->set_back_color(this, color); } //-------------------------------------------------------------------------------------------------- std::string View::get_back_color() { return _view_impl->get_back_color(this); } //-------------------------------------------------------------------------------------------------- void View::set_back_image(const std::string &path, Alignment align) { _view_impl->set_back_image(this, path, align); } //-------------------------------------------------------------------------------------------------- // Below code is used only for debug purpose. // It's using the object::retain_count. #ifdef _0 void View::show_retain_counts(int depth) { printf("%*s '%s' (%i)\n", depth, "--", get_name().c_str(), retain_count()); for (std::vector<std::pair<View *, bool> >::const_iterator iter = _subviews.begin(); iter != _subviews.end(); ++iter) { iter->first->show_retain_counts(depth + 1); } } #endif //-------------------------------------------------------------------------------------------------- void View::flush_events() { if (_view_impl->flush_events) _view_impl->flush_events(this); } //-------------------------------------------------------------------------------------------------- void View::focus() { _view_impl->focus(this); } //-------------------------------------------------------------------------------------------------- bool View::has_focus() { return _view_impl->has_focus(this); } //-------------------------------------------------------------------------------------------------- void View::register_drop_formats(DropDelegate *target, const std::vector<std::string> &drop_formats) { _view_impl->register_drop_formats(this, target, drop_formats); } //-------------------------------------------------------------------------------------------------- DragOperation View::do_drag_drop(DragDetails details, const std::string &text) { return _view_impl->drag_text(this, details, text); } //-------------------------------------------------------------------------------------------------- DragOperation View::do_drag_drop(DragDetails details, void *data, const std::string &format) { return _view_impl->drag_data(this, details, data, format); } //-------------------------------------------------------------------------------------------------- DropPosition View::get_drop_position() { return _view_impl->get_drop_position(this); } //-------------------------------------------------------------------------------------------------- bool View::mouse_leave() { if (_signal_mouse_leave.num_slots() > 0) return *_signal_mouse_leave(); return false; } //-------------------------------------------------------------------------------------------------- /** * To be called by platform code when the active control changes (either by code or user interaction). */ void View::focus_changed() { _signal_got_focus(); base::NotificationCenter::get()->send("GNFocusChanged", this); } //-------------------------------------------------------------------------------------------------- void View::resize() { _signal_resized(); } //--------------------------------------------------------------------------------------------------