Page 1 of 1

ComboBox: How to center text?

Posted: Tue Jun 30, 2020 2:06 am
by IdeasVacuum
So I thought it was time to ask another dumb question :shock:

Is it possible to force the item text of a (non editable) ComboBox to be central?
Without requiring 10 kilometers of code or a call-back?

Image

Re: ComboBox: How to center text?

Posted: Tue Jun 30, 2020 3:19 am
by RASHAD
HI
You can optimize for speed by calculating gadw and width2 after creating the gadget directly(It is needed only once)

Code: Select all

Procedure _AddGadgetItem(gad,Text$)
  gadw = GadgetWidth(gad,#PB_Gadget_ActualSize) - GadgetWidth(gad,#PB_Gadget_RequiredSize)
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    width = TextWidth(Text$)
    width2 = TextWidth(" ")
  StopDrawing()
  trim = (gadw - width)/2/width2
  text$ = Space(trim)+text$
  AddGadgetItem(gad, -1,text$)
EndProcedure

LoadFont(0,"Tahoma",12)

If OpenWindow(0, 0, 0, 400, 400, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ComboBoxGadget(0, 10, 10, 250, 24)  
  SetGadgetFont(0,FontID(0))
  _AddGadgetItem(0,"IdeasVacuum")
  _AddGadgetItem(0,"ComboBox item #!")
  _AddGadgetItem(0,"RASHAD")
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
#2 :
Center text Val. & Hal.
You must take care for if the text length exceeds the gadget width

Code: Select all

Procedure _GetGadgetText(gad)
  text$ = LTrim(GetGadgetText(gad)," ")
  Debug text$
EndProcedure

Procedure _AddGadgetItem(gad,Text$)
  gadw = GadgetWidth(gad,#PB_Gadget_ActualSize); - GadgetWidth(gad,#PB_Gadget_RequiredSize)
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    width = TextWidth(Text$)
    width2 = TextWidth(" ")
  StopDrawing()
  trim = (gadw - width)/2/width2
  text$ = Space(trim)+text$
  AddGadgetItem(gad, -1,text$)
EndProcedure

LoadFont(0,"Tahoma",14)

If OpenWindow(0, 0, 0, 400, 400, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ComboBoxGadget(0, 10, 10, 250, 20) 
  SetGadgetFont(0,FontID(0))
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    height = TextHeight("Q")+10
  StopDrawing()  
  ResizeGadget(0,#PB_Ignore,#PB_Ignore,#PB_Ignore,height)
  _AddGadgetItem(0,"IdeasVacuum")
  _AddGadgetItem(0,"ComboBox item #!")
  _AddGadgetItem(0,"RASHAD")
  SetGadgetState(0,1)
 ButtonGadget(1,10,370,80,25,"Get Text")
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            _GetGadgetText(0)
        EndSelect
    EndSelect
  Until Quit = 1
EndIf

Re: ComboBox: How to center text?

Posted: Tue Jun 30, 2020 8:07 am
by Shardik
You may also try the following example which uses Windows API functions and is therefore only usable in Windows. Unfortunately it needs a callback! I have tested it successfully in Windows 10 x64 Version 1809 with PB 5.46 x86 and x64 in ASCII and Unicode mode and with PB 5.71 x86.

Code: Select all

EnableExplicit

Procedure WindowCallback(WindowHandle.I, Message.I, WParam.I, LParam.I)
  Protected Brush.I
  Protected DC.I
  Protected *DrawItem.DRAWITEMSTRUCT
  Protected ItemText.S
  Protected Result.I
  Protected Size.SIZE
  Protected x.I

  Result = #PB_ProcessPureBasicEvents

  If Message = #WM_DRAWITEM
    *DrawItem = LParam

    If *DrawItem\CtlType = #ODT_COMBOBOX
      SetBkMode_(*DrawItem\hDC, #TRANSPARENT)

      If *DrawItem\ItemState & #ODS_FOCUS
        Brush = CreateSolidBrush_($FF901E)
        FillRect_(*DrawItem\hDC, *DrawItem\rcItem, Brush)
        DeleteObject_(Brush)
        SetTextColor_(*DrawItem\hDC, $FFFFFF)
      Else
        FillRect_(*DrawItem\hDC, *DrawItem\rcItem,
          GetStockObject_(#WHITE_BRUSH))
      EndIf

      If *DrawItem\itemID <> -1
        ItemText = Space(128)
        SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT,
          *DrawItem\itemID, @ItemText)

        DC = GetDC_(WindowHandle)
        SelectObject_(DC, GadgetID(WParam))     
        GetTextExtentPoint32_(DC, @ItemText, Len(ItemText), Size)
        ReleaseDC_(GadgetID(WParam), DC)

        x = *DrawItem\rcItem\left +
          (*DrawItem\rcItem\right - *DrawItem\rcItem\left - Size\cx) / 2
        TextOut_(*DrawItem\hDC, x, *DrawItem\rcItem\top, ItemText,
          Len(ItemText))
      EndIf
    EndIf
  EndIf

  ProcedureReturn Result
EndProcedure

Define i.I

OpenWindow(0, 200, 100, 270, 130, "ComboBoxGadget demo")
SetGadgetFont(#PB_Default, LoadFont(0, "Verdana", 10))
ComboBoxGadget(0, 10, 20, 120, 23)
ComboBoxGadget(1, 140, 20, 120, 23, #CBS_OWNERDRAWFIXED | #CBS_HASSTRINGS)
SetWindowCallback(@WindowCallback())

For i = 1 To 5
  AddGadgetItem(0, -1, "Item " + Str(i))
  AddGadgetItem(1, -1, "Item " + Str(i))
Next

SetGadgetState(0, 0)
SetGadgetState(1, 0)
  
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: ComboBox: How to center text?

Posted: Tue Jun 30, 2020 11:42 am
by IdeasVacuum
Thanks for your help Shardik, Rashad.

I have used the API method before (blasted call-back :D).

What I have done recently is to use a monoblock font, verified the text length, packed-out with spaces. Vertical center is done by matching the font height to the gadget height. That method mostly works and of course is a lot "lighter" than API.

I have also DIY'd a combo using a Button and a single column ListIcon for the pop-down, centered with a bit of API:

Code: Select all

Procedure JustifyListCol(iListIconID.i, iCol.i, iFlag.i, iColWidth.i)
;#--------------------------------------------------------------------
;Justify ListIcon and Set Column Width
;Column Flag: 1 = Left, 2 = Right, 3 = Center

Protected lvc.LVCOLUMN

          lvc\Mask = #LVCF_FMT

              Select iFlag

                            Case 1: lvc\fmt = #LVCFMT_LEFT
                            Case 2: lvc\fmt = #LVCFMT_RIGHT
                            Case 3: lvc\fmt = #LVCFMT_CENTER
                           Default: lvc\fmt = #LVCFMT_LEFT
              EndSelect

              SetGadgetItemAttribute(iListIconID, 0, #PB_ListIcon_ColumnWidth,  iColWidth, iCol)
                           SendMessage_(GadgetID(iListIconID), #LVM_SETCOLUMN, iCol, @lvc)
EndProcedure
.... now I'm thinking of another DIY approach, Button with a single column HTML table - the beauty of HTML being that it is so easy to center text, and other effects such as selection highlighting etc.

I always have a generous amount of space around combobox and text buttons because other languages like German and Dutch often have longer words for the equivalent English word.

Re: ComboBox: How to center text?

Posted: Tue Jun 30, 2020 3:31 pm
by IdeasVacuum
Well, experiments complete. For the current project, Rashad's #2 is a clear winner. HTML a close 2nd.

Re: ComboBox: How to center text?

Posted: Tue Jun 30, 2020 5:47 pm
by IdeasVacuum

Code: Select all

Procedure AddComboItem(iWin.i, iGadget.i, sText.s, iFont.i)
;#---------------------------------------------------------
Protected iGadgetW.i = GadgetWidth(iGadget, #PB_Gadget_ActualSize)
Protected iW1.i, iW2.i, iTrim.i

               StartDrawing(WindowOutput(iWin))

                        DrawingFont(iFont)

                        iW1 = TextWidth(sText)
                        iW2 = TextWidth(" ")

               StopDrawing()

               iTrim = ((iGadgetW - iW1) /2 /iW2)
               sText = Space(iTrim) + sText

               AddGadgetItem(iGadget, -1, sText)
EndProcedure

Procedure.i ComboHeight(iWin.i, iGadget.i, iFont.i)
;#-------------------------------------------------
Protected iComboHgt.i
Protected iVertPadding.i

               StartDrawing(WindowOutput(iWin))

                         DrawingFont(iFont)

                         iVertPadding = TextHeight("Q") / 2
                            iComboHgt = TextHeight("Q") + iVertPadding

               StopDrawing()

               ProcedureReturn(iComboHgt)
EndProcedure