Coloured multine browse with icons, sample from the DevCon

This forum is for eXpress++ general support.
Message
Author
User avatar
Tom
Posts: 1205
Joined: Thu Jan 28, 2010 12:59 am
Location: Berlin, Germany

Coloured multine browse with icons, sample from the DevCon

#1 Post by Tom »

The attached sample presented on the 2015 eXpress++ DevCon can be compiled and linked with 1.9 SL1 or 2.0 (use "od.bat" for this if you like). It shows a DCBROWSE that uses ownerdrawing in a subclass, where a text containing (multiple) CR/LF is translated into multiple coloured lines reflecting the color codeblocks and icons added to the cell text are shown below the text. This is not a very generic sample, but it can be used as a base for almost anything you want to paint in a browse cell. Switch the text colors for the links, add boxes or whatever.

If the browse comes up, it will not use ownerdrawing. Click on "Use ownerdrawing", which toggles an iVar of the subclass. The browse is repainted using "InvalidateRect" (a refresh is not needed, since the cell contens remains the same!). Please don't deliver the icons I added. Those are from a library I bought. Thanks.

The screenshot shows what you should see if "Use ownerdrawing" was clicked.
Attachments
DevCon_Ownerdrawing.zip
(51.44 KiB) Downloaded 897 times
screenshot.jpg
screenshot.jpg (111.61 KiB) Viewed 15411 times
Best regards,
Tom

"Did I offend you?"
"No."
"Okay, give me a second chance."

User avatar
obelix
Posts: 48
Joined: Tue Dec 03, 2013 7:44 am
Location: Villingen-Schwenningen, Black Forest, Germany

Re: Coloured multine browse with icons, sample from the DevC

#2 Post by obelix »

Many thanks, Tom
quiet old but still young and unskilled in express++

User avatar
RDalzell
Posts: 205
Joined: Thu Jan 28, 2010 6:57 am
Location: Alsip, Illinois USA

Re: Coloured multine browse with icons, sample from the DevC

#3 Post by RDalzell »

Tom,

Looks great as always and as expected by you.

Now if we could get a glimpse of Bobby's colored tab pages within the printed report the moons would align.

Rick

User avatar
rdonnay
Site Admin
Posts: 4775
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Coloured multine browse with icons, sample from the DevC

#4 Post by rdonnay »

This is a very elegant method of using owner-drawing and it inspired me to create a "generic" owner-drawing method for DC_XbpBrowse() that will use either an array or an object that is put into each cell in DCBROWSECOL. In addition, I would like to "style" it using CSS style rules.

Thanks again, Tom, for donating this sample.
The eXpress train is coming - and it has more cars.

User avatar
SvenVazan
Posts: 12
Joined: Sun May 03, 2015 11:35 am

Re: Coloured multine browse with icons, sample from the DevC

#5 Post by SvenVazan »

Fantastic - thanks Tom.

User avatar
sdenjupol148
Posts: 151
Joined: Thu Jan 28, 2010 10:27 am
Location: NYC

Re: Coloured multine browse with icons, sample from the DevC

#6 Post by sdenjupol148 »

Hey Rick,

I will work on a sample of how it's done.

Bobby :techie-hiding: Drakos

User avatar
RDalzell
Posts: 205
Joined: Thu Jan 28, 2010 6:57 am
Location: Alsip, Illinois USA

Re: Coloured multine browse with icons, sample from the DevC

#7 Post by RDalzell »

Thanks Bobby.

User avatar
rdonnay
Site Admin
Posts: 4775
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Coloured multine browse with icons, sample from the DevC

#8 Post by rdonnay »

Tom -

I have been experimenting with ways to make this more generic.

You can now give it an array of data as an option. This eliminates the need to concatenate everything with CRLF and make a tokenized string.

Also, the fonts can be defined in the DCBROWSE command.

Notice that you only need to use the OWNERDRAW clause on DCBROWSECOL commands.
My next experiment will be to use objects instead of arrays in the DCBROWSECOL DATA clauses.

Code: Select all

#INCLUDE "dcdialog.CH"

#define FONTBOLD      "Bold"    // change to "Fett" for German versions
#define FONTITALIC    "Italic"  // change to "Kursiv" for German versions
#define CRLF          Chr(13)+Chr(10)
#define GENDER_MALE   'agent.ico'
#define GENDER_FEMALE 'she_user.ico'
#define GOOD_VALUE    'online.ico'
#define BAD_VALUE     'offline.ico'

#pragma library("dclipx.lib")
#pragma library("dclip1.lib") // for DC_LoadRdds()

FUNCTION Main()

LOCAL GetList := {}, GetOptions := {}, oBrowse, ;
   aPres := ;
         { { XBP_PP_COL_DA_ROWHEIGHT, 48 }, ;  // rows are 48 pixels high
           { XBP_PP_COL_DA_CELLHEIGHT, 48 } ,;
           { XBP_PP_COL_DA_HILITE_BGCLR, GRA_CLR_PALEGRAY },;   // Hilite BG color
           { XBP_PP_COL_DA_CELLFRAMELAYOUT, XBPFRAME_BOX } ,;
           { XBP_PP_COL_DA_FRAMELAYOUT,     XBPFRAME_NONE} ,;
           { XBP_PP_COL_DA_ROWSEPARATOR, XBPCOL_SEP_LINE },  /* Row Sep  */     ;
           { XBP_PP_COL_DA_COLSEPARATOR, XBPCOL_SEP_LINE } },  /* Col Sep  */     ;
   lOwnerDraw := .F.

DCGETOPTIONS AUTORESIZE

DC_LoadRdds()

DC_BrowseColor( { nil, GRA_CLR_WHITE, nil, GraMakeRGBColor( {214,243,244} ) } )

USE customer VIA 'FOXCDX'

@ 0,0 DCBROWSE oBrowse ALIAS 'CUSTOMER' SIZE 96,25 PRESENTATION aPres FIT ;
      SUBCLASS 'XbpOwnerDrawBrowse()' USEVISUALSTYLE NOHSCROLL ;
      PREEVAL {|o|o:stdFontCompoundName := '10.Tahoma', ;
                  o:boldFontCompoundName := '10.Tahoma '+FONTBOLD, ;
                  o:boldItalicFontCompoundName := '12.Tahoma '+FONTBOLD+' '+FONTITALIC}

DCBROWSECOL DATA {||{CUSTOMER->cust_nmbr}} ;
                    HEADER 'ID' WIDTH 5 PARENT oBrowse ;
                    OWNERDRAW

DCBROWSECOL DATA {||{CUSTOMER->bill_name, ;
                     CUSTOMER->bill_strt, ;
                     Trim(CUSTOMER->bill_city)+' '+CUSTOMER->bill_zip}} ;
                    HEADER 'Name/Address'  WIDTH 25 PARENT oBrowse ;
                    COLOR {||{IF('Software'$CUSTOMER->bill_name,GraMakeRGBColor( { 253, 120, 41 } ),GRA_CLR_DARKGREEN),oBrowse:rowColor()[2]}} ;
                    OWNERDRAW

DCBROWSECOL DATA {||{CUSTOMER->contact, ;
                     CUSTOMER->email, ;
                     '[' + IF(CUSTOMER->cont_gend=='m',GENDER_MALE,GENDER_FEMALE) + ']'}} ;
                    HEADER 'Contact'  WIDTH 15 PARENT oBrowse ;
                    COLOR {||{GRA_CLR_DARKRED,oBrowse:rowColor()[2]}} ;
                    OWNERDRAW

DCBROWSECOL DATA {||{CustInfo(CUSTOMER->cust_val), ;
                     IF(CUSTOMER->cust_val==0,'['+BAD_VALUE+']',Replicate('['+GOOD_VALUE+']',CUSTOMER->cust_val))}} ;
                    HEADER 'Info/Rating'     WIDTH 10 PARENT oBrowse ;
                    COLOR {||{GRA_CLR_DARKBLUE,GRA_CLR_YELLOW}} ;
                    OWNERDRAW

DCBROWSECOL FIELD CUSTOMER->phone  HEADER 'Phone' WIDTH  10 PARENT oBrowse

@ 26,0 DCCHECKBOX lOwnerDraw PROMPT 'Use ownerdrawing' ;
       ACTION {||oBrowse:lOwnerDraw := lOwnerDraw,oBrowse:InvalidateRect()}

DCREAD GUI FIT TITLE 'Ownerdrawing sample' ADDBUTTONS OPTIONS GetOptions

CLOSE ALL
RETURN nil

STATIC FUNCTION CustInfo(nValue)
DO CASE
  CASE nValue == 0
  RETURN 'bad'
  CASE nValue == 1
  RETURN 'ok'
  CASE nValue == 2
  RETURN 'good'
  CASE nValue == 3
  RETURN 'very good'
  CASE nValue == 4
  RETURN 'excellent'
  CASE nValue == 5
  RETURN 'best ever'
ENDCASE
RETURN 'not known'

PROC appsys ; RETURN

* ============

CLASS XbpOwnerDrawBrowse FROM DC_XbpBrowse

PROTECTED:
   VAR oIcon, aLineAttrs, aBoxAttrs, oStdFont, oBoldFont, oBoldItalicFont

EXPORTED:
   VAR lOwnerDraw
   VAR stdFontCompoundName, boldFontCompoundName, boldItalicFontCompoundName

   METHOD CustomDrawCell

   INLINE METHOD destroy
      ::DC_XbpBrowse:destroy()
   RETURN self

   INLINE METHOD init( oParent, oOwner, aPos, aSize, aPP, lVisible, oGetList )

      ::DC_XbpBrowse:init( oParent, oOwner, aPos, aSize, aPP, lVisible, oGetList )
      ::drawMode:= XBP_DRAW_OWNER
      ::oIcon := XbpIcon():New():Create()
      ::lOwnerDraw := .F.
      ::aLineAttrs := ARRAY( GRA_AL_COUNT )
      ::aBoxAttrs  := ARRAY( GRA_AA_COUNT )
      ::aLineAttrs [ GRA_AL_COLOR ] := GRA_CLR_BLACK
      ::aLineAttrs [ GRA_AL_TYPE ]  := GRA_LINETYPE_SOLID
      ::stdFontCompoundName := '10.Tahoma'
      ::boldFontCompoundName := '10.Tahoma '+FONTBOLD
      ::boldItalicFontCompoundName := '10.Tahoma '+FONTBOLD+' '+FONTITALIC

   RETURN self

   INLINE METHOD create( oParent, oOwner, aPos, aSize, aPP, lVisible )
   *******************************************************************
      ::oStdFont := XbpFont():New():Create(::stdFontCompoundName)
      ::oBoldFont := XbpFont():New():Create(::boldFontCompoundName)
      ::oBoldItalicFont := XbpFont():New():Create(::boldItalicFontCompoundName)
      ::DC_XbpBrowse:create( oParent, oOwner, aPos, aSize, aPP, lVisible )

   RETURN self

ENDCLASS

METHOD XbpOwnerDrawBrowse:customDrawCell( oPS, aInfo )
   ******************************************
     LOCAL xData, aPP, nFound, nAlign, nLine, nFgCol := GRA_CLR_BLACK, nBgCol := GRA_CLR_WHITE,;
           aText, aIcons, nIcons, nHeight

    IF !::lOwnerDraw // ownerdrawing is switched off, let the system draw
      RETURN .T.
    ENDIF

    * get column data
    xData:= aInfo[ XBP_DRAWINFO_AREA ]:getCell( aInfo[ XBP_DRAWINFO_ITEM ] )
    IF xData == NIL // empty row
      RETURN .F.
    ENDIF

    * get cell alignment
    aPP := aInfo[ XBP_DRAWINFO_COLUMN ]:presArray
    nFound := AScan(aPP,{|a|Valtype(a[1])=='N'.AND. ;
                     (a[1]==XBPCOL_DA_CELLALIGNMENT .OR. ;
                      a[1]==XBP_PP_COL_DA_CELLALIGNMENT) } )

    IF nFound > 0
      nAlign := aPP[nFound,2]
    ELSE
      nAlign := XBPALIGN_VCENTER
    ENDIF

    * get cell height
    nHeight := Int((aInfo[ XBP_DRAWINFO_RECT, 4 ]-aInfo[ XBP_DRAWINFO_RECT, 2 ])/3)

    * get cell colors
    aInfo[ XBP_DRAWINFO_AREA ]:getCellColor( aInfo[ XBP_DRAWINFO_ITEM ],@nFgCol, @nBgCol )

    IF nFgCol # nil
      oPS:setColor( nFgCol, nBgCol )
    ENDIF

    IF Valtype(xData) # 'A'
      xData := Var2Char(xData)
    ENDIF

    IF Valtype(xData) == 'C' .AND. !CRLF $ xData
      * no line break, just paint the text
      GraCaptionStr( oPS, aInfo[ XBP_DRAWINFO_RECT ], { aInfo[ XBP_DRAWINFO_RECT, 3 ], aInfo[ XBP_DRAWINFO_RECT, 4 ] }, xData, nAlign )
    ELSE
      IF Valtype(xData) == 'C'
        aText := DC_TokenArray(xData,CRLF)
      ELSE
        aText := xData
      ENDIF
      FOR nLine := 1 TO Len(aText)
        IF nLine = 1
          IF BAnd(aInfo[XBP_DRAWINFO_STATE],XBP_DRAWSTATE_SELECTED) = 0 // cell is NOT selected
            oPS:SetFont(::oBoldFont)
          ELSE
            oPS:SetFont(::oBoldItalicFont)
          ENDIF
        ELSE
          oPS:SetFont(::oStdFont)
        ENDIF
        IF Left(aText[nLine],1) == '[' .AND. Right(aText[nLine],1) == ']' // paint at least one icon!
          aIcons := DC_TokenArray(aText[nLine],']') // array of icon filenames will contain at least one
          FOR nIcons := 1 TO Len(aIcons)
            aIcons[nIcons] := StrTran(StrTran(aIcons[nIcons],'[',''),']','') // remove brackets
            ::oIcon:LoadFile(aIcons[nIcons],nHeight,nHeight) // load icon in line height
            ::oIcon:Draw(oPs,{ aInfo[ XBP_DRAWINFO_RECT, 1 ]+(nHeight*(nIcons-1)), aInfo[ XBP_DRAWINFO_RECT, 2 ], aInfo[ XBP_DRAWINFO_RECT, 1 ]+(nHeight*nIcons), aInfo[ XBP_DRAWINFO_RECT, 2 ]+nHeight })
          NEXT
          ELSE
          GraCaptionStr( oPS, { aInfo[ XBP_DRAWINFO_RECT,1 ], aInfo[ XBP_DRAWINFO_RECT,4 ]-(nHeight*(nLine-1))},;
                              { aInfo[ XBP_DRAWINFO_RECT, 3 ], aInfo[ XBP_DRAWINFO_RECT, 4 ]-(nHeight*nLine) }, aText[nLine], nAlign )
        ENDIF
      NEXT
    ENDIF

RETURN .F.
The eXpress train is coming - and it has more cars.

User avatar
rdonnay
Site Admin
Posts: 4775
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Coloured multine browse with icons, sample from the DevC

#9 Post by rdonnay »

I added a new feature to DCBROWSE and DCBROWSECOL that now lets you use a single record object to access the data in a browse. The navigation code blocks of the browse force a DC_DbScatter() of the record into the record object before each row is painted.

Copy the attached _DCXBROW.PRG to \expd20\source\dclipx and DCDIALOG.CH to \expd20\include.
Run BUILD19_SL1.BAT or BUILD20.BAT to rebuild DCLIPX.dll.

Here is the usage:

Code: Select all

oRecord := CUSTOMER->(DC_DbRecord():new())

@ 0,0 DCBROWSE oBrowse ALIAS 'CUSTOMER' SIZE 96,25 PRESENTATION aPres FIT ;
      SUBCLASS 'XbpOwnerDrawBrowse()' USEVISUALSTYLE NOHSCROLL ;
      RECORDOBJECT oRecord ;
      PREEVAL {|o|o:stdFontCompoundName := '10.Tahoma', ;
                  o:boldFontCompoundName := '10.Tahoma '+FONTBOLD, ;
                  o:boldItalicFontCompoundName := '12.Tahoma '+FONTBOLD+' '+FONTITALIC}

DCBROWSECOL DATA {|o|{o:cust_nmbr}} ;
                    HEADER 'ID' WIDTH 5 PARENT oBrowse ;
                    OWNERDRAW

DCBROWSECOL DATA {|o|{o:bill_name, ;
                      o:bill_strt, ;
                      Trim(o:bill_city)+' '+o:bill_zip}} ;
                    HEADER 'Name/Address'  WIDTH 25 PARENT oBrowse ;
                    COLOR {||{IF('Software'$CUSTOMER->bill_name,GraMakeRGBColor( { 253, 120, 41 } ),GRA_CLR_DARKGREEN),oBrowse:rowColor()[2]}} ;
                    OWNERDRAW

DCBROWSECOL DATA {|o|{o:contact, ;
                      o:email, ;
                     '[' + IF(o:cont_gend=='m',GENDER_MALE,GENDER_FEMALE) + ']'}} ;
                    HEADER 'Contact'  WIDTH 15 PARENT oBrowse ;
                    COLOR {||{GRA_CLR_DARKRED,oBrowse:rowColor()[2]}} ;
                    OWNERDRAW

DCBROWSECOL DATA {|o|{CustInfo(o:cust_val), ;
                     IF(o:cust_val==0,'['+BAD_VALUE+']',Replicate('['+GOOD_VALUE+']',o:cust_val))}} ;
                    HEADER 'Info/Rating'     WIDTH 10 PARENT oBrowse ;
                    COLOR {||{GRA_CLR_DARKBLUE,GRA_CLR_YELLOW}} ;
                    OWNERDRAW

DCBROWSECOL DATA {|o|o:phone}  HEADER 'Phone' WIDTH  10 PARENT oBrowse
Attachments
recordobject.zip
(72.75 KiB) Downloaded 843 times
The eXpress train is coming - and it has more cars.

User avatar
rdonnay
Site Admin
Posts: 4775
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: Coloured multine browse with icons, sample from the DevC

#10 Post by rdonnay »

Here is one more fix:
The ::DC_XbpBrowse:init() must be called last to insure that the PREEVAL overrides the font settings.

Code: Select all

   INLINE METHOD init( oParent, oOwner, aPos, aSize, aPP, lVisible, oGetList )

      ::drawMode:= XBP_DRAW_OWNER
      ::oIcon := XbpIcon():New():Create()
      ::lOwnerDraw := .F.
      ::aLineAttrs := ARRAY( GRA_AL_COUNT )
      ::aBoxAttrs  := ARRAY( GRA_AA_COUNT )
      ::aLineAttrs [ GRA_AL_COLOR ] := GRA_CLR_BLACK
      ::aLineAttrs [ GRA_AL_TYPE ]  := GRA_LINETYPE_SOLID
      ::stdFontCompoundName := '10.Tahoma'
      ::boldFontCompoundName := '10.Tahoma '+FONTBOLD
      ::boldItalicFontCompoundName := '10.Tahoma '+FONTBOLD+' '+FONTITALIC
      ::DC_XbpBrowse:init( oParent, oOwner, aPos, aSize, aPP, lVisible, oGetList )

   RETURN self
The eXpress train is coming - and it has more cars.

Post Reply