library/forms/mforms/view.h (280 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 */ #pragma once #include <boost/signals2.hpp> #include "mforms/base.h" #include "mforms/utilities.h" #include "base/geometry.h" #include "base/trackable.h" #include "base/drawing.h" namespace mforms { // Predefined drag formats used during a drag session. Custom definitions are possible too. const std::string DragFormatText = "com.mysql.workbench.text"; // UTF-8 encoded text. const std::string DragFormatFileName = "com.mysql.workbench.file"; // A plain file name (UTF-8 encoded). class View; enum Alignment { NoAlign, BottomLeft, BottomCenter, BottomRight, MiddleLeft, MiddleCenter, MiddleRight, TopLeft, TopCenter, TopRight }; struct TextAttributes { #ifndef SWIG bool bold; bool italic; base::Color color; TextAttributes() : bold(false), italic(false), color(base::Color::invalid()) { } #endif TextAttributes(const std::string &c, bool b, bool i) : bold(b), italic(i), color(base::Color::parse(c)) { } }; // Mouse button indicators for mouse handling routines. enum MouseButton { MouseButtonLeft = 0, MouseButtonRight = 1, MouseButtonOther = 2, MouseButtonNone = 0x80, // Sometimes the values for the mouse buttons are hard coded, so better use a high value for this. // TODO: identify hard coded values and replace them. }; enum class Modifier { NoModifier = 0x00, ShiftLeft = 0x01, ShiftRight = 0x02, ControlLeft = 0x04, ControlRight = 0x08, AltLeft = 0x10, AltRight = 0x20, MetaLeft = 0x40, MetaRight = 0x80 }; enum DragOperation { DragOperationNone = 0, DragOperationCopy = 1 << 0, DragOperationMove = 1 << 1, DragOperationAll = DragOperationCopy | DragOperationMove, }; #ifndef SWIG inline DragOperation operator|(DragOperation a, DragOperation b) { return (DragOperation)((int)a | (int)b); } inline DragOperation operator&(DragOperation a, DragOperation b) { return (DragOperation)((int)a & (int)b); } inline DragOperation &operator|=(DragOperation &a, DragOperation b) { return a = (DragOperation)((int)a | (int)b); } #endif // Position relative to the target. There's no general rule what this means. View descendants // decide what to use (e.g. a node in a treeview). enum DropPosition { DropPositionUnknown, DropPositionLeft, DropPositionRight, DropPositionOn, DropPositionTop, DropPositionBottom, }; struct DragDetails { base::Point location; // Position of the mouse in client coordinates. DragOperation allowedOperations; // A combination of flags that determine the allowed actions. cairo_surface_t *image; // The drag image to show (owned by the initiator of the operation. // This must be an image surface in ARGB32 format. // When doing text dragging this image can be NULL in which case // the platforms generate a drag image from the given text. base::Point hotspot; // The position of the mouse within the drag image. DragDetails() { location = base::Point(); allowedOperations = DragOperationNone; image = NULL; hotspot = base::Point(); } }; #ifndef SWIG /** * Delegate class for events caused by a drop operation. Must be implemented by objects * that want to accept a drop operation (not necessarily mforms objects). * The sender is the View that initiated the operation. If the operation started outside WB * (or by non-mforms code) the sender is NULL. * The drop point p is given in the receiver's coordinate space. */ class MFORMS_EXPORT DropDelegate { public: /** * Called constantly while the mouse is moving over the receiver during a drag operation. * Return a combination of the drag operations that are supported with the offered formats. * This function must always be implemented by the delegate object. All others are optional. */ virtual DragOperation drag_over(View *sender, base::Point p, DragOperation allowedOperations, const std::vector<std::string> &formats) = 0; /** * Called when files were dropped on the receiver (only called if drag_over returned true). * This callback is specifically for the predefined format DragFormatFileName. * Return the operation that actually took place. This will tell the drag initiator what happened * so it can update its structures. */ virtual DragOperation files_dropped(View *sender, base::Point p, DragOperation allowedOperations, const std::vector<std::string> &file_names) { return DragOperationNone; } /** * Called when text was dropped on the receiver (only called if drag_over returned a valid drag operation). * This callback is specifically for the predefined format DragFormatText. */ virtual DragOperation text_dropped(View *sender, base::Point p, DragOperation allowedOperations, const std::string &text) { return DragOperationNone; } /** * Called when any custom data was dropped on the receiver (only called if drag_over returned a valid drag * operation). * This callback is for all custom data formats and only used for drag operations * within WB. It will never be called for data from other sources. * Note: any of the *_dropped functions can be called during a drop (in random order), * since a single such operation can carry more than one format. */ virtual DragOperation data_dropped(View *sender, base::Point p, DragOperation allowedOperations, void *data, const std::string &format) { return DragOperationNone; } }; #endif #ifndef DOXYGEN_SHOULD_SKIP_THIS #ifndef SWIG struct ViewImplPtrs { void (*destroy)(View *self); int (*get_width)(const View *self); int (*get_height)(const View *self); int (*get_preferred_width)(View *self); int (*get_preferred_height)(View *self); void (*set_size)(View *self, int, int); // Sets the minsize as well. void (*set_min_size)(View *self, int, int); void (*set_padding)(View *self, int, int, int, int); // left, top, right, bottom int (*get_x)(const View *self); int (*get_y)(const View *self); void (*set_position)(View *self, int, int); std::pair<int, int> (*client_to_screen)(View *self, int, int); std::pair<int, int> (*screen_to_client)(View *self, int, int); void (*show)(View *self, bool); bool (*is_shown)(View *self); bool (*is_fully_visible)(View *self); void (*set_tooltip)(View *self, const std::string &); void (*set_name)(View *self, const std::string &); void (*set_font)(View *self, const std::string &); void (*set_enabled)(View *self, bool); bool (*is_enabled)(View *self); void (*relayout)(View *self); void (*set_needs_repaint)(View *self); void (*suspend_layout)(View *self, bool); void (*set_front_color)(View *self, const std::string &); std::string (*get_front_color)(View *self); void (*set_back_color)(View *self, const std::string &); std::string (*get_back_color)(View *self); // for containers only void (*set_back_image)(View *self, const std::string &, Alignment alignment); void (*flush_events)(View *self); void (*focus)(View *self); bool (*has_focus)(View *self); // TODO Windows void (*register_drop_formats)(View *self, DropDelegate *target, const std::vector<std::string> &); DragOperation (*drag_text)(View *self, DragDetails details, const std::string &text); DragOperation (*drag_data)(View *self, DragDetails details, void *data, const std::string &format); DropPosition (*get_drop_position)(View *self); }; #endif #endif class Form; class MFORMS_EXPORT View : public Object, public base::trackable { friend class ControlFactory; private: std::string _internalName; bool _layout_dirty; boost::signals2::signal<void()> _signal_resized; boost::signals2::signal<bool()> _signal_mouse_leave; boost::signals2::signal<void()> _signal_got_focus; protected: View(); ViewImplPtrs *_view_impl; View *_parent; std::vector<std::pair<View *, bool> > _subviews; void cache_view(View *sv); virtual void remove_from_cache(View *sv); void reorder_cache(View *sv, int position); int get_subview_index(View *sv); View *get_subview_at_index(int index); int get_subview_count(); // This works only for containers so is made public in the Container subclass virtual void set_back_image(const std::string &path, Alignment alignment); public: virtual ~View(); virtual void set_managed(); View *find_subview(const std::string &name); bool contains_subview(View *subview); void clear_subviews(); virtual void set_name(const std::string &name); void setInternalName(const std::string &name); std::string getInternalName() const; void set_tooltip(const std::string &text); virtual void set_font(const std::string &fontDescription); // e.g. "Trebuchet MS bold 9" void set_parent(View *parent); virtual View *get_parent() const; Form *get_parent_form() const; virtual int get_width() const; virtual int get_height() const; virtual int get_preferred_width(); virtual int get_preferred_height(); virtual int get_x() const; virtual int get_y() const; virtual void set_position(int x, int y); virtual void set_size(int width, int height); virtual void set_min_size(int width, int height); std::pair<int, int> client_to_screen(int x, int y); std::pair<int, int> screen_to_client(int x, int y); /** * Show/hide view. */ void show(bool flag = true); /** * Check whenever view is visible. */ bool is_shown(); /** * Returns true if the view and all it's parents are visible. */ bool is_fully_visible(); /** * Enable view so user can interact with it. */ void set_enabled(bool flag); /** * Check whenever view is enabled. */ bool is_enabled(); /** * Mark view to be repainted with next iteration. */ void set_needs_repaint(); virtual void relayout(); virtual void set_layout_dirty(bool value); virtual bool is_layout_dirty(); /** * Freeze gui updates for this view. This method is useful when there is a need to manipulate childs of this view. * After calling suspend_layout, resume_layout need to be called! */ void suspend_layout(); /** * Resume gui updates for this view. Should be called after suspend_layout was called. */ void resume_layout(); /** * Set view foreground color. */ void set_front_color(const std::string &color); /** * Get view foreground color. */ std::string get_front_color(); /** * Set view background color. */ void set_back_color(const std::string &color); /** * Get view background color. */ std::string get_back_color(); // Below code is used only for debug purpose. // It's using the object::retain_count. #ifdef _0 void show_retain_counts(int depth = 0); #endif /** * Get string value from the view if it's holding some. */ virtual std::string get_string_value() { return ""; } /** * Get int value from the view if it's holding some. */ virtual int get_int_value() { return 0; } /** * Get bool value from the view if it's holding some. */ virtual bool get_bool_value() { return false; } /** * Iterate over all events that were queued and flush them, results in faster gui updates or faster signal calls. */ virtual void flush_events(); /** * Causes view to have keyboard focus. */ virtual void focus(); virtual bool has_focus(); #ifndef SWIG /** * Enables or disables the ability to accept a drag/drop operation (internal or from outside) * based on drop_formats. * @param target specifies a target that will receive drop events. It can be the same as the view * or any other class (even non-visual) that implements this interface. */ void register_drop_formats(DropDelegate *target, const std::vector<std::string> &drop_formats); /** * Starts an internal drag/drop operation with the given text/data and blocks until that op is finished. * The result tells the caller what actually happened. */ DragOperation do_drag_drop(DragDetails details, const std::string &text); DragOperation do_drag_drop(DragDetails details, void *data, const std::string &format); /** * Only valid during a drag operation. Returns a drop position value of the drop target * (if one can be determined, like above or below a tree node). * This is a helper to ease determination of the actual drop operation if that depends on the * position within the target. */ DropPosition get_drop_position(); #endif #ifndef DOXYGEN_SHOULD_SKIP_THIS #ifndef SWIG // Events called by the platform code. Returns a bool value to indicate if the event was handled. // False means the platform should do whatever it needs with that event. // Note: these functions are only called if the platform control supports this type of mouse handling. // Examples are: all containers (Panel, ScrollPanel, Box, Table) and DrawBox. virtual bool mouse_down(MouseButton button, int x, int y) { return false; } virtual bool mouse_up(MouseButton button, int x, int y) { return false; } virtual bool mouse_click(MouseButton button, int x, int y) { return false; } virtual bool mouse_double_click(MouseButton button, int x, int y) { return false; } virtual bool mouse_enter() { return false; } virtual bool mouse_leave(); virtual bool mouse_move(MouseButton button, int x, int y) { return false; } virtual bool focusIn() { return false; } virtual bool focusOut() { return false; } virtual bool keyPress(KeyCode code, ModifierKey modifiers) { return false; } virtual bool keyRelease(KeyCode code, ModifierKey modifiers) { return false; } #endif #endif void focus_changed(); /** Triggered by the platform layers when the size of the view changes. */ virtual void resize(); boost::signals2::signal<void()> *signal_resized() { return &_signal_resized; } boost::signals2::signal<bool()> *signal_mouse_leave() { return &_signal_mouse_leave; } boost::signals2::signal<void()> *signal_got_focus() { return &_signal_got_focus; } }; };