////////////////////////////////////////////////////////////////////// // // ALERTBOX.PRG // // Copyright: // Alaska Software, (c) 1997-2002. Alle Rechte vorbehalten. // // Inhalt: // Funktion AlertBox() // // Die Funktion ist geeignet, die beiden Funktionen MsgBox() und // ConfirmBox() zu ersetzen. Sie arbeitet analog zu der Textmodus // Alert() Funktion, jedoch nur in GUI Anwendungen. Die Funktion // AlertBox() stellt ein modales Fenster dar. // // Parameter: // - Das Fenster auf dem die Alert Box zentriert wird. // Der Standardwert ist SetAppWindow(). // // - Message Text wie bei der Alert() Funktion. // Das Semikolon ; wird als Zeilenumbruch verwendet // // - Array mit Strings zur Anzeige der Pushbutton captions // Der Standardwert ist { "Ok" } // // - #define Konstante XBPSTATIC_SYSICON_* zur Anzeige // eines Icons // // - Titel der Alert Box // // Return: // Der Rckgabewert ist die numerische Ordinalposition des // gedrckten Pushbuttons oder Null, wenn keine Auswahl erfolgte. // (ESC Taste oder Fenster wurde geschlossen) // // Bemerkungen: // Wenn kein Icon angezeigt wird, erfolgt die Anzeige von Text // zentriert im Fenster. Ansonsten wird der Text links ausgerichtet // neben dem Icon angezeigt. Die Pushbuttons werden unterhalb des // Textes zentriert. // ////////////////////////////////////////////////////////////////////// #include "Appevent.ch" #include "Common.ch" #include "Font.ch" #include "Gra.ch" #include "Xbp.ch" /* * Maximale Anzahl von Pushbuttons in der Alert Box */ #define MAX_BUTTONS 4 //#define BUTTON_FONT FONT_HELV_SMALL //#define TEXT_FONT FONT_TIMES_MEDIUM //#define TEXT_COLOR GRA_CLR_BLUE #define BUTTON_FONT "10.Arial Fett" #define TEXT_FONT "12.Times New Roman Fett" #define TEXT_COLOR GRA_CLR_DARKRED //////#ifdef DEBUG ////// ///////* ////// * Testumgebung fr die Funktion AlertBox() ////// */ //////PROCEDURE AppSys ////// LOCAL oDlg, oXbp, aPos[2], aSize ////// ////// aSize := SetAppWindow():currentSize() ////// aPos[1] := 0.1 * aSize[1] ////// aPos[2] := 0.1 * aSize[2] ////// aSize[1] *= 0.6 ////// aSize[2] *= 0.6 ////// ////// oDlg := XbpDialog():new( ,, aPos, aSize,, .F. ) ////// oDlg:title := "Ein MDI Fenster" ////// oDlg:close := {|| oDlg:destroy() } ////// oDlg:taskList := .T. ////// oDlg:create() ////// SetAppWindow( oDlg ) ////// ////// oDlg:show() ////// SetAppFocus( oDlg ) //////RETURN ////// ////// ////// ///////* ////// * Child Fenster erzeugen auf dem die AlertBox() zentriert wird ////// */ ////// //////PROCEDURE Main ////// LOCAL oDlg, aPos[2], aSize ////// ////// aSize := SetAppWindow():currentSize() ////// aPos[1] := 0.1 * aSize[1] ////// aPos[2] := 0.1 * aSize[2] ////// aSize[1] *= 0.6 ////// aSize[2] *= 0.6 ////// ////// oDlg := XbpDialog():new( ,, aPos, aSize,, .F. ) ////// oDlg:title := "Child Fenster" ////// oDlg:close := {|| oDlg:destroy() } ////// oDlg:create() ////// ////// oDlg:show() ////// SetAppFocus( oDlg ) ////// ////// AlertBox( , "Datei existiert bereits:;" + ; ////// CurDir() + ";;Was wollen Sie tun?", ; ////// { "šberschreiben", "Abbrechen" } , ; ////// XBPSTATIC_SYSICON_ICONQUESTION , ; ////// "Achtung" ) ////// ////// AlertBox( , "šberschreiben;Anfgen;Abbrechen" , ; ////// { "šberschreiben", "Anfgen", "Abbrechen" }, ; ////// XBPSTATIC_SYSICON_ICONWARNING , ; ////// "Test" ) ////// ////// AlertBox( , "Datei existiert bereits:;" + ; ////// CurDir() + ";Was wollen Sie tun?", ; ////// { "Weiter", "Abbrechen" } , ; ////// XBPSTATIC_SYSICON_ICONQUESTION ) ////// ////// AlertBox( , "Datei existiert bereits:;" + ; ////// CurDir() + ";Was wollen Sie tun?", ; ////// { "Weiter", "Abbrechen" } ) ////// ////// AlertBox( , "Das ist das Ende!",,XBPSTATIC_SYSICON_ICONINFORMATION, "Quit" ) ////// //////RETURN ////// //////#endif // DEBUG /* * Diese Funktion arbeitet wie die Textmodus Alert() Funktion, jedoch nur * fr GUI Applikationen. Die Box wird auf dem angegebenen Fenster zentriert. */ FUNCTION AlertBox( oOwner, cText, aCaption, nSysIcon, cTitle, nFarbe ) //+13.07.2009 18:44 nFarbe LOCAL nEvent , mp1 , mp2, oXbp , lExit LOCAL oParent , oDlg, oPS, oFont, oFocus, oDesktop LOCAL aPushBtn , aPbSize, nPbWidth, nPbDist, nSelect LOCAL oIcon , aIconSize LOCAL aTextSize, aText LOCAL bSelect , bKeyboard LOCAL i, imax , nPos , aPos , aPos1 , aSize , nXsize, nYsize LOCAL nFoc := 1 //+30.06.2009 12:21 Button, der den Focus bekommt LOCAL oFocAlt := SetAppFocus() //+30.06.2009 12:21 Focus im aufrufenden Fenster DEFAULT oOwner TO SetAppWindow(), ; cText TO "" , ; aCaption TO { "~Ok" } , ; cTitle TO " " oDeskTop := AppDesktop() /* * Dialogfenster der Alert Box erzeugen */ oDlg := XbpDialog():new( oDesktop, oOwner, , { 100, 100 }, , .F. ) oDlg:minButton := .F. oDlg:maxButton := .F. oDlg:alwaysontop := .T. oDlg:title := cTitle oDlg:border := XBPDLG_DLGBORDER oDlg:close := {|mp1,mp2,obj| obj:hide(), lExit := .T. } oDlg:create() oDlg:drawingArea:SetFontCompoundName( BUTTON_FONT ) IF "Ein Fehler ist aufgetreten" $ cTitle oDlg:drawingArea:SetColorBG( GRA_CLR_YELLOW ) ELSEIF !Empty(nFarbe) //+ 13.07.2009 18:43 besondere Effekte oDlg:drawingArea:SetColorBG( nFarbe ) ENDIF oDlg:drawingArea:paint := {|| Repaint( aText ) } /* * Icon erzeugen, falls erforderlich */ IF nSysIcon <> NIL oIcon := XbpStatic():new( oDlg:drawingArea, , {0,0}, {30,30} ) oIcon:caption := nSysIcon oIcon:type := XBPSTATIC_TYPE_SYSICON oIcon:create() aIconSize := oIcon:currentSize() ELSE aIconSize := {0,0} ENDIF /* * Presentation Space und Font erzeugen, um die Gr”áe der Pushbuttons * anhand der Font Metrics zu berechnen */ oPS := XbpPresSpace():new():create( oDlg:drawingArea:winDevice() ) oFont := XbpFont():new( oPS ):create( BUTTON_FONT ) oPS:setFont( oFont ) /* * L„ngsten Caption String finden */ imax := Min( MAX_BUTTONS, Len( aCaption ) ) nPos := 0 nXSize := 0 FOR i:=1 TO imax IF Len( aCaption[i] ) > nXsize nXsize := Len( aCaption[i] ) nPos := i ENDIF NEXT /* * Gr”áe der Pushbuttons berechnen */ aPbSize := GraQueryTextBox( oPS, aCaption[nPos] ) aPbSize := { aPbSize[3,1] - aPbSize[2,1] ; , aPbSize[3,2] - aPbSize[2,2] } aPbSize[1] *= 1.2 //1.5 aPbSize[2] *= 2 nPbDist := aPbSize[1] / nXsize nPbWidth := imax * ( aPbSize[1] + nPbDist ) /* * Text zur Anzeige vorbereiten und Gr”áe berechnen */ oFont := XbpFont():new( oPS ):create( TEXT_FONT ) oPS:setFont( oFont ) aTextSize := PrepareText( oPS, @aText, cText ) /* * Gr”áe des Rahmens der Alert Box berechnen (XbpDialog Fenster) */ nXsize := Max( nPbWidth + 20, aTextSize[1] + 20 ) + aIconSize[1] * 1.5 nYsize := aTextSize[2] + 2 * aPbSize[2] + 10 aSize := oDlg:calcFrameRect( { 0, 0, nXsize, nYsize } ) oDlg:setSize( { aSize[3], aSize[4] } ) MoveToOwner( oDlg ) aSize := oDlg:drawingArea:currentSize() IF nSysIcon == NIL /* * Kein Icon - Text im Fenster zentrieren */ aPos := CenterPos( aTextSize, aSize ) ELSE /* * Mit Icon - Text am Icon ausrichten */ aPos := { 0, 0 } aPos[1] := 1.75 * aIconSize[1] ENDIF aPos[2] := 2.25 * aPbSize[2] AdjustPos( aPos, aTextSize, aText, nSysIcon ) /* * Icon oben links am Text positionieren */ IF oIcon <> NIL aPos[1] := aIconSize[1] / 3 aPos[2] := aSize[2] - 1.5 * aIconSize[2] oIcon:setPos( aPos ) ENDIF IF nSysIcon == NIL /* * Kein Icon - Pushbuttons im Fenster zentrieren */ aPos := CenterPos( {nPbWidth, 2 * aPbSize[2]}, aSize ) aPos[1] += ( nPbDist / 2 ) ELSEIF nPbWidth < aTextSize[1] /* * Die Breite aller Pushbuttons ist kleiner als die Textbreite. * Pushbuttons unterhalb vom Text zentrieren. */ aPos := CenterPos( {nPbWidth, 2 * aPbSize[2]}, aTextSize ) aPos[1] += ( 1.5 * aIconSize[1] + ( nPbDist / 2 ) ) ELSE /* * Pushbuttons am Text ausrichten */ aPos[1] := 1.75 * aIconSize[1] ENDIF aPushBtn := Array( imax ) aPos[2] := aPbSize[2] / 2 nSelect := 0 bSelect := {|mp1 ,mp2,obj| nSelect := obj:cargo, lExit := .T. } bKeyBoard := {|nKey,mp2,obj| KeyHandler( nKey, obj, aPushBtn ) } /* * Pushbuttons erzeugen */ FOR i:=1 TO imax aPushBtn[i] := XbpPushButton():new( oDlg:drawingArea,, aPos, aPbSize ) aPushBtn[i]:caption := aCaption[i] IIf(aPushbtn[i]:caption[1]="_",{nFoc:=i,aPushBtn[i]:caption := SubStr(aPushBtn[i]:caption,2)},) //+30.06.2009 12:18 aPushBtn[i]:cargo := i aPushBtn[i]:tabstop := .T. aPushBtn[i]:activate := bSelect aPushBtn[i]:keyboard := bKeyboard IF imax > 1 IF i == 1 aPushBtn[i]:group := XBP_BEGIN_GROUP ELSEIF i == imax aPushBtn[i]:group := XBP_END_GROUP ELSE aPushBtn[i]:group := XBP_WITHIN_GROUP ENDIF ENDIF aPushBtn[i]:create() aPos[1] += ( aPbSize[1] + nPbDist ) NEXT oDlg:setModalState( XBP_DISP_APPMODAL ) oDlg:show() // oFocus := SetAppFocus( aPushBtn[1] ) oFocus := SetAppFocus( aPushBtn[nFoc] ) //+30.06.2009 12:20 lExit := .F. DO WHILE ! lExit nEvent := AppEvent( @mp1, @mp2, @oXbp ) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ IF nEvent == xbeP_Keyboard .AND. mp1 == xbeK_CTRL_F2 //+27.06.2009 18:54 Win_Clip_File(AppDeskTop(),cDatver+"CLIPS\S_"+Left(Time(),2)+SubStr(Time(),4,2)+Right(Time(),2) ) LOOP ENDIF //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ oXbp:handleEvent( nEvent, mp1, mp2 ) ENDDO /* * Aufr„umen: Modalit„t zurcksetzen, grafisches Segment freigeben, * Dialog freigeben und Fokus setzen. */ oDlg:setModalState( XBP_DISP_MODELESS ) GraSegDestroy( oPS, aText[2] ) oDlg:destroy() SetAppFocus( oFocAlt ) //+30.06.2009 12:36 RETURN nSelect /* * Tastenverarbeitung fr Pushbuttons in der Alert Box. * Das Array, das die Pushbuttons enth„lt wird hier nicht gebraucht. * (k”nnte aber von jemand anderem gebraucht werden...) */ STATIC PROCEDURE KeyHandler( nKey, oButton, aPushButtons ) LOCAL i //+06.06.2009 11:10 DO CASE CASE nKey == xbeK_ESC PostAppEvent( xbeP_Close,,, oButton:setParent():setParent() ) CASE nKey > 32 .AND. nKey < 128 //+06.06.2009 11:10 FOR i := 1 TO Len(aPushButtons) IF Upper(aPushButtons[i]:caption[1]) = Upper(Chr(nKey)) PostAppEvent( xbeP_Activate,,, aPushButtons[i] ) ENDIF NEXT CASE nKey == xbeK_RETURN PostAppEvent( xbeP_Activate,,, oButton ) ENDCASE RETURN /* * Gr”áe der Fl„che fr den Anzeigetext berechnen */ STATIC FUNCTION PrepareText( oPS, aText, cText ) LOCAL aAttr, aTextBox, nMaxWidth, nMaxHeight, cLine, aLine aText := {} nMaxWidth := 0 nMaxHeight := 0 aAttr := Array( GRA_AS_COUNT ) aAttr[ GRA_AS_COLOR ] := TEXT_COLOR //GRA_CLR_BLUE oPS:setAttrString( aAttr ) DO WHILE ! Empty( cText ) cLine := CutStr( ";", @cText ) IF Empty( cLine ) cLine := " " ENDIF aLine := { {0,0}, cLine, 0, 0 } aTextBox := GraQueryTextBox( oPS, aLine[2] ) aLine[3] := aTextBox[3,1] - aTextBox[2,1] // Breite des Substrings aLine[4] := aTextBox[3,2] - aTextBox[2,2] // H”he des Substrings nMaxWidth := Max( nMaxWidth, aLine[3] ) nMaxHeight += ( 2 + aLine[4] ) AAdd( aText, aLine ) ENDDO aText := { oPS, 0, aText, aAttr } RETURN { nMaxWidth, nMaxheight } /* * GraStringAt() Positionen fr zentrierte oder links ausgerichtete * Anzeige korrigieren */ STATIC PROCEDURE AdjustPos( aPos, aSize, aText, nSysIcon ) LOCAL aLines := aText[3] LOCAL i, imax := Len( aLines ) IF nSysIcon == NIL /* * Kein Icon - Text zentriert anzeigen */ FOR i := 1 TO imax aLines[i,1,1] := aPos[1] + ( (aSize[1] - aLines[i,3]) / 2 ) aLines[i,1,2] := aPos[2] + aSize[2] - i * ( 2 + aLines[i,4] ) NEXT ELSE /* * Mit Icon - Text links ausgerichtet anzeigen */ FOR i := 1 TO imax aLines[i,1,1] := aPos[1] aLines[i,1,2] := aPos[2] + aSize[2] - i * ( 2 + aLines[i,4] ) NEXT ENDIF RETURN /* * Text mittels grafischem Segment neu zeichnen */ STATIC PROCEDURE Repaint( aText ) LOCAL oPS := aText[1] LOCAL nID := aText[2] LOCAL aLines := aText[3] LOCAL aAttr := aText[4] oPS:setAttrString( aAttr ) IF nID == 0 nID := GraSegOpen( oPS ) AEval( aLines, {|a| GraStringAt( oPS, a[1], a[2] ) } ) GraSegClose( oPS ) aText[2] := nID ENDIF GraSegDraw( oPS, nID ) RETURN /* * Fenster innerhalb Parent-Window verschieben wobei der Bezugspunkt fr * die Koordinaten das Owner-Windows ist. Standardm„áig wird ein * Fenster auf seinem Owner zentriert. */ STATIC PROCEDURE MoveToOwner( oDlg, aPos ) LOCAL oOwner := oDlg:setOwner() LOCAL oParent := oDlg:setParent() LOCAL aPos1, nWidth DEFAULT aPos TO CenterPos( oDlg:currentSize(), oOwner:currentSize() ) DO WHILE oOwner <> oParent aPos1 := oOwner:currentPos() aPos[1] += aPos1[1] aPos[2] += aPos1[2] IF oOwner:isDerivedFrom( "XbpDialog" ) /* * Rahmendicke des Owner Windows bercksichtigen */ nWidth := ( oOwner:currentSize()[1] - oOwner:drawingArea:currentSize()[1] ) / 4 aPos[1] += nWidth aPos[2] += nWidth ENDIF oOwner := oOwner:setParent() ENDDO oDlg:setPos( aPos ) RETURN /* * Zentrierte Position fr ein Fenster aus der Fenstergr”áe und einer * Referenzgr”áe berechnen */ STATIC FUNCTION CenterPos( aSize, aRefSize ) RETURN { Int( (aRefSize[1] - aSize[1]) / 2 ) ; , Int( (aRefSize[2] - aSize[2]) / 2 ) } /* * String an einem Delimiter trennen und Delimiter entfernen */ STATIC FUNCTION CutStr( cCut, cString ) LOCAL cLeftPart, i := At( cCut, cString ) IF i > 0 cLeftPart := Left( cString, i-1 ) cString := SubStr( cString, i+Len(cCut) ) ELSE cLeftPart := cString cString := "" ENDIF RETURN cLeftPart