mirror of
https://github.com/c3d/DB48X-on-DM42.git
synced 2024-09-28 03:20:53 +02:00
stack: Interactive stack menu
Add menu functions for the interactive stack. Compared to the HP implementation, the interactive stack that was implemented here adds stack sort and revert features. Fixes: #1011 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
parent
85d8599ccc
commit
45ef03c4e2
9 changed files with 245 additions and 49 deletions
|
@ -598,14 +598,24 @@ COMMAND_BODY(Show)
|
|||
// Show the top-level of the stack graphically, using entire screen
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
if (object_g obj = rt.top())
|
||||
object_g obj = rt.top();
|
||||
return show(obj);
|
||||
}
|
||||
|
||||
|
||||
object::result show(object_r obj)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Draw an obejct
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
if (obj)
|
||||
{
|
||||
grob_g graph = obj->graph();
|
||||
if (!graph)
|
||||
{
|
||||
if (!rt.error())
|
||||
rt.graph_does_not_fit_error();
|
||||
return ERROR;
|
||||
return object::ERROR;
|
||||
}
|
||||
|
||||
ui.draw_graphics();
|
||||
|
@ -728,7 +738,7 @@ COMMAND_BODY(Show)
|
|||
}
|
||||
redraw_lcd(true);
|
||||
}
|
||||
return OK;
|
||||
return object::OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -115,6 +115,12 @@ inline uint ScreenHeight()
|
|||
}
|
||||
|
||||
|
||||
object::result show(object_r obj);
|
||||
// ----------------------------------------------------------------------------
|
||||
// Show the given object full screen
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
COMMAND_DECLARE(Disp,2);
|
||||
COMMAND_DECLARE(DispXY,3);
|
||||
COMMAND_DECLARE(Show,1);
|
||||
|
|
44
src/list.cc
44
src/list.cc
|
@ -807,6 +807,29 @@ HELP_BODY(list)
|
|||
//
|
||||
// ============================================================================
|
||||
|
||||
object::result to_list(uint depth)
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
scribble scr;
|
||||
for (uint i = 0; i < depth; i++)
|
||||
{
|
||||
if (object_g obj = rt.stack(depth - 1 - i))
|
||||
{
|
||||
size_t objsz = obj->size();
|
||||
byte_p objp = byte_p(obj);
|
||||
if (!rt.append(objsz, objp))
|
||||
return object::ERROR;
|
||||
}
|
||||
}
|
||||
object_g list = list::make(scr.scratch(), scr.growth());
|
||||
if (rt.drop(depth) && rt.push(list))
|
||||
return object::OK;
|
||||
return object::ERROR;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_BODY(ToList)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Convert elements to a list
|
||||
|
@ -819,24 +842,7 @@ COMMAND_BODY(ToList)
|
|||
return ERROR;
|
||||
|
||||
if (rt.pop())
|
||||
{
|
||||
scribble scr;
|
||||
for (uint i = 0; i < depth; i++)
|
||||
{
|
||||
if (object_g obj = rt.stack(depth - 1 - i))
|
||||
{
|
||||
size_t objsz = obj->size();
|
||||
byte_p objp = byte_p(obj);
|
||||
if (!rt.append(objsz, objp))
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
object_g list = list::make(scr.scratch(), scr.growth());
|
||||
if (!rt.drop(depth))
|
||||
return ERROR;
|
||||
if (rt.push(list))
|
||||
return OK;
|
||||
}
|
||||
return to_list(depth);
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
@ -1576,7 +1582,7 @@ static int memory_compare(object_p *xp, object_p *yp)
|
|||
}
|
||||
|
||||
|
||||
static int value_compare(object_p *xp, object_p *yp)
|
||||
int value_compare(object_p *xp, object_p *yp)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Sort items according to value
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
14
src/list.h
14
src/list.h
|
@ -355,4 +355,18 @@ inline list_g operator*(list_r x, uint y)
|
|||
return list_p(+(xt * y));
|
||||
}
|
||||
|
||||
|
||||
object::result to_list(uint depth);
|
||||
// ----------------------------------------------------------------------------
|
||||
// Convert `depth` items to a list
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
int value_compare(object_p *xp, object_p *yp);
|
||||
// ----------------------------------------------------------------------------
|
||||
// Value comparison for sorting
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#endif // LIST_H
|
||||
|
|
|
@ -438,7 +438,7 @@ size_t object::render(char *output, size_t length) const
|
|||
}
|
||||
|
||||
|
||||
cstring object::edit() const
|
||||
size_t object::edit() const
|
||||
// ----------------------------------------------------------------------------
|
||||
// Render an object into the scratchpad, then move it into editor
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -453,7 +453,7 @@ cstring object::edit() const
|
|||
rt.edit();
|
||||
r.clear();
|
||||
}
|
||||
return (cstring) rt.editor();
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@ struct object
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
cstring edit() const;
|
||||
size_t edit() const;
|
||||
// ------------------------------------------------------------------------
|
||||
// Render the object into the scratchpad, then move into the editor
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
17
src/stack.cc
17
src/stack.cc
|
@ -52,7 +52,7 @@ stack::stack()
|
|||
// ----------------------------------------------------------------------------
|
||||
// Constructor does nothing at the moment
|
||||
// ----------------------------------------------------------------------------
|
||||
: interactive(0)
|
||||
: interactive(0), interactive_base(0)
|
||||
#if SIMULATOR
|
||||
, history(), writer(0), reader(0)
|
||||
#endif // SIMULATOR
|
||||
|
@ -107,6 +107,19 @@ uint stack::draw_stack()
|
|||
if (!depth)
|
||||
return bottom;
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
uint height = rt.editing() ? 3 : 4;
|
||||
if (interactive < interactive_base + 1)
|
||||
interactive_base = interactive - 1;
|
||||
else if (interactive > interactive_base + height)
|
||||
interactive_base = interactive - height;
|
||||
}
|
||||
else
|
||||
{
|
||||
interactive_base = 0;
|
||||
}
|
||||
|
||||
rect clip = Screen.clip();
|
||||
Screen.fill(0, top, hdrx-1, bottom, Settings.StackLevelBackground());
|
||||
Screen.fill(hdrx, top, hdrx, bottom, Settings.StackLineForeground());
|
||||
|
@ -114,7 +127,7 @@ uint stack::draw_stack()
|
|||
char buf[16];
|
||||
coord y = bottom;
|
||||
coord yresult = y;
|
||||
for (uint level = 0; level < depth; level++)
|
||||
for (uint level = interactive_base; level < depth; level++)
|
||||
{
|
||||
if (coord(y) <= top)
|
||||
break;
|
||||
|
|
|
@ -45,6 +45,7 @@ struct stack
|
|||
uint draw_stack();
|
||||
|
||||
uint interactive;
|
||||
uint interactive_base;
|
||||
|
||||
#if SIMULATOR
|
||||
public:
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "dmcp.h"
|
||||
#include "expression.h"
|
||||
#include "functions.h"
|
||||
#include "graphics.h"
|
||||
#include "grob.h"
|
||||
#include "list.h"
|
||||
#include "menu.h"
|
||||
|
@ -1208,6 +1209,10 @@ uint user_interface::menu_planes()
|
|||
{
|
||||
planes = 1;
|
||||
}
|
||||
else if (Stack.interactive)
|
||||
{
|
||||
planes = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (planes > 0)
|
||||
|
@ -1376,6 +1381,15 @@ bool user_interface::draw_menus()
|
|||
};
|
||||
labels = helpMenu;
|
||||
}
|
||||
else if (Stack.interactive)
|
||||
{
|
||||
static cstring stackMenu[] =
|
||||
{
|
||||
"Edit", "Show", "Level", "Roll↓", "Pick", "→List",
|
||||
"DupN", "DropN", "Keep", "Roll↑", "Sort", "Revert"
|
||||
};
|
||||
labels = stackMenu + 6 * plane;
|
||||
}
|
||||
|
||||
if (single)
|
||||
if (plane != shplane)
|
||||
|
@ -2124,8 +2138,10 @@ reposition:
|
|||
// Draw the area that fits on the screen
|
||||
int lineHeight = font->height();
|
||||
int errorHeight = rt.error() ? LCD_H / 3 + 10 : 0;
|
||||
int top = HeaderFont->height() + errorHeight + 2;
|
||||
int bottom = LCD_H-1 - menuHeight;
|
||||
int top = (Stack.interactive
|
||||
? bottom - HeaderFont->height()
|
||||
: HeaderFont->height() + errorHeight + 2);
|
||||
int availableHeight = bottom - top;
|
||||
int fullRows = availableHeight / lineHeight;
|
||||
int clippedRows = (availableHeight + lineHeight - 1) / lineHeight;
|
||||
|
@ -3639,25 +3655,152 @@ bool user_interface::handle_editing(int key)
|
|||
bool consumed = false;
|
||||
size_t editing = rt.editing();
|
||||
|
||||
if (Stack.interactive && !shift && !xshift && rt.depth())
|
||||
if (uint interactive = Stack.interactive)
|
||||
{
|
||||
switch (key)
|
||||
if (shift)
|
||||
{
|
||||
case KEY_UP:
|
||||
if (++Stack.interactive > rt.depth())
|
||||
Stack.interactive = rt.depth();
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_DOWN:
|
||||
if (--Stack.interactive == 0)
|
||||
Stack.interactive = 1;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_ENTER:
|
||||
case KEY_EXIT:
|
||||
Stack.interactive = 0;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
switch (key)
|
||||
{
|
||||
case KEY_UP:
|
||||
interactive += 4;
|
||||
if (interactive > rt.depth())
|
||||
interactive = rt.depth();
|
||||
Stack.interactive = interactive;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_DOWN:
|
||||
if (interactive <= 4)
|
||||
interactive = 1;
|
||||
else
|
||||
interactive -= 4;
|
||||
Stack.interactive = interactive;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_ENTER:
|
||||
case KEY_EXIT:
|
||||
Stack.interactive = 0;
|
||||
dirtyStack = true;
|
||||
dirtyMenu = true;
|
||||
return true;
|
||||
case KEY_BSP:
|
||||
rt.roll(interactive);
|
||||
rt.drop();
|
||||
if (interactive > rt.depth())
|
||||
Stack.interactive = rt.depth();
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F1: // DupN
|
||||
for (uint i = 0; i < interactive; i++)
|
||||
if (object_p obj = rt.stack(interactive - 1))
|
||||
if (!rt.push(obj))
|
||||
break;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F2: // DropN
|
||||
rt.drop(interactive);
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F3: // Keep
|
||||
if (rt.depth() > interactive)
|
||||
{
|
||||
size_t depth = rt.depth();
|
||||
for (uint i = 0; i < interactive; i++)
|
||||
rt.stack(depth + ~i, rt.stack(interactive + ~i));
|
||||
rt.drop(depth - interactive);
|
||||
dirtyStack = true;
|
||||
}
|
||||
return true;
|
||||
case KEY_F4: // Roll
|
||||
rt.roll(interactive);
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F5: // Sort
|
||||
typedef int (*qsort_fn)(const void *, const void*);
|
||||
qsort(rt.stack_base(), interactive,
|
||||
sizeof(object_p), qsort_fn(value_compare));
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F6: // Revert
|
||||
for (uint i = 0; i < interactive / 2; i++)
|
||||
{
|
||||
object_p a = rt.stack(i);
|
||||
object_p b = rt.stack(interactive + ~i);
|
||||
rt.stack(i, b);
|
||||
rt.stack(interactive + ~i, a);
|
||||
}
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!xshift)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_UP:
|
||||
if (++interactive > rt.depth())
|
||||
interactive = rt.depth();
|
||||
Stack.interactive = interactive;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_DOWN:
|
||||
if (--interactive == 0)
|
||||
interactive = 1;
|
||||
Stack.interactive = interactive;
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_ENTER:
|
||||
case KEY_EXIT:
|
||||
Stack.interactive = 0;
|
||||
dirtyStack = true;
|
||||
dirtyMenu = true;
|
||||
return true;
|
||||
case KEY_BSP:
|
||||
rt.roll(interactive);
|
||||
rt.drop();
|
||||
if (interactive > rt.depth())
|
||||
Stack.interactive = rt.depth();
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F1: // Edit
|
||||
if (object_p obj = rt.stack(interactive - 1))
|
||||
{
|
||||
this->editing = obj;
|
||||
size_t sz = obj->edit();
|
||||
cursor += sz;
|
||||
edit(unicode(' '), PROGRAM, false);
|
||||
edRows = 0;
|
||||
dirtyEditor = true;
|
||||
}
|
||||
return true;
|
||||
case KEY_F2: // Show
|
||||
if (object_g obj = rt.stack(interactive - 1))
|
||||
show(obj);
|
||||
return true;
|
||||
case KEY_F3: // Level
|
||||
if (integer_p depth = integer::make(interactive))
|
||||
{
|
||||
rt.push(depth);
|
||||
dirtyStack = true;
|
||||
}
|
||||
return true;
|
||||
case KEY_F4: // Roll down
|
||||
rt.rolld(interactive);
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F5: // Pick
|
||||
if (object_p obj = rt.stack(interactive - 1))
|
||||
rt.push(obj);
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
case KEY_F6: // To List
|
||||
to_list(interactive);
|
||||
dirtyStack = true;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3904,7 +4047,6 @@ bool user_interface::handle_editing(int key)
|
|||
case 0:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3949,9 +4091,13 @@ bool user_interface::handle_editing(int key)
|
|||
}
|
||||
else if (!shift)
|
||||
{
|
||||
if (++Stack.interactive > rt.depth())
|
||||
Stack.interactive = rt.depth();
|
||||
dirtyStack = true;
|
||||
if (rt.args(rt.depth()))
|
||||
{
|
||||
if (++Stack.interactive > rt.depth())
|
||||
Stack.interactive = rt.depth();
|
||||
dirtyStack = true;
|
||||
dirtyMenu = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue