1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Contains the Message and MessagePosition structs, along with the MessageType
//! enumeration, which are the foundation of the "Handler Chain" design pattern
//! example.

use std::fmt::Display;


/// Represent the types of messages that can be sent to a MessageWindow (as
/// seen by the IMessageHandler::process_message() method).
///
/// Normally, the Close message type would be supported but Rust does not like
/// nested calls to mutable objects, which is required with Close (the Button
/// Up handler would send a Close message to the HandlerChain).  Instead, the
/// Button Up message handler of the MessageWindow returns a Close return code
/// so HandlerChain::send_message() can take care of removing the window from
/// the handler list.
pub enum MessageType {
    /// Selects a window based on position.
    ButtonDown = 1,

    /// Take an action on the currently selected window.
    ButtonUp,
}

//=============================================================================

/// Position of the message in global coordinates (same scope of coordinates as
/// windows).  Although this can handle negative coordinates, the example is
/// careful to use only positive coordinates.
pub struct MessagePosition {
    /// X position.
    pub x: i32,
    /// Y position.
    pub y: i32,
}

impl MessagePosition {
    /// Constructor
    ///
    /// # Parameters
    /// - x
    ///
    ///   X position to use.
    /// - y
    ///
    ///   Y position to use.
    ///
    /// # Returns
    /// Returns a new instance of the MessagePosition struct.
    pub fn new(x:i32, y:i32) -> MessagePosition {
        MessagePosition{ x, y }
    }
}

impl Display for MessagePosition {
    /// Convert The MessagePosition struct contents to a string.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("x={:2},y={:2}", self.x, self.y))
    }
}

//=============================================================================

/// Represents a message sent to the windows.  A message contains a type
/// and a position.
pub struct Message {
    /// Value from the MessageType enumeration indicating the type of this message.
    pub message_type: MessageType,
    /// Position of message when the message was sent.  In a real system, this
    /// would generally represent the position of a cursor at the time the message
    /// was generated.
    pub message_position: MessagePosition,
}

impl Message {
    /// Constructor.
    ///
    /// # Parameters
    /// - message_type
    ///
    ///   Value from the MessageType enumeration indicating the type of message
    ///   being created.
    /// - x
    ///
    ///   X Position of the message.
    /// - y
    ///
    ///   Y Position of the message.
    ///
    /// # Returns
    /// Returns a new instance of the Message struct.
    pub fn new(message_type: MessageType, x: i32, y: i32) -> Message {
        Message {
            message_type,
            message_position: MessagePosition::new(x, y),
        }
    }
}


impl Display for Message {
    /// Convert the Message struct contents to a string.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let type_as_string = match self.message_type {
            MessageType::ButtonDown => "ButtonDown",
            MessageType::ButtonUp => "ButtonUp",
        };

        f.write_fmt(format_args!("{0} at ({1})", type_as_string, self.message_position))
    }
}