Commit 82cd0dc4 authored by ROOL's avatar ROOL 🤖

Add mousewheel zoom/scroll and auto scrolling of selected tools

Detail:
  The mouse wheel can now be used to
  * scroll up/down
  * +shift to scroll left/right
  * +control to zoom in/out
  on an open sprite editing window.
  The sprite editing window will auto scroll when the mouse approaches the border with
  * the move whole sprite "hand" tool
  * the copy block "camera" tool
  * the move block "scissors" tool
Admin:
  Submission for the Paint bounty.

Version 2.23. Tagged as 'Paint-2_23'
parent 6e3eb1c1
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "2.22"
Module_Version SETA 222
Module_MajorVersion SETS "2.23"
Module_Version SETA 223
Module_MinorVersion SETS ""
Module_Date SETS "23 Sep 2017"
Module_ApplicationDate SETS "23-Sep-17"
Module_Date SETS "11 Nov 2017"
Module_ApplicationDate SETS "11-Nov-17"
Module_ComponentName SETS "Paint"
Module_ComponentPath SETS "castle/RiscOS/Sources/Apps/Paint"
Module_FullVersion SETS "2.22"
Module_HelpVersion SETS "2.22 (23 Sep 2017)"
Module_FullVersion SETS "2.23"
Module_HelpVersion SETS "2.23 (11 Nov 2017)"
END
/* (2.22)
/* (2.23)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 2.22
#define Module_MajorVersion_CMHG 2.23
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 23 Sep 2017
#define Module_Date_CMHG 11 Nov 2017
#define Module_MajorVersion "2.22"
#define Module_Version 222
#define Module_MajorVersion "2.23"
#define Module_Version 223
#define Module_MinorVersion ""
#define Module_Date "23 Sep 2017"
#define Module_Date "11 Nov 2017"
#define Module_ApplicationDate "23-Sep-17"
#define Module_ApplicationDate "11-Nov-17"
#define Module_ComponentName "Paint"
#define Module_ComponentPath "castle/RiscOS/Sources/Apps/Paint"
#define Module_FullVersion "2.22"
#define Module_HelpVersion "2.22 (23 Sep 2017)"
#define Module_LibraryVersionInfo "2:22"
#define Module_FullVersion "2.23"
#define Module_HelpVersion "2.23 (11 Nov 2017)"
#define Module_LibraryVersionInfo "2:23"
......@@ -1256,7 +1256,7 @@ void menus_insdel_frig (void)
insdel_pending = 0;
}
static void showmag (void *handle)
void menus_showmag (void *handle)
{ main_sprite_window *sprite = (main_sprite_window *) handle;
int m, d;
......@@ -1940,7 +1940,7 @@ void menus_sprite_handler (void *handle, char *hit)
case s_Zoom:
if (hit [1])
magnify_select (&sprw->blobsize.scale_xmul,
&sprw->blobsize.scale_xdiv, 999, 999, showmag, sprw);
&sprw->blobsize.scale_xdiv, 999, 999, menus_showmag, sprw);
break;
case s_Grid:
......
......@@ -25,6 +25,7 @@
#include <swis.h>
#include "Global/FileTypes.h"
#include "Global/OsBytes.h"
#include "akbd.h"
#include "bbc.h"
......@@ -58,8 +59,9 @@ int main_current_options.zoom.div = 1;
int main_current_options.grid.colour = 255;*/
static wimp_w lastnullholder = -1;
static int scrolltime = 0;
/************************************+**
/***************************************
* *
* Set the extent of a file window. *
* *
......@@ -100,6 +102,73 @@ void sprwindow_set_work_extent (main_window *window, BOOL open)
main_force_redraw (window->handle);
}
/****************************************************
* *
* Scroll a sprite window at the specified speeds. *
* *
****************************************************/
void sprwindow_scroll (main_window *window, int scrollx, int scrolly)
{ wimp_wstate currinfo;
ftracef0 ("sprwindow_scroll\n");
int oldscrollx = scrollx;
int oldscrolly = scrolly;
int elapsed;
/* Adjust scrolling speed according to CPU speed */
os_swix1r(OS_ReadMonotonicTime, 0, &elapsed);
if (scrolltime > 0)
{ elapsed -= scrolltime;
/* Divide these by a bigger constant to slow down the scroll rate */
scrollx = (scrollx * elapsed) / 3;
scrolly = (scrolly * elapsed) / 3;
/* The scrolling will only go ahead when enough time's passed to scroll in every direction requested */
/* The elapsed >= 8 clause is like a frame rate cap to avoid excess CPU load and flicker */
if (!((scrollx || scrolly) && elapsed >= 8 && (scrollx || !oldscrollx) && (scrolly || !oldscrolly)))
{ /* Do nothing until more time has elapsed */
return;
}
}
else
{ scrolltime = elapsed;
/* Do nothing until more time has elapsed */
return;
}
wimpt_noerr (wimp_get_wind_state (window->handle, &currinfo));
int oldx = currinfo.o.x;
int oldy = currinfo.o.y;
/* Apply the scrolling */
currinfo.o.x += scrollx;
currinfo.o.y += scrolly;
ftracef3 ("scrollx: %d oldx: %d currinfo.o.x: %d\n", scrollx, oldx, currinfo.o.x);
ftracef3 ("scrolly: %d oldy: %d currinfo.o.y: %d\n", scrolly, oldy, currinfo.o.y);
wimpt_noerr (wimp_open_wind (&currinfo.o)); /* force resize */
/* Find out how much the window really scrolled by */
wimpt_noerr (wimp_get_wind_state (window->handle, &currinfo));
scrollx = (currinfo.o.x - oldx) / window->data->sprite.sprite->mode.scale_xmul;
scrolly = (currinfo.o.y - oldy) / window->data->sprite.sprite->mode.scale_ymul;
if (scrollx || scrolly)
{ /* Reset the timer */
scrolltime += elapsed;
}
}
/***********************************************************
* *
* Stop the auto-scroll timer used in sprwindow_scroll () *
* *
***********************************************************/
void sprwindow_stop_scroll (void)
{ scrolltime = 0;
}
/******************************************************
* Reset the titles of all windows open on the sprite *
......@@ -341,6 +410,8 @@ void sprwindow_release_idle_events (main_sprite *sprite)
{ main_claim_idle (lastnullholder);
break;
}
/* Reset the timer used in window auto-scrolling */
sprwindow_stop_scroll ();
}
static BOOL cant_extend_stack_buffer (char **b, int *s)
......@@ -365,6 +436,7 @@ void sprwindow_event_handler (wimp_eventstr *e, void *handle)
{ main_window *window = (main_window *) handle;
BOOL read_only = window->data->sprite.read_only;
int isMouseWheel = 1;
ftracef3
("sprwindow_event_handler: event type %d, main_window 0x%X, w 0x%X\n",
......@@ -505,6 +577,84 @@ void sprwindow_event_handler (wimp_eventstr *e, void *handle)
wimp_processkey (e->data.key.chcode);
break;
case wimp_ESCROLL: /* Support for mousewheel to scroll and zoom */
ftracef2("wimp_ESCROLL in sprite window. scroll.x: %d scroll.y: %d\n", e->data.scroll.x, e->data.scroll.y);
/* Workaround for RISC OS 5 mousewheel behaviour (5 scroll events sent per wheel step) */
static int eventCount = -1;
static int scrollFix = 0;
wimp_mousestr mouse;
wimpt_noerr (wimp_get_point_info (&mouse));
/* If the pointer is over the scroll bar / buttons and select / adjust clicked, don't skip any scroll events. */
if (((mouse.bbits & wimp_BRIGHT) || (mouse.bbits & wimp_BLEFT)) &&
((mouse.i <= -6 && mouse.i >= -8) || (mouse.i <= -10 && mouse.i >= -12)))
{ ftracef0("Mouse is over vertical scroll bar / buttons. Scroll fix inactive.\n");
if (eventCount > 0)
eventCount = 0;
isMouseWheel = 0;
}
if (eventCount <= 0 && (e->data.scroll.x || e->data.scroll.y))
{ /*Read keyboard state.*/
int r1 = 0;
int r2 = 255;
if (isMouseWheel)
os_byte (OsByte_RW_KeybStatus, &r1, &r2);
/*If Ctrl pressed, adjust the zoom level*/
if (r1 & 0x40)
{ if (e->data.scroll.y == -1)
{ /* Zoom out */
if (window->data->sprite.blobsize.scale_xmul > 1)
window->data->sprite.blobsize.scale_xmul--;
else if (window->data->sprite.blobsize.scale_xdiv < 999)
window->data->sprite.blobsize.scale_xdiv++;
menus_showmag (&window->data->sprite);
}
else if (e->data.scroll.y == 1)
{ /* Zoom in */
if (window->data->sprite.blobsize.scale_xdiv > 1)
window->data->sprite.blobsize.scale_xdiv--;
else if (window->data->sprite.blobsize.scale_xmul < 999)
window->data->sprite.blobsize.scale_xmul++;
menus_showmag (&window->data->sprite);
}
}
else
{ /*If Shift pressed, scroll horizontally with mousewheel*/
if ((r1 & 8) && e->data.scroll.y)
{ e->data.scroll.x = -e->data.scroll.y;
e->data.scroll.y = 0;
}
switch (e->data.scroll.x)
{ case -2: e->data.scroll.o.x -= (e->data.scroll.o.box.x1 - e->data.scroll.o.box.x0); break;
case -1: e->data.scroll.o.x -= 64; break;
case 1: e->data.scroll.o.x += 64; break;
case 2: e->data.scroll.o.x += (e->data.scroll.o.box.x1 - e->data.scroll.o.box.x0); break;
}
switch (e->data.scroll.y)
{ case -2: e->data.scroll.o.y -= (e->data.scroll.o.box.y1 - e->data.scroll.o.box.y0); break;
case -1: e->data.scroll.o.y -= 64; break;
case 1: e->data.scroll.o.y += 64; break;
case 2: e->data.scroll.o.y += (e->data.scroll.o.box.y1 - e->data.scroll.o.box.y0); break;
}
if (wimpt_complain (wimp_open_wind (&e->data.scroll.o)))
return;
}
}
if (eventCount == -1)
{ /* At time of writing, version 0.25 and up of the USBDriver has a "feature" that sends 5 scroll events per mouse wheel step */
os_error *err = os_cli("RMEnsure USBDriver 0.25");
/* If no error is generated by RMEnsure, the troublesome driver is present and we do need the fix */
scrollFix = (err == NULL);
eventCount = 0;
}
if (scrollFix)
{ eventCount++;
ftracef1("scrollFix active. eventCount %d\n", eventCount);
if (eventCount >=5)
eventCount = 0;
}
break;
case wimp_ECLOSE:
ftracef0 ("Window close event\n");
sprwindow_delete (window);
......@@ -723,6 +873,7 @@ void sprwindow_new (main_sprite *sprite)
main_allocate_position (&wind.box);
wind.colours [wimp_WCWKAREABACK] = '\377';
wind.titleflags = (wimp_iconflags) (wind.titleflags | wimp_INDIRECT);
wind.flags = (wimp_wflags) (wind.flags | wimp_WSCROLL_R1); /* Enable scroll requests for mouse wheel */
if ((wind.title.indirecttext.buffer = m_ALLOC (20)) == NULL)
{ m_FREE (sprite_window, sizeof (main_sprite_window));
......
......@@ -200,17 +200,54 @@ static void tools_get_sprite_info_pixels(main_sprite *sprite, sprite_info *sin)
void tools_mouse_to_pixel(main_window *window, wimp_mousestr *mpos,
int *cx, int *cy)
{
/* Original code clamps coordinates overflowing the sprite bounds, so pass
NULL for new overflowx and overflowy args */
tools_mouse_to_pixel_overflow(window, mpos, cx, cy, NULL, NULL);
}
/********************************************************
* Convert mouse pos to the row or column that it is in *
* (0 <= x < width, 0 <= y < height) *
* If outside or near sprite bounds, an offset is *
* returned using overflowx and overflowy. *
********************************************************/
void tools_mouse_to_pixel_overflow(main_window *window, wimp_mousestr *mpos,
int *cx, int *cy, int *overflowx, int *overflowy)
{
sprite_info sin;
main_sprite *sprite = window->data->sprite.sprite;
wimp_winfo curr;
ftracef0 ("tools_mouse_to_pixel\n");
/* Default values for optional overflow parameters */
if (overflowx)
*overflowx = 0;
if (overflowy)
*overflowy = 0;
curr.w = window->handle;
wimpt_noerr (paintlib_get_wind_info (&curr));
tools_get_sprite_info_pixels(sprite,&sin);
/* See if we have dragged close to the edge of the window */
if (overflowx)
{
if (mpos->x >= curr.info.box.x1 - 10)
*overflowx = 1;
else if (mpos->x - curr.info.box.x0 < 10)
*overflowx = -1;
}
if (overflowy)
{
if (mpos->y >= curr.info.box.y1 - 10)
*overflowy = 1;
else if (mpos->y - curr.info.box.y0 < 10)
*overflowy = -1;
}
if (cx)
{
int x=tools_extent_to_pixel_x(&window->data->sprite, mpos->x - curr.info.box.x0 + curr.info.scx);
......@@ -1483,15 +1520,91 @@ static void order_rect (int *c)
if (c [3] < c [1]) {int t = c [1]; c [1] = c [3]; c [3] = t;}
}
/* Bound_Pointer() and Unbound_Pointer() were taken from Draw, to constrain
* the mouse pointer to the window bounds during auto scrolling */
static void Bound_Pointer (int x0, int y0, int x1, int y1)
{ int ox, oy;
char buf [20];
ftracef0 ("Tools: Bound_Pointer\n");
ox = bbc_vduvar (bbc_OrgX);
oy = bbc_vduvar (bbc_OrgY);
x0 -= ox, y0 -= oy;
x1 -= ox, y1 -= oy;
buf [0] = 1;
buf [1] = x0;
buf [2] = x0 >> 8;
buf [3] = y0;
buf [4] = y0 >> 8;
buf [5] = x1;
buf [6] = x1 >> 8;
buf [7] = y1;
buf [8] = y1 >> 8;
os_swi2 (OS_Word, 21, (int) buf);
}
static void Unbound_Pointer (void)
{ ftracef0 ("Tools: Unbound_Pointer\n");
Bound_Pointer
( 0,
0,
bbc_vduvar (bbc_XWindLimit) << bbc_vduvar (bbc_XEigFactor),
bbc_vduvar (bbc_YWindLimit) << bbc_vduvar (bbc_YEigFactor)
);
}
static void scissorpaint_null (main_window *window, wimp_mousestr *mpos)
{ main_sprite *sprite = window->data->sprite.sprite;
int state, x, y, coord = 3;
int overflowx, overflowy, scrollx, scrolly;
ftracef0 ("scissorpaint_null\n");
if (sprite->toolspace [0] < 0) return; /* we're inside an export */
tools_mouse_to_pixel (window, mpos, &x, &y);
tools_mouse_to_pixel_overflow (window, mpos, &x, &y, &overflowx, &overflowy);
/* Auto scroll if the rectangle was dragged to the edge of the window */
if ((sprite->toolspace [0] == 1 || sprite->toolspace [0] == 3) &&
(mpos->bbits & wimp_BLEFT))
{ wimp_wstate state;
/* Bound the mouse to this window while dragging / auto-scrolling, as Draw does */
wimpt_noerr (wimp_get_wind_state (window->handle,
&state));
Bound_Pointer (state.o.box.x0, state.o.box.y0,
state.o.box.x1, state.o.box.y1);
scrollx = scrolly = 0;
if (overflowx != 0)
scrollx = (overflowx>0)?20:-20;
if (overflowy != 0)
scrolly = (overflowy>0)?20:-20;
if (scrollx || scrolly)
{ /* Auto-scroll the window at a fixed speed */
sprwindow_scroll (window, scrollx, scrolly);
tools_mouse_to_pixel (window, mpos, &x, &y);
}
else
{ /* Reset the auto-scroll timer */
sprwindow_stop_scroll ();
}
}
else
{ /* Unbound the mouse */
Unbound_Pointer ();
/* Reset the auto-scroll timer */
sprwindow_stop_scroll ();
}
if ((state = sprite->toolspace [0]) == 1 && (mpos->bbits & 4) == 0)
{ /* button gone up on initial rect entry: step state */
......@@ -1689,6 +1802,10 @@ static void scissorpaint_stop (main_sprite *sprite)
sprite, sprite->toolspace [0]);
sprwindow_release_idle_events (sprite);
}
/* Unbound the mouse */
Unbound_Pointer ();
/* Reset the auto-scroll timer */
sprwindow_stop_scroll ();
}
static void copymovepaint_click (main_window *window, wimp_mousestr *mpos,
......
......@@ -69,4 +69,6 @@ extern void menus_sprite_new (main_window *, BOOL);
extern int menus_sprite_exists (sprite_area *, char *);
extern void menus_showmag (void *);
#endif
......@@ -25,6 +25,8 @@ extern main_template sprwindow_template;
extern void sprwindow_new (main_sprite *);
extern void sprwindow_delete (main_window *);
extern void sprwindow_set_work_extent(main_window *, BOOL);
extern void sprwindow_scroll (main_window *window, int scrollx, int scrolly);
extern void sprwindow_stop_scroll (void);
extern void sprwindow_swap_output_to_sprite (main_sprite *);
extern void sprwindow_remove_wastage (main_sprite *);
extern int sprwindow_swap_output_to_mask (main_sprite *, int);
......
......@@ -89,6 +89,9 @@ typedef enum
extern void tools_mouse_to_pixel (main_window *, wimp_mousestr *,
int *, int *);
extern void tools_mouse_to_pixel_overflow (main_window *, wimp_mousestr *,
int *, int *, int *, int *);
extern void tools_remove_brush (void);
extern void tools_replace_brush (void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment