der neue Code sieht auch gut aus. Du hängt wirklich Zeit und Mühe rein. Danke Dir.
Leider ist mir aufgefallen, dass der 'Zeit-String' per Direkteingabe noch ziemlich zerschossen werden kann.
-> Das war auch der Grund, warum ich zuerst hier nach Vorhandenem nachgefragt hab, bevor ich es "mal schnell"
selber machte. Es ist komplex.
gewagt - per StringGadget und ebenfalls noch ohne die SpinGadget-Pfeil-Buttons.
Hat man die Bedienung raus, vermisst man die Pfeil-Buttons auch kaum.
ein PB-StringGadget zur segmentweisen Zusammenarbeit und zu einem 'üblichen und modernen' Verhalten zu überreden.
(ohne pm/am). (12h verkompliziert das Ganze nochmals deutlich und folgt, falls mal Zeit und Reiz aufkommt und es dann auch gelingen möge!)
angezeigt und editiert werden.
- Ext. Setzen und Auslesen der TimeGadget-Zeit wird im Code gezeigt.
berücksichtigt.
- Die man. Zeiteinstellung arbeitet mit selektierten Segmenten / Blöcken für den Std.-, Min.- oder Sek.-Bereich. Der zu bearbeitende (markierte) Block wird mit den links- / rechts-Pfeiltasten ODER per Mausklick in das gewünschte Segment gewählt.
- Manuelle Einstellung ist möglich per ...
* Direkteingabe der Ziffern im selektierten Segment / Block.
* Schrittweise scrollen des Wertes im selektierten Segment / Block mit auf- / ab-Pfeiltaste oder + und - im Nummerblock.
* Schrittweise scrollen des Wertes im selektierten Segments / Blocks mit dem Maus-Scrollrad.
möglich.
(merke ich grad) habe ich vergessen. -> Funktioniert auf dem laufenden System scheinbar trotzdem?
- Blockweises 'Wrapping' der gescrollten Werte hab ich mir erstmal geschenkt.
-Taste als Notfall-Reset (für den Fall eines zerschossenen und im Programmlauf nicht reparablen Time-Strings). Dieser wird hierbei (wieder) korrekt formatiert auf '12:00:00' in die Tagesmitte gesetzt.
Sicherlich wird noch das eine oder andere quer schießen und hoffe, ich werd' den verbliebenen Problemen dann auch noch Herr.
Linux (4. Posting):
Code: Alles auswählen
; Module/File: TimeGadget_woArrows1.pb
; Function: Gadget to edit time (no am/pm, no up/down Arrow-Buttons) - Linux gtk2/gtk3
; Author: Omi
; Date: Dec. 29, 2018
; Version: 0.13
; Target Compiler: PureBasic 5.46/5.62/5.7
; Target OS: Linux: (X/K/L)ubuntu, Mint, 32/64, Ascii/Uni
;--------------------------------------------------------------
EnableExplicit
; Object constants
#Win_Main = 0
#TimeGadget = 0
#StG2 = 1
#TxtG1 = 2
#TxtG2 = 3
#BtGset = 4
Global.i gEvent, gEventGadget, gQuit
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
;-Linux TimeGadget API ...
ImportC ""
gtk_widget_has_focus(*widget.GtkWidget)
gtk_editable_get_selection_bounds(*entry.GtkEntry, *start_pos, *end_pos)
gtk_entry_set_text(*entry.GtkEntry, text.p-utf8)
gtk_entry_get_text_length(*entry.GtkEntry)
gtk_entry_set_alignment(*entry.GtkEntry, xalign.f)
g_signal_connect(*instance, detailed_signal.p-utf8, *c_handler, *data, destroy= 0, flags= 0) As "g_signal_connect_data"
EndImport
;from #define __GDK_KEYSYMS_H__
#GDK_KEY_Up = $FF52
#GDK_KEY_Down = $FF54
#GDK_KEY_Left = $FF51
#GDK_KEY_Right = $FF53
#GDK_KEY_Tab = $FF09
#GDK_KEY_Escape = $FF1B
#GDK_KEY_KP_Add = $FFAB
#GDK_KEY_KP_Subtract = $FFAD
#GDK_KEY_End = $FF57
#GDK_KEY_Home = $FF50
#GDK_KEY_KP_0 = $FFB0
#GDK_KEY_KP_9 = $FFB9
#GDK_KEY_0 = $0030
#GDK_KEY_9 = $0039
;for Windows compatibility ...
#DTS_TIMEFORMAT = 9
Structure CALLBACKUSERDATA
GadgetNo.i
WindowNo.i
EndStructure
Global NewList GadgetData.CALLBACKUSERDATA()
Procedure TimeGadgetSelectPart(*widget, Range, Colon1, Colon2)
Select Range
Case 1 : gtk_editable_select_region_(*widget, 0, Colon1 - 1)
Case 2 : gtk_editable_select_region_(*widget, Colon1, Colon2 - 1)
Case 3 : gtk_editable_select_region_(*widget, Colon2, -1)
EndSelect
EndProcedure
Procedure TimeGadgetCheckInput(*widget.GtkWidget, EditAction, *user_data.CALLBACKUSERDATA)
;EditAction: 0 = nothing, -1 = scroll-, 1 = scroll+, -2 = lower limit, 2 = upper limit, 3 = number input
Protected.i cPos, I
Protected.i cBlock;: 0= out, 1 = h, 2 = m, 3 = s
Protected.s sPart
Protected.s sTime= PeekS(gtk_entry_get_text_(*widget), -1, #PB_UTF8), sTime_
Protected.i Colon1= FindString(sTime, ":"); Find separators on existing string
Protected.i Colon2= FindString(sTime, ":", Colon1 + 1)
Static.s TimeMax= "23:59:59"
Protected.i hMax= Val(StringField(TimeMax, 1, ":"))
Protected.i mMax= Val(StringField(TimeMax, 2, ":"))
Protected.i sMax= Val(StringField(TimeMax, 3, ":"))
If gtk_widget_has_focus(*widget) And gtk_editable_get_editable_(*widget)
cPos= gtk_editable_get_position_(*widget); Get cursor offset
Select cPos; Specify segment index on existing time string
Case 0 To Colon1-1 : cBlock= 1
Case Colon1 To Colon2-1 : cBlock= 2
Case Colon2 To Len(sTime) : cBlock= 3
EndSelect
If EditAction < 3; All scroll inputs in segment (up/down, +/-, home/end or mouse scrolling) ...
For I= 1 To 3; Reformat segments
sTime_.s+ RSet(Str(Val(StringField(sTime, I, ":"))), 2, "0") + ":"
Next I
sTime = RTrim(sTime_, ":")
Colon1= FindString(sTime, ":"); Correct separators on existing string
Colon2= FindString(sTime, ":", Colon1 + 1)
gtk_entry_set_text (*widget, sTime); Reformat string
TimeGadgetSelectPart(*widget, cBlock, Colon1, Colon2); Set selected segment
sPart= StringField(sTime, cBlock, ":"); Read segments value under cursor
Select EditAction; Calculate new values from scroll inputs
Case 1 : sPart= Str(Val(sPart) + 1)
Case -1 : sPart= Str(Val(sPart) - (Bool(Val(sPart) > 0)))
Case 2 : sPart= StringField(TimeMax, 2, ":"); will be clipped per segment further down ...
Case -2 : sPart= "0"
EndSelect
If cBlock And (Abs(EditAction) = 1 Or Abs(EditAction) = 2); Monitor and restrict the new values in the segments....
Select cBlock
Case 1
If Val(sPart) > hMax : sPart = StringField(TimeMax, cBlock, ":") : EndIf
sTime= RSet(sPart, 2, "0") + ":" + StringField(sTime, 2, ":") + ":" + StringField(sTime, 3, ":")
gtk_editable_select_region_(*widget, 0, Colon1 - 1)
Case 2
If Val(sPart) > mMax : sPart = StringField(TimeMax, cBlock, ":") : EndIf
sTime= StringField(sTime, 1, ":") + ":" + RSet(sPart, 2, "0") + ":" + StringField(sTime, 3, ":")
gtk_editable_select_region_(*widget, Colon1, Colon2 - 1)
Case 3
If Val(sPart) > sMax : sPart = StringField(TimeMax, cBlock, ":") : EndIf
sTime= StringField(sTime, 1, ":") + ":" + StringField(sTime, 2, ":") + ":" + RSet(sPart, 2, "0")
gtk_editable_select_region_(*widget, Colon2, -1)
EndSelect
gtk_entry_set_text (*widget, sTime)
TimeGadgetSelectPart(*widget, cBlock, Colon1, Colon2)
PostEvent(#PB_Event_Gadget, *user_data\WindowNo, *user_data\GadgetNo, #PB_EventType_Change)
EndIf
Else; Value input in segment ...
If cBlock
sPart= StringField(sTime, cBlock, ":"); Read segments value under cursor
Select cBlock; Monitor and restrict the newly entered value in the segments....
Case 1 : If Val(sPart) > hMax : sPart = StringField(TimeMax, cBlock, ":") : sTime= sPart + ":" + StringField(sTime, 2, ":") + ":" + StringField(sTime, 3, ":") : EndIf
Case 2 : If Val(sPart) > mMax : sPart = StringField(TimeMax, cBlock, ":") : sTime= StringField(sTime, 1, ":") + ":" + sPart + ":" + StringField(sTime, 3, ":") : EndIf
Case 3 : If Val(sPart) > sMax : sPart = StringField(TimeMax, cBlock, ":") : sTime= StringField(sTime, 1, ":") + ":" + StringField(sTime, 2, ":") + ":" + sPart : EndIf
EndSelect
gtk_entry_set_text(*widget, sTime); Reformat string
gtk_editable_set_position_(*widget, cPos); Reset cursor position
EndIf
EndIf
EndIf
EndProcedure; TimeGadgetCheckInput
ProcedureC Callback_TimeGadgetLostFocus(*widget.GtkWidget, *event.GdkEventFocus, *user_data.CALLBACKUSERDATA)
gtk_editable_select_region_(*widget, 0, 0)
EndProcedure
ProcedureC Callback_TimeGadgetClickAction(*widget.GtkWidget, *event.GdkEventButton, *user_data.CALLBACKUSERDATA)
; Protected.i ModKey= *event\state & $F; reserved for bigger jumps with Shift modifier
If *event\type = #GDK_BUTTON_RELEASE
TimeGadgetCheckInput(*widget, 0, *user_data)
EndIf
EndProcedure
ProcedureC Callback_TimeGadgetKeyAction(*widget.GtkWidget, *event.GdkEventKey, *user_data.CALLBACKUSERDATA)
Protected.i ModKey= *event\state & $F; (Required 'modifier keys' masked with low nibble)
Protected.i KeyVal= *event\keyval
Protected.i KeyRelease= *event\type
Protected.i Stop= #False
Protected.i EditAction= 0
Protected.i SelStart, SelEnd
gtk_editable_get_selection_bounds(*widget, @SelStart, @SelEnd); neu 0.12 ...
If SelEnd - SelStart > 2; destroy wrong selection
gtk_editable_set_position_(*widget, 1); 'SelEnd' instead of '1' sets cursor to selection end - if so wanted
Stop= #True
EndIf
If KeyRelease = #GDK_KEY_PRESS; push key or button
If ModKey = #Null; no modifier key
Select KeyVal
Case #GDK_KEY_KP_0 To #GDK_KEY_KP_9, #GDK_KEY_0 To #GDK_KEY_9, #GDK_KEY_Tab; Digits from main- and numeric pad
Case #GDK_KEY_Up, #GDK_KEY_KP_Add; Cursor up, NumPad +
TimeGadgetCheckInput(*widget, 1, *user_data)
Stop= #True
Case #GDK_KEY_Down, #GDK_KEY_KP_Subtract; Cursor down, NumPad -
TimeGadgetCheckInput(*widget, -1, *user_data)
Stop= #True
Case #GDK_KEY_End; Upper limit, End
TimeGadgetCheckInput(*widget, 2, *user_data)
Stop= #True
Case #GDK_KEY_Home; Lower limit, Home/Pos1
TimeGadgetCheckInput(*widget, -2, *user_data)
Stop= #True
Default; Stop handler for other keys
Stop= #True
EndSelect
EndIf
EndIf
If KeyRelease = #GDK_KEY_RELEASE; release key or button
If ModKey = #Null; no modifier key
Select KeyVal
Case #GDK_KEY_Escape; <Esc> for emergency reset. Comment out if unwanted
gtk_entry_set_text(*widget, "12:00:00")
Case #GDK_KEY_Left; Cursor left
gtk_editable_set_position_(*widget, SelStart - 1)
Case #GDK_KEY_Right ; Cursor right
gtk_editable_set_position_(*widget, SelEnd + 1)
Case #GDK_KEY_KP_0 To #GDK_KEY_KP_9, #GDK_KEY_0 To #GDK_KEY_9; Digits from main- and numeric pad
EditAction= 3
Default; Stop handler for other keys
Stop= #True
EndSelect
EndIf
If Not Stop
TimeGadgetCheckInput(*widget, EditAction, *user_data)
EndIf
EndIf
ProcedureReturn Stop
EndProcedure
ProcedureC Callback_TimeGadgetScrollBlock(*widget.GtkWidget, *event.GdkEventScroll, *user_data.CALLBACKUSERDATA)
Protected.GdkEventKey *eventKey= gdk_event_new_(#GDK_KEY_RELEASE)
*eventKey\window= gtk_widget_get_root_window_(*widget)
*eventKey\type= #GDK_KEY_PRESS
If gtk_widget_has_focus(*widget)
If *user_data\GadgetNo = #TimeGadget
If *event\direction = #GDK_SCROLL_UP
*eventKey\keyval = #GDK_KEY_Up
Callback_TimeGadgetKeyAction(*widget, *eventKey, *user_data)
ElseIf *event\direction = #GDK_SCROLL_DOWN
*eventKey\keyval = #GDK_KEY_Down
Callback_TimeGadgetKeyAction(*widget, *eventKey, *user_data)
EndIf
EndIf
EndIf
EndProcedure
Procedure TimeGadget(GadgetNo, x, y, w, h, sTime.s, WindowNo, Flags= #Null)
Protected TimePattern= CreateRegularExpression(#PB_Any, "^[0-2]?[0-9]:[0-5]?[0-9]:[0-5]?[0-9]$")
If Not MatchRegularExpression(TimePattern, sTime)
Debug "Preset string is not in time format: '[h]h:[m]m:[s]s'"
Debug "Program ist stopped!"
End
EndIf
If TimePattern : FreeRegularExpression(TimePattern) : EndIf
AddElement(GadgetData())
GadgetData()\GadgetNo= GadgetNo
GadgetData()\WindowNo= WindowNo
Flags & (#PB_String_BorderLess | #PB_String_ReadOnly)
StringGadget(GadgetNo, x, y, w, h, sTime, Flags)
gtk_entry_set_max_length_(GadgetID(GadgetNo), 8)
gtk_entry_set_alignment (GadgetID(GadgetNo), 0.5)
gtk_widget_add_events_ (GadgetID(GadgetNo), #GDK_FOCUS_CHANGE | #GDK_SCROLL_MASK | #GDK_KEY_PRESS_MASK)
g_signal_connect(GadgetID(GadgetNo), "scroll-event", @Callback_TimeGadgetScrollBlock(), @GadgetData())
g_signal_connect(GadgetID(GadgetNo), "button-press-event", @Callback_TimeGadgetClickAction(), @GadgetData())
g_signal_connect(GadgetID(GadgetNo), "button-release-event", @Callback_TimeGadgetClickAction(), @GadgetData())
g_signal_connect(GadgetID(GadgetNo), "key-press-event", @Callback_TimeGadgetKeyAction(), @GadgetData())
g_signal_connect(GadgetID(GadgetNo), "key-release-event", @Callback_TimeGadgetKeyAction(), @GadgetData())
g_signal_connect(GadgetID(GadgetNo), "focus-out-event", @Callback_TimeGadgetLostFocus(), @GadgetData())
EndProcedure
;-... Linux TimeGadget API END
CompilerEndIf
Procedure Create_WinMain()
OpenWindow(#Win_Main, 0, 0, 600, 170, "X 24h-TimeGadget w/o arrows", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(#PB_Any, 5, 5, 590, 22, "Set a time as 'hh:mm:ss' with number keys, <up>/<down> | <+>/<-> keys or mouse scrolling.")
TextGadget(#PB_Any, 5, 28, 590, 22, "Jump to segments min.-/max.- values with <home>/<end>.")
TextGadget(#PB_Any, 5, 51, 590, 22, "Choose editable segment with <left>/<right> keys or mouseclick.")
TextGadget(#PB_Any, 5, 79, 98, 22, "Set time :")
TimeGadget(#TimeGadget, 200, 75, 80, 26, "5:12:45", #Win_Main, #DTS_TIMEFORMAT)
StringGadget(#StG2, 400, 75, 195, 26, "Only for focus tests!")
TextGadget(#PB_Any, 5, 110, 190, 22, "Time set:")
TextGadget(#PB_Any, 5, 135, 190, 22, "Time value set (=seconds):")
TextGadget(#TxtG1, 200, 110, 98, 22, "")
TextGadget(#TxtG2, 200, 135, 98, 22, "")
ButtonGadget(#BtGset, 400, 133, 195, 26, "Set time to 8:00:00")
EndProcedure
Create_WinMain()
Repeat
gEvent= WaitWindowEvent()
Select gEvent
Case #PB_Event_CloseWindow
gQuit= #True
Case #PB_Event_Gadget
gEventGadget= EventGadget()
Select gEventGadget
Case #TimeGadget; read time
SetGadgetText(#TxtG1, GetGadgetText(#TimeGadget))
SetGadgetText(#TxtG2, Str(ParseDate("%hh:%ii:%ss", GetGadgetText(#TimeGadget))))
Case #BtGset; Set TimeGadget to 08:00:00
SetGadgetText(#TimeGadget, FormatDate("%hh:%ii:%ss", 8 * 60 * 60))
PostEvent(#PB_Event_Gadget, #Win_Main, #TimeGadget, #PB_EventType_Change); trigger event for reading
EndSelect
EndSelect
Until gQuit