1// Aseprite UI Library
2// Copyright (C) 2018-2022 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifndef UI_MESSAGE_H_INCLUDED
9#define UI_MESSAGE_H_INCLUDED
10#pragma once
11
12#include "base/paths.h"
13#include "gfx/point.h"
14#include "gfx/rect.h"
15#include "ui/base.h"
16#include "ui/keys.h"
17#include "ui/message_type.h"
18#include "ui/mouse_button.h"
19#include "ui/pointer_type.h"
20
21namespace ui {
22
23 class Display;
24 class Timer;
25 class Widget;
26
27 class Message {
28 enum Flags {
29 FromFilter = 1, // Sent from pre-filter
30 PropagateToChildren = 2,
31 PropagateToParent = 4,
32 };
33 public:
34 Message(MessageType type,
35 KeyModifiers modifiers = kKeyUninitializedModifier);
36 virtual ~Message();
37
38 MessageType type() const { return m_type; }
39 Display* display() const { return m_display; }
40 Widget* recipient() const { return m_recipient; }
41 bool fromFilter() const { return hasFlag(FromFilter); }
42 void setFromFilter(const bool state) { setFlag(FromFilter, state); }
43 KeyModifiers modifiers() const { return m_modifiers; }
44 bool shiftPressed() const { return (m_modifiers & kKeyShiftModifier) == kKeyShiftModifier; }
45 bool ctrlPressed() const { return (m_modifiers & kKeyCtrlModifier) == kKeyCtrlModifier; }
46 bool altPressed() const { return (m_modifiers & kKeyAltModifier) == kKeyAltModifier; }
47 bool cmdPressed() const { return (m_modifiers & kKeyCmdModifier) == kKeyCmdModifier; }
48 bool winPressed() const { return (m_modifiers & kKeyWinModifier) == kKeyWinModifier; }
49 bool onlyShiftPressed() const { return m_modifiers == kKeyShiftModifier; }
50 bool onlyCtrlPressed() const { return m_modifiers == kKeyCtrlModifier; }
51 bool onlyAltPressed() const { return m_modifiers == kKeyAltModifier; }
52 bool onlyCmdPressed() const { return m_modifiers == kKeyCmdModifier; }
53 bool onlyWinPressed() const { return m_modifiers == kKeyWinModifier; }
54
55 void setDisplay(Display* display);
56 void setRecipient(Widget* widget);
57 void removeRecipient(Widget* widget);
58
59 bool propagateToChildren() const { return hasFlag(PropagateToChildren); }
60 bool propagateToParent() const { return hasFlag(PropagateToParent); }
61 void setPropagateToChildren(const bool state) { setFlag(PropagateToChildren, state); }
62 void setPropagateToParent(const bool state) { setFlag(PropagateToParent, state); }
63
64 Widget* commonAncestor() { return m_commonAncestor; }
65 void setCommonAncestor(Widget* widget) { m_commonAncestor = widget; }
66
67 private:
68 bool hasFlag(const Flags flag) const {
69 return (m_flags & flag) == flag;
70 }
71 void setFlag(const Flags flag, const bool state) {
72 m_flags = (state ? (m_flags | flag):
73 (m_flags & ~flag));
74 }
75
76 MessageType m_type; // Type of message
77 int m_flags; // Special flags for this message
78 Display* m_display;
79 Widget* m_recipient; // Recipient of this message
80 Widget* m_commonAncestor; // Common ancestor between the Leave <-> Enter messages
81 KeyModifiers m_modifiers; // Key modifiers pressed when message was created
82 };
83
84 class KeyMessage : public Message {
85 public:
86 KeyMessage(MessageType type,
87 KeyScancode scancode,
88 KeyModifiers modifiers,
89 int unicodeChar,
90 int repeat);
91
92 KeyScancode scancode() const { return m_scancode; }
93 int unicodeChar() const { return m_unicodeChar; }
94 int repeat() const { return m_repeat; }
95 bool isDeadKey() const { return m_isDead; }
96 void setDeadKey(bool state) { m_isDead = state; }
97
98 private:
99 KeyScancode m_scancode;
100 int m_unicodeChar;
101 int m_repeat; // repeat=0 means the first time the key is pressed
102 bool m_isDead;
103 };
104
105 class PaintMessage : public Message {
106 public:
107 PaintMessage(int count, const gfx::Rect& rect)
108 : Message(kPaintMessage)
109 , m_count(count)
110 , m_rect(rect) {
111 }
112
113 int count() const { return m_count; }
114 const gfx::Rect& rect() const { return m_rect; }
115
116 private:
117 int m_count; // Cound=0 if it's last msg of draw-chain
118 gfx::Rect m_rect; // Area to draw
119 };
120
121 class MouseMessage : public Message {
122 public:
123 MouseMessage(MessageType type,
124 PointerType pointerType,
125 MouseButton button,
126 KeyModifiers modifiers,
127 const gfx::Point& pos,
128 const gfx::Point& wheelDelta = gfx::Point(0, 0),
129 bool preciseWheel = false,
130 float pressure = 0.0f)
131 : Message(type, modifiers),
132 m_pointerType(pointerType),
133 m_button(button),
134 m_pos(pos),
135 m_wheelDelta(wheelDelta),
136 m_preciseWheel(preciseWheel),
137 m_pressure(pressure) {
138 }
139
140 // Copy other MouseMessage converting its type
141 MouseMessage(MessageType type,
142 const MouseMessage& other,
143 const gfx::Point& newPosition)
144 : Message(type, other.modifiers()),
145 m_pointerType(other.pointerType()),
146 m_button(other.button()),
147 m_pos(newPosition),
148 m_wheelDelta(other.wheelDelta()),
149 m_preciseWheel(other.preciseWheel()),
150 m_pressure(other.pressure()) {
151 }
152
153 PointerType pointerType() const { return m_pointerType; }
154 MouseButton button() const { return m_button; }
155 bool left() const { return (m_button == kButtonLeft); }
156 bool right() const { return (m_button == kButtonRight); }
157 bool middle() const { return (m_button == kButtonMiddle); }
158 gfx::Point wheelDelta() const { return m_wheelDelta; }
159 bool preciseWheel() const { return m_preciseWheel; }
160 float pressure() const { return m_pressure; }
161
162 const gfx::Point& position() const { return m_pos; }
163
164 // Returns the mouse message position relative to the given
165 // "anotherDisplay" (the m_pos field is relative to m_display).
166 gfx::Point positionForDisplay(Display* anotherDisplay) const;
167
168 // Absolute position of this message on the screen.
169 gfx::Point screenPosition() const;
170
171 private:
172 PointerType m_pointerType;
173 MouseButton m_button; // Pressed button
174 gfx::Point m_pos; // Mouse position
175 gfx::Point m_wheelDelta; // Wheel axis variation
176 bool m_preciseWheel;
177 float m_pressure;
178 };
179
180 class TouchMessage : public Message {
181 public:
182 TouchMessage(MessageType type,
183 KeyModifiers modifiers,
184 const gfx::Point& pos,
185 double magnification)
186 : Message(type, modifiers),
187 m_pos(pos),
188 m_magnification(magnification) {
189 }
190
191 const gfx::Point& position() const { return m_pos; }
192 double magnification() const { return m_magnification; }
193
194 private:
195 gfx::Point m_pos; // Mouse position
196 double m_magnification;
197 };
198
199 class TimerMessage : public Message {
200 public:
201 TimerMessage(int count, Timer* timer)
202 : Message(kTimerMessage), m_count(count), m_timer(timer) {
203 }
204
205 int count() const { return m_count; }
206 Timer* timer() { return m_timer; }
207
208 // Used by Manager::removeMessagesForTimer() to invalidate the
209 // message. It's like removing the message from the queue, but
210 // without touching the queue in case that we're iterating it
211 // (which can happen if we remove the timer from a kTimerMessage
212 // handler).
213 void _resetTimer() { m_timer = nullptr; }
214
215 private:
216 int m_count; // Accumulated calls
217 Timer* m_timer; // Timer handle
218 };
219
220 class DropFilesMessage : public Message {
221 public:
222 DropFilesMessage(const base::paths& files)
223 : Message(kDropFilesMessage)
224 , m_files(files) {
225 }
226
227 const base::paths& files() const { return m_files; }
228
229 private:
230 base::paths m_files;
231 };
232
233} // namespace ui
234
235#endif
236