-- some constants people might like to tweak Text_color = {r=0, g=0, b=0} Cursor_color = {r=1, g=0, b=0} Stroke_color = {r=0, g=0, b=0} Current_stroke_color = {r=0.7, g=0.7, b=0.7} -- in process of being drawn Current_name_background_color = {r=1, g=0, b=0, a=0.1} -- name currently being edited Focus_stroke_color = {r=1, g=0, b=0} -- what mouse is hovering over Highlight_color = {r=0.7, g=0.7, b=0.9} -- selected text Icon_color = {r=0.7, g=0.7, b=0.7} -- color of current mode icon in drawings Help_color = {r=0, g=0.5, b=0} Help_background_color = {r=0, g=0.5, b=0, a=0.1} Margin_top = 15 Margin_left = 25 Margin_right = 25 Drawing_padding_top = 10 Drawing_padding_bottom = 10 Drawing_padding_height = Drawing_padding_top + Drawing_padding_bottom Same_point_distance = 4 -- pixel distance at which two points are considered the same edit = {} -- run in both tests and a real run function edit.initialize_state(top, left, right, font_height, line_height) -- currently always draws to bottom of screen local result = { -- a line is either text or a drawing -- a text is a table with: -- mode = 'text', -- string data, -- a drawing is a table with: -- mode = 'drawing' -- a (y) coord in pixels (updated while painting screen), -- a (h)eight, -- an array of points, and -- an array of shapes -- a shape is a table containing: -- a mode -- an array points for mode 'freehand' (raw x,y coords; freehand drawings don't pollute the points array of a drawing) -- an array vertices for mode 'polygon', 'rectangle', 'square' -- p1, p2 for mode 'line' -- center, radius for mode 'circle' -- center, radius, start_angle, end_angle for mode 'arc' -- Unless otherwise specified, coord fields are normalized; a drawing is always 256 units wide -- The field names are carefully chosen so that switching modes in midstream -- remembers previously entered points where that makes sense. lines = {{mode='text', data=''}}, -- array of lines -- Lines can be too long to fit on screen, in which case they _wrap_ into -- multiple _screen lines_. -- rendering wrapped text lines needs some additional short-lived data per line: -- startpos, the index of data the line starts rendering from, can only be >1 for topmost line on screen -- starty, the y coord in pixels the line starts rendering from -- fragments: snippets of the line guaranteed to not straddle screen lines -- screen_line_starting_pos: optional array of grapheme indices if it wraps over more than one screen line line_cache = {}, -- Given wrapping, any potential location for the text cursor can be described in two ways: -- * schema 1: As a combination of line index and position within a line (in utf8 codepoint units) -- * schema 2: As a combination of line index, screen line index within the line, and a position within the screen line. -- -- Most of the time we'll only persist positions in schema 1, translating to -- schema 2 when that's convenient. -- -- Make sure these coordinates are never aliased, so that changing one causes -- action at a distance. screen_top1 = {line=1, pos=1}, -- position of start of screen line at top of screen cursor1 = {line=1, pos=1}, -- position of cursor screen_bottom1 = {line=1, pos=1}, -- position of start of screen line at bottom of screen selection1 = {}, -- some extra state to compute selection between mouse press and release old_cursor1 = nil, old_selection1 = nil, mousepress_shift = nil, -- cursor coordinates in pixels cursor_x = 0, cursor_y = 0, current_drawing_mode = 'line', -- one of the available shape modes previous_drawing_mode = nil, -- extra state for some ephemeral modes like moving/deleting/naming points font_height = font_height, line_height = line_height, top = top, left = math.floor(left), right = math.floor(right), width = right-left, filename = love.filesystem.getSourceBaseDirectory()..'/lines.txt', -- '/' should work even on Windows next_save = nil, -- undo history = {}, next_history = 1, -- search search_term = nil, search_backup = nil, -- stuff to restore when cancelling search } return result end -- App.initialize_state function edit.check_locs(State) -- if State is inconsistent (i.e. file changed by some other program), -- throw away all cursor state entirely if edit.invalid1(State, State.screen_top1) or edit.invalid_cursor1(State) or not edit.cursor_on_text(State) or not Text.le1(State.screen_top1, State.cursor1) then State.screen_top1 = {line=1, pos=1} State.cursor1 = {line=1, pos=1} edit.put_cursor_on_next_text_line(State) end end function edit.invalid1(State, loc1) if loc1.line > #State.lines then return true end local l = State.lines[loc1.line] if l.mode ~= 'text' then return false end -- pos is irrelevant to validity for a drawing line return loc1.pos > #State.lines[loc1.line].data end -- cursor loc in particular differs from other locs in one way: -- pos might occur just after end of line function edit.invalid_cursor1(State) local cursor1 = State.cursor1 if cursor1.line > #State.lines then return true end local l = State.lines[cursor1.line] if l.mode ~= 'text' then return false end -- pos is irrelevant to validity for a drawing line return cursor1.pos > #State.lines[cursor1.line].data + 1 end function edit.cursor_on_text(State) return State.cursor1.line <= #State.lines and State.lines[State.cursor1.line].mode == 'text' end function edit.put_cursor_on_next_text_line(State) while true do if State.cursor1.line >= #State.lines then break end if State.lines[State.cursor1.line].mode == 'text' then break end State.cursor1.line = State.cursor1.line+1 State.cursor1.pos = 1 end end -- return y drawn until function edit.draw(State) State.button_handlers = {} App.color(Text_color) assert(#State.lines == #State.line_cache, ('line_cache is out of date; %d elements when it should be %d'):format(#State.line_cache, #State.lines)) assert(Text.le1(State.screen_top1, State.cursor1), ('screen_top (line=%d,pos=%d) is below cursor (line=%d,pos=%d)'):format(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)) State.cursor_x = nil State.cursor_y = nil local y = State.top local screen_bottom1 = {line=nil, pos=nil} --? print('== draw') for line_index = State.screen_top1.line,#State.lines do local line = State.lines[line_index] --? print('draw:', y, line_index, line) if y + State.line_height > App.screen.height then break end screen_bottom1.line = line_index if line.mode == 'text' then --? print('text.draw', y, line_index) local startpos = 1 if line_index == State.screen_top1.line then startpos = State.screen_top1.pos end if line.data == '' then -- button to insert new drawing button(State, 'draw', {x=State.left-Margin_left+4, y=y+4, w=12,h=12, bg={r=1,g=1,b=0}, icon
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module ranger.gui.curses_shortcuts</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.<a href="ranger.gui.html"><font color="#ffffff">gui</font></a>.curses_shortcuts</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/work/ranger/ranger/gui/curses_shortcuts.py">/home/hut/work/ranger/ranger/gui/curses_shortcuts.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt> </tt></td><td> </td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="_curses.html">_curses</a><br>
</td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign