diff --git a/application.go b/application.go
index bd6e910..6b2afc8 100644
--- a/application.go
+++ b/application.go
@@ -73,7 +73,7 @@ func getStartPage(buffer *strings.Builder, params AppParams, addScripts string)
buffer.WriteString(addScripts)
buffer.WriteString(`
-
+
diff --git a/defaultTheme.rui b/defaultTheme.rui
index a88d6f8..c2abd21 100644
--- a/defaultTheme.rui
+++ b/defaultTheme.rui
@@ -110,6 +110,26 @@ theme {
ruiButton:active {
background-color = @ruiButtonActiveColor
},
+ ruiDefaultButton {
+ align = center,
+ padding = "@ruiButtonVerticalPadding, @ruiButtonHorizontalPadding, @ruiButtonVerticalPadding, @ruiButtonHorizontalPadding",
+ margin = @ruiButtonMargin,
+ radius = @ruiButtonRadius,
+ background-color = @ruiButtonColor,
+ text-color = @ruiButtonTextColor,
+ text-weight = bold,
+ border = _{width = 1px, style = solid, color = @ruiButtonTextColor}
+ },
+ ruiDefaultButton:hover {
+ text-color = @ruiTextColor,
+ background-color = @ruiBackgroundColor,
+ },
+ ruiDefaultButton:focus {
+ shadow = _{spread-radius = @ruiButtonHighlightDilation, blur = @ruiButtonHighlightBlur, color = @ruiHighlightColor },
+ },
+ ruiDefaultButton:active {
+ background-color = @ruiButtonActiveColor
+ },
ruiCheckbox {
radius = 2px,
padding = 1px,
diff --git a/keyEvents.go b/keyEvents.go
index e174f73..bf2522b 100644
--- a/keyEvents.go
+++ b/keyEvents.go
@@ -18,6 +18,117 @@ const (
// The additional listener formats:
// func(KeyEvent), func(View), and func().
KeyUpEvent = "key-up-event"
+
+ // AltKey is the mask of the "alt" key
+ AltKey = 1
+ // CtrlKey is the mask of the "ctrl" key
+ CtrlKey = 2
+ // ShiftKey is the mask of the "shift" key
+ ShiftKey = 4
+ // MetaKey is the mask of the "meta" key
+ MetaKey = 8
+
+ KeyA = "KeyA"
+ KeyB = "KeyB"
+ KeyC = "KeyC"
+ KeyD = "KeyD"
+ KeyE = "KeyE"
+ KeyF = "KeyF"
+ KeyG = "KeyG"
+ KeyH = "KeyH"
+ KeyI = "KeyI"
+ KeyJ = "KeyJ"
+ KeyK = "KeyK"
+ KeyL = "KeyL"
+ KeyM = "KeyM"
+ KeyN = "KeyN"
+ KeyO = "KeyO"
+ KeyP = "KeyP"
+ KeyQ = "KeyQ"
+ KeyR = "KeyR"
+ KeyS = "KeyS"
+ KeyT = "KeyT"
+ KeyU = "KeyU"
+ KeyV = "KeyV"
+ KeyW = "KeyW"
+ KeyX = "KeyX"
+ KeyY = "KeyY"
+ KeyZ = "KeyZ"
+ Digit0Key = "Digit0"
+ Digit1Key = "Digit1"
+ Digit2Key = "Digit2"
+ Digit3Key = "Digit3"
+ Digit4Key = "Digit4"
+ Digit5Key = "Digit5"
+ Digit6Key = "Digit6"
+ Digit7Key = "Digit7"
+ Digit8Key = "Digit8"
+ Digit9Key = "Digit9"
+ SpaceKey = "Space"
+ MinusKey = "Minus"
+ EqualKey = "Equal"
+ IntlBackslashKey = "IntlBackslash"
+ BracketLeftKey = "BracketLeft"
+ BracketRightKey = "BracketRight"
+ SemicolonKey = "Semicolon"
+ CommaKey = "Comma"
+ PeriodKey = "Period"
+ QuoteKey = "Quote"
+ BackquoteKey = "Backquote"
+ SlashKey = "Slash"
+ EscapeKey = "Escape"
+ EnterKey = "Enter"
+ TabKey = "Tab"
+ CapsLockKey = "CapsLock"
+ DeleteKey = "Delete"
+ HelpKey = "Help"
+ BackspaceKey = "Backspace"
+ ArrowLeftKey = "ArrowLeft"
+ ArrowRightKey = "ArrowRight"
+ ArrowUpKey = "ArrowUp"
+ ArrowDownKey = "ArrowDown"
+ HomeKey = "Home"
+ EndKey = "End"
+ PageUpKey = "PageUp"
+ PageDownKey = "PageDown"
+ F1Key = "F1"
+ F2Key = "F2"
+ F3Key = "F3"
+ F4Key = "F4"
+ F5Key = "F5"
+ F6Key = "F6"
+ F7Key = "F7"
+ F8Key = "F8"
+ F9Key = "F9"
+ F10Key = "F10"
+ F11Key = "F11"
+ F12Key = "F12"
+ F13Key = "F13"
+ NumLockKey = "NumLock"
+ NumpadKey0 = "Numpad0"
+ NumpadKey1 = "Numpad1"
+ NumpadKey2 = "Numpad2"
+ NumpadKey3 = "Numpad3"
+ NumpadKey4 = "Numpad4"
+ NumpadKey5 = "Numpad5"
+ NumpadKey6 = "Numpad6"
+ NumpadKey7 = "Numpad7"
+ NumpadKey8 = "Numpad8"
+ NumpadKey9 = "Numpad9"
+ NumpadDecimalKey = "NumpadDecimal"
+ NumpadEnterKey = "NumpadEnter"
+ NumpadAddKey = "NumpadAdd"
+ NumpadSubtractKey = "NumpadSubtract"
+ NumpadMultiplyKey = "NumpadMultiply"
+ NumpadDivideKey = "NumpadDivide"
+ ShiftLeftKey = "ShiftLeft"
+ ShiftRightKey = "ShiftRight"
+ ControlLeftKey = "ControlLeft"
+ ControlRightKey = "ControlRight"
+ AltLeftKey = "AltLeft"
+ AltRightKey = "AltRight"
+ MetaLeftKey = "MetaLeft"
+ MetaRightKey = "MetaRight"
)
type KeyEvent struct {
@@ -372,12 +483,6 @@ func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bo
return nil, false
}
-/*
- var keyEvents = map[string]struct{ jsEvent, jsFunc string }{
- KeyDownEvent: {jsEvent: "onkeydown", jsFunc: "keyDownEvent"},
- KeyUpEvent: {jsEvent: "onkeyup", jsFunc: "keyUpEvent"},
- }
-*/
func (view *viewData) setKeyListener(tag string, value any) bool {
listeners, ok := valueToEventListeners[View, KeyEvent](value)
if !ok {
@@ -390,11 +495,13 @@ func (view *viewData) setKeyListener(tag string, value any) bool {
} else {
switch tag {
case KeyDownEvent:
+ view.properties[tag] = listeners
if view.created {
view.session.updateProperty(view.htmlID(), "onkeydown", "keyDownEvent(this, event)")
}
case KeyUpEvent:
+ view.properties[tag] = listeners
if view.created {
view.session.updateProperty(view.htmlID(), "onkeyup", "keyUpEvent(this, event)")
}
@@ -435,6 +542,7 @@ func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag
}
return []func(V, E, E){}
}
+
func getEventListeners[V View, E any](view View, subviewID []string, tag string) []func(V, E) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
diff --git a/popup.go b/popup.go
index fd8316a..ac4ce3d 100644
--- a/popup.go
+++ b/popup.go
@@ -78,11 +78,21 @@ const (
// LeftArrow is value of the popup "arrow" property:
// Arrow on the left side of the pop-up window
LeftArrow = 4
+
+ // NormalButton is the constant of the popup button type: the normal button
+ NormalButton PopupButtonType = 0
+ // DefaultButton is the constant of the popup button type: button that fires when the "Enter" key is pressed
+ DefaultButton PopupButtonType = 1
+ // CancelButton is the constant of the popup button type: button that fires when the "Escape" key is pressed
+ CancelButton PopupButtonType = 2
)
+type PopupButtonType int
+
// PopupButton describes a button that will be placed at the bottom of the window.
type PopupButton struct {
Title string
+ Type PopupButtonType
OnClick func(Popup)
}
@@ -95,11 +105,14 @@ type Popup interface {
onDismiss()
html(buffer *strings.Builder)
viewByHTMLID(id string) View
+ keyEvent(event KeyEvent) bool
}
type popupData struct {
layerView View
view View
+ buttons []PopupButton
+ cancelable bool
dismissListener []func(Popup)
}
@@ -273,6 +286,7 @@ func (arrow *popupArrow) createView(popupView View) View {
func (popup *popupData) init(view View, popupParams Params) {
popup.view = view
+ popup.cancelable = false
session := view.Session()
columnCount := 3
@@ -392,13 +406,15 @@ func (popup *popupData) init(view View, popupParams Params) {
TextSize: Px(20),
Content: "✕",
NotTranslate: true,
- ClickEvent: func(View) {
- popup.Dismiss()
- },
+ ClickEvent: popup.cancel,
})
+ popup.cancelable = true
case OutsideClose:
outsideClose, _ = boolProperty(popupParams, OutsideClose, session)
+ if outsideClose {
+ popup.cancelable = true
+ }
case Buttons:
switch value := value.(type) {
@@ -494,6 +510,7 @@ func (popup *popupData) init(view View, popupParams Params) {
view.Set(Row, viewRow)
popupView.Append(view)
+ popup.buttons = buttons
if buttonCount := len(buttons); buttonCount > 0 {
buttonsAlign, _ := enumProperty(params, ButtonsAlign, session, RightAlign)
popupCellHeight = append(popupCellHeight, AutoSize())
@@ -511,21 +528,31 @@ func (popup *popupData) init(view View, popupParams Params) {
buttonsPanel.Set(Margin, gap)
}
- createButton := func(n int, button PopupButton) Button {
- return NewButton(session, Params{
- Column: n,
- Content: button.Title,
- ClickEvent: func() {
- if button.OnClick != nil {
- button.OnClick(popup)
- } else {
- popup.Dismiss()
- }
- },
- })
- }
for i, button := range buttons {
- buttonsPanel.Append(createButton(i, button))
+ title := button.Title
+ if title == "" && button.Type == CancelButton {
+ title = "Cancel"
+ }
+
+ buttonView := NewButton(session, Params{
+ Column: i,
+ Content: title,
+ })
+
+ if button.OnClick != nil {
+ fn := button.OnClick
+ buttonView.Set(ClickEvent, func() {
+ fn(popup)
+ })
+ } else if button.Type == CancelButton {
+ buttonView.Set(ClickEvent, popup.cancel)
+ }
+
+ if button.Type == DefaultButton {
+ buttonView.Set(Style, "ruiDefaultButton")
+ }
+
+ buttonsPanel.Append(buttonView)
}
popupView.Append(NewGridLayout(session, Params{
@@ -544,11 +571,8 @@ func (popup *popupData) init(view View, popupParams Params) {
}
popup.layerView = NewGridLayout(session, layerParams)
-
if outsideClose {
- popup.layerView.Set(ClickEvent, func(View) {
- popup.Dismiss()
- })
+ popup.layerView.Set(ClickEvent, popup.cancel)
}
}
@@ -560,12 +584,21 @@ func (popup *popupData) Session() Session {
return popup.view.Session()
}
+func (popup *popupData) cancel() {
+ for _, button := range popup.buttons {
+ if button.Type == CancelButton && button.OnClick != nil {
+ button.OnClick(popup)
+ return
+ }
+ }
+ popup.Dismiss()
+}
+
func (popup *popupData) Dismiss() {
popup.Session().popupManager().dismissPopup(popup)
for _, listener := range popup.dismissListener {
listener(popup)
}
- // TODO
}
func (popup *popupData) Show() {
@@ -587,6 +620,27 @@ func (popup *popupData) onDismiss() {
}
}
+func (popup *popupData) keyEvent(event KeyEvent) bool {
+ if !event.AltKey && !event.CtrlKey && !event.ShiftKey && !event.MetaKey {
+ switch strings.ToLower(event.Code) {
+ case "enter":
+ for _, button := range popup.buttons {
+ if button.Type == DefaultButton && button.OnClick != nil {
+ button.OnClick(popup)
+ return true
+ }
+ }
+
+ case "escape":
+ if popup.cancelable {
+ popup.Dismiss()
+ return true
+ }
+ }
+ }
+ return false
+}
+
// NewPopup creates a new Popup
func NewPopup(view View, param Params) Popup {
if view == nil {
diff --git a/session.go b/session.go
index 322c8ec..f1d8924 100644
--- a/session.go
+++ b/session.go
@@ -649,8 +649,15 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
default:
if viewID, ok := data.PropertyValue("id"); ok {
- if view := session.viewByHTMLID(viewID); view != nil {
- view.handleCommand(view, command, data)
+ if viewID != "body" {
+ if view := session.viewByHTMLID(viewID); view != nil {
+ view.handleCommand(view, command, data)
+ }
+ }
+ if command == KeyDownEvent {
+ var event KeyEvent
+ event.init(data)
+ session.hotKey(event)
}
} else {
ErrorLog(`"id" property not found. Event: ` + command)
@@ -658,6 +665,16 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
}
}
+func (session *sessionData) hotKey(event KeyEvent) {
+ popups := session.popupManager().popups
+ if count := len(popups); count > 0 {
+ if popups[count-1].keyEvent(event) {
+ return
+ }
+ }
+ // TODO
+}
+
func (session *sessionData) SetTitle(title string) {
title, _ = session.GetString(title)
session.callFunc("setTitle", title)