-
Notifications
You must be signed in to change notification settings - Fork 493
Widgets/text area #4995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Widgets/text area #4995
Changes from all commits
8bc9da2
55ae723
e237387
83a9a19
3ce4f1f
fa68bbe
cb549ed
ff41a5e
2ed6dcb
58c8d9b
cdda92e
a307308
b9422dc
51ff6b7
1f75f37
ff76073
6384b21
6047b40
83f9df3
4250bb4
abebac7
c005846
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| -- Multiline text area control | ||
|
|
||
| local Panel = require('gui.widgets.containers.panel') | ||
| local Scrollbar = require('gui.widgets.scrollbar') | ||
| local TextAreaContent = require('gui.widgets.text_area.text_area_content') | ||
| local HistoryStore = require('gui.widgets.text_area.history_store') | ||
|
|
||
| local HISTORY_ENTRY = HistoryStore.HISTORY_ENTRY | ||
|
|
||
| TextArea = defclass(TextArea, Panel) | ||
|
|
||
| TextArea.ATTRS{ | ||
| init_text = '', | ||
wiktor-obrebski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| init_cursor = DEFAULT_NIL, | ||
| text_pen = COLOR_LIGHTCYAN, | ||
| ignore_keys = {}, | ||
| select_pen = COLOR_CYAN, | ||
| on_text_change = DEFAULT_NIL, | ||
| on_cursor_change = DEFAULT_NIL, | ||
| one_line_mode = false, | ||
| debug = false | ||
| } | ||
|
|
||
| function TextArea:init() | ||
| self.render_start_line_y = 1 | ||
|
|
||
| self.text_area = TextAreaContent{ | ||
| frame={l=0,r=3,t=0}, | ||
| text=self.init_text, | ||
|
|
||
| text_pen=self.text_pen, | ||
| ignore_keys=self.ignore_keys, | ||
| select_pen=self.select_pen, | ||
| debug=self.debug, | ||
| one_line_mode=self.one_line_mode, | ||
|
|
||
| on_text_change=function (text, old_text) | ||
| self:updateLayout() | ||
| if self.on_text_change then | ||
| self.on_text_change(text, old_text) | ||
| end | ||
| end, | ||
| on_cursor_change=self:callback('onCursorChange') | ||
| } | ||
| self.scrollbar = Scrollbar{ | ||
| frame={r=0,t=1}, | ||
| on_scroll=self:callback('onScrollbar'), | ||
| visible=not self.one_line_mode | ||
| } | ||
|
|
||
| self:addviews{ | ||
| self.text_area, | ||
| self.scrollbar, | ||
| } | ||
| end | ||
|
|
||
| function TextArea:getText() | ||
| return self.text_area.text | ||
| end | ||
|
|
||
| function TextArea:setText(text) | ||
| self.text_area.history:store( | ||
| HISTORY_ENTRY.OTHER, | ||
| self:getText(), | ||
| self:getCursor() | ||
| ) | ||
|
|
||
| return self.text_area:setText(text) | ||
| end | ||
|
|
||
wiktor-obrebski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| function TextArea:getCursor() | ||
| return self.text_area.cursor | ||
| end | ||
|
|
||
| function TextArea:setCursor(cursor_offset) | ||
| return self.text_area:setCursor(cursor_offset) | ||
| end | ||
|
|
||
| function TextArea:clearHistory() | ||
| return self.text_area.history:clear() | ||
| end | ||
|
|
||
| function TextArea:onCursorChange(cursor, old_cursor) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to avoid polluting the public API, you can make this a local function and pass and then move the Same comment for other member functions that are not part of the public API Note this is not an issue for the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this make code much harder to read and understand just to hide private API, I do not like it. maybe instead we should incorporate e.g. Python "private" functions by convention?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be ok with something like that. @lethosor do you have a preference? |
||
| local x, y = self.text_area.wrapped_text:indexToCoords( | ||
| self.text_area.cursor | ||
| ) | ||
|
|
||
| if y >= self.render_start_line_y + self.text_area.frame_body.height then | ||
| self:updateScrollbar( | ||
| y - self.text_area.frame_body.height + 1 | ||
| ) | ||
| elseif (y < self.render_start_line_y) then | ||
| self:updateScrollbar(y) | ||
| end | ||
|
|
||
| if self.on_cursor_change then | ||
| self.on_cursor_change(cursor, old_cursor) | ||
| end | ||
| end | ||
|
|
||
| function TextArea:scrollToCursor(cursor_offset) | ||
| if self.scrollbar.visible then | ||
| local _, cursor_line_y = self.text_area.wrapped_text:indexToCoords( | ||
| cursor_offset | ||
| ) | ||
| self:updateScrollbar(cursor_line_y) | ||
| end | ||
| end | ||
|
|
||
| function TextArea:getPreferredFocusState() | ||
| return true | ||
| end | ||
|
|
||
| function TextArea:postUpdateLayout() | ||
| self:updateScrollbar(self.render_start_line_y) | ||
|
|
||
| if self.text_area.cursor == nil then | ||
| local cursor = self.init_cursor or #self.init_text + 1 | ||
| self.text_area:setCursor(cursor) | ||
| self:scrollToCursor(cursor) | ||
| end | ||
| end | ||
|
|
||
| function TextArea:onScrollbar(scroll_spec) | ||
| local height = self.text_area.frame_body.height | ||
|
|
||
| local render_start_line = self.render_start_line_y | ||
| if scroll_spec == 'down_large' then | ||
| render_start_line = render_start_line + math.ceil(height / 2) | ||
| elseif scroll_spec == 'up_large' then | ||
| render_start_line = render_start_line - math.ceil(height / 2) | ||
| elseif scroll_spec == 'down_small' then | ||
| render_start_line = render_start_line + 1 | ||
| elseif scroll_spec == 'up_small' then | ||
| render_start_line = render_start_line - 1 | ||
| else | ||
| render_start_line = tonumber(scroll_spec) | ||
| end | ||
|
|
||
| self:updateScrollbar(render_start_line) | ||
| end | ||
|
|
||
| function TextArea:updateScrollbar(scrollbar_current_y) | ||
| local lines_count = #self.text_area.wrapped_text.lines | ||
|
|
||
| local render_start_line_y = math.min( | ||
| #self.text_area.wrapped_text.lines - self.text_area.frame_body.height + 1, | ||
| math.max(1, scrollbar_current_y) | ||
| ) | ||
|
|
||
| self.scrollbar:update( | ||
| render_start_line_y, | ||
| self.frame_body.height, | ||
| lines_count | ||
| ) | ||
|
|
||
| if (self.frame_body.height >= lines_count) then | ||
| render_start_line_y = 1 | ||
| end | ||
|
|
||
| self.render_start_line_y = render_start_line_y | ||
| self.text_area:setRenderStartLineY(self.render_start_line_y) | ||
| end | ||
|
|
||
| function TextArea:renderSubviews(dc) | ||
| self.text_area.frame_body.y1 = self.frame_body.y1-(self.render_start_line_y - 1) | ||
myk002 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| -- only visible lines of text_area will be rendered | ||
| TextArea.super.renderSubviews(self, dc) | ||
| end | ||
|
|
||
| function TextArea:onInput(keys) | ||
| if (self.scrollbar.is_dragging) then | ||
| return self.scrollbar:onInput(keys) | ||
| end | ||
|
|
||
| if keys._MOUSE_L and self:getMousePos() then | ||
| self:setFocus(true) | ||
| end | ||
|
|
||
| return TextArea.super.onInput(self, keys) | ||
| end | ||
|
|
||
| return TextArea | ||
Uh oh!
There was an error while loading. Please reload this page.