Spinner and multiline textbox widgets (#8199)
This commit is contained in:
parent
bded0465fc
commit
6c5a8e923d
28 changed files with 2961 additions and 43 deletions
258
data/gui/widget/multiline_text_default.cfg
Normal file
258
data/gui/widget/multiline_text_default.cfg
Normal file
|
@ -0,0 +1,258 @@
|
|||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Definition of a basic multiline text box.
|
||||
### The base widget for a text box that supports
|
||||
### editing multiple lines of text.
|
||||
### Cannot be used on its own, use [scroll_text] instead,
|
||||
### which is a multiline text box with scrollbars.
|
||||
|
||||
#define _GUI_DRAW_BACKGROUND COLOR
|
||||
[rectangle]
|
||||
x = 0
|
||||
y = 0
|
||||
w = "(width)"
|
||||
h = "(height)"
|
||||
|
||||
fill_color = {COLOR}
|
||||
|
||||
[/rectangle]
|
||||
#enddef
|
||||
|
||||
#define _GUI_TEXTBOX_BACKGROUND_ENABLED
|
||||
{_GUI_DRAW_BACKGROUND ({GUI__BACKGROUND_COLOR_ENABLED})}
|
||||
#enddef
|
||||
|
||||
#define _GUI_TEXTBOX_BACKGROUND_DISABLED
|
||||
{_GUI_DRAW_BACKGROUND ({GUI__BACKGROUND_COLOR_DISABLED})}
|
||||
#enddef
|
||||
|
||||
#define _GUI_DRAW_BORDER COLOR
|
||||
[rectangle]
|
||||
x = 0
|
||||
y = 0
|
||||
w = "(width)"
|
||||
h = "(height)"
|
||||
|
||||
border_thickness = 1
|
||||
border_color = {COLOR}
|
||||
|
||||
[/rectangle]
|
||||
#enddef
|
||||
|
||||
#define _GUI_DRAW_TEXT SIZE COLOR
|
||||
#arg FONT_FAMILY
|
||||
#endarg
|
||||
|
||||
##### The text
|
||||
[text]
|
||||
x = "(text_x_offset)"
|
||||
y = "(text_y_offset)"
|
||||
w = "(text_width)"
|
||||
h = "(text_height)"
|
||||
maximum_width = "(text_maximum_width)"
|
||||
font_size = {SIZE}
|
||||
font_family = {FONT_FAMILY}
|
||||
color = "(if(editable=1, active_color, inactive_color) where
|
||||
active_color = [{COLOR}],
|
||||
inactive_color = [{__DISABLED_COLOR_PREPROCESSOR_WORKAROUND}]
|
||||
)"
|
||||
text = "(text)"
|
||||
highlight_color = "21, 53, 80"
|
||||
highlight_start = "(highlight_start)"
|
||||
highlight_end = "(highlight_end)"
|
||||
[/text]
|
||||
#enddef
|
||||
|
||||
#
|
||||
# The preprocessor can't process GUI__FONT_COLOR_DISABLED__DEFAULT as part of string
|
||||
# concatenation for some reason. Perhaps it's the optional argument. So I'm just copying
|
||||
# it here. Though the lack of quotes means I don't need to use concatenation anyway.
|
||||
#
|
||||
# -- vultraz, 2018-03-26
|
||||
#
|
||||
#define __DISABLED_COLOR_PREPROCESSOR_WORKAROUND
|
||||
128, 128, 128, 255 #enddef
|
||||
|
||||
#define _GUI_DRAW_TEXT_OR_HINT SIZE COLOR
|
||||
#arg FONT_FAMILY
|
||||
#endarg
|
||||
[rectangle]
|
||||
x = "(text_x_offset + selection_start_x)"
|
||||
y = "(text_y_offset)"
|
||||
w = "(selection_width)"
|
||||
h = "(text_font_height + selection_height)"
|
||||
|
||||
border_thickness = 0
|
||||
fill_color = "21, 53, 80, 255"
|
||||
[/rectangle]
|
||||
|
||||
[text]
|
||||
x = "(text_x_offset)"
|
||||
y = "(text_y_offset)"
|
||||
w = "(text_width)"
|
||||
h = "(text_height)"
|
||||
maximum_width = "(text_maximum_width)"
|
||||
|
||||
font_size = "(
|
||||
if(text = '' and hint_text != '', hint_size, reg_size) where
|
||||
hint_size = {GUI_FONT_SIZE_SMALL},
|
||||
reg_size = {SIZE}
|
||||
)"
|
||||
font_family = {FONT_FAMILY}
|
||||
|
||||
color = "(
|
||||
if((text = '' and hint_text != '') or editable = 0, hint_color, reg_color) where
|
||||
hint_color = [{__DISABLED_COLOR_PREPROCESSOR_WORKAROUND}],
|
||||
reg_color = [{COLOR}]
|
||||
)"
|
||||
|
||||
text = "(
|
||||
if(text = '' and hint_text != '', hint_text, text))"
|
||||
[/text]
|
||||
|
||||
[image]
|
||||
x = "(width - image_width)"
|
||||
y = "(max(0, height / 2 - image_height / 2))"
|
||||
name = "(if(text = '' and hint_image != '', hint_image, ''))"
|
||||
[/image]
|
||||
#enddef
|
||||
|
||||
#define _GUI_DRAW_CURSOR X_OFFSET
|
||||
[line]
|
||||
x1 = "(cursor_offset_x + {X_OFFSET})"
|
||||
y1 = "(text_y_offset + cursor_offset_y + 2)"
|
||||
x2 = "(cursor_offset_x + {X_OFFSET})"
|
||||
y2 = "(text_y_offset + cursor_offset_y + text_font_height - 2)"
|
||||
color = "([255, 255, 255, cursor_alpha])"
|
||||
thickness = 1
|
||||
[/line]
|
||||
|
||||
[rectangle]
|
||||
x = "(composition_offset + {X_OFFSET})"
|
||||
y = "(text_y_offset + text_font_height - 2)"
|
||||
w = "(composition_width)"
|
||||
h = "2"
|
||||
fill_color = "([140, 140, 0, if(composition_width > 0, 255, 0)])"
|
||||
border_thickness = 0
|
||||
[/rectangle]
|
||||
#enddef
|
||||
|
||||
#define _GUI_RESOLUTION RESOLUTION MIN_WIDTH DEFAULT_WIDTH HEIGHT X_OFFSET EXTRA_WIDTH FONT_SIZE BACKGROUND_ENABLED BACKGROUND_DISABLED
|
||||
#arg FONT_FAMILY
|
||||
#endarg
|
||||
[resolution]
|
||||
|
||||
{RESOLUTION}
|
||||
|
||||
min_width = {MIN_WIDTH}
|
||||
min_height = {HEIGHT}
|
||||
|
||||
default_width = {DEFAULT_WIDTH}
|
||||
default_height = {HEIGHT}
|
||||
|
||||
max_width = 0
|
||||
max_height = {HEIGHT}
|
||||
|
||||
text_font_size = {FONT_SIZE}
|
||||
text_font_family = {FONT_FAMILY}
|
||||
text_x_offset = {X_OFFSET}
|
||||
text_y_offset = 2
|
||||
text_extra_width = {EXTRA_WIDTH}
|
||||
|
||||
#functions = "(def show_hint_text() (text = '' and hint_text != '');)"
|
||||
|
||||
[state_enabled]
|
||||
|
||||
[draw]
|
||||
|
||||
{BACKGROUND_ENABLED}
|
||||
|
||||
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR_DARK}) }
|
||||
|
||||
{_GUI_DRAW_TEXT_OR_HINT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__DEFAULT}) FONT_FAMILY={FONT_FAMILY} }
|
||||
|
||||
[/draw]
|
||||
|
||||
[/state_enabled]
|
||||
|
||||
[state_disabled]
|
||||
|
||||
[draw]
|
||||
|
||||
{BACKGROUND_DISABLED}
|
||||
|
||||
{_GUI_DRAW_BORDER ({GUI__FONT_COLOR_DISABLED_DARK__DEFAULT}) }
|
||||
|
||||
{_GUI_DRAW_TEXT_OR_HINT ({FONT_SIZE}) ({GUI__FONT_COLOR_DISABLED__DEFAULT}) FONT_FAMILY={FONT_FAMILY} }
|
||||
|
||||
[/draw]
|
||||
|
||||
[/state_disabled]
|
||||
|
||||
[state_focused]
|
||||
|
||||
[draw]
|
||||
|
||||
{BACKGROUND_ENABLED}
|
||||
|
||||
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR_BRIGHT}) }
|
||||
|
||||
# We never draw the hint text or image if focused
|
||||
{_GUI_DRAW_TEXT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__DEFAULT}) FONT_FAMILY={FONT_FAMILY} }
|
||||
|
||||
{_GUI_DRAW_CURSOR ({X_OFFSET}) }
|
||||
|
||||
[/draw]
|
||||
|
||||
[/state_focused]
|
||||
|
||||
[state_hovered]
|
||||
|
||||
[draw]
|
||||
|
||||
{BACKGROUND_ENABLED}
|
||||
|
||||
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR}) }
|
||||
|
||||
{_GUI_DRAW_TEXT_OR_HINT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__DEFAULT}) FONT_FAMILY={FONT_FAMILY} }
|
||||
|
||||
[/draw]
|
||||
|
||||
[/state_hovered]
|
||||
|
||||
[/resolution]
|
||||
|
||||
#enddef
|
||||
|
||||
[multiline_text_definition]
|
||||
id = "default"
|
||||
description = "Default multiline text box"
|
||||
|
||||
{_GUI_RESOLUTION () 40 250 90 5 10 ({GUI_FONT_SIZE_DEFAULT}) ({_GUI_TEXTBOX_BACKGROUND_ENABLED}) ({_GUI_TEXTBOX_BACKGROUND_DISABLED})}
|
||||
[/multiline_text_definition]
|
||||
|
||||
[multiline_text_definition]
|
||||
id = "transparent"
|
||||
description = "Background-less multiline text box, used for WML messages"
|
||||
|
||||
{_GUI_RESOLUTION () 40 250 90 5 10 ({GUI_FONT_SIZE_DEFAULT}) () ()}
|
||||
|
||||
[/multiline_text_definition]
|
||||
|
||||
[multiline_text_definition]
|
||||
id = "verbatim"
|
||||
description = "Monospace multiline text box"
|
||||
|
||||
{_GUI_RESOLUTION () 40 250 90 5 10 ({GUI_FONT_SIZE_DEFAULT}) ({_GUI_TEXTBOX_BACKGROUND_ENABLED}) ({_GUI_TEXTBOX_BACKGROUND_DISABLED}) FONT_FAMILY=monospace}
|
||||
|
||||
[/multiline_text_definition]
|
||||
|
||||
#undef _GUI_RESOLUTION
|
||||
#undef _GUI_DRAW_CURSOR
|
||||
#undef _GUI_DRAW_TEXT
|
||||
#undef _GUI_DRAW_BORDER
|
||||
#undef _GUI_DRAW_BACKGROUND
|
||||
#undef _GUI_DRAW_TEXT_OR_HINT
|
||||
#undef _GUI_TEXTBOX_BACKGROUND_ENABLED
|
||||
#undef _GUI_TEXTBOX_BACKGROUND_DISABLED
|
||||
#undef __DISABLED_COLOR_PREPROCESSOR_WORKAROUND
|
127
data/gui/widget/scroll_text_default.cfg
Normal file
127
data/gui/widget/scroll_text_default.cfg
Normal file
|
@ -0,0 +1,127 @@
|
|||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Definition of a scrollable multiline text box.
|
||||
### A text box that support editing multiline text and
|
||||
### resizes/shows scrollbar depending on the entered text.
|
||||
### Use this instead of [multiline_text], which cannot be used by itself.
|
||||
###
|
||||
|
||||
#define _GUI_RESOLUTION RESOLUTION DEFINITION FONT_SIZE FONT_STYLE FONT_COLOR_ENABLED FONT_COLOR_DISABLED
|
||||
[resolution]
|
||||
|
||||
{RESOLUTION}
|
||||
|
||||
min_width = 0
|
||||
min_height = 0
|
||||
|
||||
default_width = 0
|
||||
default_height = 0
|
||||
|
||||
max_width = 0
|
||||
max_height = 0
|
||||
|
||||
text_font_size = {FONT_SIZE}
|
||||
text_font_style = {FONT_STYLE}
|
||||
|
||||
[state_enabled]
|
||||
|
||||
[draw]
|
||||
[/draw]
|
||||
|
||||
[/state_enabled]
|
||||
|
||||
[state_disabled]
|
||||
|
||||
[draw]
|
||||
[/draw]
|
||||
|
||||
[/state_disabled]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = true
|
||||
vertical_grow = true
|
||||
|
||||
[grid]
|
||||
id = "_content_grid"
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "right,bottom" # between the text and the scrollbars
|
||||
border_size = 3 # intentionally smaller than normal
|
||||
horizontal_grow = true
|
||||
vertical_grow = true
|
||||
|
||||
[multiline_text]
|
||||
id="_text"
|
||||
definition="default"
|
||||
[/multiline_text]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
|
||||
{GUI__VERTICAL_SCROLLBAR_GRID}
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
{GUI__HORIZONTAL_SCROLLBAR_GRID}
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
|
||||
[spacer]
|
||||
[/spacer]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/resolution]
|
||||
#enddef
|
||||
|
||||
#define _GUI_DEFINITION ID DESCRIPTION DEFINITION
|
||||
[scroll_text_definition]
|
||||
id = {ID}
|
||||
description = {DESCRIPTION}
|
||||
|
||||
{_GUI_RESOLUTION
|
||||
()
|
||||
({DEFINITION})
|
||||
({GUI_FONT_SIZE_DEFAULT})
|
||||
()
|
||||
({GUI__FONT_COLOR_ENABLED__DEFAULT})
|
||||
({GUI__FONT_COLOR_DISABLED__DEFAULT})
|
||||
}
|
||||
|
||||
[/scroll_text_definition]
|
||||
#enddef
|
||||
|
||||
{_GUI_DEFINITION "default" "The default scroll label." "default"}
|
||||
{_GUI_DEFINITION "default_large" "Large font size scroll label." "default_large"}
|
||||
{_GUI_DEFINITION "default_small" "Small font size scroll label." "default_small"}
|
||||
{_GUI_DEFINITION "default_italic" "Small font size scroll label." "default_italic"}
|
||||
|
||||
#undef _GUI_DEFINITION
|
||||
#undef _GUI_RESOLUTION
|
130
data/gui/widget/scroll_text_verbatim.cfg
Normal file
130
data/gui/widget/scroll_text_verbatim.cfg
Normal file
|
@ -0,0 +1,130 @@
|
|||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Definition of a scrollable multiline text area.
|
||||
### A text box that support editing multiline text and
|
||||
### resizes/shows scrollbar depending on the entered text.
|
||||
### Use this instead of [multiline_text].
|
||||
### This version is used for editing verbatim text
|
||||
### (such as WML snippets) using a fixed-width font.
|
||||
|
||||
#define _GUI_RESOLUTION RESOLUTION FONT_SIZE FONT_STYLE FONT_COLOR_ENABLED FONT_COLOR_DISABLED
|
||||
[resolution]
|
||||
|
||||
{RESOLUTION}
|
||||
|
||||
min_width = 0
|
||||
min_height = 0
|
||||
|
||||
default_width = 0
|
||||
default_height = 0
|
||||
|
||||
max_width = 0
|
||||
max_height = 0
|
||||
|
||||
text_font_size = {FONT_SIZE}
|
||||
text_font_style = {FONT_STYLE}
|
||||
text_font_family = monospace
|
||||
|
||||
[state_enabled]
|
||||
|
||||
[draw]
|
||||
|
||||
[rectangle]
|
||||
x = 0
|
||||
y = 0
|
||||
w = "(width)"
|
||||
h = "(height)"
|
||||
fill_color = {GUI__BACKGROUND_COLOR_ENABLED}
|
||||
[/rectangle]
|
||||
|
||||
[/draw]
|
||||
|
||||
[/state_enabled]
|
||||
|
||||
[state_disabled]
|
||||
|
||||
[draw]
|
||||
[/draw]
|
||||
|
||||
[/state_disabled]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = true # needed ?
|
||||
vertical_grow = true # needed ?
|
||||
|
||||
[grid]
|
||||
id = "_content_grid"
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_grow = true
|
||||
vertical_grow = true
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
[multiline_text]
|
||||
id="_text"
|
||||
definition="verbatim"
|
||||
[/multiline_text]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
|
||||
{GUI__VERTICAL_SCROLLBAR_GRID}
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
{GUI__HORIZONTAL_SCROLLBAR_GRID}
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
|
||||
[spacer]
|
||||
[/spacer]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/resolution]
|
||||
#enddef
|
||||
|
||||
[scroll_text_definition]
|
||||
id = "verbatim"
|
||||
description = "A scroll label type used for verbatim text using a fixed-width font."
|
||||
|
||||
{_GUI_RESOLUTION
|
||||
()
|
||||
({GUI_FONT_SIZE_DEFAULT})
|
||||
()
|
||||
({GUI__FONT_COLOR_ENABLED__DEFAULT})
|
||||
({GUI__FONT_COLOR_DISABLED__DEFAULT})
|
||||
}
|
||||
|
||||
[/scroll_text_definition]
|
||||
|
||||
#undef _GUI_RESOLUTION
|
223
data/gui/widget/spinner_default.cfg
Normal file
223
data/gui/widget/spinner_default.cfg
Normal file
|
@ -0,0 +1,223 @@
|
|||
#textdomain wesnoth-lib
|
||||
###
|
||||
### Definition of a spinner widget.
|
||||
### A widget with a text box and two buttons (_prev and _next) that is used for numerical entry.
|
||||
### Clicking the _prev and _next buttons reduces and increases the numerical value in the text box.
|
||||
### Non-numeric values are replaced with zero when any of the buttons are pressed.
|
||||
###
|
||||
|
||||
#define GRID_SPLIT ALIGN
|
||||
[grid]
|
||||
id = "_content_grid"
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[grid]
|
||||
[row]
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_prev"
|
||||
definition = "left_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "left,right"
|
||||
border_size = 3
|
||||
horizontal_alignment={ALIGN}
|
||||
[text_box]
|
||||
id = "_text"
|
||||
[/text_box]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_next"
|
||||
definition = "right_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
#enddef
|
||||
|
||||
#define GRID_LEFT ALIGN
|
||||
[grid]
|
||||
id = "_content_grid"
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[grid]
|
||||
[row]
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_prev"
|
||||
definition = "left_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "left"
|
||||
border_size = 3
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_next"
|
||||
definition = "right_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "left"
|
||||
border_size = 3
|
||||
horizontal_alignment={ALIGN}
|
||||
[text_box]
|
||||
id = "_text"
|
||||
[/text_box]
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
[/grid]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
#enddef
|
||||
|
||||
#define GRID_RIGHT ALIGN
|
||||
[grid]
|
||||
id = "_content_grid"
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[grid]
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "right"
|
||||
border_size = 3
|
||||
horizontal_alignment={ALIGN}
|
||||
[text_box]
|
||||
id = "_text"
|
||||
[/text_box]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "right"
|
||||
border_size = 3
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_prev"
|
||||
definition = "left_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
horizontal_alignment={ALIGN}
|
||||
[repeating_button]
|
||||
id= "_next"
|
||||
definition = "right_arrow"
|
||||
[/repeating_button]
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
[/grid]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
#enddef
|
||||
|
||||
#define _GUI_RESOLUTION RESOLUTION DEFINITION FONT_SIZE FONT_STYLE FONT_COLOR_ENABLED FONT_COLOR_DISABLED GRID
|
||||
[resolution]
|
||||
|
||||
{RESOLUTION}
|
||||
|
||||
min_width = 0
|
||||
min_height = 0
|
||||
|
||||
default_width = 0
|
||||
default_height = 0
|
||||
|
||||
max_width = 0
|
||||
max_height = 0
|
||||
|
||||
text_font_size = {FONT_SIZE}
|
||||
text_font_style = {FONT_STYLE}
|
||||
|
||||
[state_enabled]
|
||||
|
||||
[draw]
|
||||
[/draw]
|
||||
|
||||
[/state_enabled]
|
||||
|
||||
[state_disabled]
|
||||
|
||||
[draw]
|
||||
[/draw]
|
||||
|
||||
[/state_disabled]
|
||||
|
||||
{GRID}
|
||||
|
||||
[/resolution]
|
||||
#enddef
|
||||
|
||||
[spinner_definition]
|
||||
id = "default"
|
||||
description = "Default Spinner with left and right arrows, split on both sides"
|
||||
|
||||
{_GUI_RESOLUTION
|
||||
()
|
||||
()
|
||||
({GUI_FONT_SIZE_DEFAULT})
|
||||
()
|
||||
({GUI__FONT_COLOR_ENABLED__DEFAULT})
|
||||
({GUI__FONT_COLOR_DISABLED__DEFAULT})
|
||||
({GRID_SPLIT ("left")})
|
||||
}
|
||||
|
||||
[/spinner_definition]
|
||||
|
||||
[spinner_definition]
|
||||
id = "left"
|
||||
description = "Default Spinner with both left and right arrows on the left"
|
||||
|
||||
{_GUI_RESOLUTION
|
||||
()
|
||||
()
|
||||
({GUI_FONT_SIZE_DEFAULT})
|
||||
()
|
||||
({GUI__FONT_COLOR_ENABLED__DEFAULT})
|
||||
({GUI__FONT_COLOR_DISABLED__DEFAULT})
|
||||
({GRID_LEFT ("left")})
|
||||
}
|
||||
|
||||
[/spinner_definition]
|
||||
|
||||
[spinner_definition]
|
||||
id = "right"
|
||||
description = "Default Spinner with both left and right arrows on the right"
|
||||
|
||||
{_GUI_RESOLUTION
|
||||
()
|
||||
()
|
||||
({GUI_FONT_SIZE_DEFAULT})
|
||||
()
|
||||
({GUI__FONT_COLOR_ENABLED__DEFAULT})
|
||||
({GUI__FONT_COLOR_DISABLED__DEFAULT})
|
||||
({GRID_RIGHT ("left")})
|
||||
}
|
||||
|
||||
[/spinner_definition]
|
||||
|
||||
#undef _GUI_RESOLUTION
|
|
@ -136,7 +136,9 @@
|
|||
{DEFAULT_KEY "font_family" font_family "sans"}
|
||||
{REQUIRED_KEY "font_size" f_unsigned}
|
||||
{DEFAULT_KEY "font_style" font_style ""}
|
||||
{DEFAULT_KEY "h" f_unsigned 0}
|
||||
{DEFAULT_KEY "highlight_color" string "#215380"}
|
||||
{DEFAULT_KEY "highlight_start" f_unsigned 0}
|
||||
{DEFAULT_KEY "highlight_end" f_unsigned 0}
|
||||
{DEFAULT_KEY "maximum_height" f_int -1}
|
||||
{DEFAULT_KEY "maximum_width" f_int -1}
|
||||
{DEFAULT_KEY "text" f_t_string ""}
|
||||
|
@ -144,6 +146,8 @@
|
|||
{DEFAULT_KEY "text_markup" f_bool false}
|
||||
{DEFAULT_KEY "text_link_aware" f_bool false}
|
||||
{DEFAULT_KEY "text_link_color" string "#ffff00"}
|
||||
{DEFAULT_KEY "text_wrap_mode" f_unsigned 0}
|
||||
{DEFAULT_KEY "h" f_unsigned 0}
|
||||
{DEFAULT_KEY "w" f_unsigned 0}
|
||||
{DEFAULT_KEY "x" f_unsigned 0}
|
||||
{DEFAULT_KEY "y" f_unsigned 0}
|
||||
|
@ -200,4 +204,4 @@
|
|||
{DEFAULT_KEY "use_markup" bool false}
|
||||
{DEFAULT_KEY "can_shrink" bool false}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[/tag]
|
||||
|
|
|
@ -259,6 +259,44 @@
|
|||
{LINK_TAG "$cell/grid"}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="multiline_text_definition"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition"
|
||||
[tag]
|
||||
name="resolution"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition/resolution"
|
||||
[tag]
|
||||
name="state_disabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="state_enabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="state_focused"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="state_hovered"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
{DEFAULT_KEY "text_x_offset" f_unsigned ""}
|
||||
{DEFAULT_KEY "text_y_offset" f_unsigned ""}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="multi_page_definition"
|
||||
min="0"
|
||||
|
@ -391,6 +429,31 @@
|
|||
{LINK_TAG "$cell/grid"}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="scroll_text_definition"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition"
|
||||
[tag]
|
||||
name="resolution"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition/resolution"
|
||||
[tag]
|
||||
name="state_disabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="state_enabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
{LINK_TAG "$cell/grid"}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="scrollbar_panel_definition"
|
||||
min="0"
|
||||
|
@ -477,6 +540,31 @@
|
|||
max="infinite"
|
||||
super="$generic/widget_definition"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="spinner_definition"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition"
|
||||
[tag]
|
||||
name="resolution"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_definition/resolution"
|
||||
[tag]
|
||||
name="state_disabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
[tag]
|
||||
name="state_enabled"
|
||||
min="0"
|
||||
max="1"
|
||||
super="$generic/state"
|
||||
[/tag]
|
||||
{LINK_TAG "$cell/grid"}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="stacked_widget_definition"
|
||||
min="0"
|
||||
|
|
|
@ -58,6 +58,19 @@
|
|||
{DEFAULT_KEY "details" t_string ""}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="multiline_text"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_instance"
|
||||
{DEFAULT_KEY "history" string ""}
|
||||
{DEFAULT_KEY "max_input_length" int 0}
|
||||
{DEFAULT_KEY "label" t_string ""}
|
||||
{DEFAULT_KEY "hint_text" t_string ""}
|
||||
{DEFAULT_KEY "hint_image" string ""}
|
||||
{DEFAULT_KEY "editable" bool true}
|
||||
{DEFAULT_KEY "wrap" bool true}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="multimenu_button"
|
||||
min="0"
|
||||
|
@ -357,6 +370,25 @@
|
|||
{DEFAULT_KEY "text_alignment" f_h_align "left"}
|
||||
{DEFAULT_KEY "link_aware" bool false}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="spinner"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_instance"
|
||||
{DEFAULT_KEY "wrap" bool true}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="scroll_text"
|
||||
min="0"
|
||||
max="infinite"
|
||||
super="$generic/widget_instance"
|
||||
{DEFAULT_KEY "horizontal_scrollbar_mode" scrollbar_mode initial_auto}
|
||||
{DEFAULT_KEY "vertical_scrollbar_mode" scrollbar_mode initial_auto}
|
||||
{DEFAULT_KEY "wrap" bool true}
|
||||
{DEFAULT_KEY "text_alignment" f_h_align "left"}
|
||||
{DEFAULT_KEY "link_aware" bool false}
|
||||
{DEFAULT_KEY "editable" bool true}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="scrollbar_panel"
|
||||
min="0"
|
||||
|
|
|
@ -804,6 +804,8 @@
|
|||
<Unit filename="../../src/gui/widgets/minimap.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/multi_page.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/multi_page.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/multiline_text.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/multiline_text.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/multimenu_button.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/multimenu_button.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/pane.cpp" />
|
||||
|
@ -819,6 +821,8 @@
|
|||
<Unit filename="../../src/gui/widgets/retval.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/scroll_label.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/scroll_label.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/scroll_text.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/scroll_text.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/scrollbar.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/scrollbar.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/scrollbar_container.cpp" />
|
||||
|
@ -837,6 +841,8 @@
|
|||
<Unit filename="../../src/gui/widgets/slider_base.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/spacer.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/spacer.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/spinner.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/spinner.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/stacked_widget.cpp" />
|
||||
<Unit filename="../../src/gui/widgets/stacked_widget.hpp" />
|
||||
<Unit filename="../../src/gui/widgets/status_label_helper.hpp" />
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
1234567890ABCDEF12345678 /* file_progress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1234567890ABCDEF12345680 /* file_progress.cpp */; };
|
||||
1234567890ABCDEF12345679 /* file_progress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1234567890ABCDEF12345680 /* file_progress.cpp */; };
|
||||
172E48A5BD149999CE64EDF8 /* prompt.hpp in Headers */ = {isa = PBXBuildFile; fileRef = D4594633BF3F8A06D6AE752F /* prompt.hpp */; };
|
||||
179D4E93A08C5A67B071C6C1 /* spinner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4214F3DA80B54080C4B548F /* spinner.cpp */; };
|
||||
36B146FAA79A55E9F43723B1 /* general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84234C54BB84519421FD4136 /* general.cpp */; };
|
||||
36D74F7F8D7655ACCABE562D /* edit_pbl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6FA542D78393E8FF067775DA /* edit_pbl.cpp */; };
|
||||
3C254DF5B7DF196F2041955F /* mp_report.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58C649488B3014E6F7254B62 /* mp_report.cpp */; };
|
||||
|
@ -658,6 +659,7 @@
|
|||
62D24F321519987400350848 /* context_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D24F311519987400350848 /* context_manager.cpp */; };
|
||||
62D24F351519995200350848 /* palette_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D24F341519995200350848 /* palette_manager.cpp */; };
|
||||
6D574EACA3483ABEE72819F0 /* statistics_record.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27764FB68F02032F1C0B6748 /* statistics_record.cpp */; };
|
||||
77D94146A5FA29849D1A9BD8 /* multiline_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B0F48CE9CF65D9813BE6CDC /* multiline_text.cpp */; };
|
||||
7BFC4DF5BFF8CF75855BA662 /* prompt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67044415B63F5888193BD7A6 /* prompt.cpp */; };
|
||||
7FDF4E8D9C94E7DA8F41F7BB /* tod_new_schedule.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */; };
|
||||
867141839BDB89BFE876E310 /* carryover_show_gold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */; };
|
||||
|
@ -1266,8 +1268,11 @@
|
|||
C0454A6592DCD67D93323D9C /* edit_pbl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B2CC45FEA71445AE817CAA6B /* edit_pbl.hpp */; };
|
||||
C93048A9AE576B6AD016DFA4 /* tod_new_schedule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61F473D9AC43768A445E218 /* tod_new_schedule.cpp */; };
|
||||
C9D14DC39B87182A00397A3D /* choose_addon.hpp in Headers */ = {isa = PBXBuildFile; fileRef = D9A141EAAE90E98B6F6171D6 /* choose_addon.hpp */; };
|
||||
D1254FCA82471825B83AA786 /* multiline_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B0F48CE9CF65D9813BE6CDC /* multiline_text.cpp */; };
|
||||
DF974010BB46B844E83F7DDA /* tod_new_schedule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61F473D9AC43768A445E218 /* tod_new_schedule.cpp */; };
|
||||
E1DA41878F0C255769B8239D /* scroll_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 755D4555A1DEA29125E7F338 /* scroll_text.cpp */; };
|
||||
E2F24C0CBC863C3DC8A041EF /* edit_pbl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B2CC45FEA71445AE817CAA6B /* edit_pbl.hpp */; };
|
||||
E6CF415F9FD04C35A55FB24D /* scroll_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 755D4555A1DEA29125E7F338 /* scroll_text.cpp */; };
|
||||
E79249078ACE777D1E219DED /* choose_addon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 20E644DC98F26C756364EC2C /* choose_addon.cpp */; };
|
||||
EBB44A70837B84A928CB6424 /* edit_pbl_translation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00574699A982AA23F12B39E0 /* edit_pbl_translation.cpp */; };
|
||||
EC0341E11ECF46FE000F2E2B /* config_attribute_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC0341DF1ECF46FE000F2E2B /* config_attribute_value.cpp */; };
|
||||
|
@ -1420,6 +1425,7 @@
|
|||
ECFB9FA8193BFAD900146ED0 /* carryover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECFB9FA7193BFAD900146ED0 /* carryover.cpp */; };
|
||||
ECFB9FAA193BFB4B00146ED0 /* game_board.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECFB9FA9193BFB4B00146ED0 /* game_board.cpp */; };
|
||||
ECFB9FAC193BFB6E00146ED0 /* rect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECFB9FAB193BFB6E00146ED0 /* rect.cpp */; };
|
||||
F13D4C33BAA4CB9E9AACFCC2 /* spinner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4214F3DA80B54080C4B548F /* spinner.cpp */; };
|
||||
F40A13BC1A3A88BA00C4D071 /* apple_notification.mm in Sources */ = {isa = PBXBuildFile; fileRef = F40A13BB1A3A88BA00C4D071 /* apple_notification.mm */; };
|
||||
F419A1F414E21246002F9ADC /* game_end_exceptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F419A1F314E21246002F9ADC /* game_end_exceptions.cpp */; };
|
||||
F419A2C314F5BCFE002F9ADC /* info.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F419A2C114F5BCFE002F9ADC /* info.cpp */; };
|
||||
|
@ -1553,6 +1559,7 @@
|
|||
000000000000000000000010 /* network_download_file.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = network_download_file.hpp; sourceTree = "<group>"; };
|
||||
00574699A982AA23F12B39E0 /* edit_pbl_translation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = edit_pbl_translation.cpp; sourceTree = "<group>"; };
|
||||
09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = carryover_show_gold.cpp; sourceTree = "<group>"; };
|
||||
0B0F48CE9CF65D9813BE6CDC /* multiline_text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = multiline_text.cpp; path = multiline_text.cpp; sourceTree = "<group>"; };
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
1234567890ABCDEF12345680 /* file_progress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_progress.cpp; sourceTree = "<group>"; };
|
||||
1234567890ABCDEF12345681 /* file_progress.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = file_progress.hpp; sourceTree = "<group>"; };
|
||||
|
@ -2099,7 +2106,7 @@
|
|||
49478712172FF6F8002B7ABA /* tristate_button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tristate_button.cpp; sourceTree = "<group>"; };
|
||||
49478713172FF6F8002B7ABA /* tristate_button.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tristate_button.hpp; sourceTree = "<group>"; };
|
||||
58C649488B3014E6F7254B62 /* mp_report.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = mp_report.cpp; sourceTree = "<group>"; };
|
||||
5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tod_new_schedule.hpp; sourceTree = "<group>"; };
|
||||
5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tod_new_schedule.hpp; path = tod_new_schedule.hpp; sourceTree = "<group>"; };
|
||||
620A386215E9364E00A4F513 /* attack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = attack.cpp; sourceTree = "<group>"; };
|
||||
620A386315E9364E00A4F513 /* attack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = attack.hpp; sourceTree = "<group>"; };
|
||||
620A386415E9364E00A4F513 /* create.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = create.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2183,6 +2190,7 @@
|
|||
62D24F341519995200350848 /* palette_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = palette_manager.cpp; sourceTree = "<group>"; };
|
||||
67044415B63F5888193BD7A6 /* prompt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = prompt.cpp; sourceTree = "<group>"; };
|
||||
6FA542D78393E8FF067775DA /* edit_pbl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = edit_pbl.cpp; sourceTree = "<group>"; };
|
||||
755D4555A1DEA29125E7F338 /* scroll_text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scroll_text.cpp; path = scroll_text.cpp; sourceTree = "<group>"; };
|
||||
84234C54BB84519421FD4136 /* general.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = general.cpp; sourceTree = "<group>"; };
|
||||
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8D1107320486CEB800E47090 /* The Battle for Wesnoth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "The Battle for Wesnoth.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -2709,6 +2717,7 @@
|
|||
D4594633BF3F8A06D6AE752F /* prompt.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = prompt.hpp; sourceTree = "<group>"; };
|
||||
D911474D925FA88D5B856A0E /* test_sdl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = test_sdl.cpp; path = test_sdl.cpp; sourceTree = "<group>"; };
|
||||
D9A141EAAE90E98B6F6171D6 /* choose_addon.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = choose_addon.hpp; sourceTree = "<group>"; };
|
||||
E4214F3DA80B54080C4B548F /* spinner.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = spinner.cpp; path = spinner.cpp; sourceTree = "<group>"; };
|
||||
EC0341DF1ECF46FE000F2E2B /* config_attribute_value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_attribute_value.cpp; sourceTree = "<group>"; };
|
||||
EC0341E01ECF46FE000F2E2B /* config_attribute_value.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = config_attribute_value.hpp; sourceTree = "<group>"; };
|
||||
EC0680231EA920A300EEE03B /* random_deterministic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = random_deterministic.cpp; sourceTree = "<group>"; };
|
||||
|
@ -4064,6 +4073,9 @@
|
|||
46F92D342174F6A300602C1C /* window_private.hpp */,
|
||||
46F92D2E2174F6A300602C1C /* window.cpp */,
|
||||
46F92D472174F6A300602C1C /* window.hpp */,
|
||||
E4214F3DA80B54080C4B548F /* spinner.cpp */,
|
||||
0B0F48CE9CF65D9813BE6CDC /* multiline_text.cpp */,
|
||||
755D4555A1DEA29125E7F338 /* scroll_text.cpp */,
|
||||
);
|
||||
path = widgets;
|
||||
sourceTree = "<group>";
|
||||
|
@ -5866,6 +5878,9 @@
|
|||
0554467DB5FE99D85ABCDCA0 /* edit_pbl_translation.cpp in Sources */,
|
||||
8C704B6F99C824A4073EEBEE /* prompt.cpp in Sources */,
|
||||
DF974010BB46B844E83F7DDA /* tod_new_schedule.cpp in Sources */,
|
||||
179D4E93A08C5A67B071C6C1 /* spinner.cpp in Sources */,
|
||||
77D94146A5FA29849D1A9BD8 /* multiline_text.cpp in Sources */,
|
||||
E1DA41878F0C255769B8239D /* scroll_text.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -6543,6 +6558,9 @@
|
|||
EBB44A70837B84A928CB6424 /* edit_pbl_translation.cpp in Sources */,
|
||||
7BFC4DF5BFF8CF75855BA662 /* prompt.cpp in Sources */,
|
||||
C93048A9AE576B6AD016DFA4 /* tod_new_schedule.cpp in Sources */,
|
||||
F13D4C33BAA4CB9E9AACFCC2 /* spinner.cpp in Sources */,
|
||||
D1254FCA82471825B83AA786 /* multiline_text.cpp in Sources */,
|
||||
E6CF415F9FD04C35A55FB24D /* scroll_text.cpp in Sources */,
|
||||
62714C2FBE84B66CF14E3722 /* test_sdl.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -10,16 +10,19 @@ gui/widgets/matrix.cpp
|
|||
gui/widgets/menu_button.cpp
|
||||
gui/widgets/minimap.cpp
|
||||
gui/widgets/multi_page.cpp
|
||||
gui/widgets/multiline_text.cpp
|
||||
gui/widgets/multimenu_button.cpp
|
||||
gui/widgets/panel.cpp
|
||||
gui/widgets/password_box.cpp
|
||||
gui/widgets/progress_bar.cpp
|
||||
gui/widgets/repeating_button.cpp
|
||||
gui/widgets/scroll_label.cpp
|
||||
gui/widgets/scroll_text.cpp
|
||||
gui/widgets/scrollbar_panel.cpp
|
||||
gui/widgets/size_lock.cpp
|
||||
gui/widgets/slider.cpp
|
||||
gui/widgets/spacer.cpp
|
||||
gui/widgets/spinner.cpp
|
||||
gui/widgets/stacked_widget.cpp
|
||||
gui/widgets/text_box.cpp
|
||||
gui/widgets/toggle_button.cpp
|
||||
|
|
|
@ -272,6 +272,7 @@ gui/widgets/generator.cpp
|
|||
gui/widgets/grid.cpp
|
||||
gui/widgets/helper.cpp
|
||||
gui/widgets/pane.cpp
|
||||
gui/widgets/scroll_text.cpp
|
||||
gui/widgets/scrollbar.cpp
|
||||
gui/widgets/scrollbar_container.cpp
|
||||
gui/widgets/settings.cpp
|
||||
|
|
|
@ -97,7 +97,7 @@ pango_text::pango_text()
|
|||
pango_layout_set_ellipsize(layout_.get(), ellipse_mode_);
|
||||
pango_layout_set_alignment(layout_.get(), alignment_);
|
||||
pango_layout_set_wrap(layout_.get(), PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_line_spacing(layout_.get(), 1.3f);
|
||||
pango_layout_set_line_spacing(layout_.get(), get_line_spacing_factor());
|
||||
|
||||
cairo_font_options_t *fo = cairo_font_options_create();
|
||||
cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
|
||||
|
@ -193,18 +193,41 @@ unsigned pango_text::insert_text(const unsigned offset, const std::string& text)
|
|||
return len;
|
||||
}
|
||||
|
||||
int pango_text::get_byte_offset(const unsigned column) const
|
||||
{
|
||||
// First we need to determine the byte offset
|
||||
std::unique_ptr<PangoLayoutIter, std::function<void(PangoLayoutIter*)>> itor(
|
||||
pango_layout_get_iter(layout_.get()), pango_layout_iter_free);
|
||||
|
||||
// Go the wanted column.
|
||||
for(std::size_t i = 0; i < column; ++i) {
|
||||
if(!pango_layout_iter_next_char(itor.get())) {
|
||||
// It seems that the documentation is wrong and causes and off by
|
||||
// one error... the result should be false if already at the end of
|
||||
// the data when started.
|
||||
if(i + 1 == column) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the byte offset
|
||||
const int offset = pango_layout_iter_get_index(itor.get());
|
||||
return offset;
|
||||
}
|
||||
|
||||
point pango_text::get_cursor_position(const unsigned column, const unsigned line) const
|
||||
{
|
||||
this->recalculate();
|
||||
|
||||
// First we need to determine the byte offset, if more routines need it it
|
||||
// would be a good idea to make it a separate function.
|
||||
// Determing byte offset
|
||||
std::unique_ptr<PangoLayoutIter, std::function<void(PangoLayoutIter*)>> itor(
|
||||
pango_layout_get_iter(layout_.get()), pango_layout_iter_free);
|
||||
|
||||
// Go the wanted line.
|
||||
if(line != 0) {
|
||||
if(pango_layout_get_line_count(layout_.get()) >= static_cast<int>(line)) {
|
||||
|
||||
if(static_cast<int>(line) >= pango_layout_get_line_count(layout_.get())) {
|
||||
return point(0, 0);
|
||||
}
|
||||
|
||||
|
@ -222,7 +245,7 @@ point pango_text::get_cursor_position(const unsigned column, const unsigned line
|
|||
if(i + 1 == column) {
|
||||
break;
|
||||
}
|
||||
// We are beyond data.
|
||||
// Beyond data.
|
||||
return point(0, 0);
|
||||
}
|
||||
}
|
||||
|
@ -337,19 +360,40 @@ bool pango_text::set_text(const std::string& text, const bool markedup)
|
|||
<< " text '" << text
|
||||
<< "' contains invalid utf-8, trimmed the invalid parts.";
|
||||
}
|
||||
|
||||
if (highlight_start_offset_ != highlight_end_offset_) {
|
||||
/** Highlight */
|
||||
PangoAttrList *attribute_list = pango_attr_list_new();
|
||||
int col_r = highlight_color_.r / 255.0 * 65535.0;
|
||||
int col_g = highlight_color_.g / 255.0 * 65535.0;
|
||||
int col_b = highlight_color_.b / 255.0 * 65535.0;
|
||||
DBG_GUI_D << "highlight start : " << highlight_start_offset_ << "end : " << highlight_end_offset_;
|
||||
DBG_GUI_D << "highlight rgb : " << col_r << "," << col_g << "," << col_b;
|
||||
PangoAttribute *attr = pango_attr_background_new(col_r, col_g, col_b);
|
||||
attr->start_index = highlight_start_offset_;
|
||||
attr->end_index = highlight_end_offset_;
|
||||
pango_attr_list_insert(attribute_list, attr);
|
||||
|
||||
pango_layout_set_attributes(layout_.get(), attribute_list);
|
||||
}
|
||||
|
||||
if(markedup) {
|
||||
if(!this->set_markup(narrow, *layout_)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* pango_layout_set_text after pango_layout_set_markup might
|
||||
* leave the layout in an undefined state regarding markup so
|
||||
* clear it unconditionally.
|
||||
*/
|
||||
pango_layout_set_attributes(layout_.get(), nullptr);
|
||||
if (highlight_start_offset_ == highlight_end_offset_) {
|
||||
/*
|
||||
* pango_layout_set_text after pango_layout_set_markup might
|
||||
* leave the layout in an undefined state regarding markup so
|
||||
* clear it unconditionally.
|
||||
*/
|
||||
pango_layout_set_attributes(layout_.get(), nullptr);
|
||||
}
|
||||
|
||||
pango_layout_set_text(layout_.get(), narrow.c_str(), narrow.size());
|
||||
}
|
||||
|
||||
text_ = narrow;
|
||||
length_ = wide.size();
|
||||
markedup_text_ = markedup;
|
||||
|
@ -994,6 +1038,9 @@ std::size_t hash<font::pango_text>::operator()(const font::pango_text& t) const
|
|||
boost::hash_combine(hash, t.alignment_);
|
||||
boost::hash_combine(hash, t.ellipse_mode_);
|
||||
boost::hash_combine(hash, t.add_outline_);
|
||||
boost::hash_combine(hash, t.highlight_start_offset_);
|
||||
boost::hash_combine(hash, t.highlight_end_offset_);
|
||||
boost::hash_combine(hash, t.highlight_color_.to_rgba_bytes());
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <pango/pango.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -172,6 +174,18 @@ public:
|
|||
point get_cursor_position(
|
||||
const unsigned column, const unsigned line = 0) const;
|
||||
|
||||
/**
|
||||
* Gets the correct number of columns to move the cursor
|
||||
* from Pango. Needed in case the text contains multibyte
|
||||
* characters. Return value == column if the text has no
|
||||
* multibyte characters.
|
||||
*
|
||||
* @param column The column offset of the cursor.
|
||||
*
|
||||
* @returns Corrected column offset.
|
||||
*/
|
||||
int get_byte_offset(const unsigned column) const;
|
||||
|
||||
/**
|
||||
* Get maximum length.
|
||||
*
|
||||
|
@ -224,6 +238,14 @@ public:
|
|||
*/
|
||||
std::vector<std::string> get_lines() const;
|
||||
|
||||
/**
|
||||
* Get number of lines in the text.
|
||||
*
|
||||
* @returns The number of lines in the text.
|
||||
*
|
||||
*/
|
||||
unsigned get_lines_count() const { return pango_layout_get_line_count(layout_.get()); };
|
||||
|
||||
/**
|
||||
* Gets the length of the text in bytes.
|
||||
*
|
||||
|
@ -278,6 +300,21 @@ public:
|
|||
|
||||
pango_text& set_add_outline(bool do_add);
|
||||
|
||||
/**
|
||||
* Mark a specific portion of text for highlighting. Used for selection box.
|
||||
* BGColor is set in set_text(), this just marks the area to be colored.
|
||||
* Markup not used because the user may enter their own markup or special characters
|
||||
* @param start_offset Column offset of the cursor where selection/highlight starts
|
||||
* @param end_offset Column offset of the cursor where selection/highlight ends
|
||||
* @param color Highlight color
|
||||
*/
|
||||
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
highlight_start_offset_ = start_offset;
|
||||
highlight_end_offset_ = end_offset;
|
||||
highlight_color_ = color;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/***** ***** ***** ***** Pango variables ***** ***** ***** *****/
|
||||
|
@ -375,6 +412,10 @@ private:
|
|||
/** Length of the text. */
|
||||
mutable std::size_t length_;
|
||||
|
||||
unsigned highlight_start_offset_;
|
||||
unsigned highlight_end_offset_;
|
||||
color_t highlight_color_;
|
||||
|
||||
/** The pixel scale, used to render high-DPI text. */
|
||||
int pixel_scale_;
|
||||
|
||||
|
@ -488,6 +529,10 @@ pango_text& get_text_renderer();
|
|||
*/
|
||||
int get_max_height(unsigned size, font::family_class fclass = font::FONT_SANS_SERIF, pango_text::FONT_STYLE style = pango_text::STYLE_NORMAL);
|
||||
|
||||
/* Returns the default line spacing factor
|
||||
* For now hardcoded here */
|
||||
constexpr float get_line_spacing_factor() { return 1.3f; };
|
||||
|
||||
} // namespace font
|
||||
|
||||
// Specialize std::hash for pango_text
|
||||
|
|
|
@ -409,6 +409,9 @@ text_shape::text_shape(const config& cfg)
|
|||
, maximum_width_(cfg["maximum_width"], -1)
|
||||
, characters_per_line_(cfg["text_characters_per_line"])
|
||||
, maximum_height_(cfg["maximum_height"], -1)
|
||||
, highlight_start_(cfg["highlight_start"], 0)
|
||||
, highlight_end_(cfg["highlight_end"], 0)
|
||||
, highlight_color_(cfg["highlight_color"], color_t::from_hex_string("215380"))
|
||||
{
|
||||
if(!font_size_.has_formula()) {
|
||||
VALIDATE(font_size_(), _("Text has a font size of 0."));
|
||||
|
@ -436,6 +439,9 @@ void text_shape::draw(wfl::map_formula_callable& variables)
|
|||
|
||||
font::pango_text& text_renderer = font::get_text_renderer();
|
||||
|
||||
text_renderer.set_highlight_area(highlight_start_(variables), highlight_end_(variables), highlight_color_(variables));
|
||||
|
||||
|
||||
text_renderer
|
||||
.set_link_aware(link_aware_(variables))
|
||||
.set_link_color(link_color_(variables))
|
||||
|
|
|
@ -447,6 +447,12 @@ private:
|
|||
|
||||
/** The maximum height for the text. */
|
||||
typed_formula<int> maximum_height_;
|
||||
|
||||
/** Start and end offsets for highlight */
|
||||
typed_formula<int> highlight_start_;
|
||||
typed_formula<int> highlight_end_;
|
||||
/** The color to be used for highlighting */
|
||||
typed_formula<color_t> highlight_color_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
514
src/gui/widgets/multiline_text.cpp
Normal file
514
src/gui/widgets/multiline_text.cpp
Normal file
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/widgets/multiline_text.hpp"
|
||||
|
||||
#include "color.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "gui/core/register_widget.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "preferences/game.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
#include "font/text.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
|
||||
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
REGISTER_WIDGET(multiline_text)
|
||||
|
||||
multiline_text::multiline_text(const implementation::builder_styled_widget& builder)
|
||||
: text_box_base(builder, type())
|
||||
, history_()
|
||||
, max_input_length_(0)
|
||||
, text_x_offset_(0)
|
||||
, text_y_offset_(0)
|
||||
, text_height_(0)
|
||||
, dragging_(false)
|
||||
, line_num_(0)
|
||||
{
|
||||
set_wants_mouse_left_double_click();
|
||||
|
||||
connect_signal<event::MOUSE_MOTION>(std::bind(
|
||||
&multiline_text::signal_handler_mouse_motion, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
|
||||
connect_signal<event::LEFT_BUTTON_DOWN>(std::bind(
|
||||
&multiline_text::signal_handler_left_button_down, this, std::placeholders::_2, std::placeholders::_3));
|
||||
connect_signal<event::LEFT_BUTTON_UP>(std::bind(
|
||||
&multiline_text::signal_handler_left_button_up, this, std::placeholders::_2, std::placeholders::_3));
|
||||
connect_signal<event::LEFT_BUTTON_DOUBLE_CLICK>(std::bind(
|
||||
&multiline_text::signal_handler_left_button_double_click, this, std::placeholders::_2, std::placeholders::_3));
|
||||
|
||||
const auto conf = cast_config_to<multiline_text_definition>();
|
||||
assert(conf);
|
||||
|
||||
set_font_size(get_text_font_size());
|
||||
set_font_style(conf->text_font_style);
|
||||
|
||||
update_offsets();
|
||||
}
|
||||
|
||||
void multiline_text::place(const point& origin, const point& size)
|
||||
{
|
||||
// Inherited.
|
||||
styled_widget::place(origin, size);
|
||||
|
||||
set_maximum_width(get_text_maximum_width());
|
||||
set_maximum_height(get_text_maximum_height(), false);
|
||||
|
||||
set_maximum_length(max_input_length_);
|
||||
|
||||
update_offsets();
|
||||
}
|
||||
|
||||
void multiline_text::update_canvas()
|
||||
{
|
||||
/***** Gather the info *****/
|
||||
|
||||
// Set the cursor info.
|
||||
const unsigned start = get_selection_start();
|
||||
const int length = static_cast<int>(get_selection_length());
|
||||
|
||||
// Set the cursor info.
|
||||
const unsigned edit_start = get_composition_start();
|
||||
const int edit_length = get_composition_length();
|
||||
|
||||
set_maximum_length(max_input_length_);
|
||||
|
||||
// Set the composition info
|
||||
unsigned comp_start_offset = 0;
|
||||
unsigned comp_end_offset = 0;
|
||||
if(edit_length == 0) {
|
||||
// No nothing.
|
||||
} else if(edit_length > 0) {
|
||||
comp_start_offset = get_cursor_position(edit_start).x;
|
||||
comp_end_offset = get_cursor_position(edit_start + edit_length).x;
|
||||
} else {
|
||||
comp_start_offset = get_cursor_position(edit_start + edit_length).x;
|
||||
comp_end_offset = get_cursor_position(edit_start).x;
|
||||
}
|
||||
|
||||
set_line_num_from_offset();
|
||||
|
||||
/***** Set in all canvases *****/
|
||||
|
||||
const int max_width = get_text_maximum_width();
|
||||
const int max_height = get_text_maximum_height();
|
||||
|
||||
for(auto & tmp : get_canvases())
|
||||
{
|
||||
|
||||
tmp.set_variable("text", wfl::variant(get_value()));
|
||||
tmp.set_variable("text_x_offset", wfl::variant(text_x_offset_));
|
||||
tmp.set_variable("text_y_offset", wfl::variant(text_y_offset_));
|
||||
tmp.set_variable("text_maximum_width", wfl::variant(max_width));
|
||||
tmp.set_variable("text_maximum_height", wfl::variant(max_height));
|
||||
tmp.set_variable("text_wrap_mode", wfl::variant(PANGO_ELLIPSIZE_NONE));
|
||||
|
||||
tmp.set_variable("editable", wfl::variant(is_editable()));
|
||||
|
||||
if (length < 0) {
|
||||
tmp.set_variable("highlight_start", wfl::variant(get_byte_offset(start+length)));
|
||||
tmp.set_variable("highlight_end", wfl::variant(get_byte_offset(start)));
|
||||
} else {
|
||||
tmp.set_variable("highlight_start", wfl::variant(get_byte_offset(start)));
|
||||
tmp.set_variable("highlight_end", wfl::variant(get_byte_offset(start+length)));
|
||||
}
|
||||
|
||||
tmp.set_variable("cursor_offset_x",
|
||||
wfl::variant(get_cursor_position(start + length).x));
|
||||
tmp.set_variable("cursor_offset_y",
|
||||
wfl::variant(get_cursor_position(start + length).y));
|
||||
|
||||
tmp.set_variable("composition_offset", wfl::variant(comp_start_offset));
|
||||
tmp.set_variable("composition_width", wfl::variant(comp_end_offset - comp_start_offset));
|
||||
|
||||
tmp.set_variable("hint_text", wfl::variant(hint_text_));
|
||||
tmp.set_variable("hint_image", wfl::variant(hint_image_));
|
||||
}
|
||||
}
|
||||
|
||||
void multiline_text::delete_char(const bool before_cursor)
|
||||
{
|
||||
if(!is_editable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(before_cursor) {
|
||||
set_cursor(get_selection_start() - 1, false);
|
||||
}
|
||||
|
||||
set_selection_length(1);
|
||||
|
||||
delete_selection();
|
||||
}
|
||||
|
||||
void multiline_text::delete_selection()
|
||||
{
|
||||
if(get_selection_length() == 0 || (!is_editable()) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a negative range change it to a positive range.
|
||||
// This makes the rest of the algorithms easier.
|
||||
int len = get_selection_length();
|
||||
unsigned start = get_selection_start();
|
||||
if(len < 0) {
|
||||
len = -len;
|
||||
start -= len;
|
||||
}
|
||||
|
||||
std::string tmp = get_value();
|
||||
set_value(utf8::erase(tmp, start, len));
|
||||
set_cursor(start, false);
|
||||
|
||||
update_layout();
|
||||
}
|
||||
|
||||
void multiline_text::handle_mouse_selection(point mouse, const bool start_selection)
|
||||
{
|
||||
mouse.x -= get_x();
|
||||
mouse.y -= get_y();
|
||||
// FIXME we don't test for overflow in width
|
||||
if(mouse.x < static_cast<int>(text_x_offset_)
|
||||
|| mouse.y < static_cast<int>(text_y_offset_)
|
||||
|| mouse.y >= static_cast<int>(text_y_offset_ + get_lines_count() * font::get_line_spacing_factor() * text_height_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
point cursor_pos = get_column_line(point(mouse.x - text_x_offset_, mouse.y - text_y_offset_));
|
||||
int offset = cursor_pos.x;
|
||||
int line = cursor_pos.y;
|
||||
|
||||
if(offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
offset += get_line_start_offset(line);
|
||||
|
||||
line_num_ = get_line_num_from_offset(offset);
|
||||
|
||||
// moving scrollbars during click causes viewport to jump
|
||||
set_cursor(offset, !start_selection, false);
|
||||
|
||||
update_canvas();
|
||||
queue_redraw();
|
||||
dragging_ |= start_selection;
|
||||
}
|
||||
|
||||
unsigned multiline_text::get_line_end_offset(unsigned line_no) {
|
||||
// Should be cached if needed
|
||||
std::string line = get_lines().at(line_no);
|
||||
// Get correct number of characters to move for multibyte utf8 string.
|
||||
int line_size = utf8::size(line);
|
||||
return get_line_start_offset(line_no) + line_size;
|
||||
}
|
||||
|
||||
unsigned multiline_text::get_line_start_offset(unsigned line_no) {
|
||||
if (line_no > 0) {
|
||||
return get_line_end_offset(line_no-1) + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned multiline_text::get_line_num_from_offset(unsigned offset) {
|
||||
unsigned line_start = 0, line_end = 0, line_no = 0;
|
||||
for(unsigned i = 0; i < get_lines_count(); i++) {
|
||||
line_start = get_line_start_offset(i);
|
||||
line_end = get_line_end_offset(i);
|
||||
if ((offset >= line_start) && (offset <= line_end)) {
|
||||
line_no = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return line_no;
|
||||
}
|
||||
|
||||
void multiline_text::set_line_num_from_offset()
|
||||
{
|
||||
line_num_ = get_line_num_from_offset(get_selection_start());
|
||||
}
|
||||
|
||||
void multiline_text::update_offsets()
|
||||
{
|
||||
const auto conf = cast_config_to<multiline_text_definition>();
|
||||
assert(conf);
|
||||
|
||||
text_height_ = font::get_max_height(get_text_font_size(), get_font_family());
|
||||
|
||||
wfl::map_formula_callable variables;
|
||||
variables.add("height", wfl::variant(get_height()));
|
||||
variables.add("width", wfl::variant(get_width()));
|
||||
variables.add("text_font_height", wfl::variant(text_height_));
|
||||
|
||||
text_x_offset_ = conf->text_x_offset(variables);
|
||||
text_y_offset_ = conf->text_y_offset(variables);
|
||||
|
||||
// Since this variable doesn't change set it here instead of in
|
||||
// update_canvas().
|
||||
for(auto & tmp : get_canvases())
|
||||
{
|
||||
tmp.set_variable("text_font_height", wfl::variant(text_height_));
|
||||
}
|
||||
|
||||
// Force an update of the canvas since now text_font_height is known.
|
||||
update_canvas();
|
||||
}
|
||||
|
||||
bool multiline_text::history_up()
|
||||
{
|
||||
if(!history_.get_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string str = history_.up(get_value());
|
||||
if(!str.empty()) {
|
||||
set_value(str);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool multiline_text::history_down()
|
||||
{
|
||||
if(!history_.get_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string str = history_.down(get_value());
|
||||
if(!str.empty()) {
|
||||
set_value(str);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void multiline_text::handle_key_tab(SDL_Keymod modifier, bool& handled)
|
||||
{
|
||||
if(!is_editable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(modifier & KMOD_CTRL) {
|
||||
if(!(modifier & KMOD_SHIFT)) {
|
||||
handled = history_up();
|
||||
} else {
|
||||
handled = history_down();
|
||||
}
|
||||
} else {
|
||||
handled = true;
|
||||
insert_char("\t");
|
||||
}
|
||||
}
|
||||
|
||||
void multiline_text::handle_key_enter(SDL_Keymod modifier, bool& handled)
|
||||
{
|
||||
if (is_editable() && !(modifier & (KMOD_CTRL | KMOD_ALT | KMOD_GUI))) {
|
||||
insert_char("\n");
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void multiline_text::handle_key_clear_line(SDL_Keymod /*modifier*/, bool& handled)
|
||||
{
|
||||
handled = true;
|
||||
|
||||
set_value("");
|
||||
}
|
||||
|
||||
void multiline_text::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
|
||||
{
|
||||
DBG_GUI_E << LOG_SCOPE_HEADER;
|
||||
|
||||
handled = true;
|
||||
|
||||
set_line_num_from_offset();
|
||||
size_t offset = get_selection_start();
|
||||
|
||||
if (line_num_ < get_lines_count()-1) {
|
||||
offset = offset
|
||||
- get_line_start_offset(line_num_)
|
||||
+ get_line_start_offset(line_num_+1);
|
||||
|
||||
if (offset > get_line_end_offset(line_num_+1)) {
|
||||
offset = get_line_end_offset(line_num_+1);
|
||||
}
|
||||
}
|
||||
|
||||
offset += get_selection_length();
|
||||
|
||||
if (offset <= get_length()) {
|
||||
set_cursor(offset, (modifier & KMOD_SHIFT) != 0);
|
||||
}
|
||||
|
||||
update_canvas();
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
void multiline_text::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
|
||||
{
|
||||
DBG_GUI_E << LOG_SCOPE_HEADER;
|
||||
|
||||
handled = true;
|
||||
|
||||
set_line_num_from_offset();
|
||||
size_t offset = get_selection_start();
|
||||
|
||||
if (line_num_ > 0) {
|
||||
offset = offset
|
||||
- get_line_start_offset(line_num_)
|
||||
+ get_line_start_offset(line_num_-1);
|
||||
|
||||
if (offset > get_line_end_offset(line_num_-1)) {
|
||||
offset = get_line_end_offset(line_num_-1);
|
||||
}
|
||||
}
|
||||
|
||||
offset += get_selection_length();
|
||||
|
||||
/* offset is unsigned int */
|
||||
if (offset <= get_length()) {
|
||||
set_cursor(offset, (modifier & KMOD_SHIFT) != 0);
|
||||
}
|
||||
|
||||
update_canvas();
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
void multiline_text::signal_handler_mouse_motion(const event::ui_event event,
|
||||
bool& handled,
|
||||
const point& coordinate)
|
||||
{
|
||||
DBG_GUI_E << get_control_type() << "[" << id() << "]: " << event << ".";
|
||||
|
||||
if(dragging_) {
|
||||
handle_mouse_selection(coordinate, false);
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
|
||||
void multiline_text::signal_handler_left_button_down(const event::ui_event event,
|
||||
bool& handled)
|
||||
{
|
||||
DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
|
||||
|
||||
/*
|
||||
* Copied from the base class see how we can do inheritance with the new
|
||||
* system...
|
||||
*/
|
||||
get_window()->keyboard_capture(this);
|
||||
get_window()->mouse_capture();
|
||||
|
||||
handle_mouse_selection(get_mouse_position(), true);
|
||||
|
||||
handled = true;
|
||||
}
|
||||
|
||||
void multiline_text::signal_handler_left_button_up(const event::ui_event event,
|
||||
bool& handled)
|
||||
{
|
||||
DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
|
||||
|
||||
dragging_ = false;
|
||||
handled = true;
|
||||
}
|
||||
|
||||
void
|
||||
multiline_text::signal_handler_left_button_double_click(const event::ui_event event,
|
||||
bool& handled)
|
||||
{
|
||||
DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
|
||||
|
||||
select_all();
|
||||
handled = true;
|
||||
}
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
multiline_text_definition::multiline_text_definition(const config& cfg)
|
||||
: styled_widget_definition(cfg)
|
||||
{
|
||||
DBG_GUI_P << "Parsing multiline_text " << id;
|
||||
|
||||
load_resolutions<resolution>(cfg);
|
||||
}
|
||||
|
||||
multiline_text_definition::resolution::resolution(const config& cfg)
|
||||
: resolution_definition(cfg)
|
||||
, text_x_offset(cfg["text_x_offset"])
|
||||
, text_y_offset(cfg["text_y_offset"])
|
||||
{
|
||||
// Note the order should be the same as the enum state_t in multiline_text.hpp.
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", _("Missing required state for editable text box")));
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", _("Missing required state for editable text box")));
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_focused", _("Missing required state for editable text box")));
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_hovered", _("Missing required state for editable text box")));
|
||||
}
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
builder_multiline_text::builder_multiline_text(const config& cfg)
|
||||
: builder_styled_widget(cfg)
|
||||
, history(cfg["history"])
|
||||
, max_input_length(cfg["max_input_length"])
|
||||
, hint_text(cfg["hint_text"].t_str())
|
||||
, hint_image(cfg["hint_image"])
|
||||
, editable(cfg["editable"].to_bool(true))
|
||||
, wrap(cfg["wrap"].to_bool(true))
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<widget> builder_multiline_text::build() const
|
||||
{
|
||||
auto widget = std::make_unique<multiline_text>(*this);
|
||||
|
||||
widget->set_editable(editable);
|
||||
// A textbox doesn't have a label but a text
|
||||
widget->set_value(label_string);
|
||||
|
||||
if(!history.empty()) {
|
||||
widget->set_history(history);
|
||||
}
|
||||
|
||||
widget->set_max_input_length(max_input_length);
|
||||
widget->set_hint_data(hint_text, hint_image);
|
||||
|
||||
DBG_GUI_G << "Window builder: placed text box '" << id
|
||||
<< "' with definition '" << definition << "'.";
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
392
src/gui/widgets/multiline_text.hpp
Normal file
392
src/gui/widgets/multiline_text.hpp
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/widgets/text_box_base.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "gui/widgets/scrollbar_container.hpp"
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
namespace implementation
|
||||
{
|
||||
struct builder_multiline_text;
|
||||
}
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
/**
|
||||
* @ingroup GUIWidgetWML
|
||||
*
|
||||
* Base class for a multiline text area.
|
||||
*
|
||||
* The resolution for a text box also contains the following keys:
|
||||
* Key |Type |Default |Description
|
||||
* -------------|----------------------------------------|---------|-----------
|
||||
* text_x_offset| @ref guivartype_f_unsigned "f_unsigned"|"" |The x offset of the text in the text box. This is needed for the code to determine where in the text the mouse clicks, so it can set the cursor properly.
|
||||
* text_y_offset| @ref guivartype_f_unsigned "f_unsigned"|"" |The y offset of the text in the text box.
|
||||
* The following states exist:
|
||||
* * state_enabled - the text box is enabled.
|
||||
* * state_disabled - the text box is disabled.
|
||||
* * state_focussed - the text box has the focus of the keyboard.
|
||||
* The following variables exist:
|
||||
* Key |Type |Default |Description
|
||||
* -------------|------------------------------------|---------|-----------
|
||||
* label | @ref guivartype_t_string "t_string"|"" |The initial text of the text box.
|
||||
* history | @ref guivartype_string "string" |"" |The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.
|
||||
* editable | @ref guivartype_bool "bool" |"true" |If the contents of the text box can be edited.
|
||||
*/
|
||||
class multiline_text : public text_box_base
|
||||
{
|
||||
friend struct implementation::builder_multiline_text;
|
||||
|
||||
public:
|
||||
explicit multiline_text(const implementation::builder_styled_widget& builder);
|
||||
|
||||
/** See @ref widget::can_wrap. */
|
||||
bool can_wrap() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Saves the text in the widget to the history. */
|
||||
void save_to_history()
|
||||
{
|
||||
history_.push(get_value());
|
||||
}
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
void set_history(const std::string& id)
|
||||
{
|
||||
history_ = text_history::get_history(id, true);
|
||||
}
|
||||
|
||||
void set_max_input_length(const std::size_t length)
|
||||
{
|
||||
max_input_length_ = length;
|
||||
}
|
||||
|
||||
void set_hint_data(const std::string& text, const std::string& image)
|
||||
{
|
||||
hint_text_ = text;
|
||||
hint_image_ = image;
|
||||
|
||||
update_canvas();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
set_value("");
|
||||
}
|
||||
|
||||
unsigned get_line_no()
|
||||
{
|
||||
set_line_num_from_offset();
|
||||
return line_num_;
|
||||
}
|
||||
|
||||
point get_cursor_pos()
|
||||
{
|
||||
return get_cursor_position(get_selection_start());
|
||||
}
|
||||
|
||||
int get_line_end_pos()
|
||||
{
|
||||
return get_cursor_position(get_line_end_offset(line_num_)).x;
|
||||
}
|
||||
|
||||
point get_text_end_pos()
|
||||
{
|
||||
return get_cursor_position(get_length());
|
||||
}
|
||||
|
||||
protected:
|
||||
/***** ***** ***** ***** layout functions ***** ***** ***** *****/
|
||||
|
||||
/** See @ref widget::place. */
|
||||
virtual void place(const point& origin, const point& size) override;
|
||||
|
||||
/***** ***** ***** ***** Inherited ***** ***** ***** *****/
|
||||
|
||||
/** See @ref styled_widget::update_canvas. */
|
||||
virtual void update_canvas() override;
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void insert_char(const std::string& unicode) override
|
||||
{
|
||||
text_box_base::insert_char(unicode);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void set_cursor(const std::size_t offset, const bool select, const bool autoscroll = true)
|
||||
{
|
||||
text_box_base::set_cursor(offset, select);
|
||||
set_line_num_from_offset();
|
||||
|
||||
if (autoscroll) {
|
||||
// Whenever cursor moves, this tells scroll_text to update the scrollbars
|
||||
update_layout();
|
||||
}
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void goto_end_of_line(const bool select = false) override
|
||||
{
|
||||
set_line_num_from_offset();
|
||||
set_cursor(get_line_end_offset(line_num_), select);
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void goto_start_of_line(const bool select = false) override
|
||||
{
|
||||
set_line_num_from_offset();
|
||||
set_cursor(get_line_start_offset(line_num_), select);
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void goto_end_of_data(const bool select = false) override
|
||||
{
|
||||
text_box_base::goto_end_of_data(select);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void goto_start_of_data(const bool select = false) override
|
||||
{
|
||||
text_box_base::goto_start_of_data(select);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void paste_selection(const bool mouse) override
|
||||
{
|
||||
text_box_base::paste_selection(mouse);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void delete_char(const bool before_cursor) override;
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void delete_selection() override;
|
||||
|
||||
void handle_mouse_selection(point mouse, const bool start_selection);
|
||||
|
||||
private:
|
||||
/** The history text for this widget. */
|
||||
text_history history_;
|
||||
|
||||
/** The maximum length of the text input. */
|
||||
std::size_t max_input_length_;
|
||||
|
||||
/**
|
||||
* The x offset in the widget where the text starts.
|
||||
*
|
||||
* This value is needed to translate a location in the widget to a location
|
||||
* in the text.
|
||||
*/
|
||||
unsigned text_x_offset_;
|
||||
|
||||
/**
|
||||
* The y offset in the widget where the text starts.
|
||||
*
|
||||
* Needed to determine whether a click is on the text.
|
||||
*/
|
||||
unsigned text_y_offset_;
|
||||
|
||||
/**
|
||||
* The height of the text itself.
|
||||
*
|
||||
* Needed to determine whether a click is on the text.
|
||||
*/
|
||||
unsigned text_height_;
|
||||
|
||||
/** Updates text_x_offset_ and text_y_offset_. */
|
||||
void update_offsets();
|
||||
|
||||
/** Is the mouse in dragging mode, this affects selection in mouse move */
|
||||
bool dragging_;
|
||||
|
||||
/** Helper text to display (such as "Search") if the text box is empty. */
|
||||
std::string hint_text_;
|
||||
|
||||
/** Image (such as a magnifying glass) that accompanies the help text. */
|
||||
std::string hint_image_;
|
||||
|
||||
/** Line number of text */
|
||||
unsigned line_num_;
|
||||
|
||||
/** utility function to calculate and set line_num_ from offset */
|
||||
void set_line_num_from_offset();
|
||||
unsigned get_line_num_from_offset(unsigned offset);
|
||||
|
||||
/** Utility function to calculate the offset of the end of the line
|
||||
*/
|
||||
unsigned get_line_end_offset(unsigned line_no);
|
||||
/** Utility function to calculate the offset of the end of the line
|
||||
*/
|
||||
unsigned get_line_start_offset(unsigned line_no);
|
||||
|
||||
/** Update layout. To be called when text size changes */
|
||||
void update_layout() {
|
||||
set_label(get_value());
|
||||
get_window()->invalidate_layout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inherited from text_box_base.
|
||||
*
|
||||
* Unmodified Handled.
|
||||
* Control Ignored.
|
||||
* Shift Ignored.
|
||||
* Alt Ignored.
|
||||
*/
|
||||
void handle_key_up_arrow(SDL_Keymod /*modifier*/, bool& handled) override;
|
||||
|
||||
/**
|
||||
* Inherited from text_box_base.
|
||||
*
|
||||
* Unmodified Handled.
|
||||
* Control Ignored.
|
||||
* Shift Ignored.
|
||||
* Alt Ignored.
|
||||
*/
|
||||
void handle_key_down_arrow(SDL_Keymod /*modifier*/, bool& handled) override;
|
||||
|
||||
/**
|
||||
* Inherited from text_box_base.
|
||||
*
|
||||
* Unmodified Handled.
|
||||
* Control Ignored.
|
||||
* Shift Ignored.
|
||||
* Alt Ignored.
|
||||
*/
|
||||
void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) override
|
||||
{
|
||||
text_box_base::handle_key_left_arrow(modifier, handled);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherited from text_box_base.
|
||||
*
|
||||
* Unmodified Handled.
|
||||
* Control Ignored.
|
||||
* Shift Ignored.
|
||||
* Alt Ignored.
|
||||
*/
|
||||
void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) override
|
||||
{
|
||||
text_box_base::handle_key_right_arrow(modifier, handled);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes one item up in the history.
|
||||
*
|
||||
* @returns True if there's a history, false otherwise.
|
||||
*/
|
||||
bool history_up();
|
||||
|
||||
/**
|
||||
* Goes one item down in the history.
|
||||
*
|
||||
* @returns True if there's a history, false otherwise.
|
||||
*/
|
||||
bool history_down();
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void handle_key_tab(SDL_Keymod modifier, bool& handled) override;
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void handle_key_enter(SDL_Keymod modifier, bool& handled) override;
|
||||
|
||||
/** Inherited from text_box_base. */
|
||||
void handle_key_clear_line(SDL_Keymod modifier, bool& handled) override;
|
||||
|
||||
public:
|
||||
/** Static type getter that does not rely on the widget being constructed. */
|
||||
static const std::string& type();
|
||||
|
||||
private:
|
||||
|
||||
/** Inherited from styled_widget, implemented by REGISTER_WIDGET. */
|
||||
virtual const std::string& get_control_type() const override;
|
||||
|
||||
/***** ***** ***** signal handlers ***** ****** *****/
|
||||
|
||||
void signal_handler_mouse_motion(const event::ui_event event,
|
||||
bool& handled,
|
||||
const point& coordinate);
|
||||
|
||||
void signal_handler_left_button_down(const event::ui_event event,
|
||||
bool& handled);
|
||||
|
||||
void signal_handler_left_button_up(const event::ui_event event,
|
||||
bool& handled);
|
||||
|
||||
void signal_handler_left_button_double_click(const event::ui_event event,
|
||||
bool& handled);
|
||||
};
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
struct multiline_text_definition : public styled_widget_definition
|
||||
{
|
||||
explicit multiline_text_definition(const config& cfg);
|
||||
|
||||
struct resolution : public resolution_definition
|
||||
{
|
||||
explicit resolution(const config& cfg);
|
||||
|
||||
typed_formula<unsigned> text_x_offset;
|
||||
typed_formula<unsigned> text_y_offset;
|
||||
};
|
||||
};
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
struct builder_multiline_text : public builder_styled_widget
|
||||
{
|
||||
public:
|
||||
explicit builder_multiline_text(const config& cfg);
|
||||
|
||||
using builder_styled_widget::build;
|
||||
|
||||
virtual std::unique_ptr<widget> build() const override;
|
||||
|
||||
std::string history;
|
||||
|
||||
std::size_t max_input_length;
|
||||
|
||||
t_string hint_text;
|
||||
std::string hint_image;
|
||||
|
||||
bool editable;
|
||||
bool wrap;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
251
src/gui/widgets/scroll_text.cpp
Normal file
251
src/gui/widgets/scroll_text.cpp
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/widgets/scroll_text.hpp"
|
||||
|
||||
#include "gui/widgets/multiline_text.hpp"
|
||||
#include "gui/auxiliary/find_widget.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "gui/core/window_builder/helper.hpp"
|
||||
#include "gui/core/register_widget.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/scrollbar.hpp"
|
||||
#include "gui/widgets/spacer.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
|
||||
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
REGISTER_WIDGET(scroll_text)
|
||||
|
||||
scroll_text::scroll_text(const implementation::builder_scroll_text& builder)
|
||||
: scrollbar_container(builder, type())
|
||||
, state_(ENABLED)
|
||||
, wrap_on_(false)
|
||||
, text_alignment_(builder.text_alignment)
|
||||
{
|
||||
connect_signal<event::LEFT_BUTTON_DOWN>(
|
||||
std::bind(&scroll_text::signal_handler_left_button_down, this, std::placeholders::_2),
|
||||
event::dispatcher::back_pre_child);
|
||||
}
|
||||
|
||||
multiline_text* scroll_text::get_internal_text_box()
|
||||
{
|
||||
if(content_grid()) {
|
||||
return dynamic_cast<multiline_text*>(content_grid()->find("_text", false));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void scroll_text::set_label(const t_string& label)
|
||||
{
|
||||
if(multiline_text* widget = get_internal_text_box()) {
|
||||
widget->set_value(label);
|
||||
widget->set_label(label);
|
||||
|
||||
bool resize_needed = !content_resize_request();
|
||||
if(resize_needed && get_size() != point()) {
|
||||
place(get_origin(), get_size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string scroll_text::get_value()
|
||||
{
|
||||
if(multiline_text* widget = get_internal_text_box()) {
|
||||
return widget->get_value();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_text::set_text_alignment(const PangoAlignment text_alignment)
|
||||
{
|
||||
// Inherit.
|
||||
styled_widget::set_text_alignment(text_alignment);
|
||||
|
||||
text_alignment_ = text_alignment;
|
||||
|
||||
if(multiline_text* widget = get_internal_text_box()) {
|
||||
widget->set_text_alignment(text_alignment_);
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_text::set_use_markup(bool use_markup)
|
||||
{
|
||||
// Inherit.
|
||||
styled_widget::set_use_markup(use_markup);
|
||||
|
||||
if(multiline_text* widget = get_internal_text_box()) {
|
||||
widget->set_use_markup(use_markup);
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_text::set_self_active(const bool active)
|
||||
{
|
||||
state_ = active ? ENABLED : DISABLED;
|
||||
}
|
||||
|
||||
bool scroll_text::get_active() const
|
||||
{
|
||||
return state_ != DISABLED;
|
||||
}
|
||||
|
||||
unsigned scroll_text::get_state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
void scroll_text::finalize_subclass()
|
||||
{
|
||||
multiline_text* text = get_internal_text_box();
|
||||
assert(text);
|
||||
|
||||
text->set_editable(is_editable());
|
||||
text->set_label(get_label());
|
||||
text->set_text_alignment(text_alignment_);
|
||||
text->set_use_markup(get_use_markup());
|
||||
}
|
||||
|
||||
void scroll_text::place(const point& origin, const point& size) {
|
||||
scrollbar_container::place(origin, size);
|
||||
|
||||
if(multiline_text* widget = get_internal_text_box()) {
|
||||
const SDL_Rect& visible_area = content_visible_area();
|
||||
|
||||
if (widget->get_cursor_pos().x < visible_area.w/2.0) {
|
||||
scroll_horizontal_scrollbar(scrollbar_base::BEGIN);
|
||||
} else {
|
||||
scroll_horizontal_scrollbar_by(widget->get_cursor_pos().x - visible_area.w/2.0);
|
||||
}
|
||||
|
||||
if (widget->get_cursor_pos().y >= (widget->get_text_end_pos().y - visible_area.h/2.0)) {
|
||||
if (widget->get_lines_count() > 1) {
|
||||
scroll_vertical_scrollbar(scrollbar_base::END);
|
||||
} else {
|
||||
scroll_vertical_scrollbar(scrollbar_base::BEGIN);
|
||||
}
|
||||
} else if (widget->get_cursor_pos().y < visible_area.h/2.0) {
|
||||
scroll_vertical_scrollbar(scrollbar_base::BEGIN);
|
||||
} else {
|
||||
scroll_vertical_scrollbar_by(widget->get_cursor_pos().y - visible_area.h/2.0);
|
||||
}
|
||||
|
||||
if (widget->get_length() == 0) {
|
||||
scroll_horizontal_scrollbar(scrollbar_base::BEGIN);
|
||||
scroll_vertical_scrollbar(scrollbar_base::BEGIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_text::set_can_wrap(bool can_wrap)
|
||||
{
|
||||
wrap_on_ = can_wrap;
|
||||
}
|
||||
|
||||
bool scroll_text::can_wrap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void scroll_text::signal_handler_left_button_down(const event::ui_event event)
|
||||
{
|
||||
DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
|
||||
|
||||
get_window()->keyboard_capture(this);
|
||||
}
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
scroll_text_definition::scroll_text_definition(const config& cfg)
|
||||
: styled_widget_definition(cfg)
|
||||
{
|
||||
DBG_GUI_P << "Parsing scroll label " << id;
|
||||
|
||||
load_resolutions<resolution>(cfg);
|
||||
}
|
||||
|
||||
scroll_text_definition::resolution::resolution(const config& cfg)
|
||||
: resolution_definition(cfg), grid(nullptr)
|
||||
{
|
||||
// Note the order should be the same as the enum state_t is scroll_text.hpp.
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", _("Missing required state for scroll label control")));
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", _("Missing required state for scroll label control")));
|
||||
|
||||
auto child = VALIDATE_WML_CHILD(cfg, "grid", _("No grid defined for scroll label control"));
|
||||
grid = std::make_shared<builder_grid>(child);
|
||||
}
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
builder_scroll_text::builder_scroll_text(const config& cfg)
|
||||
: implementation::builder_styled_widget(cfg)
|
||||
, vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
|
||||
, horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
|
||||
, text_alignment(decode_text_alignment(cfg["text_alignment"]))
|
||||
, editable(cfg["editable"].to_bool(true))
|
||||
{
|
||||
/** Horizontal scrollbar default to auto. AUTO_VISIBLE_FIRST_RUN doesn't work. */
|
||||
if (horizontal_scrollbar_mode == scrollbar_container::AUTO_VISIBLE_FIRST_RUN) {
|
||||
horizontal_scrollbar_mode = scrollbar_container::AUTO_VISIBLE;
|
||||
}
|
||||
|
||||
if (vertical_scrollbar_mode == scrollbar_container::AUTO_VISIBLE_FIRST_RUN) {
|
||||
vertical_scrollbar_mode = scrollbar_container::AUTO_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<widget> builder_scroll_text::build() const
|
||||
{
|
||||
auto widget = std::make_unique<scroll_text>(*this);
|
||||
|
||||
widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
|
||||
widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
|
||||
widget->set_editable(editable);
|
||||
widget->set_text_alignment(text_alignment);
|
||||
|
||||
const auto conf = widget->cast_config_to<scroll_text_definition>();
|
||||
assert(conf);
|
||||
|
||||
widget->init_grid(*conf->grid);
|
||||
widget->finalize_setup();
|
||||
|
||||
DBG_GUI_G << "Window builder: placed scroll label '" << id
|
||||
<< "' with definition '" << definition << "'.";
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
220
src/gui/widgets/scroll_text.hpp
Normal file
220
src/gui/widgets/scroll_text.hpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/widgets/scrollbar_container.hpp"
|
||||
|
||||
#include "gui/core/widget_definition.hpp"
|
||||
#include "gui/core/window_builder.hpp"
|
||||
|
||||
#include "gui/widgets/multiline_text.hpp"
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
class label;
|
||||
class spacer;
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
struct builder_scroll_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup GUIWidgetWML
|
||||
*
|
||||
* Scrollable text area
|
||||
*
|
||||
* A multiline text area that shows a scrollbar if the text gets too long.
|
||||
*
|
||||
* Key |Type |Default |Description
|
||||
* -------------|----------------------------|---------|-----------
|
||||
* grid | @ref guivartype_grid "grid"|mandatory|A grid containing the widgets for main widget.
|
||||
*
|
||||
* TODO: we need one definition for a vertical scrollbar since this is the second time we use it.
|
||||
*
|
||||
* ID (return value)|Type |Default |Description
|
||||
* -----------------|----------------------------|---------|-----------
|
||||
* _content_grid | @ref guivartype_grid "grid"|mandatory|A grid which should only contain one multiline_text widget.
|
||||
* _scrollbar_grid | @ref guivartype_grid "grid"|mandatory|A grid for the scrollbar (Merge with listbox info.)
|
||||
*
|
||||
* Description of necessary widgets contained inside _content_grid :
|
||||
*
|
||||
* ID (return value)|Type |Default |Description
|
||||
* -----------------|--------------------------------|---------|-----------
|
||||
* _text | @ref gui2::text_box |mandatory|The text_box that shows the value.
|
||||
* The following states exist:
|
||||
* * state_enabled - the scroll text is enabled.
|
||||
* * state_disabled - the scroll text is disabled.
|
||||
* List with the scrollbar container specific variables:
|
||||
* Key |Type |Default |Description
|
||||
* -------------------------|------------------------------------------------|------------|-----------
|
||||
* vertical_scrollbar_mode | @ref guivartype_scrollbar_mode "scrollbar_mode"|initial_auto|Determines whether or not to show the scrollbar.
|
||||
* horizontal_scrollbar_mode| @ref guivartype_scrollbar_mode "scrollbar_mode"|initial_auto|Determines whether or not to show the scrollbar.
|
||||
* editable | @ref guivartype_bool "bool" |"true" |If the contents of included multiline_text can be edited.
|
||||
*/
|
||||
class scroll_text : public scrollbar_container
|
||||
{
|
||||
friend struct implementation::builder_scroll_text;
|
||||
|
||||
public:
|
||||
explicit scroll_text(const implementation::builder_scroll_text& builder);
|
||||
|
||||
// /** See @ref styled_widget::set_label. */
|
||||
virtual void set_label(const t_string& label) override;
|
||||
|
||||
// void set_value(const std::string text);
|
||||
|
||||
void set_value(const t_string& label) {
|
||||
set_label(label);
|
||||
}
|
||||
|
||||
std::string get_value();
|
||||
|
||||
/** See @ref styled_widget::set_text_alignment. */
|
||||
virtual void set_text_alignment(const PangoAlignment text_alignment) override;
|
||||
|
||||
/** See @ref styled_widget::set_use_markup. */
|
||||
virtual void set_use_markup(bool use_markup) override;
|
||||
|
||||
/** See @ref container_base::set_self_active. */
|
||||
virtual void set_self_active(const bool active) override;
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
/** See @ref styled_widget::get_active. */
|
||||
virtual bool get_active() const override;
|
||||
|
||||
/** See @ref styled_widget::get_state. */
|
||||
virtual unsigned get_state() const override;
|
||||
|
||||
bool can_wrap() const override;
|
||||
void set_can_wrap(bool can_wrap);
|
||||
|
||||
void set_editable(bool editable)
|
||||
{
|
||||
editable_ = editable;
|
||||
}
|
||||
|
||||
bool is_editable()
|
||||
{
|
||||
return editable_;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Possible states of the widget.
|
||||
*
|
||||
* Note the order of the states must be the same as defined in settings.hpp.
|
||||
*/
|
||||
enum state_t {
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
};
|
||||
|
||||
// It's not needed for now so keep it disabled, no definition exists yet.
|
||||
// void set_state(const state_t state);
|
||||
|
||||
/**
|
||||
* Current state of the widget.
|
||||
*
|
||||
* The state of the widget determines what to render and how the widget
|
||||
* reacts to certain 'events'.
|
||||
*/
|
||||
state_t state_;
|
||||
|
||||
bool wrap_on_;
|
||||
|
||||
PangoAlignment text_alignment_;
|
||||
|
||||
bool editable_;
|
||||
|
||||
void finalize_subclass() override;
|
||||
|
||||
/** Used for moving scrollbars.
|
||||
Has to be called from signal notify_modified, otherwise
|
||||
doesn't work after invalidate_layout. */
|
||||
void refresh();
|
||||
|
||||
unsigned get_horizontal_position() {
|
||||
assert(horizontal_scrollbar());
|
||||
return horizontal_scrollbar()->get_positioner_offset();
|
||||
}
|
||||
|
||||
unsigned get_vertical_position() {
|
||||
assert(vertical_scrollbar());
|
||||
return vertical_scrollbar()->get_positioner_offset();
|
||||
}
|
||||
|
||||
void place(const point& origin, const point& size);
|
||||
|
||||
public:
|
||||
/** Static type getter that does not rely on the widget being constructed. */
|
||||
static const std::string& type();
|
||||
|
||||
multiline_text* get_internal_text_box();
|
||||
|
||||
private:
|
||||
/***** ***** ***** inherited ****** *****/
|
||||
|
||||
/** Inherited from styled_widget, implemented by REGISTER_WIDGET. */
|
||||
virtual const std::string& get_control_type() const override;
|
||||
|
||||
/***** ***** ***** signal handlers ***** ****** *****/
|
||||
|
||||
void signal_handler_left_button_down(const event::ui_event event);
|
||||
};
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
struct scroll_text_definition : public styled_widget_definition
|
||||
{
|
||||
explicit scroll_text_definition(const config& cfg);
|
||||
|
||||
struct resolution : public resolution_definition
|
||||
{
|
||||
explicit resolution(const config& cfg);
|
||||
|
||||
builder_grid_ptr grid;
|
||||
};
|
||||
};
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
struct builder_scroll_text : public builder_styled_widget
|
||||
{
|
||||
explicit builder_scroll_text(const config& cfg);
|
||||
|
||||
using builder_styled_widget::build;
|
||||
|
||||
virtual std::unique_ptr<widget> build() const override;
|
||||
|
||||
scrollbar_container::scrollbar_mode vertical_scrollbar_mode;
|
||||
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode;
|
||||
const PangoAlignment text_alignment;
|
||||
bool editable;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
|
@ -179,14 +179,14 @@ public:
|
|||
return pixels_per_step_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void finalize_setup();
|
||||
|
||||
unsigned get_positioner_offset() const
|
||||
{
|
||||
return positioner_offset_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void finalize_setup();
|
||||
|
||||
unsigned get_positioner_length() const
|
||||
{
|
||||
return positioner_length_;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -972,6 +973,22 @@ void scrollbar_container::scroll_horizontal_scrollbar(const scrollbar_base::scro
|
|||
scrollbar_moved();
|
||||
}
|
||||
|
||||
void scrollbar_container::scroll_vertical_scrollbar_by(const int pixels)
|
||||
{
|
||||
assert(vertical_scrollbar_);
|
||||
|
||||
vertical_scrollbar_->scroll_by(pixels);
|
||||
move_viewport(0, pixels);
|
||||
}
|
||||
|
||||
void scrollbar_container::scroll_horizontal_scrollbar_by(const int pixels)
|
||||
{
|
||||
assert(horizontal_scrollbar_);
|
||||
|
||||
horizontal_scrollbar_->scroll_by(pixels);
|
||||
move_viewport(pixels, 0);
|
||||
}
|
||||
|
||||
void scrollbar_container::handle_key_home(SDL_Keymod /*modifier*/, bool& handled)
|
||||
{
|
||||
assert(vertical_scrollbar_ && horizontal_scrollbar_);
|
||||
|
@ -1057,7 +1074,6 @@ void scrollbar_container::handle_key_right_arrow(SDL_Keymod /*modifier*/, bool&
|
|||
void scrollbar_container::scrollbar_moved()
|
||||
{
|
||||
// Init.
|
||||
assert(content_ && content_grid_);
|
||||
assert(vertical_scrollbar_ && horizontal_scrollbar_);
|
||||
|
||||
/*** Update the content location. ***/
|
||||
|
@ -1069,7 +1085,15 @@ void scrollbar_container::scrollbar_moved()
|
|||
? 0
|
||||
: vertical_scrollbar_->get_item_position() * vertical_scrollbar_->get_step_size();
|
||||
|
||||
const point content_origin {content_->get_x() - x_offset, content_->get_y() - y_offset};
|
||||
move_viewport(x_offset, y_offset);
|
||||
}
|
||||
|
||||
void scrollbar_container::move_viewport(const int pixels_x, const int pixels_y)
|
||||
{
|
||||
// Init.
|
||||
assert(content_ && content_grid_);
|
||||
|
||||
const point content_origin {content_->get_x() - pixels_x, content_->get_y() - pixels_y};
|
||||
|
||||
content_grid_->set_origin(content_origin);
|
||||
content_grid_->set_visible_rectangle(content_visible_area_);
|
||||
|
|
|
@ -223,6 +223,20 @@ public:
|
|||
*/
|
||||
void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll);
|
||||
|
||||
/**
|
||||
* Scrolls the vertical scrollbar by pixel.
|
||||
*
|
||||
* @param pixels The number of pixels the bar scrolls by.
|
||||
*/
|
||||
void scroll_vertical_scrollbar_by(const int pixels);
|
||||
|
||||
/**
|
||||
* Scrolls the horizontal scrollbar by pixel.
|
||||
*
|
||||
* @param pixels The number of pixels the bar scrolls by.
|
||||
*/
|
||||
void scroll_horizontal_scrollbar_by(const int pixels);
|
||||
|
||||
/**
|
||||
* Callback when the scrollbar moves (NOTE maybe only one callback needed).
|
||||
* Maybe also make protected or private and add a friend.
|
||||
|
@ -448,6 +462,10 @@ protected:
|
|||
*/
|
||||
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
|
||||
|
||||
protected:
|
||||
/** The builder needs to call us so we do our setup. */
|
||||
void finalize_setup();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Possible states of the widget.
|
||||
|
@ -494,9 +512,6 @@ private:
|
|||
*/
|
||||
SDL_Rect content_visible_area_;
|
||||
|
||||
/** The builder needs to call us so we do our setup. */
|
||||
void finalize_setup(); // FIXME make protected
|
||||
|
||||
/**
|
||||
* Function for the subclasses to do their setup.
|
||||
*
|
||||
|
@ -523,10 +538,14 @@ private:
|
|||
*/
|
||||
virtual void set_content_size(const point& origin, const point& size);
|
||||
|
||||
/** Helper function which needs to be called after the scollbar moved. */
|
||||
/** Helper function which needs to be called after the scollbar moves by item. */
|
||||
void scrollbar_moved();
|
||||
|
||||
public:
|
||||
/** To be called after the scollbar moves manually (by pixel) to move the viewport.
|
||||
* Shifts the viewport origin pixels_x left and pixels_y right.*/
|
||||
void move_viewport(const int pixels_x, const int pixels_y);
|
||||
|
||||
/** Static type getter that does not rely on the widget being constructed. */
|
||||
static const std::string& type();
|
||||
|
||||
|
|
180
src/gui/widgets/spinner.cpp
Normal file
180
src/gui/widgets/spinner.cpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "gui/widgets/spinner.hpp"
|
||||
|
||||
#include "gui/auxiliary/find_widget.hpp"
|
||||
#include "gui/widgets/repeating_button.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "gui/core/window_builder/helper.hpp"
|
||||
#include "gui/core/register_widget.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
|
||||
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
REGISTER_WIDGET(spinner)
|
||||
|
||||
spinner::spinner(const implementation::builder_spinner& builder)
|
||||
: container_base(builder, type())
|
||||
, state_(ENABLED)
|
||||
, step_size_(1)
|
||||
, invalid_(false)
|
||||
{
|
||||
connect_signal<event::LEFT_BUTTON_DOWN>(
|
||||
std::bind(&spinner::signal_handler_left_button_down, this, std::placeholders::_2),
|
||||
event::dispatcher::back_pre_child);
|
||||
}
|
||||
|
||||
text_box* spinner::get_internal_text_box()
|
||||
{
|
||||
return find_widget<text_box>(this, "_text", false, true);
|
||||
}
|
||||
|
||||
void spinner::set_value(const int val)
|
||||
{
|
||||
text_box* edit_area = get_internal_text_box();
|
||||
if (edit_area != nullptr) {
|
||||
edit_area->set_value(std::to_string(val));
|
||||
}
|
||||
}
|
||||
|
||||
int spinner::get_value()
|
||||
{
|
||||
/* Return 0 if invalid.
|
||||
* TODO: give visual indication of wrong value
|
||||
*/
|
||||
int val;
|
||||
try {
|
||||
text_box* edit_area = get_internal_text_box();
|
||||
if (edit_area != nullptr) {
|
||||
val = stoi(edit_area->get_value());
|
||||
invalid_ = false;
|
||||
} else {
|
||||
val = 0;
|
||||
invalid_ = true;
|
||||
}
|
||||
} catch(std::invalid_argument const& /*ex*/) {
|
||||
val = 0;
|
||||
invalid_ = true;
|
||||
} catch(std::out_of_range const& /*ex*/) {
|
||||
val = 0;
|
||||
invalid_ = true;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void spinner::finalize_setup()
|
||||
{
|
||||
repeating_button* btn_prev = find_widget<repeating_button>(this, "_prev", false, true);
|
||||
repeating_button* btn_next = find_widget<repeating_button>(this, "_next", false, true);
|
||||
btn_prev->connect_signal_mouse_left_down(std::bind(&spinner::prev, this));
|
||||
btn_next->connect_signal_mouse_left_down(std::bind(&spinner::next, this));
|
||||
|
||||
}
|
||||
|
||||
void spinner::set_self_active(const bool active)
|
||||
{
|
||||
state_ = active ? ENABLED : DISABLED;
|
||||
}
|
||||
|
||||
bool spinner::get_active() const
|
||||
{
|
||||
return state_ != DISABLED;
|
||||
}
|
||||
|
||||
unsigned spinner::get_state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
bool spinner::can_wrap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void spinner::signal_handler_left_button_down(const event::ui_event event)
|
||||
{
|
||||
DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
|
||||
|
||||
get_window()->keyboard_capture(this);
|
||||
}
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
spinner_definition::spinner_definition(const config& cfg)
|
||||
: styled_widget_definition(cfg)
|
||||
{
|
||||
DBG_GUI_P << "Parsing spinner " << id;
|
||||
|
||||
load_resolutions<resolution>(cfg);
|
||||
}
|
||||
|
||||
spinner_definition::resolution::resolution(const config& cfg)
|
||||
: resolution_definition(cfg), grid(nullptr)
|
||||
{
|
||||
// Note the order should be the same as the enum state_t is spinner.hpp.
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", _("Missing required state for scroll label control")));
|
||||
state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", _("Missing required state for scroll label control")));
|
||||
|
||||
auto child = VALIDATE_WML_CHILD(cfg, "grid", _("No grid defined for scroll label control"));
|
||||
grid = std::make_shared<builder_grid>(child);
|
||||
}
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
builder_spinner::builder_spinner(const config& cfg)
|
||||
: implementation::builder_styled_widget(cfg)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<widget> builder_spinner::build() const
|
||||
{
|
||||
auto widget = std::make_unique<spinner>(*this);
|
||||
|
||||
const auto conf = widget->cast_config_to<spinner_definition>();
|
||||
assert(conf);
|
||||
|
||||
widget->init_grid(*conf->grid);
|
||||
widget->finalize_setup();
|
||||
|
||||
DBG_GUI_G << "Window builder: placed spinner '" << id
|
||||
<< "' with definition '" << definition << "'.";
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
197
src/gui/widgets/spinner.hpp
Normal file
197
src/gui/widgets/spinner.hpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
Copyright (C) 2023 - 2024
|
||||
by babaissarkar(Subhraman Sarkar) <suvrax@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/widgets/container_base.hpp"
|
||||
|
||||
#include "gui/core/widget_definition.hpp"
|
||||
#include "gui/core/window_builder.hpp"
|
||||
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace gui2
|
||||
{
|
||||
|
||||
// ------------ WIDGET -----------{
|
||||
|
||||
class label;
|
||||
class spacer;
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
struct builder_spinner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup GUIWidgetWML
|
||||
*
|
||||
* Spinner widget.
|
||||
*
|
||||
* A widget with a text_box and two button (named _prev and _next) that allows user to increase
|
||||
* or decrease the numeric value inside the text_box. Non-numeric values are considered as zero.
|
||||
*
|
||||
* Key |Type |Default |Description
|
||||
* -------------|----------------------------|---------|-----------
|
||||
* grid | @ref guivartype_grid "grid"|mandatory|A grid containing the widgets for main widget.
|
||||
*
|
||||
* TODO: we need one definition for a vertical scrollbar since this is the second time we use it.
|
||||
*
|
||||
* ID (return value)|Type |Default |Description
|
||||
* -----------------|--------------------------------|---------|-----------
|
||||
* _content_grid | @ref guivartype_grid "grid" |mandatory|A grid which should contain a text_box and two buttons.
|
||||
*
|
||||
* Description of necessary widgets contained inside _content_grid :
|
||||
*
|
||||
* ID (return value)|Type |Default |Description
|
||||
* -----------------|--------------------------------|---------|-----------
|
||||
* _text | @ref gui2::text_box |mandatory|The text_box that shows the value.
|
||||
* _prev | @ref gui2::button |mandatory|The previous button, clicking on it decreases value by 1.
|
||||
* _next | @ref gui2::button |mandatory|The next button, clicking on it increases value by 1.
|
||||
* The following states exist:
|
||||
* * state_enabled - the spinner is enabled.
|
||||
* * state_disabled - the spinner is disabled.
|
||||
*/
|
||||
class spinner : public container_base
|
||||
{
|
||||
friend struct implementation::builder_spinner;
|
||||
|
||||
public:
|
||||
explicit spinner(const implementation::builder_spinner& builder);
|
||||
|
||||
/** See @ref container_base::set_self_active. */
|
||||
virtual void set_self_active(const bool active) override;
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
/** See @ref styled_widget::get_active. */
|
||||
virtual bool get_active() const override;
|
||||
|
||||
/** See @ref styled_widget::get_state. */
|
||||
virtual unsigned get_state() const override;
|
||||
|
||||
bool can_wrap() const override;
|
||||
|
||||
void set_value(const int val);
|
||||
|
||||
int get_value();
|
||||
|
||||
void prev()
|
||||
{
|
||||
// Allow negatives?
|
||||
if (get_value() > 0) {
|
||||
set_value(get_value() - step_size_);
|
||||
} else {
|
||||
if (invalid_) {
|
||||
set_value(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void next()
|
||||
{
|
||||
int val = get_value();
|
||||
if (!invalid_) {
|
||||
// No max value
|
||||
set_value(val + step_size_);
|
||||
} else {
|
||||
set_value(0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Possible states of the widget.
|
||||
*
|
||||
* Note the order of the states must be the same as defined in settings.hpp.
|
||||
*/
|
||||
enum state_t {
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
};
|
||||
|
||||
// It's not needed for now so keep it disabled, no definition exists yet.
|
||||
// void set_state(const state_t state);
|
||||
|
||||
/**
|
||||
* Current state of the widget.
|
||||
*
|
||||
* The state of the widget determines what to render and how the widget
|
||||
* reacts to certain 'events'.
|
||||
*/
|
||||
state_t state_;
|
||||
|
||||
/** The grid that holds the content. */
|
||||
std::unique_ptr<grid> content_grid_;
|
||||
|
||||
int step_size_;
|
||||
|
||||
/** If the entered data is invalid. */
|
||||
bool invalid_;
|
||||
|
||||
text_box* get_internal_text_box();
|
||||
|
||||
void finalize_setup();
|
||||
|
||||
public:
|
||||
/** Static type getter that does not rely on the widget being constructed. */
|
||||
static const std::string& type();
|
||||
|
||||
private:
|
||||
/***** ***** ***** inherited ****** *****/
|
||||
|
||||
/** Inherited from styled_widget, implemented by REGISTER_WIDGET. */
|
||||
virtual const std::string& get_control_type() const override;
|
||||
|
||||
/***** ***** ***** signal handlers ***** ****** *****/
|
||||
|
||||
void signal_handler_left_button_down(const event::ui_event event);
|
||||
};
|
||||
|
||||
// }---------- DEFINITION ---------{
|
||||
|
||||
struct spinner_definition : public styled_widget_definition
|
||||
{
|
||||
explicit spinner_definition(const config& cfg);
|
||||
|
||||
struct resolution : public resolution_definition
|
||||
{
|
||||
explicit resolution(const config& cfg);
|
||||
|
||||
builder_grid_ptr grid;
|
||||
};
|
||||
};
|
||||
|
||||
// }---------- BUILDER -----------{
|
||||
|
||||
namespace implementation
|
||||
{
|
||||
|
||||
struct builder_spinner : public builder_styled_widget
|
||||
{
|
||||
explicit builder_spinner(const config& cfg);
|
||||
|
||||
using builder_styled_widget::build;
|
||||
|
||||
virtual std::unique_ptr<widget> build() const override;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
// }------------ END --------------
|
||||
|
||||
} // namespace gui2
|
|
@ -233,7 +233,7 @@ public:
|
|||
return label_;
|
||||
}
|
||||
|
||||
virtual void set_label(const t_string& label);
|
||||
virtual void set_label(const t_string& text);
|
||||
|
||||
virtual void set_use_markup(bool use_markup);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ text_box_base::text_box_base(const implementation::builder_styled_widget& builde
|
|||
, text_()
|
||||
, selection_start_(0)
|
||||
, selection_length_(0)
|
||||
, editable_(true)
|
||||
, ime_composing_(false)
|
||||
, ime_start_point_(0)
|
||||
, cursor_timer_(0)
|
||||
|
@ -48,7 +49,7 @@ text_box_base::text_box_base(const implementation::builder_styled_widget& builde
|
|||
, text_changed_callback_()
|
||||
{
|
||||
auto cfg = get_control(control_type, builder.definition);
|
||||
text_.set_family_class(cfg->text_font_family);
|
||||
set_font_family(cfg->text_font_family);
|
||||
|
||||
#ifdef __unix__
|
||||
// pastes on UNIX systems.
|
||||
|
@ -153,8 +154,11 @@ void text_box_base::set_cursor(const std::size_t offset, const bool select)
|
|||
queue_redraw();
|
||||
|
||||
} else {
|
||||
assert(offset <= text_.get_length());
|
||||
selection_start_ = offset;
|
||||
if (offset <= text_.get_length()) {
|
||||
selection_start_ = offset;
|
||||
} else {
|
||||
selection_start_ = 0;
|
||||
}
|
||||
selection_length_ = 0;
|
||||
|
||||
update_canvas();
|
||||
|
@ -164,6 +168,11 @@ void text_box_base::set_cursor(const std::size_t offset, const bool select)
|
|||
|
||||
void text_box_base::insert_char(const std::string& unicode)
|
||||
{
|
||||
if(!editable_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
delete_selection();
|
||||
|
||||
if(text_.insert_text(selection_start_, unicode)) {
|
||||
|
@ -220,6 +229,11 @@ void text_box_base::copy_selection(const bool mouse)
|
|||
|
||||
void text_box_base::paste_selection(const bool mouse)
|
||||
{
|
||||
if(!editable_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& text = desktop::clipboard::copy_from_clipboard(mouse);
|
||||
if(text.empty()) {
|
||||
return;
|
||||
|
@ -584,17 +598,28 @@ void text_box_base::signal_handler_sdl_key_down(const event::ui_event event,
|
|||
break;
|
||||
|
||||
case SDLK_BACKSPACE:
|
||||
if (!is_editable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
handle_key_backspace(modifier, handled);
|
||||
break;
|
||||
|
||||
case SDLK_u:
|
||||
if(!(modifier & KMOD_CTRL)) {
|
||||
if( !(modifier & KMOD_CTRL) || !is_editable() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
handle_key_clear_line(modifier, handled);
|
||||
break;
|
||||
|
||||
case SDLK_DELETE:
|
||||
if (!is_editable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
handle_key_delete(modifier, handled);
|
||||
break;
|
||||
|
||||
|
@ -610,17 +635,20 @@ void text_box_base::signal_handler_sdl_key_down(const event::ui_event event,
|
|||
break;
|
||||
|
||||
case SDLK_x:
|
||||
if(!(modifier & modifier_key)) {
|
||||
if( !(modifier & modifier_key) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy_selection(false);
|
||||
delete_selection();
|
||||
|
||||
if ( is_editable() ) {
|
||||
delete_selection();
|
||||
}
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case SDLK_v:
|
||||
if(!(modifier & modifier_key)) {
|
||||
if( !(modifier & modifier_key) || !is_editable() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -630,11 +658,14 @@ void text_box_base::signal_handler_sdl_key_down(const event::ui_event event,
|
|||
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER:
|
||||
if(!is_composing() || (modifier & (KMOD_CTRL | KMOD_ALT | KMOD_GUI | KMOD_SHIFT))) {
|
||||
return;
|
||||
}
|
||||
// The IME will handle it, we just need to make sure nothing else handles it too.
|
||||
handled = true;
|
||||
|
||||
// TODO: check if removing the following check causes any side effects
|
||||
// To be removed if there aren't any text rendering problems.
|
||||
// if(!is_composing()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
handle_key_enter(modifier, handled);
|
||||
break;
|
||||
|
||||
case SDLK_ESCAPE:
|
||||
|
@ -645,6 +676,10 @@ void text_box_base::signal_handler_sdl_key_down(const event::ui_event event,
|
|||
handled = true;
|
||||
break;
|
||||
|
||||
case SDLK_TAB:
|
||||
handle_key_tab(modifier, handled);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Don't call the text changed callback if nothing happened.
|
||||
return;
|
||||
|
|
|
@ -65,11 +65,52 @@ public:
|
|||
|
||||
void set_maximum_length(const std::size_t maximum_length);
|
||||
|
||||
/**
|
||||
* Wrapper function, returns length of the text in pango column offsets.
|
||||
* See @ref font::pango_text::get_length.
|
||||
*/
|
||||
std::size_t get_length() const
|
||||
{
|
||||
return text_.get_length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function, returns a vector with the lines.
|
||||
* See @ref font::pango_text::get_lines.
|
||||
*/
|
||||
std::vector<std::string> get_lines()
|
||||
{
|
||||
return text_.get_lines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function, return number of lines.
|
||||
* See @ref font::pango_text::get_lines_count.
|
||||
*/
|
||||
unsigned get_lines_count() const
|
||||
{
|
||||
return text_.get_lines_count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function, returns corrected column offset from pango.
|
||||
* See @ref font::pango_text::get_byte_offset.
|
||||
*/
|
||||
int get_byte_offset(const unsigned column) const
|
||||
{
|
||||
return text_.get_byte_offset(column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function, sets the area between column start and end
|
||||
* offset to be highlighted in a specific color.
|
||||
* See @ref font::pango_text::set_highlight_area.
|
||||
*/
|
||||
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
text_.set_highlight_area(start_offset, end_offset, color);
|
||||
}
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
/**
|
||||
|
@ -118,6 +159,17 @@ public:
|
|||
*/
|
||||
void set_selection(std::size_t start, int length);
|
||||
|
||||
void set_editable(bool editable)
|
||||
{
|
||||
editable_ = editable;
|
||||
update_canvas();
|
||||
}
|
||||
|
||||
bool is_editable()
|
||||
{
|
||||
return editable_;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Get length of composition text by IME **/
|
||||
size_t get_composition_length() const;
|
||||
|
@ -138,7 +190,7 @@ protected:
|
|||
* @param select Select the text from the original cursor
|
||||
* position till the end of the data?
|
||||
*/
|
||||
void goto_end_of_data(const bool select = false)
|
||||
virtual void goto_end_of_data(const bool select = false)
|
||||
{
|
||||
set_cursor(text_.get_length(), select);
|
||||
}
|
||||
|
@ -157,7 +209,7 @@ protected:
|
|||
* @param select Select the text from the original cursor
|
||||
* position till the beginning of the data?
|
||||
*/
|
||||
void goto_start_of_data(const bool select = false)
|
||||
virtual void goto_start_of_data(const bool select = false)
|
||||
{
|
||||
set_cursor(0, select);
|
||||
}
|
||||
|
@ -176,7 +228,7 @@ protected:
|
|||
* @param select Select the text from the original cursor
|
||||
* position till the new position?
|
||||
*/
|
||||
void set_cursor(const std::size_t offset, const bool select);
|
||||
virtual void set_cursor(const std::size_t offset, const bool select);
|
||||
|
||||
/**
|
||||
* Inserts a character at the cursor.
|
||||
|
@ -219,6 +271,17 @@ protected:
|
|||
return text_.get_column_line(position);
|
||||
}
|
||||
|
||||
font::family_class get_font_family()
|
||||
{
|
||||
return font_family_;
|
||||
}
|
||||
|
||||
void set_font_family(font::family_class fclass)
|
||||
{
|
||||
font_family_ = fclass;
|
||||
text_.set_family_class(font_family_);
|
||||
}
|
||||
|
||||
void set_font_size(const unsigned font_size)
|
||||
{
|
||||
text_.set_font_size(font_size);
|
||||
|
@ -303,6 +366,9 @@ private:
|
|||
/** The text entered in the widget. */
|
||||
font::pango_text text_;
|
||||
|
||||
/** font family */
|
||||
font::family_class font_family_;
|
||||
|
||||
/** Cached version of the text without any pending IME modifications. */
|
||||
std::string text_cached_;
|
||||
|
||||
|
@ -318,6 +384,9 @@ private:
|
|||
*/
|
||||
int selection_length_;
|
||||
|
||||
/** If this text_box_base is editable */
|
||||
bool editable_;
|
||||
|
||||
// Values to support input method editors
|
||||
bool ime_composing_;
|
||||
int ime_start_point_;
|
||||
|
@ -377,7 +446,7 @@ private:
|
|||
* Alt Ignored.
|
||||
*/
|
||||
virtual void handle_key_clear_line(SDL_Keymod modifier, bool& handled) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Left arrow key pressed.
|
||||
*
|
||||
|
@ -400,6 +469,7 @@ private:
|
|||
*/
|
||||
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Home key pressed.
|
||||
*
|
||||
|
@ -483,6 +553,18 @@ private:
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter key.
|
||||
*
|
||||
* Unmodified Handled by Window.
|
||||
* Control Implementation defined.
|
||||
* Shift Implementation defined.
|
||||
* Alt Implementation defined.
|
||||
*/
|
||||
virtual void handle_key_enter(SDL_Keymod /*modifier*/, bool& /*handled*/)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void handle_commit(bool& handled,
|
||||
const std::string& unicode);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "gui/dialogs/tooltip.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/container_base.hpp"
|
||||
#include "gui/widgets/multiline_text.hpp"
|
||||
#include "gui/widgets/text_box_base.hpp"
|
||||
#include "gui/core/register_widget.hpp"
|
||||
#include "gui/widgets/grid.hpp"
|
||||
|
@ -1306,9 +1307,18 @@ void window::signal_handler_sdl_key_down(const event::ui_event event,
|
|||
}
|
||||
}
|
||||
}
|
||||
if(!enter_disabled_ && (key == SDLK_KP_ENTER || key == SDLK_RETURN)) {
|
||||
set_retval(retval::OK);
|
||||
handled = true;
|
||||
if(key == SDLK_KP_ENTER || key == SDLK_RETURN) {
|
||||
if (mod & (KMOD_CTRL | KMOD_ALT | KMOD_GUI | KMOD_SHIFT)) {
|
||||
// Don't handle if modifier is pressed
|
||||
handled = false;
|
||||
} else {
|
||||
// Trigger window OK button only if Enter enabled,
|
||||
// otherwise pass handling to widget
|
||||
if (!enter_disabled_) {
|
||||
set_retval(retval::OK);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
} else if(key == SDLK_ESCAPE && !escape_disabled_) {
|
||||
set_retval(retval::CANCEL);
|
||||
handled = true;
|
||||
|
|
Loading…
Add table
Reference in a new issue