text: /*
   * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #pragma once
  
  #include <AK/String.h>
  #include <Kernel/KeyCode.h>
  #include <LibCore/Event.h>
  #include <LibGfx/Rect.h>
  #include <WindowServer/Cursor.h>
  #include <WindowServer/WindowType.h>
  
  namespace WindowServer {
  
  class Event : public Core::Event {
  public:
      enum Type {
          Invalid = 3000,
          MouseMove,
          MouseDown,
          MouseDoubleClick,
          MouseUp,
          MouseWheel,
          WindowEntered,
          WindowLeft,
          KeyDown,
          KeyUp,
          WindowActivated,
          WindowDeactivated,
          WindowCloseRequest,
          WindowResized,
      };
  
      Event() {}
      explicit Event(Type type)
          : Core::Event(type)
      {
      }
      virtual ~Event() {}
  
      bool is_mouse_event() const { return type() == MouseMove || type() == MouseDown || type() == MouseDoubleClick || type() == MouseUp || type() == MouseWheel; }
      bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
  };
  
  enum class MouseButton : u8 {
      None = 0,
      Left = 1,
      Right = 2,
      Middle = 4,
  };
  
  class KeyEvent final : public Event {
  public:
      KeyEvent(Type type, int key, char character, u8 modifiers)
          : Event(type)
          , m_key(key)
          , m_character(character)
          , m_modifiers(modifiers)
      {
      }
  
      int key() const { return m_key; }
      bool ctrl() const { return m_modifiers & Mod_Ctrl; }
      bool alt() const { return m_modifiers & Mod_Alt; }
      bool shift() const { return m_modifiers & Mod_Shift; }
      bool logo() const { return m_modifiers & Mod_Logo; }
      u8 modifiers() const { return m_modifiers; }
      char character() const { return m_character; }
  
  private:
      friend class EventLoop;
      friend class Screen;
      int m_key { 0 };
      char m_character { 0 };
      u8 m_modifiers { 0 };
  };
  
  class MouseEvent final : public Event {
  public:
      MouseEvent(Type type, const Gfx::Point& position, unsigned buttons, MouseButton button, unsigned modifiers, int wheel_delta = 0)
          : Event(type)
          , m_position(position)
          , m_buttons(buttons)
          , m_button(button)
          , m_modifiers(modifiers)
          , m_wheel_delta(wheel_delta)
      {
      }
  
      Gfx::Point position() const { return m_position; }
      int x() const { return m_position.x(); }
      int y() const { return m_position.y(); }
      MouseButton button() const { return m_button; }
      unsigned buttons() const { return m_buttons; }
      unsigned modifiers() const { return m_modifiers; }
      int wheel_delta() const { return m_wheel_delta; }
      bool is_drag() const { return m_drag; }
      const String& drag_data_type() const { return m_drag_data_type; }
  
      void set_drag(bool b) { m_drag = b; }
      void set_drag_data_type(const String& drag_data_type) { m_drag_data_type = drag_data_type; }
  
      MouseEvent translated(const Gfx::Point& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
  
  private:
      Gfx::Point m_position;
      unsigned m_buttons { 0 };
      MouseButton m_button { MouseButton::None };
      unsigned m_modifiers { 0 };
      int m_wheel_delta { 0 };
      bool m_drag { false };
      String m_drag_data_type;
  };
  
  class ResizeEvent final : public Event {
  public:
      ResizeEvent(const Gfx::Rect& old_rect, const Gfx::Rect& rect)
          : Event(Event::WindowResized)
          , m_old_rect(old_rect)
          , m_rect(rect)
      {
      }
  
      Gfx::Rect old_rect() const { return m_old_rect; }
      Gfx::Rect rect() const { return m_rect; }
  
  private:
      Gfx::Rect m_old_rect;
      Gfx::Rect m_rect;
  };
  
  }
  