by Ter13
Interact with the mouse more easily and more concisely

Mouse Actions:

In order to keep track of the current state of the mouse, /mouse_action datums have been created. Mouse actions are unique datums that track the mouse state from hover until the mouse is pressed and released. A new mouse action is created only after client.MouseUp() is called, thus completing a specific mouse action.


The current mouse action is stored on the client in the mouse_action variable. This variable is only valid for the duration of the current mouse action. There will always be a current mouse_action for the duration of the client's lifetime.

Mouse actions have two variables:


/mouse_action.state is an integer value that will be one of the following values:


When a mouse action has never had a mouse button held during its lifetime, it will be in the state MOUSE_HOVER.

When a button has been pressed, but the mouse has not been dragged, the state of the mouse action is MOUSE_HOLD.

If the mouse is released before a drag action starts, the state of the mouse action is MOUSE_RELEASE. The mouse actions state is set to MOUSE_RELEASE after MouseUp() is called, but before a new mouse action replaces the current one on the client.

Once MouseDragStart() has been called, the state of the mouse action is set to MOUSE_DRAG.

Once MouseDrop() or certain MouseUp() actions are called, the state of the mouse action is set to MOUSE_DROP prior to the creation of a new mouse_action to replace the current one.

/ should not be accessed directly unless you wish to override mouse actions to create new behavior. This is not currently recommended or supported. It is recommended to access this data by indexing the mouse action directly as though the datum were a list.

The following properties are recognized by default:

  src-object or object or start-object
  src-location or location or start-location
  src-control or control or start-control
  src-params or params or start-params
  over-object or end-object
  over-location or end-location
  over-control or end-control
  over-params or end-params

Accessing the properties of a mouse action is simple:

//do something

You can also get the state of a mouse object using the same indexing:

world.log << mouse_action["state"]
world.log << mouse_action.state

You can also set the variables of a mouse action, and store additional data in a similar manner:

mouse_action["state"] = MOUSE_DRAG
mouse_action["src-object"] = src
mouse_action["tempdata"] = usr

Note that the temporary data is only valid for the lifetime of the mouse action. If you need to do something with a mouse action over time, be sure to store the mouse action you want to use, as the client will discard it immediately when a new action takes precedence after the next MouseUp() call.
Mouse Params:

This library has completely overridden how mouse params work by wrapping the param strings in a datum that makes them easier to work with and takes out a lot of the boilerplate required to work with mouse param strings.

If you want to plug this library into an existing project that handles the param variable of mouse procs as strings, you should define PARAMS2LIST_OVERRIDE prior to including the library in your project. This will implement a safety check that allows all future uses of paramstrings to disambiguate between a mouse_params datum and a param string. This will allow your existing code to continue to work properly while you adapt your code to the new approach. Be aware that this adds a very small amount of overhead to every params2list() call globally, so it should only be a temporary measure to allow proper integration of this library.

By default, this library wraps the params argument of all mouse procs in a mouse_params datum. This datum is not parsed until data is requested from it. Be aware that this means that any overrides to client mouse procs that are compiled after the inclusion of this library will not have their parameters overridden, so it is best to include this library at the end of your project's DME.

The mouse_params datum can be accessed like a list using indexing similarly to mouse actions. The following params are valid:

  params  returns the full param string
  params-list  returns the param string as a list

  icon-pos  returns icon-x and icon-y as a list of numbers
  icon-x  returns icon-x as a number
  icon-y  returns icon-y as a number
  icon-loc  returns icon-x and icon-y as a comma-separated string

  screen-loc  returns the screen-loc as a string
  screen-pos  returns a parsed list in screen_loc format
  screen-x  returns a numeric screen x value
  screen-y  returns a numeric screen y value
  screen-control  returns the id of the control from screen-loc as text

  vis-pos  returns a list of vis-x and vis-y in numeric format
  vis-x  returns vis-x in numeric format
  vis-y  returns vis-y in numeric format
  vis-loc  returns vis-x and vis-y as a comma-separated string

  buttons  returns bitflags that correspond to which modifiers and keys are held
  left  returns true as a string if left is pressed
  middle  returns true as a string if middle is pressed
  right  returns true as a string if right is pressed
  shift  returns true as a string if shift is pressed
  ctrl  returns true as a string if ctrl is pressed
  alt  returns true as a string if alt is pressed

  drag-cell  returns the cell a drag action started in
  drop-cell  returns the cell a drop action started in
  drag  returns the button used to initiate a drag action

  link  returns the link pressed in maptext

Mouse flags:
  MOUSE_ALT (32)

When getting the buttons parameter from mouse_params, use these values can be used to test which mouse modifiers and buttons are pressed.

Screen loc format:
  list(screen-x as num,screen-y as num,control as text|null)

Utility functions:
  parse_screen_loc("C:TX:PX,TY:PY"): returns a screen-loc format list
  parse_size("WxH"): returns a list of numbers
  parse_pos("X,Y"): returns a list of numbers

Temporary data:
  Temporary data can be stored similarly to how it is stored in mouse_actions. This data will only persist until the parameter is no longer referenced, and is preferred for shorter term information storage.

client and atom MouseDragStart() have been added to allow you to track when a drag action has begun more easily. It is only called on the first call to MouseDrag() for a given mouse action.

Mob callbacks:

  onMouseMove(atom/object,atom/ location,control,params)
  onMouseEntered(atom/object,atom/ location,control,params)
  onMouseExited(atom/object,atom/ location,control,params)
  onMouseDown(atom/object,atom/ location,control,params)
  onMouseUp(atom/object,atom/ location,control,params)
  onMouseWheel(atom/object,delta_x,delta_y,atom/ location,control,params)
  onMouseDrag(atom/src_object,atom/ over_object,atom/src_location,atom/ over_location,src_control,over_control,params)
  onMouseDragStart(atom/ object,delta_x,delta_y,atom/location,control,params)
  onMouseDrop(atom/src_object,atom/ over_object,atom/src_location,atom/ over_location,src_control,over_control,params)

These are called as part of client mouse procs prior to calling the supercall of mouse actions.

If they return any non-zero value, they will prevent the supercall from being triggered. These all return 0 by default.

This allows mouse actions to be intercepted by the mob so per-mob mouse functionality can be implemented with proper polymorphic context.
Map info

client.map_info stores a series of associative lists that describe the map info of any map elements. These structures are necessary to correctly convert screen positions to window positions. This may or may not be necessary for your project.

On client initialization, this will get information from the default map element by calling client.InitDefaultMap(). This will query the default map for a range of properties.

If you want to use screen2wndpos() in your project to convert a screen position to a window position for a given element, you need to ensure that when map elements are resized that they call the client.mapResize() verb with the following format:

mapResize [[id]] [[parent]] [[pos]] [[size]] [[view-size]] [[zoom]] [[is-default]]

If you have more than one map element and want to use screen2wndpos from non-default map elements, you will want to also call mapResize from the on-show command of any non-default map elements just like the above, and you will want that element's on-resize command to the same.


client.screen2wndpos takes a pixel screen-loc and converts it to a window position as a list of numbers using the stored map info for the supplied element.

the arguments are:

(screen-x, screen-y, element).

If no element is supplied, it will assume the default map element is the default.

If you are changing a map element's zoom, default status, position, or size via a winset, you may have to call UpdateMapElem(element) immediately after. Please be aware that this function is asynchronous, so you should call this after a manual change, rather than when you need to know about that change later.

each map_info list has the following structure:

  pos  position of the map element as a list of numbers
  parent  the id of the parent element of the map element
  size  size of the map element a list of numbers
  view  the pixel size of the viewport rendered in the map as a list of numbers
  zoom  the zoom of the viewport as a number

client.map_info is an associative list where each map_info list is indexed by the map's id.

client.default_map is set to the id of the last map that was marked as default.
Implementing Mouselib:

Mouselib is not a project you can simply #include into your project and expect to take advantage of all of the features. There is one additional step. Include the library normally, preferrably at the top of your DME file's include block.

However, in order to fully integrate all of mouselib's behaviors, you need to the file separately later in compilation order than you plan to override any client, atom, or mob mouse procs.

This will ensure that my mouse overrides are the first version of themselves that are called, and ensure that mouse_params and mouse_action datums are created by the time that your own overrides are executed.

Here's an example of a DME file that properly integrates this library:

#include <ter13\mouselib2\MouseLib2.dme>
#include ""
#include ""
#include "ui.dmf"
#include "test.dmm"
#include "code\core\"
#include "code\core\"
#include "code\core\"
#include "code\core\"
#include "code\core\"
#include "code\core\"
#include "code\core\"
#include "content\"
#include "content\"
#include "content\"

#include <ter13\mouselib2\>