Observations about pointers, coordinates, and halfstepping. * Pointer placement by bisecting regions * Placement and resizing of the pointer * Placement of a midpoint in a pointer part * Locations and regions * Vectors * Possibilities for storing coordinates Pointer placement by bisecting regions A pointer can be placed anywhere within the bounds of a view by centering the pointer within one half at a time: left, right, top, or bottom. Start in the center of a view, then split it and recenter the pointer within one of the halves. The maximum number of steps for placing the pointer on any dot of a line is also the number times of dividing the length in half until the result is the value of 1 or less. That is also the same as the magnitude of the value of 2 that results in a value equal or greater than the length of that line. For example, a length of 1200 dots is between 2^10 and 2^11 (t.i. 1024 and 2048), therefore the maximum number of steps to a single dot is 11. For a view 1200 by 900, the maximum is 11 for the x-axis and 10 for the y-axis, a total maximum of 21 steps to any dot within the view. Starting with the pointer in the center is the same as dividing in half twice, once for each axis, thereby potentially reducing the number of additional steps by two. Thereafter, each step divides only one axis, but is required only until the pointer is placed where needed. Guidelines for human-computer interfaces (HCI) have recommended a minimum of 32 dots for width and height of regions intended for selection with a pointer, such as commands presented as regions on a "toolbar". Placing the pointer within a region of 32 dots by 32 dots (preferably slightly smaller) is potentially five steps fewer (32 = 2^5) for each axis than for a single dot in a view. For example, a view of 1200 by 900 divided into regions of 30 by 30 effectively reduces the view to 40 regions by 30 regions. The magnitudes for the value of 2 for each axis is then 6 (2^6 = 64 > 40) and 5 (2^5 = 32 > 30), a total maximum of 11 steps to any 30 by 30 region. As six steps accounts for 64 regions, a view with 64 regions of 30 by 30 dots along each axis has a size of 1920 by 1920 and a total maximum of 12 steps. Similarly, seven steps for regions of 30 by 30 covers a view of 3840 by 3840 dots with a total maximum of 14 steps. A line of text is typically at least 16 dots tall, such as within a menu or a hypertext link. A single word averages about five characters, and the width of each character is about half the height of a line. Therefore, a word might be at least 40 dots wide, though less with narrower characters. Menus are typically more than one word wide, and widen further with left and right margins of empty space. The maximum number of steps is potentially reduced when the width of a menu (or a hypertext link) is greater than the next magnitude of 2. > 64 dots wide (1.5 words): max steps reduced by six > 128 dots wide (3 words): max steps reduced by seven > 256 dots wide (6 words): max steps reduced by eight That is 1, 2, or 3 fewer steps for the maximum when compared to a region 32 dots wide. Vertically, a line height of 16 dots is half the 32 dots of the HCI guidelines for regions requiring a pointer for activation. That potentially increases the maximum steps by one for the y-axis. Overall, placing the pointer on text is potentially the same or less maximum steps than for a subregion on toolbars. Dividing in half is about proportions. A sequence of halving remains relevant when scaling a region (and its content), regardless of a change in aspect ratio, f.e. a change of screen resolution. The ratio of the sizes guides the translation of the coordinates. The exact same number of steps suffices for a region scaled larger, or even when squished or stretched. Placement and resizing of the pointer A step length is half of either the width or height of the current region. Beginning with the whole Xwindow, the first position is the center of the Xwindow, a step in both directions. The number of steps for each axis and the coordinates are both stored per Xwindow, in its plist property 'nu-pointer-step'. The pointer visually divides the current region in half horizonatlly and vertically, wherewith it reveals the potential result of the next step. A gap at the center provides a view of the focal point, coordinated with the actual cursor, thereby segmenting the pointer into four parts. These four parts are stored per root Xwindow, in its plist property 'nu-pointer'. Each part of the pointer is a thin line masked (bordered) by a contrasting color, the standard approach for ensuring contrast with any content. Each line is isolated in a separate Xwindow, all with greater priority than any other managed Xwindow. For an Xserver, the width and height of an Xwindow is distinct from its border width, and the border is the same width for the whole perimeter. An Xwindow is placed at the origin of its border, so its own origin is displaced by the border width. The pointer gap width and height is 16 by 16, based on the typical minimal line height for text. The minimal length of the pointer dividing line is the same as gap, and its thickness (line width) is 2. The border is the mask and its width is 1. The pointer breadth is the pointer thickness (line width) plus the border on either side. Therefrom: 1 + 2 + 1. The left and right parts are distanced by the gap width, so the width of each part is the current horizontal step minus half the gap width (and Xwindow border). The length of the current horizontal step: Xwindow width / 2 ^ number of horizontal steps As it might be less than the minimal pointer line length, the actual line length (width of pointer part) is used for calculating the position of the line. The width of the left and right pointer parts: horizontal step length - (2 * pointer border) - half width of pointer gap but at least the minimal pointer line length. The height of the left and right pointer parts is the thickness (width) of the pointer line. The left and right coordinates, for point (x, y): |<-- Xwindow origin |<-- Xwindow origin | point | | | |b|---- line ----|b|------ + ------|b|---- line ----|b| |1/2 gap|1/2 gap| |possible split length ----|---- possible split length| Left pointer part x coordinate. x of point - (width of left pointer part + (2 * pointer border) + half width of pointer gap) Right pointer part x coordinate. x of point + half width of pointer gap Both left and right y coordinate. y of point - half breadth of pointer The top and bottom parts are distanced by the gap height, so the height of each part is the current vertical step minus half the gap height (and Xwindow border). The length of the current vertical step: Xwindow height / 2 ^ number of vertical steps As it might be less than the minimal pointer line length, the actual line length (height of pointer part) is used for calculating the position of the line. The width of the top and bottom pointer parts is the thickness (width) of the pointer line. The height of the top and bottom pointer parts: vertical step length - (2 * pointer border) - half height of pointer gap but at least the minimal pointer line length. The top and bottom coordinates, ---------- Xwin origin for point (x, y): | border ---- Both top and bottom x coordinate. | line (height) x of point ---- - half breadth of pointer | border ---- Top pointer part y coordinate. | 1/2 gap y of point -+--------- point - (height of top pointer part | 1/2 gap + (2 * pointer border) ---------- Xwin origin + half height of pointer gap) | border ---- Bottom pointer part y coordinate. | line (height) y of point ---- + half height of pointer gap | border ---- Placement of a midpoint in a pointer part The split length spans from gap center to the edge of the narrowed region. A pointer part spans the split length minus half the pointer gap. The line of a pointer part is between its border edges. The origin of the line begins at the inside edge of the border. A midpoint is at half the distance of the split length from gap center (and as wide as the line thickness). The midpoint is positioned from the line origin. The left part (x-axis) and top part (y-axis), for a border width of 1, and a midpoint width of 2: |<-- line origin | |b|----- line -----|b|----- gap -----| |1/2 gap| |split length ---------------| |---- 1/2 split| |mid| | 2 | Remember, the split length might be less than the minimum pointer line length, so depend on the line length instead. The midpoint from line origin is at: line length + one border + 1/2 gap width - 1/2 split length - 1/2 midpoint width and zero for the other axis. The right part (x-axis) and bottom part (y-axis), for a pointer gap width and height of 16, (and the aforementioned measurements): |<-- line origin | |------ gap -----|b|----- line -----|b| |1/2 gap| |--------------- split length| |1/2 split ----| |mid| | 2 | The midpoint from line origin is at: 1/2 split length - 1/2 gap width - one border - 1/2 midpoint width and zero for the other axis. Locations and regions The location of the pointer of an Xserver is a pair of coordinates based on the left-top corner of a view as the origin. Relatedly, the width and height of that view is equivalent to the kitty-corner coordinate for the origin of that view. For example, a 1200 by 900 view is represented by a list of kitty-corner coordinates '((xy 0 0)(xy 1200 900)) or by its location with its width and height '((xy 0 0)(wh 1200 900)) Thereby, the top-right region of a quartered-view is within '((xy 600 0)(xy 1200 450)) or represented by its location and size within the view as '((xy 600 0)(wh 600 450)) The location of the pointer centered within the view might be represented as '((xy 600 450)((xy 0 0)(wh 1200 900))) or simplified as with any region with a presumed origin '((xy 600 450)(wh 1200 900)) Clearly, coordinates can have different meanings, even when associated with a width and height, so the context must be documented for the data. Vectors A list of coordinates is like a vector for each perpendicular axis, declaring direction with length. For an origin in the left-top corner, the directions are summarized for a set of coordinates by pairing left and right as negative and positive values for the horizontal, and up and down as negative and positive values for the vertical. For example, the location from the origin at left-top '(xy 600 450) is equivalent to '((right 600)(down 450)) A path of vectors with most recent step first '((up 225)(down 450)(right 600)) can be represented as '((xy 0 -225)(xy 600 450)) The initial placement of the pointer in the center of the screen is the same as two steps from the origin, one for each axis as half the length of an axis. The coordinates represent the difference for both axes. For example, a screen of 1200 by 900 has its center at '(xy 600 450) or represented as differences of vectors with each step '((xy 0 450)(xy 600 0)) thereby each step has one axis with a difference of zero. Possibilities for storing coordinates Horizontal stepping is separate from vertical stepping. The initial distances can be different, thereby the halving would have different values. The number of steps along an axis is the same as the magnitude for the value of 2 that would divide the axis length for the distance of a step on that axis, f.e. plus or minus (/ axislength(expt 2 3)) for the third step. The final coordinate for an axis results from summing the positive or negative distances of each step. Establish the origin (0, 0) at left-top. Horizontally, left is negative and right is positive, and up is negative and down is positive for the vertical. Push each step into a list of steps, t.i. the first step becomes last in the list of steps as each new step is prepended. For example, gradually stepping "right, right, left" from the origin along an x-axis of length 1200: 1st step: right from (0, 0) => 1200/2^1 => 1200/2 => 600 (0 + 600, 0) => (600, 0) 2nd step: right from (600, 0) => 1200/2^2 => 1200/4 => 300 (600 + 300, 0) => (900, 0) 3rd step: left from (900, 0) => 1200/2^3 => 1200/8 => 150 (900 - 150, 0) => (750, 0) Or, the steps summarized into a list as '(horizontal 1200 (left right right)) then restored: => - 1200/2^3 - 1200/2^2 + 1200/2^1 => - 1200/8 + 1200/4 + 1200/2 => - 150 + 300 + 600 => 750 The number of steps for halving reveals the next (and prior) magnitude for either axis. For example, '((xy 750 0)(steps 3 0)) The number of steps is the magnitude of the value of 2 for dividing the length of an axis for the length of the next vector. Thereby, the magnitude for each axis is enough for progressing from the current coordinate by bit-shifting the length of an axis by the number of steps. The list of coordinates of prior pointer placement is a means of backtracking without recalculation. It can begin with the coordinates of the pointer prior to centering for returning to the location prior to stepping. For example, '((steps 2 1) (xy 750 225)(xy 900 225)(xy 900 450) (xy 600 450) (xy 289 337)) or succinctly as '((2 . 1) (750 225 900 225 900 450 600 450 289 337)) Halving would be for only one view at a time, so the size of the view is obtainable from the environment. When desired for future reference, the size can be appended. For example, '((steps 2 1) ((xy 750 225)(xy 900 225)(xy 900 450) (xy 600 450) (xy 289 337)) (wh 1200 900)) or succinctly as '((2 . 1) (750 225 900 225 900 450 600 450 289 337) (1200 . 900)) That might be helpful when focusing on a tiled view, or eventually saving coordinates for a scaled region. Fractional results are truncated, so either the actual value added is stored or the number of steps so the value can be reliably derived. For example, track the number of steps with the vector differences: '((steps 2 1) ((150 0)(0 225)(300 0)(600 450)))