diff --git a/TabletFriend/TabletFriend/.editorconfig b/TabletFriend/TabletFriend/.editorconfig new file mode 100644 index 0000000..0d27111 --- /dev/null +++ b/TabletFriend/TabletFriend/.editorconfig @@ -0,0 +1,200 @@ +# Rules in this file were initially inferred by Visual Studio IntelliCode from the \TabletFriend\TabletFriend\ codebase based on best match to current usage at 15.04.2022 +# You can modify the rules from these initially generated values to suit your own policies +# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference +[*.cs] + + +#Core editorconfig formatting - indentation + +#use hard tabs for indentation +indent_style = tab + +#Formatting - new line options + +#place catch statements on a new line +csharp_new_line_before_catch = true +#place else statements on a new line +csharp_new_line_before_else = true +#require members of object initializers to be on the same line +csharp_new_line_before_members_in_object_initializers = false +#require braces to be on a new line for control_blocks, lambdas, object_collection_array_initializers, methods, types, and properties (also known as "Allman" style) +csharp_new_line_before_open_brace = control_blocks, lambdas, object_collection_array_initializers, methods, types, properties + +#Formatting - organize using options + +#sort System.* using directives alphabetically, and place them before other usings +dotnet_sort_system_directives_first = true + +#Formatting - spacing options + +#require NO space between a cast and the value +csharp_space_after_cast = false +#require a space before the colon for bases or interfaces in a type declaration +csharp_space_after_colon_in_inheritance_clause = true +#require a space after a keyword in a control flow statement such as a for loop +csharp_space_after_keywords_in_control_flow_statements = true +#require a space before the colon for bases or interfaces in a type declaration +csharp_space_before_colon_in_inheritance_clause = true +#remove space within empty argument list parentheses +csharp_space_between_method_call_empty_parameter_list_parentheses = false +#remove space between method call name and opening parenthesis +csharp_space_between_method_call_name_and_opening_parenthesis = false +#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call +csharp_space_between_method_call_parameter_list_parentheses = false +#remove space within empty parameter list parentheses for a method declaration +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list. +csharp_space_between_method_declaration_parameter_list_parentheses = false + +#Formatting - wrapping options + +#leave code block on single line +csharp_preserve_single_line_blocks = true +#leave statements and member declarations on the same line +csharp_preserve_single_line_statements = true + +#Style - Code block preferences + +#prefer curly braces even for one line of code +csharp_prefer_braces = true:suggestion + +#Style - expression bodied member options + +#prefer expression-bodied members for accessors +csharp_style_expression_bodied_accessors = true:suggestion +#prefer block bodies for constructors +csharp_style_expression_bodied_constructors = false:suggestion +#prefer expression-bodied members for methods when they will be a single line +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +#prefer expression-bodied members for properties +csharp_style_expression_bodied_properties = true:suggestion + +#Style - expression level options + +#prefer out variables to be declared inline in the argument list of a method call when possible +csharp_style_inlined_variable_declaration = true:suggestion +#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them +dotnet_style_predefined_type_for_member_access = true:suggestion + +#Style - Expression-level preferences + +#prefer default(T) over default +csharp_prefer_simple_default_expression = false:suggestion +#prefer objects to be initialized using object initializers when possible +dotnet_style_object_initializer = true:suggestion + +#Style - implicit and explicit types + +#prefer var over explicit type in all cases, unless overridden by another code style rule +csharp_style_var_elsewhere = true:suggestion +#prefer var is used to declare variables with built-in system types such as int +csharp_style_var_for_built_in_types = true:suggestion +#prefer var when the type is already mentioned on the right-hand side of a declaration expression +csharp_style_var_when_type_is_apparent = true:suggestion + +#Style - language keyword and framework type options + +#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion + +#Style - Miscellaneous preferences + +#prefer local functions over anonymous functions +csharp_style_pattern_local_over_anonymous_function = true:suggestion + +#Style - modifier options + +#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods. +dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion + +#Style - Modifier preferences + +#when this rule is set to a list of modifiers, prefer the specified ordering. +csharp_preferred_modifier_order = public,private,internal,protected,static,readonly,async,extern,override:suggestion + +#Style - qualification options + +#prefer events not to be prefaced with this. or Me. in Visual Basic +dotnet_style_qualification_for_event = false:suggestion +#prefer fields not to be prefaced with this. or Me. in Visual Basic +dotnet_style_qualification_for_field = false:suggestion +#prefer methods not to be prefaced with this. or Me. in Visual Basic +dotnet_style_qualification_for_method = false:suggestion +#prefer properties not to be prefaced with this. or Me. in Visual Basic +dotnet_style_qualification_for_property = false:suggestion +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case diff --git a/TabletFriend/TabletFriend/Data/ButtonData.cs b/TabletFriend/TabletFriend/Data/ButtonData.cs index d7b2819..e93889b 100644 --- a/TabletFriend/TabletFriend/Data/ButtonData.cs +++ b/TabletFriend/TabletFriend/Data/ButtonData.cs @@ -5,6 +5,10 @@ public class ButtonData { public string Action; public string[] Actions; + + public string ActionRelease; + public string[] ActionsRelease; + public string Text; public string Icon; public StretchData IconStretch; diff --git a/TabletFriend/TabletFriend/Models/ButtonModel.cs b/TabletFriend/TabletFriend/Models/ButtonModel.cs index 468aa4d..9ef6a45 100644 --- a/TabletFriend/TabletFriend/Models/ButtonModel.cs +++ b/TabletFriend/TabletFriend/Models/ButtonModel.cs @@ -10,9 +10,22 @@ namespace TabletFriend.Models { + public enum ButtonProcessedEvent + { + None, + Down, + Up + + } public class ButtonModel : IDisposable { public ButtonAction Action; + public ButtonAction ActionRelease; + + /// + /// Logging of last processed event to avoid multiple invocations due to double triggered mouse and touch events when action(s)_release is used + /// + public ButtonProcessedEvent LastProcessedEvent { get; set; } = ButtonProcessedEvent.None; public string Text = ""; public object Icon; @@ -81,6 +94,15 @@ public ButtonModel(ButtonData data) Action = new BatchAction(ButtonActionResolver.Resolve(data.Actions)); } + if (data.ActionsRelease == null || data.ActionsRelease.Length == 0) + { + ActionRelease = ButtonActionResolver.Resolve(data.ActionRelease); + } + else + { + ActionRelease = new BatchAction(ButtonActionResolver.Resolve(data.ActionsRelease)); + } + Style = data.Style; Font = data.Font; diff --git a/TabletFriend/TabletFriend/UiFactory.cs b/TabletFriend/TabletFriend/UiFactory.cs index 3f357f8..81d9346 100644 --- a/TabletFriend/TabletFriend/UiFactory.cs +++ b/TabletFriend/TabletFriend/UiFactory.cs @@ -262,9 +262,43 @@ Vector2 offset } } - if (button.Action != null) + if (button.ActionRelease == null) { - uiButton.Click += (e, o) => _ = button.Action.Invoke(); + // Default Click Action + if (button.Action != null) + { + uiButton.Click += (e, o) => _ = button.Action.Invoke(); + } + } + else + { // Separate actions for Pointer-Down and Pointer-Up + + // disable long press context menu on button + uiButton.SetValue(Stylus.IsPressAndHoldEnabledProperty, false); + + if (button.Action != null) + { + void downAction(object o, EventArgs e) + { + if (button.LastProcessedEvent == ButtonProcessedEvent.Down) return; // invoke only once + button.LastProcessedEvent = ButtonProcessedEvent.Down; + button.Action.Invoke(); + } + uiButton.TouchDown += downAction; + uiButton.PreviewMouseLeftButtonDown += downAction; + + } + if (button.ActionRelease != null) + { + void releaseAction(object o, EventArgs e) + { + if (button.LastProcessedEvent == ButtonProcessedEvent.Up) return; + button.LastProcessedEvent = ButtonProcessedEvent.Up; + button.ActionRelease.Invoke(); + }; + uiButton.PreviewMouseLeftButtonUp += releaseAction; + uiButton.TouchUp += releaseAction; + } } Canvas.SetTop(uiButton, theme.CellSize * position.Y + theme.Margin + offset.Y); diff --git a/TabletFriend/TabletFriend/files/layouts/sample_layout.yaml b/TabletFriend/TabletFriend/files/layouts/sample_layout.yaml index 7a43936..3958840 100644 --- a/TabletFriend/TabletFriend/files/layouts/sample_layout.yaml +++ b/TabletFriend/TabletFriend/files/layouts/sample_layout.yaml @@ -91,6 +91,18 @@ buttons: icon: apple_keyboard_shift text: shift size: 2,1 + + shift2: + action: hold shift # shift is pressed while the button is pressed + action_release: release shift # for multiple actions use actions_release + style: outlined + icon: apple_keyboard_shift + text: shift (while button is pressed) + size: 2,1 + + spacer2: + spacer: true + size: 2,1 type: actions: # Typing "actions" instead of "action" will make the button chain multiple actions. Any action can be used.